+++ /dev/null
-The following is a list of the people (in roughly chronological order)
-who've helped out. If anyone's name has been left out (probably), or if
-something has been incorrectly attributed to you (ditto), please let us
-know.
-
-Rich Salz:
- Designed and wrote most of it.
-
-Bob Halley:
- Did the TCL extension.
-
-Christophe Wolfhugel:
- Did the Perl extension and provided several other fixes.
-
-Doug Needham:
- Made nnrpd spool if innd is unavailable. Made nnrpd handle the
- LIST SUBSCRIPTIONS command. Added the rebuilding of control
- connections to innd (SIGUSR1). Got inews to ask the nntp peer for
- moderator info instead of digging it out of a local file.
-
-David Lawrence:
- Did the hooks for PGP verificiation of control messages, added
- actived support for syncing against an active file obtained via
- ftp.
-
-John Stapleton:
- Wrote the poison newsgroup code ('@') for newsfeeds(5). Wrote the
- too-many-connects support ('-X -H -T' flags to innd).
-
-Landon Curt Noll:
- Wrote or co-wrote actsync, nntpsend, shrinkfile, innstat,
- news.daily, tally.control and various man pages. He also was the
- person originally behind the site directory
- configuration/installation process.
-
-John Levine:
- Wrote the '-e' support for expire (expire on shortest time).
-
-Matthias Urlichs:
- Made rnews recognise gzip compression. Made newsfeeds(5) take the
- 'Wp' flag.
-
-Stefan Petri:
- Did the original XBATCH support
-
-Russel Street:
- Did more XBATCH support.
-
-Alan Barrett:
- Did the work-limiter in the select loop to stop streaming from
- killing performance.
-
-Greg Patten:
- Wrote the perl innlog.
-
-Clayton O'Neill:
- Wrote the articles storage API and implemented the timehash
- and regular storage mechanisms with it. He made significant
- modifications to dbz. Integrating innfeed, adding Xref slaving,
- the history cache, the WIP rewrite and various speedups were
- also his doing. Provided the tradindexed overview mechanism.
- Implemented the O flag in newsfeeds. Did a bunch of early work on
- the CVS repository, reorganization of the code, and committing
- patches from others.
-
-Vincent Archer:
- Wrote the initial autoconf scripts.
-
-Forrest J. Cavalier III:
- Provided a lot of bug fixes to 1.5.2. He extended the autoconf
- setup a lot to work with version 2.0, and has provided a lot of
- valuable design input and testing.
-
-Scott Fritchie:
- Wrote the CNFS storage back end.
-
-Fabien Tassin:
- Wrote the innreport package. Implemented the new incoming.conf
- configuration file. Added support for nested profile timers.
-
-Jeremy Nixon:
- Wrote the initial patch for Perl filtering of message IDs on IHAVE
- or CHECK and other patches related to the filtering code.
-
-Karl Kleinpaste:
- Wrote the experimental code for automatically generating keywords
- from incoming articles and putting those keywords in the overview
- for the use of readers.
-
-Dave Hayes:
- Along with some bugfixes, Dave wrote the posting-backoff code for
- nnrpd and the patches to the perl hooks to make the headers
- modifiable.
-
-Joe Greco:
- Wrote the code for measuring the timing of various parts of innd
- and the original actived code.
-
-Sang-yong Suh:
- Provided the fuzzy offset technique to dbz.
-
-Katsuhiro Kondou:
- Provided unified overview, the buffindexed overview method, trash
- storage method, spool translation method, traditional expire
- policy for articles stored through storage API and expireindex, as
- well as hundreds of fixes to clean up defects as changes were
- made. Did a large amount of man page documentation and clean up.
- Has also been a major force in the CVS pool maintenace.
-
-Russell Vincent:
- Expanded inn.conf to make many of the old compile time options
- into run time variables. Numerous bug fixes, small feature
- enhancements and man updates.
-
-Darrell Fuhriman:
- Provided various bug fixes and contributed to the pre-SM CNFS
- development.
-
-Steve Carrie:
- Modified nnrpd to allow detailed client tracking, added the -R
- flag to nnrpd.
-
-Ed Mooring:
- Wrote the first Perl filter callbacks into INN.
-
-Aidan Cully:
- Provided the patches to support the new readers.conf file, and
- wrote the initial user authenticators and resolvers for the
- readers.conf. Provided the patches to support the new
- storage.conf format. Added the option to store articles based on
- the Expires header. Also added the '@' article exclusion code to
- incoming.conf.
-
-Andrew Gierth:
- Contributed improvements to the nnrpd Perl filtering support to
- give access to message bodies and support the DROP and SPOOL
- keywords in filter returns.
-
-Russ Allbery:
- Has done large amounts of clean-up on various pieces of the system
- (especially the documentation and build system), and has helped
- with the CVS pool maintenance. Improved the speed and portability
- of the Perl filter. Rewrote the tradindexed overview method for
- additional robustness. Has done extensive work on libinn,
- breaking out common code from other parts of INN. Lots of other
- fixes to various parts of INN.
-
-Kai Henningsen:
- Implemented the C and U flags in newsfeeds.
-
-Julio Sanchez:
- Wrote the initial libtool support for INN.
-
-Igor Timkin:
- Added min-queue-connection support to innfeed, added outgoing
- volume logging and reporting, and provided a variety of bug
- fixes.
-
-Heath Kehoe:
- Various portability and bug fixes, wrote the ovdb overview
- mechanism that uses Berkeley DB.
-
-Richard Todd:
- Implemented the timecaf and tradspool storage mechanisms, as well
- as many bug fixes and other contributions.
-
-Brian Kantor:
- Wrote the news2mail gateway.
-
-Ilya Etingof:
- Added Python authentication support for nnrpd.
-
-Kenichi OKADA:
- Added preliminary SSL and SASL support for nnrpd.
-
-Olaf Titz:
- Implemented MODE CANCEL support, as well as other patches and bug
- fixes.
-
-Sven Paulus:
- Wrote the support for variables in newsfeeds, contributed various
- other patches and bug fixes.
-
-Krischan Jodies:
- Wrote the SMB authenticator.
-
-Alex Kiernan:
- Wrote the history API, generalized the timer code in innd and
- innfeed into a generic timer library, reworked the NEWNEWS code
- and added a history cache, and contributed various other bug fixes.
-
-Marco d'Itri:
- Wrote gpgverify and overhauled controlchan and its modules. Added
- IPv6 support to innd and inndstart. Contributed a rewritten
- send-uucp. Has also contributed a variety of bug fixes and helped
- with testing.
-
-Jeffrey M. Vinocur:
- Broke parts of the interface with nnrpd for authentication programs
- into a separate library, added various features to readers.conf,
- and wrote various other fixes and feature improvements,
- particularly to nnrpd.
-
-Erik Klavon:
- Significantly reworked nnrpd Perl and Python hooks to be more useful
- in combination with the readers.conf mechanism.
-
-Nathan Lutchansky:
- Added IPv6 support to innfeed, nnrpd, and supporting programs.
-
-Also:
-
-Dave Barr:
- Kept INN alive after Rich Salz didn't have the time any more but
- before the ISC took over. He released 4 unofficial versions that
- provided a good boost to what the ISC started with. Minor work
- on 2.0, mostly with example files and minor code tweaks.
-
-James Brister:
- The chief maintainer of INN from when the ISC took over
- maintenance through the 2.2 release, James is also the original
- author of innfeed and has made fixes, improvements, and feature
- additions all over the code.
-
-Marc Fournier:
- Provided various bug fixes and did a lot of work integrating other
- peoples patches and looking after the CVS pool. Helped
- significantly with the conversion to autoconf. Added the ability
- to set connection limits on a per-host basis.
-
-Joshua M. Thompson
- Wrote the original INSTALL documentation.
-
-The following people helped above and beyond the call of duty with testing
-(provided patches, bug reports, suggestions, documentation improvements,
-and lobbying):
-
-Paul Vixie, Robert Elz, Evan Champion, Robert Keller, Barry Bouwsma,
-markd@mira.net.au, Ollivier Robert, Kevin Jameson, Heiko W. Rupp,
-Fletcher Mattox, Matus Uhlar, Gabor Kiss, Matthias Scheler,
-Richard Michael Todd, Trevor Riley, Alex Bligh, J. Porter Clark,
-Alan Brown, Bert Hyman, Petter Nilsen, Gary E. Miller, Kim Culhan,
-Marc Baudoin, Neal Becker, Bjorn Knutsson, Stephen Marquard,
-Frederick Korz, Benedict Lofstedt, Dan Ellis, Joe Ramey,
-Odd Einar Aurbakken, Jon Lewis, Dan Riley, Peter Eriksson, Ken Lalonde,
-Koichi Mouri, J. Richard Sladkey, Trine Krogstad, Holger Burbach,
-Per Hedeland, Larry Rosenman, Andrew Burgess, Michael Brunnbauer,
-Mohan Kokal, Robert R. Collier, Mark Hittinger, Miquel van Smoorenburg,
-Boyd Lynn Gerber, Yury B. Razbegin, Joe St. Sauver, Heiko Schlichting,
-John P. Speno, Scott Gifford, Steve Parr, Robert Kiessling,
-Francis Swasey, Paul Tomblin, Florian La Roche, Curt Welch,
-Thomas Mike Michlmayr, KIZU Takashi, Michael Hall, Jeff King,
-Edward S. Marshall, Michael Schroeder, George Lindholm, Don Lewis,
-Christopher Masto, Hiroaki Sengoku, Yury July, Yar Tikhiy, Kees Bakker,
-Peter da Silva, Matt McLeod, Ed Korthof, Jan Rychter, Winfried Magerl,
-Andreas Lamrecht, Duane Currie, Ian Dickinson, Bettina Fink,
-Jochen Erwied, Rebecca Ore, Felicia Neff, Antonio Querubin, Bear Giles,
-Christopher P. Lindsey, Winfried Szukalski, Edvard Tuinder,
-Frank McConnell, Ilya Kovalenko, Steve Youngs, Jacek Konieczny,
-Ilya Voronin, Sergey Babitch, WATANABE Katsuhiro, Chris Caputo,
-Thomas Parmelan
+++ /dev/null
-2008-06-29 iulius
-
- * lib/perl.c: Use snprintf instead of asprintf.
-
- * doc/hook-python, doc/pod/hook-python.pod: Use initial capital
- letters for head titles.
-
- * NEWS, doc/pod/news.pod, lib/perl.c: Fixed a hang in Perl hooks on
- (at least) HP/PA since Perl 5.10. On such architectures,
- pthread_mutex_lock() hangs inside perl_parse() if
- PERL_SYS_INIT3() hasn't been called.
-
- Also rewrite "do" and "eval" calls to use perl_eval_pv().
-
-2008-06-25 iulius
-
- * samples/innreport.conf.in: For two sections in innreport.conf
- there is a mismatch between sort function and sorted hash.
-
- Thanks to Alexander Bartolich for this patch.
-
-2008-06-24 iulius
-
- * NEWS, doc/pod/news.pod, scripts/innreport_inn.pm: Fix another
- long-standing bug in innreport which prevented it from correctly
- reporting innfeed log messages.
-
- * scripts/innreport_inn.pm: Suppress a few other nnrpd and
- controlchan notices in innreport.
-
-2008-06-23 iulius
-
- * NEWS, doc/pod/news.pod: Add changelog for innreport.
-
- * NEWS, doc/pod/news.pod: Changelog for INN 2.4.5 :-)
-
- * doc/hook-python: Update the auto-generated documentation for INN
- 2.4.5.
-
- * scripts/innreport_inn.pm: Fix a long-standing bug in innreport
- which prevented it from correctly reporting nnrpd log messages.
-
- * scripts/innreport_inn.pm: Suppress a few warnings in innreport
- (especially from Python hooks and nnrpd). Also backport some
- other improvements made in TRUNK.
-
- * site, site/.cvsignore, site/Makefile: Install nnrpd.py which
- previously was not.
-
- * MANIFEST, samples/nnrpd_access.py, samples/nnrpd_auth.py,
- samples/nnrpd_dynamic.py, site, site/.cvsignore, site/Makefile:
- Update the Python nnrpd filter. New samples for access and
- dynamic hooks.
-
-2008-06-22 iulius
-
- * samples/filter_innd.py: Update the Python innd filter.
-
- * doc/pod/hook-python.pod: Typo (canceled -> cancelled).
-
- * samples/nnrpd_access_wrapper.py, samples/nnrpd_auth_wrapper.py,
- samples/nnrpd_dynamic_wrapper.py: Update old Python wrappers.
-
- * samples/INN.py, samples/nnrpd.py: Update stub Python scripts. Fix
- a compilation problem with INN.py (undefined variable) and add
- missing methods.
-
- * doc/hook-python, doc/man/readers.conf.5, doc/pod/hook-python.pod,
- doc/pod/readers.conf.pod: Update POD documentation for Python
- hooks. It is a complete proof-reading.
-
- * nnrpd/python.c: No need to check the existence of methods not
- used by the hooked script.
-
- * innd/python.c, nnrpd/python.c: Fix an issue with Python exception
- handling.
-
- * nnrpd/python.c: Fix typos.
-
- * nnrpd/python.c: Fix a segfault when one closes and then reopens
- Python in the same process. files and dynamic_file are still
- pointing to the old freed memory and INN blithely tries to write
- to it. Thanks to Russ Allbery for the patch.
-
-2008-06-21 iulius
-
- * innd/python.c: Better be more careful when decrementing the
- reference count for these objects.
-
-2008-06-16 iulius
-
- * doc/external-auth, doc/hook-perl, doc/hook-python,
- doc/man/active.5, doc/man/active.times.5, doc/man/auth_krb5.8,
- doc/man/auth_smb.8, doc/man/ckpasswd.8, doc/man/control.ctl.5,
- doc/man/convdate.1, doc/man/cycbuff.conf.5,
- doc/man/distrib.pats.5, doc/man/domain.8, doc/man/expire.ctl.5,
- doc/man/expireover.8, doc/man/fastrm.1, doc/man/grephistory.1,
- doc/man/ident.8, doc/man/inews.1, doc/man/inn.conf.5,
- doc/man/innconfval.1, doc/man/innd.8, doc/man/inndf.8,
- doc/man/inndstart.8, doc/man/innmail.1, doc/man/innupgrade.8,
- doc/man/libauth.3, doc/man/libinnhist.3, doc/man/list.3,
- doc/man/mailpost.8, doc/man/makehistory.8, doc/man/motd.news.5,
- doc/man/newsfeeds.5, doc/man/ninpaths.8, doc/man/nnrpd.8,
- doc/man/ovdb.5, doc/man/ovdb_init.8, doc/man/ovdb_monitor.8,
- doc/man/ovdb_server.8, doc/man/ovdb_stat.8,
- doc/man/passwd.nntp.5, doc/man/qio.3, doc/man/radius.8,
- doc/man/radius.conf.5, doc/man/rc.news.8, doc/man/readers.conf.5,
- doc/man/sasl.conf.5, doc/man/sendinpaths.8, doc/man/simpleftp.1,
- doc/man/sm.1, doc/man/subscriptions.5, doc/man/tdx-util.8,
- doc/man/tst.3, doc/man/uwildmat.3: Update version number for INN
- 2.4.5 documentation.
-
-2008-06-11 iulius
-
- * support/config.guess, support/config.sub: Update support files
- for autoconf to their last stable version.
-
-2008-06-10 iulius
-
- * innd/python.c: Fix the name of a variable used in Python filters.
-
-2008-06-09 iulius
-
- * innd/python.c: Fix a bug when reloading Python filters. They
- might not be correctly reloaded. They must be reimported before
- being reloaded.
-
- * nnrpd/python.c: Fix a segfault when generating access groups with
- embedded Python filters for nnrpd. Thanks to David Hlacik for the
- bug report.
-
-2008-06-08 iulius
-
- * frontends/pullnews.in: Two minor issues resolved with this patch
- by Geraint Edwards: * an off-by-one error on the limit to the
- amount of articles to get; * when an article is not available, we
- may have redundantly retried that article.
-
-2008-06-07 iulius
-
- * doc/pod/cycbuff.conf.pod, doc/pod/hook-perl.pod,
- doc/pod/hook-python.pod, innd/python.c, samples/filter_innd.pl:
- Fix the use of "ctlinnd reload something 'reason'" in
- documentation.
-
-2008-06-05 iulius
-
- * doc/hook-perl, doc/hook-python, doc/pod/hook-perl.pod,
- doc/pod/hook-python.pod, innd/innd.c, innd/innd.h,
- samples/filter_innd.py: Add access to several new headers within
- Perl and Python hooks for innd. Thanks to Matija Nalis for the
- patch.
-
- Also update the POD documentation and the Python sample.
-
- * doc/man/pullnews.1, doc/pod/pullnews.pod, frontends/pullnews.in:
- A new improved version of pullnews. Great thanks to Geraint A.
- Edwards for all his work. He added no more than 16 flags, fixed
- some bugs and integrated the backupfeed contrib script by Kai
- Henningsen, adding again 6 other flags.
-
- A long-standing but very minor bug in the -g option was
- especially fixed and items from the to-do list implemented.
-
- From TODO:
-
- + reset highwater mark to match server (-w) + reset highwater
- mark to zero (also -w) + add group to config (-G) + drop articles
- with headers matching (or not matching) regexp (-m)
-
- From backupfeed:
-
- + pull only a proportion (factor) of articles (-f) + sleeps
- between articles/groups (-z/-Z) + Path: fake hop insert (-F) +
- NNTP connection timeout (-N) + overall session timeout (-S)
-
- Other new flags/features:
-
- -l logfile log to logfile (rather than /dev/null when rnews'ing!)
- -s host:port add local port option (can use -p already) -t
- retries attempt connect to upstream retries times -T retry_pause
- wait between retries -k checkpt checkpoint the config file every
- checkpt arts -C width when writing the progress bar - use width
- columns -d debug_level self-explanatory -M max_arts only process
- max_arts articles per run -H headers remove these headers from
- articles -Q quietness set how quiet we are -R be a reader -n
- no-op -P paths feed articles depending on number of hops in Path:
-
-2008-05-25 iulius
-
- * control/modules/newgroup.pl: Fix a Perl warning.
-
-2008-05-24 iulius
-
- * nnrpd/tls.c: When an article of a size greater than remaining
- stack is retrieved via SSL, a segmentation fault will occur due
- to the use of alloca(). The below patch uses heap based realloc()
- instead of stack based alloca(), with a static buffer growing as
- needed. It uses realloc() instead of malloc() for performance
- reasons since this function is called frequently. The caveat is
- that the memory is never free()'ed, so if more correct code is
- desired, it should be adjusted.
-
- Thanks to Chris Caputo for this patch.
-
-2008-05-19 iulius
-
- * innd/Makefile, nnrpd/line.c: Implementation of the "alarm signal"
- around SSL_read so that to prevent dead connections from leading
- nnrpd processes to wait forever in SSL_read(). "clienttimeout"
- now also works on SSL connections.
-
- Thanks to Matija Nalis for the patch.
-
- * nnrpd/tls.c: Implementation on systems that support it of
- SO_KEEPALIVE in SSL TCP connections, allowing system detection
- and closing the dead TCP SSL connections automatically after
- system-specified time (usually at least 2 hours as recommended by
- RFC (on Linux, see /proc/sys/net/ipv4/tcp_keepalive_*).
-
- Thanks to Matija Nalis for the patch.
-
-2008-05-18 iulius
-
- * innfeed/host.c: Fix a problem of undefined constant.
-
-2008-05-14 iulius
-
- * innfeed/host.c: Fix a bug in ipAddrs which contained thrice the
- same IPs. Rotating the peer IP addresses was a bit slower than it
- could be.
-
- Thanks, D. Stussy, for having seen that. Miquel van Smoorenburg
- provided the patch.
-
- * Makefile.global.in: Bump the revision number to 2.4.5 (in case it
- is released one day).
-
+++ /dev/null
-Hacking INN
-
- This file is for people who are interested in making modifications to
- INN. Normal users can safely skip reading it. It is intended primarily
- as a guide, resource, and accumulation of tips for maintainers and
- contributors, and secondarily as documentation of some of INN's
- internals.
-
- This is $Revision: 7736 $ dated $Date: 2006-04-15 04:52:06 +0200 (Sat,
- 15 Apr 2006) $.
-
- First of all, if you plan on working on INN source, please start from
- the current development tree. There may be significant changes from the
- previous full release, so starting from development sources will make it
- considerably easier to integrate your work. You can get nightly
- snapshots of the current development source from ftp.isc.org in
- /isc/inn/snapshots (the snapshots named inn-CURRENT-*.tar.gz), or you
- can get the current CVS tree by using CVSup (see "Using CVSup").
-
-Configuring and Portability
-
- All INN code should be written expecting ANSI C and POSIX. There is no
- need to attempt to support pre-ANSI compilers, and ANSI-only features
- such as <stdarg.h>, string concatenation, #elif, and token pasting may
- be used freely. So far as possible, INN is written to attempt to be
- portable to any system new enough that someone is likely to want to run
- a news server on it, but whenever possible this portability should be
- provided by checking for standard behavior in configure and supplying
- replacements for standard functions that are missing.
-
- When there is a conflict between ANSI C and C99, INN code should be
- written expecting C99 and autoconf used to patch up the differences.
-
- Try to avoid using #ifdef and the like in the middle of code as much as
- possible. Instead, try to isolate the necessary portability bits and
- include them in libinn or at least in conditional macros separate from
- the code. Trying to read code littered with conditional compilation
- directives is much more difficult.
-
- The shell script configure at the top level of the source tree is
- generated by autoconf from configure.in, and include/config.h.in is
- generated by autoheader from configure.in and include/acconfig.h. At
- configure time, configure generates include/config.h and several other
- files based on options it was given and what it discovers about the
- target system.
-
- All modifications to configure should instead be made to configure.in.
- Similarly, modifications to include/config.h.in should instead be made
- to include/acconfig.h. The autoconf manual (available using info
- autoconf if you have autoconf and the GNU info utilities installed on
- your system) is a valuable reference when making any modifications.
-
- To regenerate configure, just run "autoconf". To regenerate
- include/config.h.in, run:
-
- autoheader -l include
-
- to tell it where to find acconfig.h. Please don't include patches to
- either configure or include/config.h.in when sending patches to INN;
- instead, note in your patch that those files must be regenerated.
-
- The generated files are checked into the CVS repository so that people
- working on INN don't have to have autoconf on their system, and to make
- packaging easier.
-
- At the time of this writing, autoconf 2.13 is required.
-
- The supporting files for autoconf are in the support subdirectory,
- including the files config.guess and config.sub to determine the system
- name and and ltmain.sh for libtool support. The latter file comes from
- the libtool distribution; the canonical version of the former two are
- available from ftp.gnu.org in /gnu/config. In addition, m4/libtool.m4
- is just a copy of libtool.m4 from the libtool distribution. (Using
- libtool without using automake requires a few odd hacks.) These files
- used to be on a separate vendor branch so that we could make local
- modifications, but local modifications have not been necessary for some
- time. Now, new versions can just be checked in like any other file
- modifications.
-
- INN should not compile with libtool by default, only when requested,
- since otherwise normal compilations are quite slow. (Using libtool is
- not without some cost.) Basic compilation with libtool works fine as of
- this writing, with both static and shared compiles, but the dependencies
- aren't quite right for make -j using libtool.
-
-Documentation
-
- INN's documentation is currently somewhat in a state of flux. The vast
- majority is still in the form of man pages written directly in nroff.
- Some parts of the documentation have been rewritten in POD; that
- documentation can be found in doc/pod. The canonical source for README,
- INSTALL, NEWS, doc/hook-perl, doc/hook-python, and this file are also in
- POD.
-
- If you're modifying some part of INN's documentation and see that it has
- a POD version in doc/pod, it's preferred if you can make the
- modifications to the POD source and then regenerate the derived files.
- For a quick introduction to POD, see the perlpod(1) man page on your
- system (it should be installed if you have Perl installed).
-
- When writing new documentation, write in whatever format you care to; if
- necessary, we can always convert it to POD or whatever else we want to
- use. Having the documentation exist in *some* form is more important
- than what language you write it in. If you really don't have any
- particular preference, there's a slight preference currently for POD.
-
- If you use POD or regenerate POD documentation, please install something
- close to the latest versions of the POD processing utilities to avoid
- changes to the documentation depending on who generated it last. You
- can find the latest version on CPAN (ftp.perl.org or another mirror) in
- modules/by-module/Pod. You'll need PodParser (for versions of Perl
- before 5.6.1; 5.6.1 and later come with a recent enough version) and the
- latest version of podlators. For versions of Perl earlier than 5.005,
- you'll also need File::Spec in modules/by-module/File.
-
- podlators 1.25 or later will build INN's documentation without
- significant changes from the versions that are checked into the
- repository.
-
- There are Makefile rules in doc/pod/Makefile to build all of the
- documentation whose master form is POD; if you add additional
- documentation, please add a rule there as well. Documentation should be
- generated by cd'ing to doc/pod and typing "make file" where "file" is
- the relative path to the documentation file. This will get all of the
- various flags right for pod2text or pod2man.
-
-Error Handling
-
- INN has a set of generic error handling routines that should be used as
- much as possible so that the same syntax can be used for reporting
- errors everywhere in INN. The four basic functions are warn, syswarn,
- die, and sysdie; warn prints or logs a warning, and die does the same
- and then exits the current program. The sys* versions add a colon, a
- space, and the value of strerror(errno) to the end of the message, and
- should be used to report failing system calls.
-
- All of the actual error reporting is done via error handlers, and a
- program can register its own handlers in addition to or instead of the
- default one. The default error handler (error_log_stderr) prints to
- stderr, prepending the value of error_program_name if it's set to
- something other than NULL. Three other error handlers are available,
- error_log_syslog_crit, error_log_syslog_err, and
- error_log_syslog_warning, which log the message to syslog at LOG_CRIT,
- LOG_ERR, or LOG_WARNING priority, respectively.
-
- There is a different set of error handlers for warn/syswarn and
- die/sysdie. To set them, make calls like:
-
- warn_set_handlers(2, error_log_stderr, error_log_syslog_warning);
- die_set_handlers(2, error_log_stderr, error_log_syslog_err);
-
- The first argument is the number of handlers, and the remaining
- arguments are pointers to functions taking an int (the length of the
- formatted message), a const char * (the format), a va_list (the
- arguments), and an int that's 0 if warn or die was called and equal to
- the value of errno if syswarn or sysdie was called. The length of the
- formatted message is obtained by calling vsnprintf with the provided
- format and arguments, and therefore is reliable to use as the size of a
- buffer to malloc to hold the result of formatting the message provided
- that vsnprintf is used to format it (warning: the system vsprintf may
- produce more output under some circumstances, so always use vsnprintf).
-
- The error handler can do anything it wishes; each error handler is
- called in the sequence given. Error handlers shouldn't call warn or die
- unless great caution is taken to prevent infinite recursion. Also be
- aware that sysdie is called if malloc fails in xmalloc, so if the error
- handler needs to allocate memory, it must not use xmalloc or a related
- function to do so and it shouldn't call die to report failure. The
- default syslog handlers report memory allocation failure to stderr and
- exit.
-
- Finally, die and sysdie support an additional handler that's called
- immediate before exiting, takes no arguments, and returns an int which
- is used as the argument for exit. It can do any necessary global
- cleanup, call abort instead to generate a core dump or the like.
-
- The advantage of using this system everywhere in INN is that library
- code can use warn and die to report errors and each calling program can
- set up the error handlers as appropriate to make sure the errors go to
- the right place. The default handler is fine for interactive programs;
- for programs that run from interactive scripts, adding something like:
-
- error_program_name = "program";
-
- to the beginning of main (where program is the name of the program) will
- make it easier to figure out which program the script calls is failing.
- For programs that may also be called non-interactively, like inndstart,
- one may want to set up handlers like:
-
- warn_set_handlers(2, error_log_stderr, error_log_syslog_warning);
- die_set_handlers(2, error_log_stderr, error_log_syslog_err);
-
- Finally, for daemons and other non-interactive programs, one may want to
- do:
-
- warn_set_handlers(1, error_log_syslog_warning);
- die_set_handlers(1, error_log_syslog_err);
-
- to report errors only via syslog. (Note that if you use syslog error
- handlers, the program should call openlog first thing to make sure they
- are logged with the right facility.)
-
- For historical reasons, error messages that are fatal to the news
- subsystem are logged at the LOG_CRIT priority, and therefore die in innd
- should use error_log_syslog_crit.
-
-Test Suite
-
- The test suite for INN is located in the tests directory and is just
- getting started. The test suite consists of a set of programs listed in
- tests/TESTS and the scaffolding in the runtests program.
-
- Adding new tests is very straightforward and very flexible. Just write
- a program that tests some part of INN, put it in a directory under tests
- named after the part of INN it's testing (all the tests so far are in
- lib because they're testing libinn routines), and have it output first a
- line containing the count of test cases in that file, and then for each
- test a line saying "ok n" or "not ok n" where n is the test case number.
- (If a test is skipped for some reason, such as a test of an optional
- feature that wasn't compiled into INN, the test program should output
- "ok n # skip".) Add any rules necessary to build the test to
- tests/Makefile (note that for simplicity it doesn't recurse into
- subdirectories) and make sure it creates an executable ending in .t.
- Then add the name of the test to tests/TESTS, without the .t ending.
-
- One naming convention: to distinguish more easily between e.g.
- lib/error.c (the implementation) and tests/lib/error-t.c (the test
- suite), we add -t to the end of the test file names. So
- tests/lib/error-t.c is the source that compiles into an executable
- tests/lib/error.t which is run by putting a line in tests/TESTS of just
- "lib/error".
-
- Note that tests don't have to be written in C; in fact, lib/xmalloc.t is
- just a shell script (that calls a supporting C program). Tests can be
- written in shell or Perl (but other languages should be avoided because
- someone who wants to run the test suite may not have it) and just have
- to follow the above output conventions.
-
- Additions to the test suite, no matter how simple, are very welcome.
-
-Makefiles
-
- All INN makefiles include Makefile.global at the top level, and only
- that makefile is a configure substitution target. This has the
- disadvantage that configure's normal support for building in a tree
- outside of the source tree doesn't work, but it has the significant
- advantage of making configure run much faster and allowing one to run
- make in any subdirectory and pick up all the definitions and settings
- from the top level configuration.
-
- All INN makefiles should also set $(top) to be the path to the top of
- the build directory (usually relative). This path is used to find
- various programs like fixscript and libtool so that the same macros (set
- in Makefile.global) can be used all over INN.
-
- The format of INN's makefiles is mostly standardized; the best examples
- of the format are probably frontends/Makefile and backends/Makefile, at
- least for directories with lots of separate programs. The ALL variable
- holds all the files that should be generated, EXTRA those additional
- files that were generated by configure, and SOURCES the C source files
- for generating tag information.
-
- There are a set of standard installation commands defined in make
- variables by Makefile.global, and these should be used for all file
- installations. See the comment blocks in Makefile.global.in for
- information on what commands are available and when they should be used.
- There are also variables set for each of the installation directories
- that INN uses, for use in building the list of installed paths to files.
-
- Each subdirectory makefile should have the targets all (the default),
- clean, clobber, install, tags, and profiled. The tags target generates
- vi tags files, and the profiled target generates a profiling version of
- the programs (although this hasn't been tested much recently). These
- rules should be present and empty in those directories where they don't
- apply.
-
- Be sure to test compiling with both static and dynamic libraries and
- make sure that all the libtool support works correctly. All linking
- steps, and the compile steps for all library source, should be done
- through $(LIBTOOL) (which will be set to empty in Makefile.global if
- libtool support isn't desired).
-
-Scripts
-
- INN comes with and installs a large number of different scripts, both
- Bourne shell and Perl, and also comes with support for Tcl scripts
- (although it doesn't come with any). Shell variables containing both
- configure-time information and configuration information from inn.conf
- are set by the innshellvars support libraries, so the only
- system-specific configuration that should have to be done is fixing the
- right path to the interpretor and adding a line to load the appropriate
- innshellvars.
-
- support/fixscript, built by configure, does this. It takes a .in file
- and generates the final script (removing the .in) by fixing the path to
- the interpretor on the first line and replacing the second line,
- whatever it is, with code to load the innshellvars appropriate for that
- interpretor. (If invoked with -i, it just fixes the interpretor path.)
-
- Scripts should use innshellvars (via fixscript) to get the right path
- and the right variables whenever possible, rather than having configure
- substitute values in them. Any values needed at run-time should instead
- be available from all of the different innshellvars.
-
- See the existing scripts for examples of how this is done.
-
-Include Files
-
- Include files relevant to all of INN, or relevant to the two libraries
- built as part of INN (the utility libinn library and the libstorage
- library that contains all storage and overview functions) are found in
- the include directory; other include files relevant only to a portion of
- INN are found in the relevant directory.
-
- Practically all INN source files will start with:
-
- #include "config.h"
- #include "clibrary.h"
-
- The first picks up all defines generated by autoconf and is necessary
- for types that may not be present on all systems (uid_t, pid_t, size_t,
- int32_t, and the like). It therefore should be included before any
- other headers that use those types, as well as to get general
- configuration information.
-
- The second is portably equivalent to:
-
- #include <sys/types.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <string.h>
- #include <unistd.h>
-
- except that it doesn't include headers that are missing on a given
- system, replaces functions not found on the system with the INN
- equivalents, provides macros that INN assumes are available but which
- weren't found, and defines some additional portability things. Even if
- this is more headers than the source file actually needs, it's generally
- better to just include clibrary.h rather than trying to duplicate the
- autoconf-driven hackery that it does to do things portably. The primary
- exception is for source files in lib that only define a single function
- and are used for portability; those may want to include only config.h so
- that they can be easily used in other projects that use autoconf.
- config.h is a fairly standard header name for this purpose.
-
- clibrary.h does also include config.h, but it's somewhat poor form to
- rely on this; it's better to explicitly list the header dependencies for
- the benefit of someone else reading the code.
-
- There are portable wrappers around several header files that have known
- portability traps or that need some fixing up on some platforms. Look
- in include/portable and familiarize yourself with them and use them
- where appropriate.
-
- Another frequently included header file is libinn.h, which among other
- things defines xmalloc(), xrealloc(), xstrdup(), and xcalloc(), which
- are checked versions of the standard memory allocation routines that
- terminate the program if the memory allocation fails. These should
- generally always be used instead of the regular C versions. libinn.h
- also provides various other utility functions that are frequently used.
-
- paths.h includes a wide variety of paths determined at configure time,
- both default paths to various parts of INN and paths to programs. Don't
- just use the default paths, though, if they're also configurable in
- inn.conf; instead, call ReadInnConf() and use the global innconf
- structure.
-
- Other files in include are interfaces to particular bits of INN library
- functionality or are used for other purposes; see the comments in each
- file.
-
- Eventually, the header files will be separated into installed header
- files and uninstalled header files; the latter are those headers that
- are used only for compiling INN and aren't useful for users of INN's
- libraries (such as clibrary.h). All of the installed headers will live
- in include/inn and be installed in a subdirectory named inn in the
- configured include directory. This conversion is still in progress.
-
- When writing header files, remember that C reserves all identifiers
- beginning with two underscores and all identifiers beginning with an
- underscore and a capital letter for the use of the implementation; don't
- use any identifiers with names like that. Additionally, any identifier
- beginning with an underscore and a lower-case letter is reserved in file
- scope, which means that such identifiers can only be used by INN for the
- name of structure members or function arguments in function prototypes.
-
- Try to pay attention to the impact of a header file on the program
- namespace, particularly for installed header files in include/inn. All
- symbols defined by a header file should ideally begin with INN_, inn_,
- or some other unique prefix indicating the subsystem that symbol is part
- of, to avoid accidental conflicts with symbols defined by the program
- that uses that header file.
-
-Coding Style
-
- INN has quite a variety of coding styles intermixed. As with all
- programs, it's preferrable when making minor modifications to keep the
- coding style of the code you're modifying. In INN, that will vary by
- file. (Over time we're trying to standardize on one coding style, so
- changing the region you worked on to fit the general coding style is
- also acceptable).
-
- If you're writing a substantial new piece of code, the prevailing
- "standard" INN coding style appears to be something like the following:
-
- * Write in regular ANSI C whenever possible. Use the normal ANSI and
- POSIX constructs and use autoconf or portability wrappers to fix
- things up beforehand so that the code itself can read like regular
- ANSI or POSIX code. Code should be written so that it works as
- expected on a modern platform and is fixed up with portability tricks
- for older platforms, not the other way around. You may assume an
- ANSI C compiler.
-
- Try to use const wherever appropriate. Don't use register; modern
- compilers will do as good of a job as you will in choosing what to
- put into a register. Don't bother with restrict (at least yet).
-
- * Use string handling functions that take counts for the size of the
- buffer whenever possible. This means using snprintf in preference to
- sprintf and using strlcpy and strlcat in preference to strcpy and
- strcat. Also, use strlcpy and strlcat instead of strncpy and strncat
- unless the behavior of the latter is specifically required, as it is
- much easier to audit uses of the former than the latter. (strlcpy is
- like strncpy except that it always nul-terminates and doesn't fill
- the rest of the buffer with nuls, making it more efficient. strlcat
- is like strncat except that it always nul-terminates and it takes the
- total size of the buffer as its third argument rather than just the
- amount of space left.) All of these functions are guaranteed to be
- available; there are replacements in lib for systems that don't have
- them.
-
- * Avoid #ifdef and friends whenever possible. Particularly avoid using
- them in the middle of code blocks. Try to hide all portability
- preprocessor magic in header files or in portability code in lib.
- When something just has to be done two completely different ways
- depending on the platform or compile options or the like, try to
- abstract that functionality out into a generic function and provide
- two separate implementations using #ifdef; then the main code can
- just call that function.
-
- If you do have to use preprocessor defines, note that if you always
- define them to either 0 or 1 (never use #define without a second
- argument), you can use the preprocessor define in a regular if
- statement rather than using #if or #ifdef. Make use of this instead
- of #ifdef when possible, since that way the compiler will still
- syntax-check the other branch for you and it makes it far easier to
- convert the code to use a run-time check if necessary.
- (Unfortunately, this trick can't be used if one branch may call
- functions unavailable on a particular platform.)
-
- * Avoid uses of fixed-width buffers except in performance-critical
- code, as it's harder to be sure that such code is correct and it
- tends to be less flexible later on. If you need a reusable,
- resizable memory buffer, one is provided in lib/buffer.c.
-
- * Avoid uses of static variables whenever possible, particularly in
- libraries, because it interferes with making the code re-entrant down
- the road and makes it harder to follow what's going on. Similarly,
- avoid using global variables whenever possible, and if they are
- required, try to wrap them into structures that could later be
- changed into arguments to the affected functions.
-
- * Roughly BSD style but with four-space indents. This means no space
- before the parens around function arguments, open brace on the same
- line as if/while/for, and close and open brace on the same line as
- else).
-
- * Introductory comments for functions or files are generally written
- as:
-
- /*
- ** Introductory comment.
- */
-
- Other multiline comments in the source are generally written as:
-
- /* This is a
- multiline comment. */
-
- Comments before functions saying what they do are nice to have. In
- general, the RCS/CVS Id tag is on the first line of each source file
- since it's useful to know when a file was last modified.
-
- * Checks for NULL pointers are preferrably written out explicitly; in
- other words, use:
-
- if (p != NULL)
-
- rather than:
-
- if (p)
-
- to make it clearer what the code is assuming.
-
- * It's better to always put the body of an if statement on a separate
- line, even if it's only a single line. In other words, write:
-
- if (p != NULL)
- return p;
-
- and not:
-
- if (p != NULL) return p;
-
- This is in part for a practical reason: some code coverage analysis
- tools like purecov will count the second example above as a single
- line and won't notice if the condition always evaluates the same way.
-
- * Plain structs make perfectly reasonable abstract data types; it's not
- necessary to typedef the struct to something else. Structs are
- actually very useful for opaque data structures, since you can
- predeclare them and then manipulate pointers to them without ever
- having to know what the contents look like. Please try to avoid
- typedefs except for function pointers or other extremely confusing
- data types, or for data types where we really gain some significant
- data abstraction from hiding the underlying data type. Also avoid
- using the _t suffix for any type; all types ending in _t are reserved
- by POSIX. For typedefs of function pointer types, a suffix of _func
- usually works.
-
- This style point is currently widely violated inside of INN itself;
- INN originally made extensive use of typedefs.
-
- * When noting something that should be improved later, add a comment
- containing "FIXME:" so that one can easily grep for such comments.
-
- INN's indentation style roughly corresponds to that produced by GNU
- indent 2.2.6 with the following options:
-
- -bad -bap -nsob -fca -lc78 -cd41 -cp1 -br -ce -cdw -cli0 -ss -npcs
- -ncs -di1 -nbc -psl -brs -i4 -ci4 -lp -ts8 -nut -ip5 -lps -l78 -bbo
- -hnl
-
- Unfortunately, indent currently doesn't get everything right (it has
- problems with spacing around struct pointer arguments in functions,
- wants to put in a space between a dereference of a function pointer and
- the arguments to the called function, misidentifies some macro calls as
- being type declarations, and fouls up long but simple case statements).
- It would be excellent if someday we could just run all of INN's code
- through indent routinely to enforce a consistant coding style, but
- indent isn't quite ready for that.
-
- For users of emacs cc-mode, use the "bsd" style but with:
-
- (setq c-basic-offset 4)
-
- Finally, if possible, please don't use tabs in source files, since they
- can expand differently in different environments. In particular, please
- try not to use the mix of tabs and spaces that is the default in emacs.
- If you use emacs to edit INN code, you may want to put:
-
- ; Use only spaces when indenting or centering, no tabs.
- (setq-default indent-tabs-mode nil)
-
- in your ~/.emacs file.
-
- Note that this is only a rough guideline and the maintainers aren't
- style nazis; we're more interested in your code contribution than in how
- you write it.
-
-Using CVSup
-
- If you want to get updated INN source more easily or more quickly than
- by downloading nightly snapshots, or if you want to see the full CVS
- history, you may want to use CVSup to download the source. CVSup is a
- client and server designed for replicating CVS repositories between
- sites.
-
- Unfortunately, CVSup is written in Modula-3, so getting a working binary
- can be somewhat difficult. Binaries are available in the *BSD ports
- collection or (for a wide variety of different platforms) available from
- <ftp://ftp.freebsd.org/pub/FreeBSD/CVSup/binaries/> and its mirrors.
- Alternately, you can get a compiler from <http://m3.polymtl.ca/m3/>
- (this is more actively maintained than the DEC Modula-3 compiler) and
- the source from <ftp://ftp.freebsd.org/pub/FreeBSD/CVSup/>.
-
- After you have the CVSup client, you need to have space to download the
- INN repository and space for CVSup to store its data files. You also
- need to write a configuration file (a supfile) for CVSup. The following
- supfile will download the latest versions from the mainline source:
-
- *default host=inn-cvs.isc.org
- *default base=<data-location>
- *default prefix=<download-location>
- *default release=cvs
- *default tag=.
- *default delete use-rel-suffix
- inn
-
- where <data-location> should be a directory where CVSup can put its data
- files and <download-location> is where the downloaded source will go (it
- will be put into a subdirectory named inn). If you want to pull down
- the entire CVS repository instead (warning: this is much larger than
- just the latest versions of the source), delete the "*default tag=."
- line. The best way to download the CVS repository is to download it
- into a portion of a locally-created CVS repository, so that then you can
- perform standard CVS operations (like cvs log) against the downloaded
- repository. Creating your own local CVS repository is outside the scope
- of this document.
-
- Note that only multiplexed mode is supported (this mode should be the
- default).
-
- For more general information on using CVSup, see the FreeBSD page on it
- at <http://www.freebsd.org/handbook/mirrors-cvsup.html>.
-
-Making a Release
-
- This is a checklist that INN maintainers should go through when
- preparing a new release of INN.
-
- 1. If making a major release, branch the source tree and create a new
- STABLE branch tag. This branch will be used for minor releases
- based on that major release and can be done a little while before
- the .0 release of that major release. At the same time as the
- branch is cut, tag the trunk with a STABLE-<version>-branch marker
- tag so that it's easy to refer to the trunk at the time of the
- branch.
-
- 2. Update doc/pod/news.pod and regenerate NEWS. Be more detailed for a
- minor release than for a major release. For a major release, also
- add information on how to upgrade from the last major release,
- including anything special to be aware of. (Minor releases
- shouldn't require any special care when upgrading.)
-
- 3. Make sure that support/config.sub and support/config.guess are the
- latest versions (from <ftp://ftp.gnu.org/gnu/config/>). See the
- instructions in "Configuring and Portability" for details on how to
- update these files.
-
- 4. Make sure that samples/control.ctl is in sync with the master
- version at <ftp://ftp.isc.org/pub/usenet/CONFIG/control.ctl>.
-
- 5. Check out a copy of the release branch. It's currently necessary to
- run configure to generate Makefile.global. Then run "make
- check-manifest". The only differences should be files that are
- generated by configure; if there are any other differences, fix the
- MANIFEST.
-
- 6. Run "make release". Note that you need to have a copy of svn2cl
- from <http://ch.tudelft.nl/~arthur/svn2cl/> to do this; at least
- version 0.7 is required. Start the ChangeLog at the time of the
- previous release. (Eventually, the script will be smart enough to
- do this for you.)
-
- 7. Make the resulting tar file available for testing in a non-listable
- directory on ftp.isc.org and announce its availability on
- inn-workers. Install it on at least one system and make sure that
- system runs fine for at least a few days. This is also a good time
- to send out a draft of the release announcement to inn-workers for
- proof-reading.
-
- 8. Generate a diff between this release and the previous release if
- feasible (always for minor releases, possibly not a good idea due to
- the length of the diff for major releases).
-
- 9. Move the release into the public area of the ftp site and update the
- inn.tar.gz link. Make an MD5 checksum of the release tarball and
- put it on the ftp site as well, and update the inn.tar.gz.md5 link.
- Put the diff up on the ftp site as well. Contact the ISC folks to
- get the release PGP-signed. Possibly move older releases off into
- the OLD directory.
-
- 10. Announce the new release on inn-announce and in news.software.nntp.
-
- 11. Tag the checked-out tree that was used for generating the release
- with a release tag (INN-<version>).
-
- 12. Bump the revision number in Makefile.global.in.
-
-References
-
- Some additional references that may be hard to find and may be of use to
- people working on INN:
-
- <http://www.eyrie.org/~eagle/nntp/>
- The home page for the IETF NNTP standardization effort, including
- links to the IETF NNTP working group archives and copies of the
- latest drafts of the new NNTP standard. The old archived mailing
- list traffic contains a lot of interesting discussion of why NNTP is
- the way it is.
-
- <http://www.imc.org/ietf-usefor/>
- The archives for the USEFOR IETF working group, the working group
- for the RFC 1036 replacement (the format of Usenet articles). Also
- contains a lot of references to other relevant work, such as the RFC
- 822 replacement work.
-
- <http://www.mibsoftware.com/userkt/inn/dev/>
- Forrest Cavalier provides several tools for following INN
- development at this page and elsewhere in the Usenet RKT. Under
- here is a web-accessible checked-out copy of the current INN source
- tree and pointers to how to use CVSup.
-
- <http://www.sas.com/standards/large.file/>
- The standards for large file support on Unix that are being
- generally implemented by vendors. INN sort of partially uses these,
- but a good full audit of the code to check them should really be
- done and there are occasional problems.
-
- <http://v6web.litech.org/ipv6primer/>
- A primer on IPv6 with pointers to the appropriate places for more
- technical details as needed, useful when working on IPv6 support in
- INN.
-
+++ /dev/null
-Welcome to INN 2.4!
-
- Please read this document thoroughly before trying to install INN.
- You'll be glad you did.
-
- If you are upgrading from a major release of INN prior to 2.3, it is
- recommended that you make copies of your old configuration files and use
- them as guides for doing a clean installation and configuration of 2.4.
- Many config files have changed, some have been added, and some have been
- removed. You'll find it much easier to start with a fresh install than
- to try to update your old installation. This is particularly true if
- you're upgrading from a version of INN prior to 2.0.
-
- If you are upgrading from INN 2.3 or later, you may be able to just
- update the binaries, scripts, and man pages by running:
-
- make update
-
- after building INN and then comparing the new sample configuration files
- with your current ones to see if anything has changed. If you take this
- route, the old binaries, scripts, and man pages will be saved with an
- extension of ".OLD" so that you can easily back out. Be sure to
- configure INN with the same options that you used previously if you take
- this approach (in particular, INN compiled with --enable-largefiles
- can't read the data structures written by INN compiled without that
- flag, and vice versa). If you don't remember what options you used but
- you have your old build tree, look at the comments at the beginning of
- config.status.
-
- If you made ckpasswd setuid root so that you could use system passwords,
- you'll have to do that again after make update. (It's much better to
- use PAM instead if you can.)
-
- If you use "make update" to upgrade from INN 2.3, also look at the new
- sample configuration files in samples to see if there are new options of
- interest to you. In particular, control.ctl has been updated and
- inn.conf has various new options.
-
- For more information about recent changes, see NEWS.
-
-Supported Systems
-
- As much as possible, INN is written in portable C and should work on any
- Unix platform. It does, however, make extensive use of mmap(2) and
- certain other constructs that may be poorly or incompletely implemented,
- particularly on very old operating systems.
-
- INN has been confirmed to work on the following operating systems:
-
- AIX 4.3
- FreeBSD 2.2.x and up
- HP-UX 10.20 and up
- Linux 2.x (tested with libc 5.4, glibc 2.0 and up)
- Mac OS X 10.2 and up
- NetBSD 1.6 and up
- OpenBSD 2.8 and up
- SCO 5.0.4 (tested with gcc 2.8.1, cc)
- Solaris 2.5.x and up
- UnixWare 7.1
- UX/4800 R11 and up
-
- If you have gotten INN working on an operating system other than the
- ones listed above, please let us know at <inn-bugs@isc.org>.
-
-Before You Begin
-
- INN requires several other packages be installed in order to be fully
- functional (or in some cases, to work at all):
-
- * In order to build INN, you will need a C compiler that understands
- ANSI C. If you are trying to install INN on an operating system that
- doesn't have an ANSI C compiler (such as SunOS), installing gcc is
- recommended. You can get it from <ftp://ftp.gnu.org/gnu/gcc/> or its
- mirrors. INN is tested with gcc more thoroughly than with any other
- compiler, so even if you have another compiler available, you may wish
- to use gcc instead.
-
- * Currently, in order to build INN, you will need an implementation of
- yacc. GNU bison (from <ftp://ftp.gnu.org/gnu/bison/> or its mirrors)
- will work fine. We hope to remove this requirement in the future.
-
- * INN requires at least Perl 5.004_03 to build and to run several
- subsystems. INN is tested primarily with newer versions of Perl, so
- it's generally recommended that you install the latest stable
- distribution of Perl before compiling INN. For instructions on
- obtaining and installing Perl, see
- <http://www.perl.com/pub/language/info/software.html>. Note that you
- may need to use the same compiler and options (particularly largefile
- support) for Perl and INN.
-
- If you're using a version of Perl prior to 5.6.0, you may need to make
- sure that the Perl versions of your system header files have been
- generated in order for Sys::Syslog to work properly (used by various
- utility programs, including controlchan). To do this, run the
- following two commands:
-
- # cd /usr/include
- # h2ph * sys/*
-
- An even better approach is to install Perl 5.6.1 or later, which have
- a fixed version of Sys::Syslog that doesn't require this (as well as
- many other improvements over earlier versions of Perl).
-
- * The INN Makefiles use the syntax "include FILE", rather than the
- syntax expected by some BSDish systems of ".include <FILE>". If your
- system expects the latter syntax, the recommended solution is to
- install GNU make from <ftp://ftp.gnu.org/make/>. You may have GNU
- make already installed as gmake, in which case using gmake rather than
- make to build INN should be sufficient.
-
- * If you want to enable support for authenticated control messages (this
- is not required, but is highly recommended for systems carrying public
- Usenet hierarchies) then you will need to install some version of PGP.
- The recommended version is GnuPG, since it's actively developed,
- supports OpenPGP, is freely available and free to use for any purpose
- (in the US and elsewhere), and (as of version 1.0.4 at least) supports
- the RSA signatures used by most current control message senders.
-
- Alternately, you can install PGP from <http://www.pgp.com/> or one of
- the international versions of it. Be warned, however, that the
- licensing restrictions on PGP inside the United States are extremely
- unclear; it's possible that if you are installing INN for a company in
- the U.S., even if the news server is not part of the business of that
- company, you would need to purchase a commercial license for PGP. For
- an educational or non-profit organization, this shouldn't be a
- problem.
-
- * If you want to use either the Python embedded hooks, you'll need to
- have a suitable versions of Python installed. See doc/hook-python for
- more information.
-
- * Many of INN's optional features require other packages (primarily
- libraries) be installed. If you wish to use any of these optional
- features, you will need to install those packages first. Here is a
- table of configure options enabling optional features and the software
- and versions you'll need:
-
- --with-perl Perl 5.004_03 or higher, 5.6.1+ recommended
- --with-python Python 1.5.2 or higher
- --with-berkeleydb BerkeleyDB 2.0 or higher, 4.2+ recommended
- --with-openssl OpenSSL 0.9.6 or higher
- --with-sasl SASL 2.x or higher
- --with-kerberos MIT Kerberos v5 1.2.x or higher
-
- If any of these libraries (other than Perl or Python) are built shared
- and installed in locations where your system doesn't search for shared
- libraries by default, you may need to encode the paths to those shared
- libraries in the INN binaries. For more information on shared library
- paths, see:
-
- <http://www.eyrie.org/~eagle/notes/rpath.html>
-
- For most systems, setting the environment variable LD_RUN_PATH to a
- colon-separated list of additional directories in which to look for
- shared libraries before building INN will be sufficient.
-
-Unpacking the Distribution
-
- Released versions of INN are available from ftp.isc.org in /isc/inn.
- New major releases will be announed on <inn-announce@isc.org> (see
- README) when they're made.
-
- If you want more a more cutting-edge version, you can obtain current
- snapshots from from ftp.isc.org in directory /isc/inn/snapshots. These
- are snapshots of the INN CVS tree taken daily; there are two snapshots
- made each night (one of the current development branch, and one of the
- stable branch consisting of bug fixes to the previous major release).
- They are stored in date format; in other words the snapshots from April
- 6th, 2000, would be named inn-CURRENT-20000406.tar.gz and
- inn-STABLE-20000406.tar.gz. Choose the newest file of whichever branch
- you prefer. (Note that the downloading, configuring, and compiling
- steps can be done while logged in as any user.)
-
- The distribution is in gzip compressed tar archive format. To extract
- it, execute:
-
- gunzip -c <inn-src-file> | tar -xf -
-
- Extracting the source distribution will create a directory named
- inn-<version> or inn-<BRANCH>-<date> where the source resides.
-
-Installing INN
-
- Before beginning installation, you should make sure that there is a user
- on your system named "news", and that this user's primary group is set
- to a group called "news". You can change these with the
- --with-news-user and --with-news-group options to configure (see below).
- The home directory of this user should be set to the directory under
- which you wish to install INN (/usr/local/news is the default and is a
- good choice). INN will install itself as this user and group. You can
- change these if you want, but these are the defaults and it's easier to
- stick with them on a new installation.
-
- By default, INN sends reports to the user "usenet". This account isn't
- used for any other purposes. You can change it with the
- --with-news-master option to configure (see below).
-
- WARNING: By default, INN installs various configuration files as
- group-writeable, and in general INN is not hardened from a security
- standpoint against an attack by someone who is already in the news
- group. In general, you should consider membership in the news group as
- equivalent to access to the news account. You should not rely on being
- able to keep anyone with access to the news GID from converting that
- into access to the news UID. The recommended configuration is to have
- the only member of the group "news" be the user "news".
-
- Installing INN so that all of its files are under a single directory
- tree, rather than scattering binaries, libraries, and man pages
- throughout the file system, is strongly recommended. It helps keep
- everything involved in the operation of INN together as a unit and will
- make the installation instructions easier to follow.
-
- As a side note, whenever doing anything with a running news server,
- first log in as this user. That way, you can ensure that all files
- created by any commands you run are created with the right ownership to
- be readable by the server. Particularly avoid doing anything in the
- news spool itself as root, and make sure you fix the ownership of any
- created files if you have to. INN doesn't like files in the news spool
- owned by a user other than the news user. However, since certain
- binaries need to be setuid root, indiscriminate use of "chown news" is
- not the solution. (If you don't like to log in to system accounts,
- careful use of "chmod g+s" on directories and a umask of 002 or 007 may
- suffice.)
-
- INN uses GNU autoconf and a generated configure script to make
- configuration rather painless. Unless you have a rather abnormal setup,
- configure should be able to completely configure INN for your system.
- If you want to change the defaults, you can invoke the configure script
- with one or more command line options. Type:
-
- ./configure --help
-
- for a full list of supported options. Some of the most commonly used
- options are:
-
- --prefix=PATH
- Sets the installation prefix for INN. The default is
- /usr/local/news. All of INN's programs and support files will be
- installed under this directory. This should match the home
- directory of your news user (it will make installation and
- maintenance easier). It is not recommended to set this to /usr; if
- you decide to do that anyway, make sure to point INN's temporary
- directory at a directory that isn't world-writeable (see
- --with-tmp-dir below).
-
- --with-db-dir=PATH
- Sets the prefix for INN database files. The default is PREFIX/db,
- where PREFIX is /usr/local/news unless overridden with the option
- above. The history and active files will be stored in this
- directory, and writes to those files are an appreciable percentage
- of INN's disk activity. The history file can also be quite large
- (requiring up to 2 GB or more during nightly expire), so this is a
- common portion of INN to move to a different file system.
-
- --with-spool-dir=PATH
- Sets the prefix for the news spool (when using any storage method
- other than CNFS) and the overview spool. The default is
- PREFIX/spool. This is another common portion of INN to move to a
- different file system (often /news).
-
- --with-tmp-dir=PATH
- Sets the directory in which INN will create temporary files. This
- should under no circumstances be the same as the system temporary
- directory or otherwise be set to a world-writeable directory, since
- INN doesn't take care to avoid symlink attacks and other security
- problems possible with a world-writeable directory. This directory
- should be reserved for the exclusive use of INN and only writeable
- by the news user. Usage is generally light, so this is unlikely to
- need a separate partition.
-
- It's also possible to set the paths for most other sections of the
- INN installation independently; see "./configure --help" and look
- for the --with-*-dir=PATH options.
-
- --enable-largefiles
- Enables large file support. This is not enabled by default, even on
- platforms that support it, because it changes the format of INN's
- on-disk databases (making it difficult to upgrade an earlier INN
- installation) and can significantly increase the size of some of the
- history database files. Large file support is not necessary unless
- your history database is so large that it exceeds 2 GB or you want
- to use CNFS buffers larger than 2 GB.
-
- The history, tradindexed and buffindexed overview, CNFS, and timecaf
- databases written by an INN built with this option are incompatible
- with those written by an INN without this option.
-
- --enable-tagged-hash
- Use tagged hash table for the history database. The tagged hash
- format uses much less memory but is somewhat slower. This option is
- recommended if you have less than 256 MB of RAM on your news server.
- If you install INN without tagged hash (the default) and expire
- takes an excessive amount of time, you should make sure the RAM in
- your system satisfies the following formula:
-
- ram > 10 * tablesize
-
- ram: Amount of system RAM (in bytes)
- tablesize: 3rd field on the 1st line of history.dir (bytes)
-
- If you don't have at least that much RAM, try rebuilding INN with
- tagged hash enabled.
-
- NOTE: --enable-largefiles cannot be used with --enable-tagged-hash.
-
- --with-perl
- Enables support for embedded Perl, allowing you to install filter
- scripts written in Perl. Highly recommended, because many really
- good spam filters are written in Perl. See doc/hook-perl for all
- the details.
-
- Even if you do not use this option, INN still requires Perl as
- mentioned above.
-
- --with-python
- Enables support for Python, allowing you to install filter and
- authentication scripts written in Python. You will need Python
- 1.5.2 or later installed on your system to enable this option. See
- doc/hook-python for all the details. Note that there is an
- incompatibility between INN and Python 2.0 when Python is compiled
- with cycle garbage collection; this problem was reported fixed in
- Python 2.1a1.
-
- --with-innd-port=PORT
- By default, inndstart(8) refuses to bind to any port under 1024
- other than 119 and 433 for security reasons (to prevent attacks on
- rsh(1)-based commands and replacing standard system daemons). If
- you want to run innd on a different port under 1024, you'll need to
- tell configure what port you intend to use. (You'll also still need
- to set the port number in inn.conf or give it to inndstart on the
- command line.)
-
- --with-syslog-facility=FACILITY
- Specifies the syslog facility that INN programs should log to. The
- default is LOG_NEWS unless configure detects that your system
- doesn't understand that facility, in which case it uses LOG_LOCAL1.
- This flag overrides the automatic detection. Be sure to specify a
- facility not used by anything else on your system (one of LOG_LOCAL0
- through LOG_LOCAL7, for example).
-
- --enable-libtool
- INN has optional support for libtool to generate shared versions of
- INN's libraries. This can significantly decrease the size of the
- various binaries that come with a complete INN installation. You
- can also choose to use libtool even when only building static
- libraries; a libtool build may be somewhat more portable on weird
- systems. libtool builds aren't the default because they take
- somewhat longer. See "./configure --help" for the various available
- options related to libtool builds.
-
- Please note that INN's shared library interface is not stable and
- may change drastically in future releases. For this reason, it's
- also not properly versioned and won't be until some degree of
- stability is guaranteed, and the relevant header files are not
- installed. Only INN should use INN's shared libraries, and you
- should only use the shared libraries corresponding to the version of
- INN that you're installing.
-
- Also, when updating an existing version of INN, INN tries to save
- backup copies of all files so that you can revert to the previous
- installed version. Unfortunately, when using shared libraries, this
- confuses ldconfig on some systems (such as Linux) and the symbolic
- links for the libraries may point to the .OLD versions. If this
- happens, you can either fix the links by hand or remove the .OLD
- versions and re-run ldconfig.
-
- --enable-uucp-rnews
- If this option is given to configure, rnews will be installed setuid
- news, owned by group uucp, and mode 4550. This will allow the UUCP
- subsystem to run rnews to process UUCP batches of news articles.
- Prior to INN 2.3, installing rnews setuid news was standard; since
- most sites no longer use UUCP, it is no longer the default as of INN
- 2.3 and must be requested at configure time. You probably don't
- want to use this option unless your server accepts UUCP news
- batches.
-
- --enable-setgid-inews
- If this option is given to configure, inews will be installed setgid
- news and world-executable so that non-privileged users on the news
- server machine can use inews to post articles locally (somewhat
- faster than opening a new network connection). For standalone news
- servers, by far the most common configuration now, there's no need
- to use this option; even if you have regular login accounts on your
- news server, INN's inews can post fine via a network connection to
- your running news server and doesn't need to use the local socket
- (which is what setgid enables it to do). Installing inews setgid
- was the default prior to INN 2.3.
-
- --with-berkeleydb=PATH
- Enables support for Berkeley DB (2.x or 3.x), which means that it
- will then be possible to use the ovdb overview method if you wish.
- Enabling this configure option doesn't mean you'll be required to
- use ovdb, but it does require that Berkeley DB be installed on your
- system (including the header files, not just the runtime libraries).
- If a path is given, it sets the installed directory of Berkeley DB
- (configure will search for it in some standard locations, but if you
- have it installed elsewhere, you may need this option).
-
- --with-openssl=PATH
- Enables support for SSL for news reading, which means it will be
- possible to have SSL or TLS encrypted NNTP connections between your
- server and newsreaders. This option requires OpenSSL be installed
- on your system (including the header files, not just the runtime
- libraries). If a path is given, it sets the installed directory of
- OpenSSL. After compiling and installing INN with this option,
- you'll still need to make a certificate and private key to use SSL.
- See below for details on how to do that.
-
- --enable-ipv6
- Enables support for IPv6 in innd, innfeed, nnrpd, and several of the
- supporting programs. This option should be considered developmental
- at present. For more information see doc/IPv6-info (and if you have
- any particularly good or bad news to report, please let us know at
- <inn-bugs@isc.org>).
-
- For the most common installation, a standalone news server, a suggested
- set of options is:
-
- ./configure --with-perl
-
- provided that you have the necessary version of Perl installed.
- (Compiling with an embedded Perl interpretor will allow you to use one
- of the available excellent spam filters if you so choose.)
-
- If the configure program runs successfully, then you are ready to build
- the distribution. From the root of the INN source tree, type:
-
- make
-
- At this point you can step away from the computer for a little while and
- have a quick snack while INN compiles. On a decently fast system it
- should only take five or ten minutes at the most to build.
-
- Once the build has completed successfully, you are ready to install INN
- into its final home. Type:
-
- make install
-
- You will need to run this command as root so that INN can create the
- directories it needs, change ownerships (if you did not compile as the
- news user) and install a couple of setuid wrapper programs needed to
- raise resource limits and allow innd to bind to ports under 1024. This
- step will install INN under the install directory (/usr/local/news,
- unless you specified something else to the configure script).
-
- If you are configuring SSL support for newsreaders, you must make a
- certificate and private key at least once. Type:
-
- make cert
-
- as root in order to do this.
-
- You are now ready for the really fun part: configuring your copy of
- INN!
-
-Choosing an Article Storage Format
-
- The first thing to decide is how INN should store articles on your
- system. There are four different methods for you to choose from, each
- of which has its own advantages and disadvantages. INN can support all
- four at the same time, so you can store certain newsgroups in one method
- and other newsgroups in another method.
-
- The supported storage formats are:
-
- tradspool
- This is the storage method used by all versions of INN previous to
- 2.0. Articles are stored as individual text files whose names are
- the same as the article number. The articles are divided up into
- directories based on the newsgroup name. For example, article 12345
- in news.software.nntp would be stored as news/software/nntp/12345
- relative to the root of the article spool.
-
- Advantages: Widely used and well-understood storage mechanism, can
- read article spools written by older versions of INN, compatible
- with all third-party INN add-ons, provides easy and direct access to
- the articles stored on your server and makes writing programs that
- fiddle with the news spool very easy, and gives you fine control
- over article retention times.
-
- Disadvantages: Takes a very fast file system and I/O system to keep
- up with current Usenet traffic volumes due to file system overhead.
- Groups with heavy traffic tend to create a bottleneck because of
- inefficiencies in storing large numbers of article files in a single
- directory. Requires a nightly expire program to delete old articles
- out of the news spool, a process that can slow down the server for
- several hours or more.
-
- timehash
- Articles are stored as individual files as in tradspool, but are
- divided into directories based on the arrival time to ensure that no
- single directory contains so many files as to cause a bottleneck.
-
- Advantages: Heavy traffic groups do not cause bottlenecks, and fine
- control of article retention time is still possible.
-
- Disadvantages: The ability to easily find all articles in a given
- newsgroup and manually fiddle with the article spool is lost, and
- INN still suffers from speed degredation due to file system overhead
- (creating and deleting individual files is a slow operation).
-
- timecaf
- Similar to timehash, articles are stored by arrival time, but
- instead of writing a separate file for each article, multiple
- articles are put in the same file.
-
- Advantages: Roughly four times faster than timehash for article
- writes, since much of the file system overhead is bypassed, while
- still retaining the same fine control over article retention time.
-
- Disadvantages: Even worse than timehash, and similar to cnfs
- (below), using this method means giving up all but the most careful
- manually fiddling with your article spool. As one of the newer and
- least widely used storage types, timecaf has not been as thoroughly
- tested as the other methods.
-
- cnfs
- CNFS stores articles sequentially in pre-configured buffer files.
- When the end of the buffer is reached, new articles are stored from
- the beginning of the buffer, overwriting older articles.
-
- Advantages: Blazingly fast because no file creations or deletions
- are necessary to store an article. Unlike all other storage
- methods, does not require manual article expiration; old articles
- are deleted to make room for new ones when the buffers get too full.
- Also, with CNFS your server will never throttle itself due to a full
- spool disk, and groups are restricted to just the buffer files you
- give them so that they can never use more than the amount of disk
- space you allocate to them.
-
- Disadvantages: Article retention times are more difficult to
- control because old articles are overwritten automatically. Attacks
- on Usenet, such as flooding or massive amounts of spam, can result
- in wanted articles expiring much faster than you intended (with no
- warning).
-
- Some general recommendations: If you are installing a transit news
- server (one that just accepts news and sends it out again to other
- servers and doesn't support any readers), use CNFS exclusively and don't
- worry about any of the other storage methods. Otherwise, put
- high-volume groups and groups whose articles you don't need to keep
- around very long (binaries groups, *.jobs*, news.lists.filters, etc.) in
- CNFS buffers, and use timehash, timecaf, or tradspool (if you have a
- fast I/O subsystem or need to be able to go through the spool manually)
- for everything else. You'll probably find it most convenient to keep
- special hierarchies like local hierarchies and hierarchies that should
- never expire in tradspool.
-
- If your news server will be supporting readers, you'll also need to
- choose an overview storage mechanism (by setting *ovmethod* in
- inn.conf). There are three overview mechanisms to choose from:
- tradindexed, buffindexed, and ovdb. tradindexed is very fast for
- readers, but it has to update two files for each incoming article and
- can be quite slow to write. buffindexed can keep up with a large feed
- more easily, since it uses large buffers to store all overview
- information, but it's somewhat slower for readers (although not as slow
- as the unified overview in INN 2.2). ovdb stores overview data in a
- Berkeley DB database; it's fast and very robust, but requires more disk
- space. See the ovdb(5) man page for more information on it.
-
- Note that ovdb has not been as widely tested as the other overview
- mechanisms and should be considered experimental. tradindexed is the
- best tested and most widely used of the overview implementations.
-
- If buffindexed is chosen, you will need to create the buffers for it to
- use (very similar to creating CNFS buffers) and list the available
- buffers in buffindexed.conf. See buffindexed.conf(5) for more
- information.
-
-Configuring INN
-
- All documentation from this point on assumes that you have set up the
- news user on your system as suggested in "Installing INN" so that the
- root of your INN installation is ~news/. If you've moved things around
- by using options with "configure", you'll need to adjust the
- instructions to account for that.
-
- All of INN's configuration files are located in ~news/etc. Unless noted
- otherwise, any files referred to below are in this directory. When you
- first install INN, a sample of each file (containing lots of comments)
- is installed in ~news/etc; refer to these for concrete examples of
- everything discussed in this section.
-
- All of INN's configuration files, all of the programs that come with it,
- and some of its library routines have documentation in the form of man
- pages. These man pages were installed in ~news/man as part of the INN
- installation process and are the most complete reference to how INN
- works. You're strongly encouraged to refer to the man pages frequently
- while configuring INN, and for quick reference afterwards. Any detailed
- questions about individual configuration files or the behavior of
- specific programs should be answered in them. You may want to add
- ~news/man to your MANPATH environment variable; otherwise, you may have
- to use a command like:
-
- man -M ~news/man inn.conf
-
- to see the inn.conf(5) man page (for example).
-
- Before we begin, it is worth mentioning the wildmat pattern matching
- syntax used in many configuration files. These are simple wildcard
- matches using the asterisk ("*") as the wildcard character, much like
- the simple wildcard expansion used by Unix shells.
-
- In many cases, wildmat patterns can be specified in a comma-separated
- list to indicate a list of newsgroups. When used in this fashion, each
- pattern is checked in turn to see if it matches, and the last pattern in
- the line that matches the group name is used. Patterns beginning with
- "!" mean to exclude groups matching that pattern. For example:
-
- *, !comp.*, comp.os.*
-
- In this case, we're saying we match everything ("*"), except that we
- don't match anything under comp ("!comp.*"), unless it is actually under
- the comp.os hierarchy ("comp.os.*"). This is because non-comp groups
- will match only the first pattern (so we want them), comp.os groups will
- match all three patterns (so we want them too, because the third pattern
- counts in this case), and all other comp groups will match the first and
- second patterns and will be excluded by the second pattern.
-
- Some uses of wildmat patterns also support "poison" patterns (patterns
- starting with "@"). These patterns behave just like "!" patterns when
- checked against a single newsgroup name. Where they become special is
- for articles crossposted to multiple newsgroups; normally, such an
- article will be considered to match a pattern if any of the newsgroups
- it is posted to matches the pattern. If any newsgroup the article is
- posted to matches an expression beginning with "@", however, that
- article will not match the pattern even if other newsgroups to which it
- was posted match other expressions.
-
- See uwildmat(3) for full details on wildmat patterns.
-
- In all INN configuration files, blank lines and lines beginning with a
- "#" symbol are considered comments and are ignored. Be careful, not all
- files permit comments to begin in the middle of the line.
-
- inn.conf
-
- The first, and most important file is inn.conf. This file is organized
- as a series of parameter-value pairs, one per line. The parameter is
- first, followed by a colon and one or more whitespace characters, and
- then the value itself. For some parameters the value is a string or a
- number; for others it is true or false. (True values can be written as
- "yes", "true", or "on", whichever you prefer. Similarly, false values
- can be written as "no", "false", or "off".)
-
- inn.conf contains dozens of changeable parameters (see inn.conf(5) for
- full details), but only a few really need to be edited during normal
- operation:
-
- allownewnews
- If set to true then INN will support the NEWNEWS command for news
- readers. While this can be an expensive operation, its speed has
- been improved considerably as of INN 2.3 and it's probably safe to
- turn on without risking excessive server load. The default is true.
- (Note that the *access:* setting in readers.conf overrides this
- value; see readers.conf(5) for more details.)
-
- complaints
- Used to set the value of the X-Complaints-To: header, which is added
- to all articles posted locally. The usual value would be something
- like "abuse@example.com" or "postmaster@example.com". If not
- specified, the newsmaster email address will be used.
-
- hiscachesize
- The amount of memory (in kilobytes) to allocate for a cache of
- recently used history file entries. Setting this to 0 disables
- history caching. History caching can greatly increase the number of
- articles per second that your server is capable of processing. A
- value of 256 is a good default choice.
-
- logipaddr
- If set to true (the default), INN will log the IP address (or
- hostname, if the host is listed in incoming.conf with a hostname) of
- the remote host from which it received an article. If set to false,
- the trailing Path: header entry is logged instead. If you are using
- controlchan (see below) and need to process ihave/sendme control
- messages (this is very, very unlikely, so if you don't know what
- this means, don't worry about it), make sure you set this to false,
- since controlchan needs a site name, not an IP address.
-
- organization
- Set this to the name of your organization as you want it to appear
- in the Organization: header of all articles posted locally and not
- already containing that header. This will be overridden by the
- value of the ORGANIZATION environment variable (if it exists). If
- neither this parameter nor the environment variable or set, no
- Organization: header will be added to posts which lack one.
-
- pathhost
- This is the name of your news server as you wish it to appear in the
- Path: header of all postings which travel through your server (this
- includes local posts and incoming posts that you forward out to
- other sites). If this parameter is unspecified, the fully-qualified
- domain name (FQDN) of the machine will be used instead. Please use
- the FQDN of your server or an alias for your server unless you have
- a very good reason not to; a future version of the news RFCs may
- require this.
-
- rlimitnofile
- If set to a non-negative value (the default is -1), INN (both innd
- and innfeed) will try to raise the maximum number of open file
- descriptors to this value when it starts. This may be needed if you
- have lots of incoming and outgoing feeds. Note that the maximum
- value for this setting is very operating-system-dependent, and you
- may have to reconfigure your system (possibly even recompile your
- kernel) to increase it. See "File Descriptor Limits" for complete
- details.
-
- There are tons of other possible settings; you may want to read through
- inn.conf(5) to get a feel for your options. Don't worry if you don't
- understand the purpose of most of them right now. Some of the settings
- are only needed for very obscure things, and with more experience
- running your news server the rest will make more sense.
-
- newsfeeds
-
- newsfeeds determines how incoming articles are redistributed to your
- peers and to other INN processes. newsfeeds is very versatile and
- contains dozens of options; we will touch on just the basics here. The
- manpage contains more detailed information.
-
- newsfeeds is organized as a series of feed entries. Each feed entry is
- composed of four fields separated by colons. Entries may span multiple
- lines by using a backslash ("\") to indicate that the next line is a
- continuation of the current line. (Note that comments don't interact
- with backslashes in the way you might expect. A commented-out line
- ending in a backslash will still be considered continued on the next
- line, possibly resulting in more commented out than you intended or
- bizarre syntax errors. In general, it's best to avoid commenting out
- lines in the middle of continuation lines.)
-
- The first field in an entry is the name of the feed. It must be unique,
- and for feeds to other news servers it is usually set to the actual
- hostname of the remote server (this makes things easier). The name can
- optionally be followed by a slash and a comma-separated exclude list.
- If the feed name or any of the names in the exclude list appear in the
- Path line of an article, then that article will not be forwarded to the
- feed as it is assumed that it has passed through that site once already.
- The exclude list is useful when a news server's hostname is not the same
- as what it puts in the Path header of its articles, or when you don't
- want a feed to receive articles from a certain source.
-
- The second field specifies a set of desired newsgroups and distribution
- lists, given as newsgroup-pattern/distribution-list. The distribution
- list is not described here; see newsfeeds(5) for information (it's not
- used that frequently in practice). The newsgroup pattern is a
- wildmat-style pattern list as described above (supporting "@").
-
- The third field is a comma-separated list of flags that determine both
- the type of feed entry and sets certain parameters for the entry. See
- newsfeeds(5) for information on the flag settings; you can do a
- surprising amount with them. The three most common patterns, and the
- ones mainly used for outgoing news feeds to other sites, are "Tf,Wnm"
- (to write out a batch file of articles to be sent, suitable for
- processing by nntpsend and innxmit), "Tm" (to send the article to a
- funnel feed, used with innfeed), and "Tc,Wnm*" (to collect a funnel feed
- and send it via a channel feed to an external program, used to send
- articles to innfeed).
-
- The fourth field is a multi-purpose parameter whose meaning depends on
- the settings of the flags in the third field. To get a feel for it
- using the examples above, for file feeds ("Tf") it's the name of the
- file to write, for funnel feeds ("Tm") it's the name of the feed entry
- to funnel into, and for channel feeds ("Tc") it's the name of the
- program to run and feed references to articles.
-
- Now that you have a rough idea of the file layout, we'll begin to add
- the actual feed entries. First, we'll set up the special ME entry.
- This entry is required and serves two purposes: the newsgroup pattern
- specified here is prepended to the newsgroup list of all other feeds,
- and the distribution pattern for this entry determines what
- distributions (from the Distribution: header of incoming articles) are
- accepted from remote sites by your server. The example in the sample
- newsfeeds file is a good starting point. If you are going to create a
- local hierarchy that should not be distributed off of your system, it
- may be useful to exclude it from the default subscription pattern, but
- default subscription patterns are somewhat difficult to use right so you
- may want to just exclude it specifically from every feed instead.
-
- The ME entry tends to confuse a lot of people, so this point is worth
- repeating: the newsgroup patterns set the default subscription for
- *outgoing* feeds, and the distribution patterns set the acceptable
- Distribution: header entries for *incoming* articles. This is confusing
- enough that it may change in later versions of INN.
-
- There are two basic ways to feed articles to remote sites. The most
- common for large sites and particularly for transit news servers is
- innfeed(8), which sends articles to remote sites in real time (the
- article goes out to all peers that are supposed to receive it
- immediately after your server accepts it). For smaller sites,
- particularly sites where the only outgoing messages will be locally
- posted articles, it's more common to batch outgoing articles and send
- them every ten minutes or so from cron using nntpsend(8) and innxmit(8).
- Batching gives you more control and tends to be extremely stable and
- reliable, but it's much slower and can't handle high volume very well.
-
- Batching outgoing posts is easy to set up; for each peer, add an entry
- to newsfeeds that looks like:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tf,Wnm:
-
- where <newsgroups> is the wildmat pattern for the newsgroups that site
- wants. In this example, the actual name of the remote site is
- "remote.example.com", but it puts "news.example.com" in the Path:
- header. If the remote site puts its actual hostname in the Path:
- header, you won't need the "/news.example.com" part.
-
- This entry will cause innd to write out a file in ~news/spool/outgoing
- named remote.example.com and containing the Message-ID and storage token
- of each message to send to that site. (The storage token is INN's
- internal pointer to where an article is stored; to retrieve an article
- given its storage token, use sm(8)). innxmit knows how to read files of
- this format and send those articles to the remote site. For information
- on setting it up to run periodically, see "Setting Up the Cron Jobs"
- below. You will also need to set up a config file for nntpsend; see the
- man page for nntpsend.ctl(5) for more information.
-
- If instead you want to use innfeed to send outgoing messages
- (recommended for sites with more than a couple of peers), you need some
- slightly more complex magic. You still set up a separate entry for each
- of your peers, but rather than writing out batch files, they all
- "funnel" into a special innfeed entry. That special entry collects all
- of the separate funnel feeds and sends the data through a special sort
- of feed to an external program (innfeed in this case); this is a
- "channel" feed.
-
- First, the special channel feed entry for innfeed that will collect all
- the funnel feeds:
-
- innfeed!\
- :!*\
- :Tc,Wnm*:/usr/local/news/bin/startinnfeed -y
-
- (adjust the path to startinnfeed(1) if you installed it elsewhere).
- Note that we don't feed this entry any articles directly (its newsgroup
- pattern is "!*"). Note also that the name of this entry ends in an
- exclamation point. This is a standard convention for all special feeds;
- since the delimiter for the Path: header is "!", no site name containing
- that character can ever match the name of a real site.
-
- Next, set up entries for each remote site to which you will be feeding
- articles. All of these entries should be of the form:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tm:innfeed!
-
- specifying that they funnel into the "innfeed!" feed. As in the
- previous example for batching, "remote.example.com" is the actual name
- of the remote peer, "news.example.com" is what it puts in the Path:
- header (if different than the actual name of the server), and
- <newsgroups> is the wildmat pattern of newsgroups to be sent.
-
- As an alternative to NNTP, INN may also feed news out to an IMAP server,
- by using imapfeed(8), which is almost identical to innfeed. The
- startinnfeed process can be told to start imapfeed instead of innfeed.
- The feed entry for this is as follows:
-
- imapfeed!\
- :!*\
- :Tc,Wnm*,S16384:/usr/local/news/bin/startinnfeed imapfeed
-
- And set up entries for each remote site like:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tm:imapfeed!
-
- For more information on imapfeed, look at the innfeed/imap_connection.c.
- For more information on IMAP in general, see RFC 2060.
-
- Finally, there is a special entry for controlchan(8), which processes
- newsgroup control messages, that should always be in newsfeeds unless
- you never want to honor any control messages. This entry should look
- like:
-
- controlchan!\
- :!*,control,control.*,!control.cancel\
- :Tc,Wnsm:/usr/local/news/bin/controlchan
-
- (modified for the actual path to controlchan if you put it somewhere
- else). See "Processing Control Messages" for more details.
-
- For those of you upgrading from earlier versions of INN, note that the
- functionality of overchan(8) and crosspost is now incorporated into INN
- and neither of those programs is necessary. Unfortunately, crosspost
- currently will not work even with the tradspool storage method. You can
- still use overchan if you make sure to set *useoverchan* to true in
- inn.conf so that innd doesn't write overview data itself, but be
- careful: innd may accept articles faster than overchan can process the
- data.
-
- incoming.conf
-
- incoming.conf file specifies which machines are permitted to connect to
- your host and feed it articles. Remote servers you peer with should be
- listed here. Connections from hosts not listed in this file will (if
- you don't allow readers) be rejected or (if you allow readers) be handed
- off to nnrpd and checked against the access restrictions in
- readers.conf.
-
- Start with the sample incoming.conf and, for each remote peer, add an
- entry like:
-
- peer remote.example.com { }
-
- This uses the default parameters for that feed and allows incoming
- connections from a machine named "remote.example.com". If that peer
- could be connecting from several different machines, instead use an
- entry like:
-
- peer remote.example.com {
- hostname: "remote.example.com, news.example.com"
- }
-
- This will allow either "remote.example.com" or "news.example.com" to
- feed articles to you. (In general, you should add new peer lines for
- each separate remote site you peer with, and list multiple host names
- using the *hostname* key if one particular remote site uses multiple
- servers.)
-
- You can restrict the newsgroups a remote site is allowed to send you,
- using the same sort of pattern that newsfeeds(5) uses. For example, if
- you want to prevent "example.com" hosts from sending you any articles in
- the "local.*" hierarchy (even if they're crossposted to other groups),
- change the above to:
-
- peer remote.example.com {
- patterns: "*, @local.*"
- hostname: "remote.example.com, news.example.com"
- }
-
- Note, however, that restricting what a remote side can send you will
- *not* reduce your incoming bandwidth usage. The remote site will still
- send you the entire article; INN will just reject it rather than saving
- it to disk. To reduce bandwidth, you have to contact your peers and ask
- them not to send you the traffic you don't want.
-
- There are various other things you can set, including the maximum number
- of connections the remote host will be allowed. See incoming.conf(5)
- for all the details.
-
- Note for those familiar with older versions of INN: this file replaces
- the old hosts.nntp configuration file.
-
- cycbuff.conf
-
- cycbuff.conf is only required if CNFS is used. If you aren't using
- CNFS, skip this section.
-
- CNFS stores articles in logical objects called *metacycbuffs*. Each
- metacycbuff is in turn composed of one or more physical buffers called
- *cycbuffs*. As articles are written to the metacycbuff, each article is
- written to the next cycbuff in the list in a round-robin fashion (unless
- "sequential" mode is specified, in which case each cycbuff is filled
- before moving on to the next). This is so that you can distribute the
- individual cycbuffs across multiple physical disks and balance the load
- between them.
-
- There are two ways to create your cycbuffs:
-
- 1. Use a block device directly. This will probably give you the most
- speed since it avoids the file system overhead of large files, but
- it requires your OS support mmap(2) on a block device. Solaris
- supports this, as do late Linux 2.4 kernels. FreeBSD does not at
- last report. Also on many PC-based Unixes it is difficult to create
- more than eight partitions, which may limit your options.
-
- 2. Use a real file on a filesystem. This will probably be a bit slower
- than using a block device directly, but it should work on any Unix
- system.
-
- If you're having doubts, use option #2; it's easier to set up and should
- work regardless of your operating system.
-
- Now you need to decide on the sizes of your cycbuffs and metacycbuffs.
- You'll probably want to separate the heavy-traffic groups
- ("alt.binaries.*" and maybe a few other things like "*.jobs*" and
- "news.lists.filters") into their own metacycbuff so that they don't
- overrun the server and push out articles on the more useful groups. If
- you have any local groups that you want to stay around for a while then
- you should put them in their own metacycbuff as well, so that they don't
- get pushed out by other traffic. (Or you might store them in one of the
- other storage methods, such as tradspool.)
-
- For each metacycbuff, you now need to determine how many cycbuffs will
- make up the metacycbuff, the size of those cycbuffs, and where they will
- be stored. Some OSes do not support files larger than 2 GB, which will
- limit the size you can make a single cycbuff, but you can still combine
- many cycbuffs into each metacycbuff. Older versions of Linux are known
- to have this limitation; FreeBSD does not. Some OSes that support large
- files don't support direct access to block devices for large partitions
- (Solaris prior to Solaris 7, or not running in 64-bit mode, is in this
- category); on those OSes, if you want cycbuffs over 2 GB, you'll have to
- use regular files. If in doubt, keep your cycbuffs smaller than 2 GB.
- Also, when laying out your cycbuffs, you will want to try to arrange
- them across as many physical disks as possible (or use a striped disk
- array and put them all on that).
-
- In order to use any cycbuff larger than 2 GB, you need to build INN with
- the --enable-largefiles option. See "Installing INN" for more
- information and some caveats.
-
- For each cycbuff you will be creating, add a line to cycbuff.conf like
- the following:
-
- cycbuff:NAME:/path/to/buffer:SIZE
-
- NAME must be unique and must be at most seven characters long.
- Something simple like "BUFF00", "BUFF01", etc. is a decent choice, or
- you may want to use something that includes the SCSI target and slice
- number of the partition. SIZE is the buffer size in kilobytes (if
- you're trying to stay under 2 GB, keep your sizes below 2097152).
-
- Now, you need to tell INN how to group your cycbuffs into metacycbuffs.
- This is similar to creating cycbuff entries:
-
- metacycbuff:BUFFNAME:CYCBUFF,CYCBUFF,CYCBUFF
-
- BUFFNAME is the name of the metacycbuff and must be unique and at most
- eight characters long. These should be a bit more meaningful than the
- cycbuff names since they will be used in other config files as well.
- Try to name them after what will be stored in them; for example, if this
- metacycbuff will hold alt.binaries postings, "BINARIES" would be a good
- choice. The last part of the entry is a comma-separated list of all of
- the cycbuffs that should be used to build this metacycbuff. Each
- cycbuff should only appear in one metacycbuff line, and all metacycbuff
- lines must occur after all cycbuff lines in the file.
-
- If you want INN to fill each cycbuff before moving on to the next one
- rather than writing to them round-robin, add ":SEQUENTIAL" to the end of
- the metacycbuff line. This may give noticeably better performance when
- using multiple cycbuffs on the same spindle (such as partitions or
- slices of a larger disk), but will probably give worse performance if
- your cycbuffs are spread out across a lot of spindles.
-
- By default, CNFS data is flushed to disk every 25 articles. If you're
- running a small server with a light article load, this could mean losing
- quite a few articles in a crash. You can change this interval by adding
- a cycbuffupdate line to your cycbuff.conf file; see cycbuff.conf(5) for
- more details.
-
- Finally, you have to create the cycbuffs. See "Creating the Article
- Spool" for more information on how to do that.
-
- storage.conf
-
- storage.conf determines where incoming articles will be stored (what
- storage method, and in the case of CNFS, what metacycbuff). Each entry
- in the file defines a storage class for articles. The first matching
- storage class is used to store the article; if no storage class matches,
- INN will reject that article. (This is almost never what you want, so
- make sure this file ends in a catch-all entry that will match
- everything.)
-
- A storage class definition looks like this:
-
- method <methodname> {
- newsgroups: <wildmat>
- class: <storage_class>
- size: <minsize>[,<maxsize>]
- expires: <mintime>[,<maxtime>]
- options: <options>
- }
-
- <methodname> is the name of the storage method to use to store articles
- in this class ("cnfs", "timehash", "timecaf", "tradspool", or the
- special method "trash" that accepts the article and throws it away).
-
- The first parameter is a wildmat pattern in the same format used by the
- newsfeeds(5) file, and determines what newsgroups are accepted by this
- storage class.
-
- The second parameter is a unique number identifying this storage class
- and should be between 0 and 255. It can be used to control article
- expiration, and for timehash and timecaf will set the top-level
- directory in which articles accepted by this storage class are stored.
- The easiest way to deal with this parameter is to just number all
- storage classes in storage.conf sequentially. The assignment of a
- particular number to a storage class is arbitrary but *permanent* (since
- it is used in storage tokens).
-
- The third parameter can be used to accept only articles in a certain
- size range into this storage class. A <maxsize> of 0 (or a missing
- <maxsize>) means no upper limit (and of course a <minsize> of 0 would
- mean no lower limit, because all articles are more than zero bytes
- long). If you don't want to limit the size of articles accepted by this
- storage class, leave this parameter out entirely.
-
- The fourth parameter you probably don't want to use; it lets you assign
- storage classes based on the Expires: header of incoming articles. The
- exact details are in storage.conf(5). It's very easy to use this
- parameter incorrectly; leave it out entirely unless you've read the man
- page and know what you're doing.
-
- The fifth parameter is the options parameter. Currently only CNFS uses
- this field; it should contain the name of the metacycbuff used to store
- articles in this storage class.
-
- If you're using CNFS exclusively, just create one storage class for each
- metacycbuff that you have defined in cycbuff.conf and set the newsgroups
- pattern according to what newsgroups should be stored in that buffer.
-
- If you're using timehash or timecaf, the storage class IDs are used to
- store articles in separate directory trees, which you can take advantage
- of to put particular storage classes on different disks. Also,
- currently storage class is the only way to specify expiration time, so
- you will need to divide up your newsgroups based on how long you want to
- retain articles in those groups and create a storage class for each such
- collection of newsgroups. Make note of the storage class IDs you assign
- as they will be needed when you edit expire.ctl a bit later.
-
- expire.ctl
-
- expire.ctl sets the expiration policy for articles stored on the server.
- Be careful, since the default configuration will expire most articles
- after 10 days; in most circumstances this deletion is *permanent*, so
- read this whole section carefully if you want to keep local hierarchies
- forever. (See archive(8) for a way to automate backups of important
- articles.)
-
- Only one entry is required for all storage classes; it looks like:
-
- /remember/:10
-
- This entry says how long to keep the Message-IDs for articles that have
- already expired in the history file so that the server doesn't accept
- them again. Occasionally, fairly old articles will get regurgitated
- somewhere and offered to you again, so even after you've expired
- articles from your spool, you want to keep them around in your history
- file for a little while to ensure you don't get duplicates.
-
- INN will reject any articles more than a certain number of days old (the
- *artcutoff* parameter in inn.conf, defaulting to 10); the number on the
- "/remember/" line should match that.
-
- CNFS makes no further use of expire.ctl, since articles stored in CNFS
- buffers expire automatically when the buffer runs out of free space (but
- see the "-N" option in expireover(8) if you really want to expire them
- earlier). For other storage methods, there are two different syntaxes
- of this file, depending on *groupbaseexpiry* in inn.conf. If it is set
- to false, expire.ctl takes entries of the form:
-
- <storage_class>:<keep>:<default>:<purge>
-
- <storage_class> is the number assigned to a storage class in
- storage.conf. <default> is the number of days to keep normal articles
- in that storage class (decimal values are allowed). For articles that
- don't have an Expires: header, those are the only two values that
- matter. For articles with an Expires: header, the other two values come
- into play; the date given in the Expires: header of an article will be
- honored, subject to the contraints set by <keep> and <purge>. All
- articles in this storage class will be kept for at least <keep> days,
- regardless of their Expires: headers, and all articles in this storage
- class will be expired after <purge> days, even if their Expires: headers
- specify a longer life.
-
- All three of these fields can also contain the special keyword "never".
- If <default> is "never", only articles with explicit Expires: headers
- will ever be expired. If <keep> is "never", articles with explicit
- Expires: headers will be kept forever. Setting <purge> to "never" says
- to honor Expires: headers even if they specify dates far into the
- future. (Note that if <keep> is set to "never", all articles with
- Expires: headers are kept forever and the value of <purge> is not used.)
-
- If the value of "groupbaseexpiry" is true, expire.ctl takes entries of
- the form:
-
- <wildmat>:<flag>:<keep>:<default>:<purge>
-
- <wildmat> is a wildmat expression ("!" and "@" not permitted, and only a
- single expression, not a comma-separated set of them). Each expiration
- line applies to groups matching the wildmat expression. <flag> is "M"
- for moderated groups, "U" for unmoderated groups, and "A" for groups
- with any moderation status; the line only matches groups with the
- indicated expiration status. All of the other fields have the same
- meaning as above.
-
- readers.conf
-
- Provided that *noreader* is set to false in inn.conf, any connection
- from a host that doesn't match an entry in incoming.conf (as well as any
- connection from a host that does match such an entry, but has issued a
- MODE READER command) will be handed off to nnrpd(8), the part of INN
- that supports newsreading clients. nnrpd uses readers.conf to determine
- whether a given connection is allowed to read news, and if so what
- newsgroups the client can read and post to.
-
- There are a variety of fairly complicated things that one can do with
- readers.conf, things like run external authentication programs that can
- query RADIUS servers. See readers.conf(5) and the example file for all
- the gory details. Here's an example of probably the simplest reasonable
- configuration, one that only allows clients in the example.com domain to
- read from the server and allows any host in that domain to read and post
- to all groups:
-
- auth "example.com" {
- hosts: "example.com, *.example.com"
- default: "<user>"
- default-domain: "example.com"
- }
-
- access "all" {
- users: "*@example.com"
- newsgroups: "*"
- }
-
- If you're running a server for one particular domain, want to allow all
- hosts within that domain to read and post to any group on the server,
- and want to deny access to anyone outside that domain, just use the
- above and change "example.com" in the above to your domain and you're
- all set. Lots of examples of more complicated things are in the sample
- file.
-
-Creating the Article Spool (CNFS only)
-
- If you are using actual files as your CNFS buffers, you will need to
- pre-create those files, ensuring they're the right size. The easiest
- way to do this is with dd. For each cycbuff in cycbuff.conf, create the
- buffer with the following commands (as the news user):
-
- dd if=/dev/zero of=/path/to/buffer bs=1k count=BUFFERSIZE
- chmod 664 /path/to/buffer
-
- Substitute the correct path to the buffer and the size of the buffer as
- specified in cycbuff.conf. This will create a zero-filled file of the
- correct size; it may take a while, so be prepared to wait.
-
- Here's a command that will print out the dd(1) commands that you should
- run:
-
- awk -F: \
- '/^cy/ { printf "dd if=/dev/zero of=%s bs=1k count=%s\n", $3, $4 }' \
- ~news/etc/cycbuff.conf
-
- If you are using block devices, you don't technically have to do
- anything at all (since INN is capable of using the devices in /dev), but
- you probably want to create special device files for those devices
- somewhere for INN's private use. It s more convenient to keep all of
- INN's stuff together, but more importantly, the device files used by INN
- really should be owned by the news user and group, and you may not want
- to do that with the files in /dev.
-
- To create the device files for INN, use mknod(8) with a type of "b",
- getting the major and minor device numbers from the existing devices in
- /dev. There's a small shell script in cycbuff.conf(5) that may help
- with this. Make sure to create the device files in the location INN
- expects them (specified in cycbuff.conf).
-
- Solaris users please note: on Solaris, do not use block devices that
- include the first cylinder of the disk. Solaris doesn't protect the
- superblock from being overwritten by an application writing to block
- devices and includes it in the first cylinder of the disk, so unless you
- use a slice that starts with cylinder 1 instead of 0, INN will
- invalidate the partition table when it tries to initialize the cycbuff
- and all further accesses will fail until you repartition.
-
-Creating the Database Files
-
- At this point, you need to set up the news database directory
- (~news/db). This directory will hold the active(5) file (the list of
- newsgroups you carry), the active.times(5) file (the creator and
- creation time of newsgroups created since the server was initialized),
- the newsgroups(5) file (descriptions for all the newsgroups you carry),
- and the history(5) file (a record of every article the server currently
- has or has seen in the past few days, used to decide whether to accept
- or refuse new incoming messages).
-
- Before starting to work on this, make sure you're logged on as the news
- user, since all of these files need to be owned by that user. This is a
- good policy to always follow; if you are doing any maintenance work on
- your news server, log on as the news user. Don't do maintenance work as
- root. Also make sure that ~news/bin is in the default path of the news
- user (and while you're at it, make sure ~news/man is in the default
- MANPATH) so that you can run INN maintenance commands without having to
- type the full path.
-
- If you already have a server set up (if you're upgrading, or setting up
- a new server based on an existing server), copy active and newsgroups
- from that server into ~news/db. Otherwise, you'll need to figure out
- what newsgroups you want to carry and create new active and newsgroups
- files for them. If you plan to carry a full feed, or something close to
- that, go to <ftp://ftp.isc.org/pub/usenet/CONFIG/> and download active
- and newsgroups from there; that will start you off with reasonably
- complete files. If you plan to only carry a small set of groups, the
- default minimal active file installed by INN is a good place to start;
- you can create additional groups after the server is running by using
- "ctlinnd newgroup". (Another option is to use actsync(8) to synchronize
- your newsgroup list to that of another server.)
-
- "control" and "junk" must exist as newsgroups in your active file for
- INN to start, and creating pseudogroups for the major types of control
- messages is strongly encouraged for all servers that aren't standalone.
- If you don't want these groups to be visible to clients, do *not* delete
- them; simply hide them in readers.conf. "to" must also exist as a
- newsgroup if you have mergetogroups set in inn.conf.
-
- Next, you need to create an empty history database. To do this, type:
-
- cd ~news/db
- touch history
- makedbz -i
-
- When it finishes, rename the files it created to remove the ".n" in the
- file names and then make sure the file permissions are correct on all
- the files you've just created:
-
- chmod 644 *
-
- Your news database files are now ready to go.
-
-Configuring syslog
-
- While some logs are handled internally, INN also logs a wide variety of
- information via syslog. INN's nightly report programs know how to roll
- and summarize those syslog log files, but when you first install INN you
- need to set them up.
-
- If your system understands the "news" syslog facility, INN will use it;
- otherwise, it will log to "local1". Nearly every modern system has a
- "news" syslog facility so you can safely assume that yours does, but if
- in doubt take a look at the output from running "configure". You should
- see a line that looks like:
-
- checking log level for news... LOG_NEWS
-
- If that says LOG_LOCAL1 instead, change the below instructions to use
- "local1" instead of "news".
-
- Edit /etc/syslog.conf on your system and add lines that look like the
- following:
-
- news.crit /usr/local/news/log/news.crit
- news.err /usr/local/news/log/news.err
- news.notice /usr/local/news/log/news.notice
-
- (Change the path names as necessary if you installed INN in a different
- location than /usr/local/news.) These lines *must* be tab-delimited, so
- don't copy and paste from these instructions. Type it in by hand and
- make sure you use a tab, or you'll get mysterious failures. You'll also
- want to make sure that news log messages don't fill your other log files
- (INN generates a lot of log traffic); so for every entry in
- /etc/syslog.conf that starts with "*", add ";news.none" to the end of
- the first column. For example, if you have a line like:
-
- *.err /dev/console
-
- change it to:
-
- *.err;news.none /dev/console
-
- (You can choose not to do this for the higher priority log messages, if
- you want to make sure they go to your normal high-priority log files as
- well as INN's. Don't bother with anything lower priority than "crit",
- though. "news.err" isn't interesting enough to want to see all the
- time.) Now, make sure that the news log files exist; syslog generally
- won't create files automatically. Enter the following commands:
-
- touch /usr/local/news/log/news.crit
- touch /usr/local/news/log/news.err
- touch /usr/local/news/log/news.notice
- chown news /usr/local/news/log/news.*
- chgrp news /usr/local/news/log/news.*
-
- (again adjusting the paths if necessary for your installation).
- Finally, send a HUP signal to syslogd to make it re-read its
- configuration file.
-
-Setting Up the Cron Jobs
-
- INN requires a special cron job to be set up on your system to run
- news.daily(8) which performs daily server maintenance tasks such as
- article expiration and the processing and rotation of the server logs.
- Since it will slow the server down while it is running, it should be run
- during periods of low server usage, such as in the middle of the night.
- To run it at 3am, for example, add the following entry to the news
- user's crontab file:
-
- 0 3 * * * /usr/local/news/bin/news.daily expireover lowmark
-
- or, if your system does not have per-user crontabs, put the following
- line into your system crontab instead:
-
- 0 3 * * * su -c "/usr/local/news/bin/news.daily expireover lowmark" news
-
- If you're using any non-CNFS storage methods, add "delayrm" to the above
- option list for news.daily.
-
- The news user obviously must be able to run cron jobs. On Solaris, this
- means that it must have a valid /etc/shadow entry and must not be locked
- (although it may be a non-login account). There may be similar
- restrictions with other operating systems.
-
- If you use the batching method to send news, also set up a cron job to
- run nntpsend(8) every ten minutes. nntpsend will run innxmit for all
- non-empty pending batch files to send pending news to your peers. That
- cron entry should look something like:
-
- 0,10,20,30,40,50 * * * * /usr/local/news/bin/nntpsend
-
- The pathnames and user ID used above are the installation defaults;
- change them to match your installation if you used something other than
- the defaults.
-
- The parameters passed to news.daily in the above example are the most
- common (and usually the most efficient) ones to use. More information
- on what these parameters do can be found in the news.daily(8) man page.
-
-File Descriptor Limits
-
- INN likes to use a lot of file descriptors, particularly if you have a
- lot of peers. Depending on what your system defaults are, you may need
- to make sure the default limit is increased for INN (particularly for
- innd and innfeed). This is vital on Solaris, which defaults (at least
- as of 2.6) to an absurdly low limit of 64 file descriptors per process.
-
- One way to increase the number of file descriptors is to set
- *rlimitnofile* in inn.conf to a higher value. This will cause both
- startinnfeed and inndstart (the setuid root wrapper scripts that start
- innfeed and innd, respectively) to increase the file descriptor limits
- before they run the regular INN programs. Note, however, that INN won't
- be able to increase the limits above the hard limits set by your
- operating system; on some systems, that hard limit is normally 256 file
- descriptors (Linux, for example). On others, like Solaris, it's 1024.
- Increasing the limit beyond that value may require serious system
- configuration work. (On some operating systems, it requires patching
- and recompiling the kernel. On Solaris it can be changed in
- /etc/system, but for 2.6 or earlier the limit cannot be increased beyond
- 1024 without breaking select(2) and thereby breaking all of INN. For
- current versions of Linux, you may be able to change the maximum by
- writing to /proc/sys/fs/file-max.)
-
- 256 file descriptors will probably be enough for all but the largest
- sites. There is no harm in setting the limits higher than you actually
- need (provided they're set to something lower than or equal to your
- system hard limit). 256 is therefore a reasonable value to try.
-
- If you're installing INN on a Solaris system, particularly if you're
- installing it on a dedicated news server machine, it may be easier to
- just increase the default file descriptor limit across the board for all
- processes. You can do that by putting the line:
-
- set rlim_fd_cur = 256
-
- in /etc/system and rebooting. You can increase it all the way to 1024
- (and may need to if you have a particularly large site), but that can
- cause RPC and some stdio applications to break. It therefore probably
- isn't a good idea on a machine that isn't dedicated to INN.
-
-Starting and Stopping the System
-
- INN is started via the shell script rc.news. This must be run as the
- news user and not as root. To start INN on system boot, you therefore
- want to put something like:
-
- su - news -c /usr/local/news/bin/rc.news
-
- in the system boot scripts. If innd is stopped or killed, you can
- restart it by running rc.news by hand as the news user.
-
- The rc.news script may also be used to shut down INN, with the "stop"
- option:
-
- su - news -c '/usr/local/news/bin/rc.news stop'
-
- In the contrib directory of this source tree is a sample init script for
- people using System V-style init.d directories.
-
-Processing Newsgroup Control Messages
-
- Control messages are specially-formatted messages that tell news servers
- to take various actions. Cancels (commands to delete messages) are
- handled internally by INN, and all other control messages are processed
- by controlchan. controlchan should be run out of newsfeeds if you want
- your news server to process any control messages; see "Configuring INN"
- for specific instructions.
-
- The actions of controlchan are determined by control.ctl, which lists
- who can perform what actions. The primary control messages to be
- concerned with are "newgroup" (to create a newsgroup), "rmgroup" (to
- remove a newsgroup), and "checkgroups" (to compare the list of groups
- carried in a hierarchy to a canonical list). INN comes with a
- control.ctl file that processes control messages in most major public
- hierarchies; if you don't want to act on all those control messages, you
- should remove from that file all entries for hierarchies you don't want
- to carry.
-
- You can tell INN to just authenticate control messages based on the From
- header of the message, but this is obviously perilous and control
- messages are widely forged. Many hierarchies sign all of their control
- messages with PGP, allowing news servers to verify their authenticity,
- and checking those signatures for hierarchies that use them is highly
- recommended. controlchan knows how to do this (using pgpverify) without
- additional configuration, but you do have to provide it with a public
- key ring containing the public keys of all of the hierarchy
- administrators whose control messages you want to check.
-
- INN expects the public key ring to either be in the default location for
- a PGP public key ring for the news user (generally ~news/.gnupg for
- GnuPG and ~news/.pgp for old PGP implementations), or in pathetc/pgp
- (/usr/local/news/etc/pgp by default). The latter is the recommended
- path. To add a key to that key ring, use:
-
- gpg --import --homedir=/usr/local/news/etc/pgp <file>
-
- where <file> is a file containing the hierarchy key. Change the homedir
- setting to point to pathetc/pgp if you have INN installed in a
- non-default location. If you're using the old-style PGP program, an
- equivalent command is:
-
- env PGPPATH=/usr/local/news/etc/pgp pgp <file>
-
- You can safely answer "no" to questions about whether you want to sign,
- trust, or certify keys.
-
- The URLs from which you can get hierarchy keys are noted in comments in
- control.ctl. <ftp://ftp.isc.org/pub/pgpcontrol/PGPKEYS> tries to
- collect the major hierarchy keys.
-
- If you are using GnuPG, please note that the first user ID on the key
- will be the one that's used by INN for verification and must match the
- key listed in control.ctl. If a hierarchy key has multiple user IDs,
- you may have to remove all the user IDs except the one that matches the
- control.ctl entry using "gpg --edit-key" and the "delkey" command.
-
+++ /dev/null
-INN as a whole and all code contained in it not otherwise marked with
-different licenses and/or copyrights is covered by the following copyright
-and license:
-
- Copyright (c) 2004, 2005, 2006, 2007, 2008
- by Internet Systems Consortium, Inc. ("ISC")
- Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003 by The Internet Software Consortium and Rich Salz
-
- This code is derived from software contributed to the Internet Software
- Consortium by Rich Salz.
-
- Permission to use, copy, modify, and distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-Some specific portions of INN are covered by different licenses. Those
-licenses, if present, will be noted prominantly at the top of those source
-files. Specifically (but possibly not comprehensively):
-
- authprogs/smbval/*, backends/send-uucp.in, and control/perl-nocem.in
- are under the GNU General Public License. See doc/GPL for a copy of
- this license.
-
- backends/shrinkfile.c, frontends/scanspool.in, lib/concat.c,
- lib/hstrerror.c, lib/inet_aton.c, lib/inet_ntoa.c, lib/memcmp.c,
- lib/parsedate.y, lib/pread.c, lib/pwrite.c, lib/setenv.c, lib/seteuid.c,
- lib/strerror.c, lib/strlcat.c and lib/strlcpy.c are in the public
- domain.
-
- lib/snprintf.c may be used for any purpose as long as the author's
- notice remains intact in all source code distributions.
-
- control/gpgverify.in, control/pgpverify.in and control/signcontrol.in
- are under a BSD-style license (with the advertising clause) with UUNET
- Technologies, Inc. as the copyright holder. See the end of those files
- for details.
-
- control/controlchan.in and control/modules/*.pl are covered by a
- two-clause BSD-style license (no advertising clause). See the
- beginning of those files for details.
-
- lib/strcasecmp.c, lib/strspn.c, and lib/strtok.c are taken from BSD
- sources and are covered by the standard BSD license. See those files
- for more details.
-
- lib/md5.c is covered under the standard free MD5 license from RSA Data
- Security. See the file for more details. A clarification is also
- provided here: <http://www.ietf.org/ietf/IPR/RSA-MD-all>.
-
- "Implementations of these message-digest algorithms, including
- implementations derived from the reference C code in RFC-1319,
- RFC-1320, and RFC-1321, may be made, used, and sold without
- license from RSA for any purpose."
-
- history/his.c and history/hisv6/hisv6.c are under a license very
- similar to the new BSD license (no advertising clause) but with Thus
- plc as the copyright holder. See those files for details.
-
- lib/tst.c, include/inn/tst.h and doc/pod/tst.pod are derived from
- <http://www.octavian.org/cs/tst1.3.tar.gz> and are under the new BSD
- license (no advertising clause), but with Peter A. Friend as the
- copyright holder.
-
- tests/runtests.c is covered under a license very similar to the MIT/X
- Consortium license. See the beginning of the file for details.
-
-Note that all portions of INN that link with core INN code have to be
-covered by licenses compatible with the license at the top of this file,
-and since INN links with several external libraries if so configured (such
-as OpenSSL), should also be compatible with the licenses of those external
-libraries to be safe. Some portions of this distribution are covered by
-more restrictive licenses, but all of that code is completely stand-alone,
-either as a standalone script or as code that compiles into a separate
-executable.
-
-Please note that the files in the contrib directory are not properly part
-of INN and may be under widely varying licenses. Please see each file
-and/or its documentation for license information.
+++ /dev/null
-File Name Description
--------------------------------------------------------------------------------
-CONTRIBUTORS List of contributors
-HACKING Docs for INN coders and maintainers
-INSTALL INN installation instructions
-LICENSE Legal mumbo-jumbo
-MANIFEST This shipping list
-Makefile Top-level makefile
-Makefile.global.in Make variables for all Makefiles
-NEWS Changes since last version
-README Introduction to the INN package
-TODO The list of pending INN projects
-aclocal.m4 M4 macro for libtool
-authprogs The authentication programs (Directory)
-authprogs/Makefile Makefile for auth programs
-authprogs/auth_krb5.c Authenticator against Kerberos v5
-authprogs/auth_smb.c Authenticator against Samba servers
-authprogs/ckpasswd.c Check password
-authprogs/domain.c Get username from remote user's hostname
-authprogs/ident.c Get username from ident
-authprogs/libauth.c Library for talking to nnrpd
-authprogs/libauth.h Interface for libauth
-authprogs/radius.c Authenticator against RADIUS servers
-authprogs/smbval The smb auth libraries (Directory)
-authprogs/smbval/Makefile Libraries for smb auth
-authprogs/smbval/byteorder.h Libraries for smb auth
-authprogs/smbval/rfcnb-common.h Libraries for smb auth
-authprogs/smbval/rfcnb-error.h Libraries for smb auth
-authprogs/smbval/rfcnb-io.c Libraries for smb auth
-authprogs/smbval/rfcnb-io.h Libraries for smb auth
-authprogs/smbval/rfcnb-priv.h Libraries for smb auth
-authprogs/smbval/rfcnb-util.c Libraries for smb auth
-authprogs/smbval/rfcnb-util.h Libraries for smb auth
-authprogs/smbval/rfcnb.h Libraries for smb auth
-authprogs/smbval/session.c Libraries for smb auth
-authprogs/smbval/smbdes.c Libraries for smb auth
-authprogs/smbval/smbencrypt.c Libraries for smb auth
-authprogs/smbval/smblib-common.h Libraries for smb auth
-authprogs/smbval/smblib-priv.h Libraries for smb auth
-authprogs/smbval/smblib-util.c Libraries for smb auth
-authprogs/smbval/smblib.c Libraries for smb auth
-authprogs/smbval/smblib.h Libraries for smb auth
-authprogs/smbval/valid.c Libraries for smb auth
-authprogs/smbval/valid.h Libraries for smb auth
-backends Outgoing feed programs (Directory)
-backends/Makefile Makefile for outgoing feed programs
-backends/actmerge.in Merge two active files to stdout
-backends/actsync.c Poll remote(s) for active file & merge
-backends/actsyncd.in Daemon to run actsync periodically
-backends/archive.c Simple article archiver
-backends/batcher.c Make news batches
-backends/buffchan.c Buffered funnel to file splitter
-backends/crosspost.c Create links for crossposts (obselete)
-backends/cvtbatch.c Add fields to simple batchfile
-backends/filechan.c Split a funnel into separate files
-backends/inndf.c df used for innwatch
-backends/innxbatch.c Send batches using XBATCH to remote
-backends/innxmit.c Send articles to remote site
-backends/map.c Site name to filename mapping routines
-backends/map.h Headers for backends/map.c
-backends/mod-active.in Batch do active file modifications
-backends/news2mail.in News to mail gateway
-backends/ninpaths.c Path statistics accumulation program
-backends/nntpget.c Get articles from remote site
-backends/nntpsend.in Invoke all innxmit's at once
-backends/overchan.c Update news overview database
-backends/send-ihave.in Script to post ihave messages
-backends/send-nntp.in Shell script to call innxmit
-backends/send-uucp.in Script to call batcher
-backends/sendinpaths.in Send accumulated Path statistics
-backends/sendxbatches.in Shell wrapper around innxbatch
-backends/shlock.c Program to make lockfiles in scripts
-backends/shrinkfile.c Shrink file from beginning
-configure Script to configure INN
-configure.in Source file for configure
-contrib External contributions (Directory)
-contrib/Makefile Makefile for contrib programs
-contrib/README Contents of the contrib directory
-contrib/archivegz.in Compressing version of archive
-contrib/auth_pass.README README corresponding to auth_pass.c
-contrib/auth_pass.c Sample for use with AUTHINFO GENERIC
-contrib/backlogstat.in Analyze innfeed's backlog status
-contrib/backupfeed.in Suck down news via a reading connection
-contrib/cleannewsgroups.in Script to clean newsgroups file
-contrib/count_overview.pl Count overview entries
-contrib/delayer.in Delay data in a pipe, for innfeed
-contrib/expirectl.c Generate expire.ctl from template
-contrib/findreadgroups.in Track which groups are being read
-contrib/fixhist Script to clean history
-contrib/innconfcheck Merge inn.conf with its man page
-contrib/makeexpctl.in Create expire.ctl from read groups
-contrib/makestorconf.in Create storage.conf from read groups
-contrib/mkbuf Create cycbuff for HP-UX
-contrib/mlockfile.c Lock files into memory using mlock
-contrib/newsresp.c Measure responsiveness of remote server
-contrib/pullart.c Recover articles from cyclic buffers
-contrib/reset-cnfs.c Reset the state parts of a CNFS buffer
-contrib/respool.c Respool articles in the storage manager
-contrib/sample.init.script Example SysV-style init.d script
-contrib/showtoken.in Decode storage API tokens
-contrib/stathist.in Parse history statistics
-contrib/thdexpire.in Dynamic expire for timehash and timecaf
-contrib/tunefeed.in Tune a feed by comparing active files
-control Control message handling (Directory)
-control/Makefile Makefile for control programs
-control/controlbatch.in Batch program for controlchan
-control/controlchan.in Channel program for control messages
-control/docheckgroups.in Script to execute checkgroups
-control/gpgverify.in Verify control messages with GnuPG
-control/modules Modules for controlchan (Directory)
-control/modules/checkgroups.pl checkgroups controlchan handler
-control/modules/ihave.pl ihave controlchan handler
-control/modules/newgroup.pl newgroup controlchan handler
-control/modules/rmgroup.pl rmgroup controlchan handler
-control/modules/sendme.pl sendme controlchan handler
-control/modules/sendsys.pl sendsys controlchan handler
-control/modules/senduuname.pl senduuname controlchan handler
-control/modules/version.pl version controlchan handler
-control/perl-nocem.in NoCeM on spool implementation
-control/pgpverify.in Verify control messages with PGP
-control/signcontrol.in PGP control message signing program
-doc Documentation (Directory)
-doc/GPL The GNU General Public License 2.0
-doc/IPv6-info Nathan Lutchansky's IPv6 notes
-doc/Makefile Makefile for documentation
-doc/checklist Checklist for installing INN
-doc/compliance-nntp INN compliance with the NNTP standard
-doc/config-design Configuration parser design principles
-doc/config-semantics Configuration file semantics
-doc/config-syntax Configuration file syntax
-doc/external-auth readers.conf external interface notes
-doc/history Messages of historical significance
-doc/hook-perl Christophe Wolfhugel's Perl hook notes
-doc/hook-python Python hook notes
-doc/hook-tcl Bob Halley's TCL hook notes
-doc/man nroff documentation (Directory)
-doc/man/Makefile Makefile for nroff documentation
-doc/man/active.5 Manpage for active database
-doc/man/active.times.5 Manpage for active.times file
-doc/man/actsync.8 Manpage for active file synch program
-doc/man/actsyncd.8 Manpage for active synch daemon
-doc/man/archive.8 Manpage for archive backend
-doc/man/auth_krb5.8 Manpage for auth_krb5 authenticator
-doc/man/auth_smb.8 Manpage for auth_smb authenticator
-doc/man/batcher.8 Manpage for batcher
-doc/man/buffchan.8 Manpage for buffchan backend
-doc/man/buffindexed.conf.5 Manpage for buffindexed.conf config file
-doc/man/ckpasswd.8 Manpage for ckpasswd authenticator
-doc/man/clientlib.3 Manpage for C News library interface
-doc/man/cnfsheadconf.8 Manpage for cnfsheadconf
-doc/man/cnfsstat.8 Manpage for cnfsstat
-doc/man/control.ctl.5 Manpage for control.ctl config file
-doc/man/controlchan.8 Manpage for controlchan backend
-doc/man/convdate.1 Manpage for convdate utility
-doc/man/ctlinnd.8 Manpage for ctlinnd frontend
-doc/man/cvtbatch.8 Manpage for cvtbatch utility
-doc/man/cycbuff.conf.5 Manpage for cycbuff.conf config file
-doc/man/dbz.3 Manpage for DBZ database interface
-doc/man/distrib.pats.5 Manpage for distrib.pats config file
-doc/man/domain.8 Manpage for domain resolver
-doc/man/expire.8 Manpage for expire
-doc/man/expire.ctl.5 Manpage for expire.ctl config file
-doc/man/expireover.8 Manpage for expireover
-doc/man/expirerm.8 Manpage for expirerm
-doc/man/fastrm.1 Manpage for fastrm utility
-doc/man/filechan.8 Manpage for filechan backend
-doc/man/getlist.1 Manpage for getlist frontend
-doc/man/grephistory.1 Manpage for grephistory
-doc/man/history.5 Manpage for history database
-doc/man/ident.8 Manpage for ident resolver
-doc/man/incoming.conf.5 Manpage for incoming.conf config file
-doc/man/inews.1 Manpage for inews frontend
-doc/man/inn.conf.5 Manpage for inn.conf config file
-doc/man/inncheck.8 Manpage for inncheck utility
-doc/man/innconfval.1 Manpage for innconfval
-doc/man/innd.8 Manpage for innd server
-doc/man/inndcomm.3 Manpage for part of INN library
-doc/man/inndf.8 Manpage for inndf utility
-doc/man/inndstart.8 Manpage for inndstart
-doc/man/innfeed.1 Manpage for innfeed backend
-doc/man/innfeed.conf.5 Manpage for innfeed.conf config file
-doc/man/innmail.1 Manpage for innmail utility
-doc/man/innreport.8 Manpage for innreport
-doc/man/innstat.8 Manpage for innstat utility
-doc/man/innupgrade.8 Manpage for innupgrade utility
-doc/man/innwatch.8 Manpage for innwatch
-doc/man/innwatch.ctl.5 Manpage for innwatch.ctl config file
-doc/man/innxbatch.8 Manpage for innxbatch
-doc/man/innxmit.8 Manpage for innxmit
-doc/man/libauth.3 Manpage for authprogs utilty routines
-doc/man/libinn.3 Manpage for INN library routines
-doc/man/libinnhist.3 Manpage for history API library routines
-doc/man/libstorage.3 Manpage for storage API library routines
-doc/man/list.3 Manpage for list routines
-doc/man/mailpost.8 Manpage for mailpost frontend
-doc/man/makeactive.8 Manpage for makeactive
-doc/man/makedbz.8 Manpage for makedbz
-doc/man/makehistory.8 Manpage for makehistory
-doc/man/mod-active.8 Manpage for mod-active
-doc/man/moderators.5 Manpage for moderators config file
-doc/man/motd.news.5 Manpage for motd.news config file
-doc/man/news.daily.8 Manpage for news.daily
-doc/man/news2mail.8 Manpage for news2mail
-doc/man/newsfeeds.5 Manpage for newsfeeds config file
-doc/man/newslog.5 Manpage for log files
-doc/man/ninpaths.8 Manpage for ninpaths
-doc/man/nnrpd.8 Manpage for nnrpd daemon
-doc/man/nnrpd.track.5 Manpage for nnrpd.track config file
-doc/man/nntpget.1 Manpage for nntpget frontend
-doc/man/nntpsend.8 Manpage for nntpsend
-doc/man/nntpsend.ctl.5 Manpage for nntpsend.ctl config file
-doc/man/ovdb.5 Manpage for the ovdb storage module
-doc/man/ovdb_init.8 Manpage for ovdb_init
-doc/man/ovdb_monitor.8 Manpage for ovdb_monitor
-doc/man/ovdb_server.8 Manpage for ovdb_server
-doc/man/ovdb_stat.8 Manpage for ovdb_stat
-doc/man/overchan.8 Manpage for overchan backend
-doc/man/overview.fmt.5 Manpage for overview.fmt config file
-doc/man/parsedate.3 Manpage for parsedate library routine
-doc/man/passwd.nntp.5 Manpage for passwd.nntp config file
-doc/man/perl-nocem.8 Manpage for perl-nocem
-doc/man/pgpverify.1 Manpage for pgpverify
-doc/man/prunehistory.8 Manpage for prunehistory
-doc/man/pullnews.1 Manpage for pullnews
-doc/man/putman.sh Install a manpage
-doc/man/qio.3 Manpage for fast I/O file routines
-doc/man/radius.8 Manpage for radius authenticator
-doc/man/radius.conf.5 Manpage for radius.conf config file
-doc/man/rc.news.8 Manpage for rc.news
-doc/man/readers.conf.5 Manpage for readers.conf config file
-doc/man/rnews.1 Manpage for rnews frontend
-doc/man/sasl.conf.5 Manpage for sasl.conf config file
-doc/man/scanlogs.8 Manpage for scanlogs
-doc/man/send-nntp.8 Manpage for send-nntp and send-ihave
-doc/man/send-uucp.8 Manpage for send-uucp
-doc/man/sendinpaths.8 Manpage for sendinpaths
-doc/man/shlock.1 Manpage for shlock backend utility
-doc/man/shrinkfile.1 Manpage for shrinkfile utility
-doc/man/simpleftp.1 Manpage for simpleftp utility
-doc/man/sm.1 Manpage for sm
-doc/man/startinnfeed.1 Manpage for startinnfeed
-doc/man/storage.conf.5 Manpage for storage.conf config file
-doc/man/subscriptions.5 Manpage for subscriptions list
-doc/man/tally.control.8 Manpage for tally.control
-doc/man/tdx-util.8 Manpage for tdx-util
-doc/man/tst.3 Manpage for ternary search tree routines
-doc/man/uwildmat.3 Manpage for uwildmat library routine
-doc/man/writelog.8 Manpage for writelog
-doc/pod POD documentation (Directory)
-doc/pod/Makefile Maintainer rules for derived files
-doc/pod/active.pod Master file for active.5
-doc/pod/active.times.pod Master file for active.times.5
-doc/pod/auth_krb5.pod Master file for auth_krb5.8
-doc/pod/auth_smb.pod Master file for auth_smb.8
-doc/pod/checklist.pod Master file for doc/checklist
-doc/pod/ckpasswd.pod Master file for ckpasswd.8
-doc/pod/control.ctl.pod Master file for control.ctl.5
-doc/pod/convdate.pod Master file for convdate.1
-doc/pod/cycbuff.conf.pod Master file for cycbuff.conf.5
-doc/pod/distrib.pats.pod Master file for distrib.pats.5
-doc/pod/domain.pod Master file for domain.8
-doc/pod/expire.ctl.pod Master file for expire.ctl.5
-doc/pod/expireover.pod Master file for expireover.8
-doc/pod/external-auth.pod Master file for doc/external-auth
-doc/pod/fastrm.pod Master file for fastrm.1
-doc/pod/grephistory.pod Master file for grephistory.1
-doc/pod/hacking.pod Master file for HACKING
-doc/pod/hook-perl.pod Master file for doc/hook-perl
-doc/pod/hook-python.pod Master file for doc/hook-python
-doc/pod/ident.pod Master file for ident.8
-doc/pod/inews.pod Master file for inews.1
-doc/pod/inn.conf.pod Master file for inn.conf.5
-doc/pod/innconfval.pod Master file for innconfval.1
-doc/pod/innd.pod Master file for innd.8
-doc/pod/inndf.pod Master file for inndf.8
-doc/pod/inndstart.pod Master file for inndstart.8
-doc/pod/innmail.pod Master file for innmail.1
-doc/pod/innupgrade.pod Master file for innupgrade.8
-doc/pod/install.pod Master file for INSTALL
-doc/pod/libauth.pod Master file for libauth.3
-doc/pod/libinnhist.pod Master file for libinnhist.3
-doc/pod/list.pod Master file for list.3
-doc/pod/mailpost.pod Master file for mailpost.8
-doc/pod/makehistory.pod Master file for makehistory.8
-doc/pod/motd.news.pod Master file for motd.news.5
-doc/pod/news.pod Master file for NEWS
-doc/pod/newsfeeds.pod Master file for newsfeeds.5
-doc/pod/ninpaths.pod Master file for ninpaths.8
-doc/pod/nnrpd.pod Master file for nnrpd.8
-doc/pod/ovdb.pod Master file for ovdb.5
-doc/pod/ovdb_init.pod Master file for ovdb_init.8
-doc/pod/ovdb_monitor.pod Master file for ovdb_monitor.8
-doc/pod/ovdb_server.pod Master file for ovdb_server.8
-doc/pod/ovdb_stat.pod Master file for ovdb_stat.8
-doc/pod/passwd.nntp.pod Master file for passwd.nntp.5
-doc/pod/pullnews.pod Master file for pullnews.1
-doc/pod/qio.pod Master file for qio.3
-doc/pod/radius.conf.pod Master file for radius.conf.5
-doc/pod/radius.pod Master file for radius.8
-doc/pod/rc.news.pod Master file for rc.news.8
-doc/pod/readers.conf.pod Master file for readers.conf.5
-doc/pod/readme.pod Master file for README
-doc/pod/sasl.conf.pod Master file for sasl.conf.5
-doc/pod/sendinpaths.pod Master file for sendinpaths.8
-doc/pod/simpleftp.pod Master file for simpleftp.1
-doc/pod/sm.pod Master file for sm.1
-doc/pod/subscriptions.pod Master file for subscriptions.5
-doc/pod/tdx-util.pod Master file for tdx-util.8
-doc/pod/tst.pod Master file for tst.3
-doc/pod/uwildmat.pod Master file for uwildmat.3
-doc/sample-control Sample PGP-signed control message
-expire Expiration and recovery (Directory)
-expire/Makefile Makefile for expiration
-expire/convdate.c Date string conversions
-expire/expire.c Expire old articles and history lines
-expire/expireover.c Expire news overview data
-expire/expirerm.in Remove articles from expire -z
-expire/fastrm.c Remove list of files
-expire/grephistory.c Find entries in history database
-expire/makedbz.c Recover dbz
-expire/makehistory.c Recover the history database
-expire/prunehistory.c Prune file names from history file
-frontends inews, rnews, ctlinnd (Directory)
-frontends/Makefile Makefile for frontends
-frontends/cnfsheadconf.in Setup cycbuff header
-frontends/cnfsstat.in Show cycbuff status
-frontends/ctlinnd.c Send control request to innd
-frontends/decode.c Decode 7-bit data into binary file
-frontends/encode.c Encode binary file into 7-bit data
-frontends/feedone.c Test rig to feed a single NNTP article
-frontends/getlist.c Get active or other list from server
-frontends/inews.c Send article to local NNTP server
-frontends/innconfval.c Get an INN configuration parameter
-frontends/mailpost.in Mail to news gateway
-frontends/ovdb_init.c Prepare ovdb database for use
-frontends/ovdb_monitor.c Database maintainance for ovdb
-frontends/ovdb_server.c Helper server for ovdb
-frontends/ovdb_stat.c Display information from ovdb database
-frontends/pullnews.in Sucking news feeder
-frontends/rnews.c UUCP unbatcher
-frontends/scanspool.in Scan spool directory for trash
-frontends/sm.c Get article or overview data from token
-frontends/sys2nf.c Sys file to newsfeeds conversion aid
-history History library routines (Directory)
-history/Make.methods Makefile for history methods
-history/Makefile Makefile for history library
-history/buildconfig.in Construct history interface
-history/his.c History API glue implementation
-history/hisinterface.h History API interface
-history/hisv6 History v6 method (Directory)
-history/hisv6/hismethod.config hisbuildconfig definition
-history/hisv6/hisv6-private.h Private header file for hisv6
-history/hisv6/hisv6.c hisv6 history method
-history/hisv6/hisv6.h Header for hisv6 history
-include Header files (Directory)
-include/Makefile Makefile for header files
-include/acconfig.h Master file for config.h.in
-include/clibrary.h C library portability
-include/conffile.h Header file for reading *.conf files
-include/config.h.in Template configuration data
-include/dbz.h Header file for DBZ
-include/inn Installed header files (Directory)
-include/inn/buffer.h Header file for reusable counted buffers
-include/inn/confparse.h Header file for configuration parser
-include/inn/defines.h Portable defs for installed headers
-include/inn/hashtab.h Header file for generic hash table
-include/inn/history.h Header file for the history API
-include/inn/innconf.h Header file for the innconf struct
-include/inn/list.h Header file for list routines
-include/inn/md5.h Header file for MD5 digests
-include/inn/messages.h Header file for message functions
-include/inn/mmap.h Header file for mmap() functions
-include/inn/qio.h Header file for quick I/O package
-include/inn/sequence.h Header file for sequence space arithmetic
-include/inn/timer.h Header file for generic timers
-include/inn/tst.h Header file for ternary search tries
-include/inn/vector.h Header file for vectors of strings
-include/inn/wire.h Header file for wire-format functions
-include/inndcomm.h innd control channel commands
-include/innperl.h Header file for embedded Perl
-include/libinn.h INN library declarations
-include/nntp.h NNTP command and reply codes
-include/ov.h Header file for overview
-include/paths.h.in Paths to common programs and files
-include/portable Portability wrappers (Directory)
-include/portable/mmap.h Wrapper for <sys/mman.h>
-include/portable/setproctitle.h Portable setup for setproctitle
-include/portable/socket.h Wrapper for <sys/socket.h> and friends
-include/portable/time.h Wrapper for <time.h> and <sys/time.h>
-include/portable/wait.h Wrapper for <sys/wait.h>
-include/ppport.h Header file for Perl support
-include/storage.h Header file for storage API
-innd Server (Directory)
-innd/Makefile Makefile for server
-innd/art.c Process a received article
-innd/cc.c Control channel routines
-innd/chan.c I/O channel routines
-innd/icd.c Read and write the active file
-innd/innd.c Main and utility routines
-innd/innd.h Header file for server
-innd/inndstart.c Open the NNTP port, then exec innd
-innd/keywords.c Generate article keywords
-innd/lc.c Local NNTP channel routines
-innd/nc.c NNTP channel routines
-innd/newsfeeds.c Routines to parse the newsfeeds file
-innd/ng.c Newsgroup routines
-innd/perl.c Perl routines for innd
-innd/proc.c Process routines
-innd/python.c Python routines for innd
-innd/rc.c Remote channel accepting routines
-innd/site.c Site feeding routines
-innd/status.c Status routines for innd
-innd/tcl.c Bob Halley's Tcl hook
-innd/util.c Utility functions for innd
-innd/wip.c Work-in-progress routines for innd
-innfeed innfeed (Directory)
-innfeed/Makefile Makefile for innfeed
-innfeed/README Assorted notes
-innfeed/article.c Implementation of the Article class
-innfeed/article.h Public interface to Articles
-innfeed/buffer.c Implementation of the Buffer class
-innfeed/buffer.h Public interface to the Buffer class
-innfeed/config_l.c Lexer for the innfeed config file
-innfeed/configfile.h Header file for configfile.y
-innfeed/configfile.l Master file for config_l.c
-innfeed/configfile.y Parser for innfeed config file
-innfeed/connection.c Implementation of the Connection class
-innfeed/connection.h Public interface to the Connection class
-innfeed/endpoint.c Implementation of the EndPoint class
-innfeed/endpoint.h Public interface to the EndPoint class
-innfeed/host.c Implementation of the Host class
-innfeed/host.h Public interface to the Host class
-innfeed/imap_connection.c Implementation of IMAP Connection class
-innfeed/innfeed-convcfg.in Script to convert old innfeed.conf
-innfeed/innfeed.h Application configuration values
-innfeed/innlistener.c Implementation of the InnListener class
-innfeed/innlistener.h Public interface of InnListener class
-innfeed/main.c Main routines for the innfeed program
-innfeed/misc.c Miscelloneous routines for innfeed
-innfeed/misc.h Header file for misc.c
-innfeed/procbatch.in Script to process dropped articles
-innfeed/startinnfeed.c Start innfeed
-innfeed/tape.c Implementation of the Tape class
-innfeed/tape.h Public interface to the Tape class
-innfeed/testListener.pl Script to hand articles to innfeed
-lib INN library routines (Directory)
-lib/Makefile Makefile for library
-lib/buffer.c Reusable counted buffer
-lib/cleanfrom.c Clean out a From line
-lib/clientactive.c Client access to the active file
-lib/clientlib.c Replacement for C News library routine
-lib/concat.c Concatenate strings with dynamic memory
-lib/conffile.c Routines for reading *.conf files
-lib/confparse.c Generic configuration file parser
-lib/daemonize.c Code necessary to become a daemon
-lib/date.c Date parsing and conversion routines
-lib/dbz.c DBZ database library
-lib/defdist.c Determine default Distribution header
-lib/fdflags.c Set or clear file descriptor flags
-lib/fdlimit.c File descriptor limits
-lib/fseeko.c fseeko replacement
-lib/ftello.c ftello replacement
-lib/genid.c Generate a message ID
-lib/getfqdn.c Get FQDN of local host
-lib/getmodaddr.c Get a moderator's address
-lib/getpagesize.c getpagesize replacement
-lib/gettime.c Get time and timezone info
-lib/hash.c Create hash from message ID
-lib/hashtab.c Generic hash table
-lib/hstrerror.c Error reporting for resolver
-lib/inet_aton.c Extra source for inet_aton routine
-lib/inet_ntoa.c Convert inaddr to string (BSD)
-lib/innconf.c Parsing and manipulation of inn.conf
-lib/inndcomm.c Library routines to talk to innd
-lib/list.c List routines
-lib/localopen.c Open a local NNTP connection
-lib/lockfile.c Try to lock a file descriptor
-lib/makedir.c Make directory recursively
-lib/md5.c MD5 checksum calculation
-lib/memcmp.c memcmp replacement
-lib/messages.c Error reporting and debug output
-lib/mkstemp.c mkstemp replacement
-lib/mmap.c mmap manipulation routines
-lib/parsedate.y Date parsing
-lib/perl.c Perl hook support for nnrpd and innd
-lib/pread.c pread replacement
-lib/pwrite.c pwrite replacement
-lib/qio.c Quick I/O package
-lib/radix32.c Encode a number as a radix-32 string
-lib/readin.c Read file into memory
-lib/remopen.c Open a remote NNTP connection
-lib/reservedfd.c File descriptor reservation
-lib/resource.c Get process CPU usage
-lib/sendarticle.c Send an article, NNTP style
-lib/sendpass.c Send NNTP authentication
-lib/sequence.c Sequence space arithmetic routines
-lib/setenv.c setenv replacement
-lib/seteuid.c seteuid replacement
-lib/setproctitle.c setproctitle replacement
-lib/snprintf.c snprintf and vsnprintf replacement
-lib/sockaddr.c Manipulation of sockaddr structs
-lib/strcasecmp.c Case-insenstive string comparison (BSD)
-lib/strerror.c String representation of errno
-lib/strlcat.c strlcat replacement
-lib/strlcpy.c strlcpy replacement
-lib/strspn.c Skip bytes in a string (BSD)
-lib/strtok.c Split a string into tokens (BSD)
-lib/timer.c Generic profile timer
-lib/tst.c Ternary search trie implementation
-lib/uwildmat.c Pattern match routine
-lib/vector.c Manipulate vectors of strings
-lib/version.c INN version constants
-lib/wire.c Manipulate wire-format articles
-lib/xfopena.c Open a FILE in append mode
-lib/xmalloc.c Failsafe memory allocation wrapper
-lib/xsignal.c signal() wrapper using sigaction
-lib/xwrite.c write that handles partial transfers
-nnrpd Reader server (Directory)
-nnrpd/Makefile Makefile for nnrpd
-nnrpd/article.c Article-related routines
-nnrpd/cache.c MessageID cache routines
-nnrpd/cache.h MessageID cache interfaces
-nnrpd/commands.c Assorted server commands
-nnrpd/group.c Group-related routines
-nnrpd/line.c Long line-by-line reading routines
-nnrpd/list.c The LIST commands
-nnrpd/misc.c Miscellaneous support routines
-nnrpd/newnews.c The NEWNEWS command
-nnrpd/nnrpd.c Main and some utility routines
-nnrpd/nnrpd.h Header file for nnrpd
-nnrpd/perl.c Perl routines for nnrpd
-nnrpd/perm.c Reading readers.conf
-nnrpd/post.c Article processing and posting
-nnrpd/post.h Article data types
-nnrpd/python.c Python routines for nnrpd
-nnrpd/sasl_config.c Configuration for SASL
-nnrpd/sasl_config.h SASL data types
-nnrpd/tls.c Transport layer security
-nnrpd/tls.h Transport layer security data types
-nnrpd/track.c Track client behavior
-samples Prototype INN config files (Directory)
-samples/INN.py Stub Python functions
-samples/Makefile Makefile for samples
-samples/active.minimal Minimal starting active file
-samples/actsync.cfg Config file for actsync
-samples/actsync.ign Ignore file for actsync
-samples/buffindexed.conf Buffindexed overview config file
-samples/control.ctl Access control for control messages
-samples/cycbuff.conf Sample cycbuff.conf file
-samples/distrib.pats Default values for Distribution header
-samples/expire.ctl Expiration config file
-samples/filter.tcl Sample Tcl filter for innd
-samples/filter_innd.pl Sample Perl filter for innd
-samples/filter_innd.py Sample Python filter for innd
-samples/filter_nnrpd.pl Sample Perl filter for nnrpd
-samples/incoming.conf Permissions for incoming feeds
-samples/inn.conf.in General INN configuration
-samples/innfeed.conf Outgoing feed configuration
-samples/innreport.conf.in Log summary configuration
-samples/innwatch.ctl INN monitoring configuration
-samples/moderators Moderation submission addresses
-samples/motd.news Sample MOTD file
-samples/news2mail.cf news2mail config file
-samples/newsfeeds.in innd feed configuration
-samples/newsgroups.minimal Minimal starting newsgroups file
-samples/nnrpd.py Python hooks for nnrpd
-samples/nnrpd.track Reader tracking configuration
-samples/nnrpd_access.pl.in Sample nnrpd Perl access hooks
-samples/nnrpd_access.py Sample nnrpd Python access hooks
-samples/nnrpd_access_wrapper.pl.in Wrapper around old Perl access hooks
-samples/nnrpd_access_wrapper.py Wrapper around old Python access hooks
-samples/nnrpd_auth.pl.in Sample nnrpd Perl authorization hooks
-samples/nnrpd_auth.py Sample nnrpd Python authorization hooks
-samples/nnrpd_auth_wrapper.pl.in Wrapper around old Perl auth hooks
-samples/nnrpd_auth_wrapper.py Wrapper around old Python auth hooks
-samples/nnrpd_dynamic.py Sample nnrpd Python dynamic access hooks
-samples/nnrpd_dynamic_wrapper.py Wrapper around old Python dynamic hooks
-samples/nntpsend.ctl Outgoing nntpsend feed configuration
-samples/ovdb.conf Berkeley DB overview configuration
-samples/overview.fmt Format of news overview database
-samples/passwd.nntp Passwords for remote connections
-samples/radius.conf Sample config for RADIUS authentication
-samples/readers.conf Reader connection configuration
-samples/sasl.conf.in SASL configuration
-samples/startup.tcl Tcl startup code for innd
-samples/startup_innd.pl Perl startup code for innd
-samples/storage.conf Sample storage configuration
-samples/subscriptions Sample default subscriptions list
-scripts Various utilities (Directory)
-scripts/Makefile Makefile for script files
-scripts/inncheck.in Syntax-check INN config files
-scripts/innmail.in Perl front-end to sendmail
-scripts/innreport.in Script to analyze INN logs
-scripts/innreport_inn.pm Config file for innreport
-scripts/innshellvars.in Config parameters for shell scripts
-scripts/innshellvars.pl.in Config parameters for Perl scripts
-scripts/innshellvars.tcl.in Config parameters for Tcl scripts
-scripts/innstat.in Display INN status snapshot
-scripts/innupgrade.in Upgrade INN configuration files
-scripts/innwatch.in Throttle innd based on load and space
-scripts/news.daily.in Front-end script to run expire, etc.
-scripts/rc.news.in News boot script
-scripts/scanlogs.in Summarize log files
-scripts/simpleftp.in Rudimentary ftp client
-scripts/tally.control.in Count newgroup/rmgroup messages
-scripts/writelog.in Write a log entry or mail it
-site Site-local files (Directory)
-site/Makefile Makefile for site-local files
-site/getsafe.sh Safely get config file from samples
-storage Storage library (Directory)
-storage/Make.methods Makefile for storage methods
-storage/Makefile Makefile for storage library
-storage/buffindexed buffindexed overview method (Directory)
-storage/buffindexed/buffindexed.c buffindexed overview routines
-storage/buffindexed/buffindexed.h Header file for buffindexed overview
-storage/buffindexed/ovmethod.config buildconfig definition
-storage/buffindexed/ovmethod.mk Make rules for buffindexed overview
-storage/buildconfig.in Construct method interface
-storage/cnfs CNFS storage method (Directory)
-storage/cnfs/cnfs-private.h Private header file for CNFS
-storage/cnfs/cnfs.c CNFS storage routines
-storage/cnfs/cnfs.h Header file for CNFS
-storage/cnfs/method.config buildconfig definition
-storage/expire.c Overview-drive expire implementation
-storage/interface.c Storage API glue implementation
-storage/interface.h Storage API interface
-storage/ov.c Overview API glue implementation
-storage/ovdb ovdb overview method (Directory)
-storage/ovdb/ovdb-private.h Private header file for ovdb
-storage/ovdb/ovdb.c ovdb (Berkeley DB) overview method
-storage/ovdb/ovdb.h Header for ovdb (Berkeley DB) overview
-storage/ovdb/ovmethod.config buildconfig definition
-storage/overdata.c Overview data manipulation
-storage/ovinterface.h Overview API interface
-storage/timecaf timecaf storage method (Directory)
-storage/timecaf/README.CAF README the CAF file format
-storage/timecaf/caf.c CAF file implementation
-storage/timecaf/caf.h Header for CAF files
-storage/timecaf/method.config buildconfig definition
-storage/timecaf/timecaf.c timecaf storage routines
-storage/timecaf/timecaf.h Header file for timecaf
-storage/timehash timehash storage method (Directory)
-storage/timehash/method.config buildconfig definition
-storage/timehash/timehash.c timehash storage routines
-storage/timehash/timehash.h Header for timehash
-storage/tradindexed tradindexed overview method (Directory)
-storage/tradindexed/ovmethod.config buildconfig definition
-storage/tradindexed/ovmethod.mk Make rules for tradindexed overview
-storage/tradindexed/tdx-cache.c Data file cache handling for tradindexed
-storage/tradindexed/tdx-data.c Data file handling for tradindexed
-storage/tradindexed/tdx-group.c Group index handling for tradindexed
-storage/tradindexed/tdx-private.h Private header file for tradindexed
-storage/tradindexed/tdx-structure.h On disk layout of tradindexed files
-storage/tradindexed/tdx-util.c Utility program for tradindexed
-storage/tradindexed/tradindexed.c Interface code for the overview API
-storage/tradindexed/tradindexed.h Interface for tradindexed
-storage/tradspool tradspool storage method (Directory)
-storage/tradspool/README.tradspool Docs for tradspool storage method
-storage/tradspool/method.config buildconfig definition
-storage/tradspool/tradspool.c tradspool storage routines
-storage/tradspool/tradspool.h Header for tradspool
-storage/trash Trash storage method (Directory)
-storage/trash/method.config buildconfig definition
-storage/trash/trash.c Trash storage routines
-storage/trash/trash.h Header file for trash storage
-support Tools for building INN (Directory)
-support/config.guess Determine system type for libtool
-support/config.sub Canonicalize system type for libtool
-support/fixscript.in Interpreter path fixup script
-support/indent A mostly working wrapper around indent
-support/install-sh Installation utility
-support/ltmain.sh Source for libtool utility
-support/makedepend Generate dependencies for C files
-support/mkchangelog Generate ChangeLog from CVS
-support/mkmanifest Generate a list of files for the manifest
-support/mksnapshot Generate a snapshot of the tree
-support/mksystem Generate <inn/system.h> from config.h
-support/mkversion Generate <inn/version.h> with INN version
-tests Test suite for INN (Directory)
-tests/Makefile Makefile for test suite
-tests/TESTS List of tests to run
-tests/authprogs Test suite for auth programs (Directory)
-tests/authprogs/ckpasswd.t Tests for authprogs/ckpasswd
-tests/authprogs/domain.t Tests for authprogs/domain
-tests/authprogs/passwd Password data for ckpasswd tests
-tests/lib Test suite for libinn (Directory)
-tests/lib/articles Testing news articles (Directory)
-tests/lib/articles/no-body An article without a body
-tests/lib/articles/strange An article with CR and LF in headers
-tests/lib/articles/truncated An article truncated in the headers
-tests/lib/buffer-t.c Tests for lib/buffer.c
-tests/lib/concat-t.c Tests for lib/concat.c
-tests/lib/config Testing config files (Directory)
-tests/lib/config/errors Various config files with errors
-tests/lib/config/line-endings A config file with varied line endings
-tests/lib/config/no-newline A config file without an ending newline
-tests/lib/config/null A config file containing a nul character
-tests/lib/config/simple A simple config file
-tests/lib/config/valid Various valid config parameters
-tests/lib/config/warn-bool Invalid boolean parameters
-tests/lib/config/warn-int Invalid integer parameters
-tests/lib/config/warnings Various config files with warnings
-tests/lib/confparse-t.c Tests for lib/confparse.c
-tests/lib/date-t.c Tests for lib/date.c
-tests/lib/fakewrite.c Helper functions for xwrite tests
-tests/lib/hash-t.c Tests for lib/hash.c
-tests/lib/hashtab-t.c Tests for lib/hashtab.c
-tests/lib/hstrerror-t.c Tests for lib/hstrerror.c
-tests/lib/inet_aton-t.c Tests for lib/inet_aton.c
-tests/lib/inet_ntoa-t.c Tests for lib/inet_ntoa.c
-tests/lib/innconf-t.c Tests for lib/innconf.c
-tests/lib/list-t.c Tests for lib/list.c
-tests/lib/md5-t.c Tests for lib/md5.c
-tests/lib/memcmp-t.c Tests for lib/memcmp.c
-tests/lib/messages-t.c Tests for lib/messages.c
-tests/lib/mkstemp-t.c Tests for lib/mkstemp.c
-tests/lib/pread-t.c Tests for lib/pread.c
-tests/lib/pwrite-t.c Tests for lib/pwrite.c
-tests/lib/qio-t.c Tests for lib/qio.c
-tests/lib/setenv-t.c Tests for lib/setenv.c
-tests/lib/setenv.t Wrapper for setenv tests
-tests/lib/snprintf-t.c Tests for lib/snprintf.c
-tests/lib/strerror-t.c Tests for lib/strerror.c
-tests/lib/strlcat-t.c Tests for lib/strlcat.c
-tests/lib/strlcpy-t.c Tests for lib/strlcpy.c
-tests/lib/tst-t.c Tests for lib/tst.c
-tests/lib/uwildmat-t.c Tests for lib/uwildmat.c
-tests/lib/vector-t.c Tests for lib/vector.c
-tests/lib/wire-t.c Tests for lib/wire.c
-tests/lib/xmalloc.c Helper program for xmalloc tests
-tests/lib/xmalloc.t Tests for lib/xmalloc.c
-tests/lib/xwrite-t.c Tests for lib/xwrite.c
-tests/libtest.c Helper library for writing tests
-tests/libtest.h Interface to libtest
-tests/overview Test suite for overview (Directory)
-tests/overview/data Test overview data (Directory)
-tests/overview/data/basic Basic set of overview test data
-tests/overview/data/bogus Bad newsgroup name test data
-tests/overview/data/high-numbered High-numbered article test data
-tests/overview/data/reversed Same as basic, but in reverse order
-tests/overview/munge-data Support script to generate test data
-tests/overview/tradindexed-t.c Tests for storage/tradindexed/*
-tests/runtests.c The test suite driver program
-tests/util Test suite for utilities (Directory)
-tests/util/convdate.t Tests for expire/convdate
+++ /dev/null
-Changes in 2.4.5
-
- * Fixed the "alarm signal" around "SSL_read" in nnrpd: it allows a
- proper disconnection of news clients which were previously hanging
- when posting an article through a SSL connection. Moreover, the
- *clienttimeout* parameter now works on SSL connections. Thanks to
- Matija Nalis for the patch.
-
- * SO_KEEPALIVE is now implemented for SSL TCP connections on systems
- which support it, allowing system detection and closing the dead TCP
- SSL connections automatically after system-specified time. Thanks to
- Matija Nalis for the patch.
-
- * Fixed a segmentation fault when an article of a size greater than
- remaining stack is retrieved via SSL. Thanks to Chris Caputo for this
- patch.
-
- * Fixed a few segfaults and bugs which affected both Python innd and
- nnrpd hooks. They no longer check the existence of methods not used
- by the hooked script. An issue with Python exception handling was
- also fixed, as well as a segfault fixed by Russ Allbery which happened
- whenever one closes and then reopens Python in the same process.
- Julien Elie also fixed a bug when reloading Python filters (they were
- not always correctly reloaded) and a segfault when generating access
- groups with embedded Python filters for nnrpd. Many thanks to David
- Hlacik for its bug reports.
-
- * The nnrpd.py stub file in order to test Python nnrpd hooks, as
- mentioned in their documentation, is now installed; only INN.py was
- previously installed in *pathfilter*. Also fixed a bug in INN.py and
- add missing methods to it.
-
- * Fixed a long-standing bug in innreport which prevented it from
- correctly reporting nnrpd and innfeed log messages.
-
- * Fixed a hang in Perl hooks on (at least) HP/PA since Perl 5.10.
-
- * Fixed a compilation problem on some platforms because of AF_INET6
- which was not inside a HAVE_INET6 block in innfeed.
-
- * Fixed a bug in innfeed which contained thrice the same IPs for each
- peer; it unnecessarily slowed the peer IP rotation for innfeed.
- Thanks, D. Stussy, for having seen that. Miquel van Smoorenburg
- provided the patch.
-
- * A new *heavily* improved version of pullnews is shipped with this INN
- release. This new version is provided by Geraint Edwards. He added
- no more than 16 flags, fixed some bugs and integrated the backupfeed
- contrib script by Kai Henningsen, adding again 6 other flags. A
- long-standing but very minor bug in the -g option was especially fixed
- and items from the to-do list implemented. Many thanks again to
- Geraint Edwards.
-
- * New headers are accessible through Perl and Python innd filtering
- hooks. You will find the exact list in the INN Python Filtering and
- Authentication Hooks documentation (doc/hook-python) and in Python
- samples. Thanks to Matija Nalis for this addition of new useful
- headers.
-
- * New samples for Python nnrpd hooks are shipped with INN:
- nnrpd_access.py for access control and nnrpd_dynamic.py for dynamic
- access control. The nnrpd_auth.py script is now only used for
- authorization control. See the readers.conf man page for more
- information (especially the *python_auth*, *python_access* and
- *python_dynamic* parameters). The documention about INN Python
- Filtering and Authentication Hooks has also been improved by Julien
- Elie.
-
-Changes in 2.4.4
-
- * Fixed incomplete checking of packet sizes in the ctlinnd interface in
- the no-Unix-domain-sockets case. This is a potential buffer overflow
- in dead code since basically all systems INN builds on support Unix
- domain sockets these days. Also track the buffer size more correctly
- in the client side of this interface for the Unix domain socket case.
-
- * Group blocks in incoming.conf are now correctly parsed and no longer
- cause segfaults when loading this file.
-
- * Fixed a problem with innfeed continuously segfaulting on amd64
- hardware (and possibly on lots of 64-bit platforms). Many thanks to
- Ollivier Robert for his patch and also to Kai Gallasch for having
- reported the problem and provided the FreeBSD server to debug it.
-
- * scanlogs now rotates innfeed's log file, which prevents innfeed from
- silently dying when its log file reaches 2 GB.
-
- * Perl 5.10 support has been added to INN thanks to Jakub Bogusz.
-
- * Some news clients hang when posting an article through a SSL
- connection: it seems that nnrpd's SSL routines make it wrongly wait
- for data completion. In order to fix the problem, the select() wait
- is now just bypassed. However, the IDLE timer stat is currently not
- collected for such connections. Thanks to Kachun Lee for this
- workaround.
-
- * Fixed a bug in the display of the used compressor ("cunbatch" was used
- if arguments were passed to gzip or bzip2).
-
- * Fixed a bug in mailpost and pullnews which prevented useful error
- messages to be seen. Also add the -x flag to pullnews in order to
- insert Xref: headers in articles which lack one.
-
- * If compiling with Berkeley DB, use its ndbm compatibility layer for
- ckpasswd in preference to searching for a traditional dbm library.
- INN also supports Berkeley DB 4.4, 4.5 and 4.6 thanks to Marco d'Itri.
-
- * ovdb_init now properly closes stdin/out/err when it becomes a daemon.
- The issue was reported by Viktor Pilpenok and fixed by Marco d'Itri.
-
- * Added support for Diablo quickhash and hashfeed algorithms. It allows
- to distribute the messages among several peers (new Q flag for
- newsfeeds). Thanks to Miquel van Smoorenburg for this implementation
- in INN.
-
- * innd now listen on separate sockets for IPv4 and IPv6 connections if
- the IPV6_V6ONLY socket option is available. There might also be
- operating systems that still have separate IPv4 and IPv6 TCP
- implementations, and advanced features like TCP SACK might not be
- available on v6 sockets. Thanks to Miquel van Smoorenburg for this
- patch.
-
- * The two configuration options *bindaddress* and *bindaddress6* can now
- be set on a per-peer basis for innfeed. Setting *bindaddress6* to
- "none" tells innfeed to never attempt an IPv6 connection to that host.
- Thanks to Miquel van Smoorenburg for this patch.
-
- * Added a *nnrpdflags* parameter to inn.conf (modeled on the concept of
- *innflags*) to permit passing of command line arguments to instances
- of nnrpd spawned from innd.
-
- * A new inn.conf parameter called *pathcluster* has been added: it
- allows to append a common name to the Path: header on all incoming
- articles. *pathhost* and *pathalias* (if set) are still appended to
- the path as usual, but *pathcluster* is always appended as the last
- element (e.g. on the leftmost side of the Path: header). Thanks to
- Miquel van Smoorenburg for this feature.
-
- * simpleftp has been rewritten to use "Net::FTP". Indeed, ftp.pl is no
- longer shipped with Perl 5 and the script did not work.
-
- * perl-nocem will now check for a timeout and re-open the socket if
- required. Additionally, perl-nocem will switch to cancel_ctlinnd in
- case cancel_nntp fails after sending the Message-ID. Thanks to
- Christoph Biedl for the patch. A more detailed documentation has also
- been written for perl-nocem(8).
-
- * The RADIUS configuration is now wrapped in a "server {}" block in
- radius.conf.
-
- * Checkgroups when there is nothing to change no longer result in
- sending a blank mail to administrators. Besides, no mail is sent by
- controlchan for the creation of a newsgroup when the action is "no
- change".
-
- * Checkgroups are now properly propagated even though the news server
- does not carry the groups they are posted to.
-
- * controlchan and docheckgroups now handle wire format messages so that
- articles from the spool can be directly fed to them.
-
- * Newgroup control messages for existing groups now change their
- description. If a mail is sent to administrators, it reminds them to
- update their newsgroups file. It also warns when there are missing or
- obsolete descriptions. Furthermore, the newsgroups file is now
- written prettier (from one to three tabulations between the name of
- the group and its short description) and to.* groups cannot be
- created.
-
- * The sample control.ctl file has been extensively updated.
-
- * Fixed empty LISTGROUP replies which were not terminated. Thanks to
- David Canzi for the patch.
-
- * In response to a LIST [file] command, if the file does not exist, we
- assume it is not maintained and return 503 instead of 215 and an empty
- file. Moreover, capability to LIST ACTIVE.TIMES for a wildmat pattern
- as its third argument has been added in order to select wanted
- newsgroups.
-
- * inews now tries to authenticate if it does not receive a 200 return
- code after MODE READER. Indeed, it might be able to post even with a
- 201 return code and also with another codes like 440 or 480.
-
- * If creating a new history file, set the ownership and mode
- appropriately. inncheck also expects fewer things to be private to
- the news user. Most of the configuration files will never contain
- private information like passwords.
-
- * Other minor bug fixes and documentation improvements.
-
-Changes in 2.4.3
-
- * Previous versions of INN had an optimization for handling XHDR
- Newsgroups that used the Xref: header from overview. While this does
- make the command much faster, it doesn't produce accurate results and
- breaks the NNTP protocol, so this optimization has been removed.
-
- * Fixed a bug in innd that allowed it to accept articles with duplicated
- headers if the header occurred an odd number of times. Modified the
- programs for rebuilding overview to use the last Xref: header if there
- are multiple ones to avoid problems with spools that contain such
- invalid articles.
-
- * Fixed yet another problem with verifying that a user has permissions
- to approve posts to a moderated group. Thanks, Jens Schlegel.
-
- * Increase the send and receive buffer on the Unix domain socket used by
- ctlinnd. This should allow longer replies (particularly for innstat)
- on platforms with very low default Unix domain socket buffer sizes.
-
- * rnews's handling of articles with nul characters, NNTP errors, header
- problems, and deferrals has been significantly improved.
-
- * Thomas Parmelan added support to send-uucp for specifying the funnel
- or exploder site to flush for feeds managed through one and fixed a
- problem with picking up old stranded work files.
-
- * Many other more minor bug fixes, optimization improvements, and
- documentation fixes.
-
-Changes in 2.4.2
-
- * INN is now licensed under a less restrictive license (about as
- minimally restrictive as possible shy of public domain), and the
- clause similar to the old BSD advertising clause has been dropped.
-
- * "make install" and "make update" now always install the newly built
- binaries, rather than only installing them if the modification times
- are newer. This is the behavior that people expect. "make install"
- now also automatically builds a new (empty) history database if one
- doesn't already exist.
-
- * The embedded Tcl filter code has been disabled (and will be removed
- entirely in the next major release of INN). It hasn't worked for some
- time and causes innd crashes if compiled in (even if not used). If
- someone wants to step forward and maintain it, I recommend starting
- from scratch and emulating the Perl and Python filters.
-
- * ctlinnd should now successfully handle messages from INN up to the
- maximum allowable packet size in the protocol, fixing problems sites
- with many active peers were having with innstat output.
-
- * Overview generation has been fixed in both makehistory and innd to
- follow the rules in the latest NNTP draft rather than just replacing
- special characters with spaces. This means that the unfolding of
- folded header lines will not introduce additional, incorrect
- whitespace in the overview data.
-
- * nnrpd now uniformly responds with a 480 or 502 status code to attempts
- to read a newsgroup to which the user does not have access, depending
- on whether the user has authenticated. Previously, it returned a 411
- status code, claiming the group didn't exist, which confuses the
- reactive authentication capability of news readers.
-
- * If a user is not authorized to approve articles (using the "A"
- *access* control in readers.conf), articles that include Approved:
- headers will be rejected even if posted to unmoderated groups. Some
- other site may consider that group to be moderated.
-
- * The configuration parser used for readers.conf and others now
- correctly handles "#" inside quoted strings and is more robust against
- unmatched double quotes.
-
- * Messages mailed to moderators had two spaces after the colons in the
- headers, rather than one. This bug has been fixed.
-
- * A bug that could cause heap corruption and random crashes in innd if
- INN were compiled with Python support has been fixed.
-
- * Some problems with innd's tracking of article size and enforcement of
- the configured maximum article size have been fixed.
-
- * pgpverify will now correctly verify signatures generated by GnuPG and
- better supports GnuPG as the PGP implementation.
-
- * INN's code should now be more 64-bit clean in its handling of size_t,
- pointer differences, and casting of pointers, correcting problems that
- showed up on 64-bit platforms like AMD64.
-
- * Improved the error reporting in the history database code, in inews,
- in controlchan, and in expire.
-
- * Many other, more minor bugs have also been fixed.
-
-Changes in 2.4.1
-
- * SECURITY: Handle the special filing of control messages into per-type
- newsgroups more robustly. This closes a potentially exploitable
- buffer overflow. Thanks to Dan Riley for his excellent bug report.
-
- * Fixed article handling in innd so that articles without a Path: header
- (arising from peers sending malformatted articles or injecting
- malformatted articles through rnews) would not cause innd to crash.
- (This was not exploitable.)
-
- * Fixed a serious bug in XPAT handling, thanks to Tommy van Leeuwen.
-
- * "configure" now looks for sendmail only in /usr/sbin and /usr/lib, not
- on the user's path. This should reduce the need for --with-sendmail
- if your preferred sendmail is in a standard location.
-
- * The robustness of the tradindexed overview method has been further
- increased, handling more edge cases arising from corrupted databases
- and oddly-named newsgroups.
-
- * innd now never decreases the high water mark of a newsgroup when
- renumbering, which should help ameliorate overview and active file
- synchronization problems.
-
- * Do not close and reopen the history file on ctlinnd reload when the
- server is paused or throttled. This was breaking ctlinnd reload all
- during a server pause.
-
- * Various minor portability and compilation issues fixed. Substantial
- numbers of compiler warnings have been cleaned up, thanks largely to
- work by Ilya Kovalenko.
-
- * Multiple other more minor bugs have been fixed.
-
- * Documentation and man pages have been clarified and updated.
-
-Upgrading from 2.3 to 2.4
-
- The inn.conf parser has changed between INN 2.3 and 2.4. Due to that
- change, options in inn.conf that contain whitespace or a few other
- special characters must be quoted with double quotes, and empty
- parameters (parameters with no value) are not allowed. INN 2.4 comes
- with a script, innupgrade, run automatically during "make update", that
- will attempt to fix any problems that it finds with your inn.conf file,
- saving the original as inn.conf.OLD.
-
- This change is the beginning of standardization of parsing and syntax
- across all of INN's configuration files.
-
- The history subsystem now has a standard API that allows other backends
- to be used. Because of this, you now need to specify the history method
- in inn.conf. Adding:
-
- hismethod: hisv6
-
- will tell INN to use the same history backend as was used in previous
- versions. innupgrade should take care of this for you.
-
- ovdb is known to have some locking and timing issues related to how
- nnrpd shuts down (or fails to shut down) the overview databases. If you
- have stability problems with ovdb, try setting *readserver* to "true" in
- ovdb.conf. This will funnel all ovdb reads through a single process
- with a cleaner interface to the underlying Berkeley DB database.
-
- If you use Perl authentication for nnrpd (if *nnrpdperlauth* in inn.conf
- is "true"), there have been major changes. See "Changes to Perl
- Authentication Support for nnrpd" in doc/hook-perl for details.
-
- Similarly, if you use Python authentication for nnrpd (if
- *nnrpdpythonauth* in inn.conf is "true"), there have been major changes.
- See "Changes to Python Authentication and Access Control Support for
- nnrpd" in doc/hook-python for details.
-
- If you use send-uucp, it has been completely rewritten and now takes a
- configuration file to specify its behavior. See its man page for more
- information. If you use sendbatch, it is no longer included in INN
- since the new send-uucp can handle all of the same functionality.
-
- The wildmat API has been renamed (to uwildmat and friends; see
- uwildmat(3) for the interfaces) to distinguish it from Rich $alz's
- original version, since it now supports UTF-8. This may require changes
- in other software packages that link against INN's libraries.
-
- If you are upgrading from a version prior to INN 2.3, see "Upgrading
- from 2.2 to 2.3".
-
-Changes in 2.4.0
-
- * IPv6 support has been added, disabled by default. If you have IPv6
- connectivity, build with --enable-ipv6 to try it. There are no known
- bugs, but please report any problems you find (or even successes, if
- you use an unusual platform). There are a few changes of interest;
- further information is available in doc/IPv6-info.
-
- * The tradindexed overview method has been completely rewritten and
- should be considerably more robust in the face of system crashes. A
- new utility, tdx-util, is provided to examine the contents of the
- overview database, repair inconsistencies, and rebuild the overview
- for particular groups from a tradspool news spool. See tdx-util(8)
- for more details.
-
- * The Perl and Python authentication hooks for readers have been
- extensively overhauled and integrated better with readers.conf. See
- the Changes sections in doc/hook-perl and doc/hook-python for more
- details.
-
- * nnrpd now optionally supports article injection via IHAVE, see
- readers.conf(5). Any articles injected this way must have Date, From,
- Message-ID, Newsgroups, Path, and Subject headers. X-Trace and
- X-Complaints-To headers will be added if the appropriate options are
- set in readers.conf, but other headers will not be modified/inserted
- (e.g. NNTP-Posting-Host, NNTP-Posting-Date, Organization, Lines, Cc,
- Bcc, and To headers).
-
- * nnrpd now handles arbitrarily long lines in POST and IHAVE;
- administrators who want to limit the length of lines in locally posted
- articles will need to add this to their local filters instead.
-
- * nnrpd no longer handles the poorly-specified RFC 977 optional fourth
- argument to the NEWGROUPS command specifying the "distributions" that
- the command was supposed to apply to.
-
- Clients that use that argument will break. There are not believed to
- be any such clients, and it's easy enough to just filter the returned
- list of newsgroups (which is generally fairly short) to achieve the
- same results.
-
- * nnrpd no longer accepts UTC as a synonym for GMT for NEWGROUPS or
- NEWNEWS. This usage was never portable, and was rejected by the NNTP
- working group. It is being removed now in the hope that it will be
- caught before anyone starts to rely on it.
-
- * innfeed supports a new peer parameter, *backlog-feed-first*, that if
- set to "true" feeds any backlog to a peer before new articles, see
- innfeed.conf(5). When used in combination with *max-connections* set
- to 1, this can be used to enforce in-order delivery of messages to a
- peer that is doing Xref slaving, avoiding cases where a
- higher-numbered message is received before a lower-numbered message in
- the same group.
-
- * Several other, more minor protocol issues have been fixed:
- connections rejected due to the connection rate limiting in innd
- receive 400 replies instead of 504 or 505, and ARTICLE without an
- argument will always either retrieve the current article or return a
- 423 error, never advance the current article number to the next valid
- article.
-
- See doc/compliance-nntp for all of the known issues with INN's
- compliance with the current NNTP draft.
-
- * All accesses to the history file for all parts of INN now go through a
- generic API like the storage and overview subsystems do. This will
- eventually allow new history implementations to be dropped in without
- affecting the rest of INN, and will significantly improve the
- encapsulation of the history subsystem. See the libinnhist(3) man
- page for the details of the interface.
-
- * INN now uses a new parser for the inn.conf file. This means that
- parameters containing whitespace or other special characters must now
- be quoted; see inn.conf(5). It fixes the long-standing bug that
- certain values must be included in inn.conf even if using the defaults
- for the use of shell or Perl scripts, and it will serve as the basis
- for standardizing and cleaning up the configuration file parsing in
- other parts of INN. innupgrade is run during "make update" and should
- convert an existing inn.conf file for you.
-
- * send-uucp has been replaced by a completely rewritten version from
- Marco d'Itri, Edvard Tuinder, and Miquel van Smoorenburg, which uses a
- configuration file that specifies batch sizes, compression methods,
- and hours during which batches should be generated. The old sendbatch
- script has been retired, since send-uucp can now handle everything
- that it did.
-
- * Two "configure" options have changed names: --with-tmp-path is now
- --with-tmp-dir, and --with-largefiles is now --enable-largefiles, to
- improve consistency and better match the "autoconf" option guidelines.
-
- * Variables can now be used in the newsfeeds file to make it easier to
- specify many similar feeds or feed patterns. See the newsfeeds(5) man
- page for details.
-
- * Local connections to INN support a new special mode, MODE CANCEL, that
- allows efficient batch cancellation of messages. This is intended to
- be the preferred interface for external spam and abuse filters like
- NoCeM. See "CANCEL FEEDS" in innd(8) for details.
-
- * Two new options, *nfsreader* and *nfswriter*, have been added to
- inn.conf to aid in building NFS based shared reader/writer platforms.
- On the writer server configure *nfswriter* to "true" and on all of the
- readers configure *nfsreader* to "true"; these options add calls to
- force data out to the NFS server and force it to be read directly from
- the NFS server at the appropriate moments. Note that it has only been
- tested on Solaris 8, using CNFS as the storage mechanism and
- tradindexed as the overview method.
-
- * A new option, *tradindexedmmap*, has been added to inn.conf. If set
- to "true" (the default), then the tradindexed overview method will use
- mmap() to access its overview data (in 2.3 you couldn't control this;
- it always used mmap).
-
- * Thanks to code contributed by CMU, innfeed can now feed an IMAP server
- as well as other NNTP servers. See the man page for innfeed(8) for
- more information.
-
- * An authenticator, auth_smb, that checks a username and password
- against a remote Samba server is now included. See auth_smb(8) for
- details.
-
- * The wildmat functions in INN now support UTF-8, in a way that should
- allow them to still work with most simple 8-bit character sets in
- widespread use. As part of this change, some additional wildmat
- interfaces are now available and the names have changed (to uwildmat,
- where "u" is for Unicode). See uwildmat(3) for the details.
-
- * The interface between external authenticators and nnrpd is now
- properly documented, in doc/external-auth. A library implementing
- this interface in C is provided, which should make it easier to write
- additional authenticators resolvers. See libauth(3) for details, and
- any of the existing programs in authprogs/ for examples.
-
- * Most (if not all) of the temporary file creation in INN now uses
- functions that create temporary files properly and safely.
-
-Changes in 2.3.5
-
- * Clients using POST are no longer permitted to provide an
- Injector-Info: header.
-
- * Fixed a bug causing posts with Followup-To: set to a moderated group
- to be rejected if the posting user didn't have permission to approve
- postings.
-
- * Fixed bugs in inncheck with setuid rnews or setgid inews, in
- *innconfval* with inn.conf parameters containing shell metacharacters
- but no spaces, and in parsedate.y with some versions of yacc. Fixed a
- variety of size-related printf format warnings (e.g., %d vs. %ld)
- thanks to the work of Winfried Szukalski.
-
-Changes in 2.3.4
-
- * LIST ACTIVE no longer returns data when given a single group argument
- if the client is not authorized to read that group.
-
- * XHDR and XPAT weren't correctly parsing article headers, resulting in
- searches for the header "newsgroup" matching the header "newsgroups".
-
- * Made CNFS more robust against crashes by actually syncing the cycbuff
- headers to disk as was originally intended. Fixed a memory leak in
- the tradspool code.
-
- * Two bugs in pgpverify when using GnuPG were fixed: it now correctly
- checks for gpgv (rather than pgp) when told to use GnuPG and expects
- the keyring to be pubring.gpg (not pubring.pgp).
-
- * Substantial updates to the sample provided control.ctl file.
-
- * Compilation fixes with Perl 5.8.0, Berkeley DB 4.x, current versions
- of Linux (including with large file support), and Tru64. inndf fixes
- for ReiserFS.
-
- * Various bugs in the header handling in nnrpd have been fixed,
- including hangs when using virtual domains and improper processing of
- folded headers under certain circumstances.
-
- * Other minor bug fixes and documentation improvements.
-
-Changes in 2.3.3
-
- * pgpverify now supports using GnuPG to check signatures (rather than
- PGP) without the pgpgpg wrapper. GnuPG can check both old-style RSA
- signatures and new OpenPGP signatures and is recommended over PGP 2.6.
- If you have GnuPG installed, pgpverify will use it rather than PGP,
- which means that you may have to create a new key ring for GnuPG to
- use to verify signatures if you were previously using PGP.
-
- * Users can no longer post articles containing Approved: headers to
- moderated groups by default; they must be specifically given that
- permission with the *access* parameter in readers.conf. See the man
- page for more details.
-
- * Two bugs in repacking overview index files and a reliability bug with
- writing overview data were all fixed in the tradindexed overview
- method, hopefully making it somewhat more reliable, particularly for
- makehistory.
-
- * If rc.news.local exists in the INN binary directory, it will be run
- with the start or stop argument whenever rc.news is run. This is
- available as a hook for local startup and shutdown code.
-
- * The default history table hash sizes were increased because a
- too-small value can cause serious performance problems (whereas a
- too-large hash just wastes a bit of disk space).
-
- * The sample control.ctl file has been extensively updated.
-
- * Wildmat exclusions ("@" and "!") should now work properly in
- storage.conf newsgroup patterns.
-
- * The implementation of the -w flag for expireover was fixed;
- previously, the value given to -w to change expireover's notion of the
- current time was scaled by too much.
-
- * Various other more minor bug fixes, standards compliance fixes, and
- documentation improvements.
-
-Changes in 2.3.2
-
- * innxmit can again handle regular filenames as input as well as storage
- API tokens (allowing it to be used to import an old traditional
- spool).
-
- * Several problems with tagged-hash history files have been fixed thanks
- to the debugging efforts of Andrew Gierth and Sang-yong Suh.
-
- * A very long-standing (since INN 1.0!) NNTP protocol bug in nnrpd was
- fixed. The response to an ARTICLE command retrieving a message by
- Message-ID should have the Message-ID as the third word of the
- response, not the fourth. Fixing this is reported to *possibly* cause
- problems with some Netscape browsers, but other news servers correctly
- follow the protocol.
-
- * Some serious performance problems with expiration of tradspool should
- now be at least somewhat alleviated. tradspool and timehash now know
- how to output file names for removal rather than tokens, and fastrm's
- ability to remove regular files has been restored. This should bring
- expiration times for tradspool back to within a factor of two of
- pre-storage-API expiration times.
-
- * Added a sample subscriptions file and documentation for it and
- innmail.
-
-Changes in 2.3.1
-
- * inews no longer downloads the active file, no longer tries to send
- postings to moderated groups to the moderator directly, and in general
- duplicates less of the functionality of nnrpd, instead letting nnrpd
- handle it. This fixes the problem of inews not working properly for
- users other than news without being setgid.
-
- * Added a man page for ckpasswd.
-
- * A serious bug in the embedded Perl authentication hooks was fixed,
- thanks to Jan Rychter.
-
- * The annoying compilation problem with embedded Perl filtering on Linux
- systems without libgdbm installed should be fixed.
-
- * INN now complains loudly at "configure" time if the configured path
- for temporary files is world-writeable, since this configuration can
- be a security hole.
-
- * Many other varied bug fixes and documentation fixes of all sorts.
-
-Upgrading from 2.2 to 2.3
-
- There may be additional things to watch out for not listed here; if you
- run across any, please let <inn-bugs@isc.org> know about them.
-
- Simply doing a "make update" is not sufficient to upgrade; the history
- and overview information will also have to be regenerated, since the
- formats of both files have changed between 2.2 and 2.3. Regardless of
- whether you were using the storage API or traditional spool under 2.2,
- you'll need to rebuild your overview and history files. You will also
- need to add a storage.conf file, if you weren't using the storage API
- under INN 2.2. A good default storage.conf file for 2.2 users would be:
-
- method tradspool {
- newsgroups: *
- class: 0
- }
-
- Create this storage.conf file before rebuilding history or overview.
-
- If you want to allow readers, or if you want to expire based on
- newsgroup name, you need to tell INN to generate overview data and pick
- an overview method by setting *ovmethod* in inn.conf. See INSTALL and
- inn.conf(5) for more details.
-
- The code that generates the dbz index files has been split into a
- separate program, makedbz. makehistory still generates the base history
- file and the overview information, but some of its options have been
- changed. To rebuild the history and overview files, use something like:
-
- makehistory -b -f history.n -O -T /usr/local/news/tmp -l 600000
-
- (change the /usr/local/news/tmp path to some directory that has plenty
- of temporary space, and leave off -O if you're running a transit-only
- server and don't intend to expire based on group name, and therefore
- don't need overview.) Or if your overview is buffindexed, use:
-
- makehistory -b -f history.n -O -F
-
- Both will generate a new history file as history.n and rebuild overview
- at the same time. If you want to preseve a record of expired
- Message-IDs in the history file, run:
-
- awk 'NF==2 { print; }' < history >> history.n
-
- to append them to the new history file you created above. Look over the
- new history file and make sure it looks right, then generate the new
- index files and move them into place:
-
- makedbz -s `wc -l < history.n` -f history.n
- mv history.n history
- mv history.n.dir history.dir
- mv history.n.hash history.hash
- mv history.n.index history.index
-
- (Rather than .hash and .index files, you may have a .pag file if you're
- using tagged hash.)
-
- For reader machines, nnrp.access has been replaced by readers.conf.
- There currently isn't a program to convert between the old format and
- the new format (if you'd like to contribute one, it would be welcomed
- gratefully). The new file is unfortunately considerably more complex as
- a result of its new capabilities; please carefully read the example
- readers.conf provided and the man page when setting up your initial
- configuration. The provided commented-out examples cover the most
- common installation (IP-based authentication for all machines on the
- local network).
-
- INN makes extensive use of mmap(2) for the new overview mechanisms, so
- at the present time NFS-mounting the spool and overview on multiple
- reader machines from one central server probably isn't feasible in this
- version. mmap tends to interact poorly with NFS (at the least, NFS
- clients won't see updates to the mapped files in situations where they
- should). (The preferred way to fix this would, rather than backing out
- the use of mmap or making it optional, to add support for Diablo-style
- header feeds and pull-on-demand of articles from a master server.)
-
- The flags for overchan have changed, plus you probably don't want to run
- overchan at all any more. Letting innd write overview data itself
- results in somewhat slower performance, but is more reliable and has a
- better failure mode under high loads. Writing overview data directly is
- the default, so in a normal upgrade from 2.2 to 2.3 you'll want to
- comment out or remove your overchan entry in newsfeeds and set
- *useoverchan* to "false" in inn.conf.
-
- crosspost is no longer installed, and no longer works (even with
- traditional spool). If you have an entry for crosspost in newsfeeds,
- remove it.
-
- If you're importing a traditional spool from a pre-storage API INN
- server, it's strongly recommended that you use NNTP to feed the articles
- to your new server rather than trying to build overview and history
- directly from the old spool. It's more reliable and ensures that
- everything gets put into the right place. The easiest way to do this is
- to generate, on your old server, a list of all of your existing article
- files and then feed that list to innxmit. Further details can be found
- in the FAQ at <http://www.eyrie.org/~eagle/faqs/inn.html>.
-
- If you are using a version of Cleanfeed that still has a line in it
- like:
-
- $lines = $hdr{'__BODY__'} =~ tr/\n/\n/;
-
- you will need to change this line to:
-
- $lines = $hdr{'__LINES__'};
-
- to work with INN 2.3 or later. This is due to an internal optimization
- of the interface to embedded filters that's new in INN 2.3.
-
-Changes in 2.3.0
-
- * New readers.conf file (replaces nnrp.access) which allows more
- flexible specification of access restrictions. Included in the sample
- implementations is a RADIUS-based authenticator.
-
- * Unified overview has been replaced with an overview API, and there are
- now three separate overview implementations to choose from. One
- (tradindexed) is very like traditional overview but uses an additional
- index file. The second (buffindexed) uses large buffers rather than
- separate files for each group and can handle a higher incoming article
- rate while still being fast for readers. The third (ovdb) uses
- Berkeley DB to store overview information (so you need to have
- Berkeley DB installed to use it). The *ovmethod* key in inn.conf
- chooses the overview method to use.
-
- Note that ovdb has not been as widely tested as the other overview
- mechanisms and should be considered experimental.
-
- * All article storage and retrieval is now done via the storage API.
- Traditional spool is now available as a storage type under the storage
- API. (Note that the current traditional spool implementation causes
- nightly expire to be extremely slow for a large number of articles, so
- it's not recommended that you use the tradspool storage method for the
- majority of a large spool.)
-
- * The timecaf storage method has been added, similar to timehash but
- storing multiple articles in a single file. See INSTALL for details
- on it.
-
- * INN now supports embedded Python filters as well as Perl and Tcl
- filters, and supports Python authentication hooks.
-
- * There is preliminary support for news reading over SSL, using OpenSSL.
-
- * To simplify anti-abuse filtering, and to be more compliant with news
- standards and proposed standards, INN now treats as control messages
- only articles containing a Control: header. A Subject: line beginning
- with "cmsg " is no longer sufficient for a message to be considered a
- control message, and the Also-Control: header is no longer supported.
-
- * The INN build system no longer uses subst. (This will be transparent
- to most users; it's an improvement and modernization of how INN is
- configured.)
-
- * The build and installation system has been substantially overhauled.
- "make update" now updates scripts as well as binaries and
- documentation, there is better support for parallel builds ("make
- -j"), there is less "make" recursion, and far more of the
- system-dependent configuration is handled directly by "autoconf".
- libtool build support (including shared library support) should be
- better than previous releases.
-
-Changes in 2.2.3
-
- * inews is not installed setgid news and rnews is not installed setuid
- root by default any more. If you need the old permissions, you have
- to give a flag to configure. See INSTALL for more details.
-
- * Fixed a security hole when *verifycancels* was enabled in inn.conf
- (not the default).
-
- * Message-IDs are now limited to 250 octets to prevent interoperability
- problems with other servers.
-
- * Embedded Perl filters now work with Perl 5.6.0.
-
- * Lots of bug fixes and changes for security paranoia.
-
-Changes in 2.2.2
-
- * Various minor bug fixes and a Y2K bug fix. The Y2K bug is in version
- version 2.2.1 only and will show up after Jan 1st, 2000 when a news
- reader issues a NEWNEWS command for a date prior to the year 2000.
-
-Changes in 2.2.1
-
- * Various bug fixes, mostly notably fixes for potential buffer overflow
- security vulnerabilities.
-
-Changes in 2.2.0
-
- * New storage.conf file (replaces storage.ctl).
-
- * New (optional) way of handling non-cancel control messages
- (controlchan) that serializes them and prevents server overload from
- control message storms.
-
- * Support for actsyncd to fetch active file with ftp; configured by
- default to use <ftp://ftp.isc.org/pub/usenet/CONFIG/active.Z> if you
- run actsyncd. Be sure to read the manual page for actsync to
- configure an actsync.ign file for your site, and test simpleftp if you
- do not "configure" with wget or ncftp. Also see
- <ftp://ftp.isc.org/pub/usenet/CONFIG/README>.
-
- * Some options to "configure" are now moved to inn.conf
- (*merge-to-groups* and *pgp-verify*, without the hyphen).
-
- * inndf, a portable version of df(1), is supplied.
-
- * New cnfsstat program to show stats of CNFS buffers.
-
- * news2mail and mailpost programs for gatewaying news to mail and mail
- to news are supplied.
-
- * pullnews program for doing a sucking feed is provided (not meant for
- large feeds).
-
- * The innshellvars.csh.in script is obsolete (and lives in the obsolete
- directory, for now).
-
+++ /dev/null
-Welcome to INN 2.4!
-
- This work is sponsored by Internet Systems Consortium.
-
- Please see INSTALL for installation instructions, NEWS for what's
- changed from the previous release, and LICENSE for the copyright,
- license, and distribution terms.
-
-What is INN?
-
- INN (InterNetNews), originally written by Rich Salz, is an extremely
- flexible and configurable Usenet / netnews news server. For a complete
- description of the protocols behind Usenet and netnews, see RFC 1036 and
- RFC 977 (or their replacements). In brief, netnews is a set of
- protocols for exchanging messages between a decentralized network of
- news servers. News articles are organized into newsgroups, which are
- themselves organized into hierarchies. Each individual news server
- stores locally all articles it has received for a given newsgroup,
- making access to stored articles extremely fast. Netnews does not
- require any central server; instead, each news server passes along
- articles it receives to all of the news servers it peers with, those
- servers pass the articles along to their peers, and so on, resulting in
- "flood fill" propagation of news articles.
-
- A news server performs three basic functions: it accepts articles from
- other servers and stores them on disk, sends articles it has received
- out to other servers, and offers stored news articles to readers on
- demand. It additionally has to perform some periodic maintenance tasks,
- such as deleting older articles to make room for new ones.
-
- Originally, a news server would just store all of the news articles it
- had received in a file system. Users could then read news by reading
- the article files on disk (or more commonly using news reading software
- that did this efficiently). These days, news servers are almost always
- stand-alone systems and news reading is supported via network
- connections. A user who wants to read a newsgroup opens that newsgroup
- in their newsreader software, which opens a network connection to the
- news server and sends requests for articles and related information.
- The protocol that a newsreader uses to talk to a news server and that a
- news server uses to talk to another news server over TCP/IP is called
- NNTP (Network News Transport Protocol).
-
- INN supports accepting articles via either NNTP connections or via UUCP.
- innd, the heart of INN, handles NNTP feeding connections directly; UUCP
- newsfeeds use rnews (included in INN) to hand articles off to innd.
- Other parts of INN handle feeding articles out to other news servers,
- most commonly innfeed (for real-time outgoing feeds) or nntpsend and
- innxmit (used to send batches of news created by innd to a remote site
- via TCP/IP). INN can also handle outgoing UUCP feeds.
-
- The part of INN that handles connections from newsreaders is nnrpd.
-
- Also included in INN are a wide variety of supporting programs to handle
- periodic maintenance and recovery from crashes, process special control
- messages, maintain the list of active newsgroups, and generate and
- record a staggering variety of statistics and summary information on the
- usage and performance of the server.
-
- INN also supports an extremely powerful filtering system that allows the
- server administrator to reject unwanted articles (such as spam and other
- abuses of Usenet).
-
- INN is free software, supported by Internet Systems Consortium and
- volunteers around the world. See "Supporting the INN Effort" below.
-
-Prerequisites
-
- Compiling INN requires an ANSI C compiler (gcc is recommended). INN was
- originally written in K&R C, but supporting pre-ANSI compilers has
- become enough of a headache that a lot of the newer parts of INN will no
- longer compile with a non-ANSI compiler. gcc itself will compile with
- most vendor non-ANSI compilers, however, so if you're stuck with one,
- installing gcc is highly recommended. Not only will it let you build
- INN, it will make installing lots of other software much easier. You
- may also need GNU make (particularly if your system make is
- BSD-derived), although most SysV make programs should work fine.
- Compiling INN also currently requires a yacc implementation (bison will
- do fine).
-
- INN uses GNU autoconf to probe the capabilities of your system, and
- therefore should compile on nearly any Unix system. It does, however,
- make extensive use of mmap(), which can cause problems on some older
- operating systems. See INSTALL for a list of systems it is known to
- work on. If you encounter problems compiling or running INN, or if you
- successfully run INN on a platform that isn't listed in INSTALL, please
- let us know (see "Reporting Bugs" below).
-
- Perl 5.003 or later is required to build INN. Perl 5.004 is required if
- you want the embedded Perl filter support (which is highly recommended;
- some excellent spam filters have been written for INN). Since all
- versions of Perl previous to 5.004 are buggy (including security
- problems) and have fewer features, installing Perl 5.004 or later is
- recommended.
-
- If you want to enable PGP verification of control messages (highly
- recommended), you will need to have a PGP implementation installed. See
- INSTALL for more details.
-
-Getting Started
-
- A news server can be a fairly complicated piece of software to set up
- just because of the wide variety of pieces that have to be configured
- (who is authorized to read from the server, what newsgroups it carries,
- and how the articles are stored on disk at a bare minimum, and if the
- server isn't completely stand-alone -- and very few servers are -- both
- incoming and outgoing feeds have to be set up and tested). Be prepared
- to take some time to understand what's going on and how all the pieces
- fit together. If you have any specific suggestions for documentation,
- or comments about things that are unclear, please send them to the INN
- maintainers (see "Reporting Bugs" below).
-
- See INSTALL for step-by-step instructions for setting up and configuring
- a news server.
-
- INN also comes with a very complete set of man pages; there is a man
- page for every configuration file and program that comes with INN. (If
- you find one that doesn't have a man page, that's a bug. Please do
- report it.) When trying to figure out some specific problem, reading
- the man pages for all of the configuration files involved is a very good
- start.
-
-Reporting Bugs
-
- We're interested in all bug reports. Not just on the programs, but on
- the documentation too. Please send *all* such reports to
-
- inn-bugs@isc.org
-
- (patches are certainly welcome, see below). Even if you post to Usenet,
- please CC the above address. All other INN mail should go to
-
- inn@isc.org
-
- (please do *not* send bug reports to this address).
-
- If you have general "how do I do this" questions or problems configuring
- your server that you don't believe are due to a bug in INN, you should
- post them to news.software.nntp. A lot of experienced INN users,
- including several of the INN maintainers, read that newsgroup regularly.
- Please don't send general questions to the above addresses; those
- addresses are specifically for INN, and the INN maintainers usually
- won't have time to answer general questions.
-
-Contributing Code
-
- If you have a patch or a utility that you'd like to be considered for
- inclusion into INN, please mail it to
-
- inn-patches@isc.org
-
- in the body of the message (not as an attachment), or put it on a
- webpage and send a link. Patches included with a bug report as
- described above should follow the same procedure, but need not be sent
- to both addresses (either will do).
-
- Have fun!
-
-Mailing Lists
-
- There are various INN-related mailing lists you can join or send
- messages to if you like. Some of them you must be a member of before
- you can send mail to them (thank the spammers for that policy), and one
- of them is read-only (no postings allowed).
-
- inn-announce@isc.org Where announcements about INN are set (only
- maintainers may post).
-
- inn-workers@isc.org Discussion of INN development (postings by
- members only).
-
- inn-patches@isc.org Where to send patches for consideration for
- inclusion into INN (open posting).
-
- inn-committers@isc.org CVS commit messages for INN are sent to this
- list (only the automated messages are sent here,
- no regular posting).
-
- inn-bugs@isc.org Where to send bug reports (open posting). If
- you're an INN expert and have the time to help
- out other users, we encourage you to join this
- mailing list to answer questions. (You may also
- want to read the newsgroup news.software.nntp,
- which gets a lot of INN-related questions.)
-
- To join these lists, send a subscription request to the "-request"
- address. The addresses for the above lists are:
-
- inn-announce-request@isc.org
- inn-workers-request@isc.org
- inn-patches-request@isc.org
- inn-committers-request@isc.org
- inn-bugs-request@isc.org
-
-Who's Responsible / Who to Thank
-
- See CONTRIBUTORS for a long list of past contributors as well as people
- from the inn-workers mailing list who have dedicated a lot of time and
- effort to getting this new version together. They deserve a big round
- of applause. They've certainly got our thanks.
-
- This product includes software developed by UUNET Technologies, Inc. and
- by the University of California, Berkeley and its contributors.
-
- Last, but certainly not least, Rich Salz, the original author of INN
- deserves a lion's share of the credit for writing INN in the first place
- and making it the most popular news server software on the planet (no
- NNTP yet to the moon, but we plan to be there first).
-
-Related Packages
-
- INN users may also be interested in the following software packages that
- work with INN or are based on it. Please note that none of this
- software is developed or maintained by ISC; we don't support it and
- generally can't answer questions about it.
-
- CleanFeed
- URL: <http://www.bofh.it/~md/cleanfeed/>
-
- CleanFeed is an extremely powerful spam filter, probably the most
- widely used spam filter on Usenet currently. It catches excessive
- multiposting and a host of other things, and is highly configurable.
- Note that it requires that INN be built with Perl support (the
- --with-perl option to configure).
-
- GUP (Group Update Program)
- URL: <ftp://ftp.debian.org/debian/pool/main/g/gup/>
-
- GUP provides a way for your peers to update their newsfeeds entries
- as they want without having to ask you to edit the configuration
- file all the time. It's useful when feeding peers who take limited
- and very specific feeds that change periodically.
-
- inflow
- URL: <http://www.switch.ch/netnews/wg/netnews-wg.html>
-
- inflow generates graphs of news flow statistics in real time from
- INN's logs (things like articles accepted per peer, volume accepted
- per peer, and the like).
-
- News-Portal
- URL: <http://floh.gartenhaus.net/newsportal/>
-
- A PHP-based web news reader that works as a front-end to a regular
- news server such as INN and lets people read and post without
- learning a news reader.
-
- PersonalINN
- URL: <http://www.ritual.org/summer/pinn/>
-
- PersonalINN is a version of INN modified for personal use and with a
- friendly GUI built on top of it. It is available for NeXTSTEP or
- OPENSTEP only, unfortunately.
-
- suck
- URL: <http://home.comcast.net/~bobyetman/index.html>
-
- suck is a separate package for downloading a news feed via a reading
- connection (rather than via a direct NNTP or UUCP feed) and sending
- outgoing local posts via POST. It's intended primarily for personal
- or small-organization news servers who get their news via an ISP and
- are too small to warrant setting up a regular news feed.
-
- newsx
- URL: <http://www.kvaleberg.com/newsx.html>
-
- Serving the same purpose as suck, newsx is a separate package for
- downloading a news feed via a reading connectino and sending
- outgoing local posts via POST. Some people find suck easier to
- configure and use, and some people find newsx easier. If you have
- problems with one, try the other.
-
-Supporting the INN Effort
-
- Note that INN is supported by Internet Systems Consortium, and although
- it is free for use and redistribution and incorporation into vendor
- products and export and anything else you can think of, it costs money
- to produce. That money comes from ISPs, hardware and software vendors,
- companies who make extensive use of the software, and generally
- kind-hearted folk such as yourself.
-
- Internet Systems Consortium has also commissioned a DHCP server
- implementation and handles the official support/release of BIND. You
- can learn more about the ISC's goals and accomplishments from the web
- page at <http://www.isc.org/>.
-
- Russ Allbery
- Katsuhiro Kondou
- <inn@isc.org>
+++ /dev/null
-This is a rough and informal list of suggested improvements to INN, parts
-of INN that need work, and other tasks yet undone. Some of these may be
-in progress, in which case the person working on them will be noted in
-square brackets and should be contacted if you want to help. Otherwise,
-let inn-workers@isc.org know if you'd like to work on any item listed
-below.
-
-The list is divided into changes already tentatively scheduled for a
-particular release, higher priority changes that will hopefully be done in
-the near future, small or medium-scale projects for the future, and
-long-term, large-scale problems. Note that just because a particular
-feature is scheduled for a later release doesn't mean it can't be
-completed earlier if someone decides to take it on. The association of
-features with releases is intended to be a rough guide for prioritization
-and a set of milestones to use to judge when a new major release is
-justified.
-
-Also, one major thing that is *always* welcome is additions to the test
-suite, which is currently very minimal. Any work done on the test suite
-to allow more portions of INN to be automatically tested will make all
-changes easier and will be *greatly* appreciated.
-
-Last modified $Id: TODO 7575 2006-09-11 22:59:38Z eagle $.
-
-
-Scheduled for INN 2.5
-
-* Rewrite configure, breaking all of the tests out into separate files
- using the new capabilities in autoconf 2.5x. Replace our local macros
- with the more general features provided by autoconf. At the same time,
- configure.in and Makefile.global.in should be fixed to use the same
- names as each other for various parameters. [Russ plans to work on
- this.]
-
-* Add support for groups, nesting, and vectors to the new configuration
- parsing code. [Russ plans on doing this.]
-
-* Convert readers.conf and storage.conf (and related configuration files)
- to use the new parsing system and break out program-specific sections
- of inn.conf into their own groups.
-
-* The current WIP cache and history cache should be integrated into the
- history API, things like message ID hashing should become a selectable
- property of the history file, and the history API should support
- multiple backend storage formats and automatically select the right one
- for an existing history file based on stored metainformation.
-
-* The interface to embedded filters needs to be reworked. The information
- about which filters are enabled should be isolated in the filtering API,
- and there should be standard API calls for filtering message IDs, remote
- posts, and local posts. As part of this revision, all of the Perl
- callbacks should be defined before any of the user code is loaded, and
- the Perl loading code needs considerable cleanup. At the same time as
- this is done, the implementation should really be documented; we do some
- interesting things with embedded filters and it would be nice to have a
- general document describing how we do it. [Russ is planning on working
- on this at some point, but won't get upset if someone starts first.]
-
-* All of INN's documentation should be written in POD, with text and man
- pages generated from the POD source. Anyone is encouraged to work on
- this by just taking any existing documentation in man format and convert
- it to POD while checking that it's still accurate and adding any
- additional useful information that was missed.
-
-* Replace the current innshellvars.pl file with a real INN Perl module for
- Perl programs, and include the necessary glue so that other Perl modules
- can be added to INN's build tree and installed with INN, allowing their
- capabilities to be available to the portions of INN written in Perl.
-
-* Switch nnrpd over to using the new wildmat routines rather than breaking
- apart strings on commas and matching each expression separately. This
- involves a lot of surgery, since PERMmatch is used all over the place,
- and may change the interpretation of ! and @ in group permission
- wildmats.
-
-* Rework and clean up the storage API. The major change is that the
- initialization function should return a pointer to an opaque struct
- which stores all of the state of the storage subsystem, rather than all
- of that being stored in static variables, and then all other functions
- should take that pointer. More of the structures should also be opaque,
- all-caps structure names should be avoided in favor of named structures,
- SMsetup and SMinit should be combined into one function that takes
- flags, SMerrno and SMerrorstr should be replaced with functions that
- return that information, and the wire format utilities should be moved
- into libinn.
-
-* Rework and clean up the overview API. The major change is that the
- initialization function should return a pointer to an opaque struct
- which stores all of the state of the overview subsystem, rather than all
- of that being stored in static variables, and then all other functions
- should take that pointer. OVctl possibly should instead take and return
- a struct rather than using an ioctl-style interface. Currently, the
- overview functions do a lot of breaking apart of Xref headers and
- parsing them, which is very ugly; consider having the overview interface
- always key off a newsgroup name and article number, even for storing.
- OVadd should probably take a structure and OVsearch should probably
- return a structure.
-
-
-Scheduled for INN 2.6
-
-* Add a generic, modular anti-spam and anti-abuse filter, off by default,
- but coming with INN and prominently mentioned in the INSTALL
- documentation. [Andrew Gierth has work in progress that may be usable
- for this.]
-
-* A unified configuration file combining the facilities of newsfeeds,
- incoming.conf, and innfeed.conf, but hopefully more readable and easier
- for new INN users to edit. This should have all of the capabilities of
- the existing configuration files, but specifying common things (such as
- file feeds or innfeed feeds) should be very simple and straightforward.
- This configuration file should use the new parsing infrastructure.
-
-* Convert all remaining INN configuration files to the new parsing
- infrastructure.
-
-* INN really should be capable of both sending and receiving a
- headers-only feed (or even an overview-only feed) similar to Diablo and
- using it for the same things that Diablo does, namely clustering,
- pull-on-demand for articles, and the like. This should be implementable
- as a new backend, although the API may need a few more hooks. Both a
- straight headers-only feed that only pulls articles down via NNTP from a
- remote server and a caching feed where some articles are pre-fed, some
- articles are pulled down at first read, and some articles are never
- stored locally should be possible. [Patches for a header-only feed have
- already been written and submitted to inn-workers.]
-
-* The libinn, libstorage, and other library interfaces should be treated
- as stable libraries and properly versioned using libtool's
- recommendation for library versioning when changes are made so that they
- can be installed as shared libraries and work properly through releases
- of INN. This is currently waiting on a systematic review of the
- interface and removal of things that we don't want to support long-term.
-
-* The include files necessary to use libinn, libstorage, and other
- libraries should be installed in a suitable directory so that other
- programs can link against them. All such include files should be under
- include/inn and included with <inn/header.h>. All such include files
- should only depend on other inn/* header files and not on, e.g.,
- config.h. All such include files should be careful about namespace to
- avoid conflicts with other include files used by applications.
-
-
-High Priority Projects
-
-* Modulo warnings from system headers and warnings where the compiler is
- simply wrong and there's no equally readable way to rewrite the code,
- INN should compile cleanly under "make warnings". It should be possible
- for maintainers to routinely compile INN with make warnings to catch
- problems. Note that -Wcast-qual warnings cannot be avoided entirely
- because we don't want to write redundant functions for regular and const
- strings and because of such things as struct iovec; -Wcast-qual will be
- removed from make warnings when this task is reasonably complete.
-
-* INN shouldn't flush all feeds (particularly all program feeds) on
- newgroup or rmgroup. Currently it reloads newsfeeds to reparse all of
- the wildmat patterns and rebuild the peer lists associated with the
- active file on group changes, and this forces a flush of all feeds.
- The best fix is probably to stash the wildmat pattern (and flags) for
- each peer when newsfeeds is read and then just using the stashed copy on
- newgroup or rmgroup, since otherwise the newsfeeds loading code would
- need significant modification. But in general, innd is too
- reload-happy; it should be better at making incremental changes without
- reloading everything.
-
-* Add authenticated Path support, based on the current USEFOR draft or the
- behavior of some other servers (such as Diablo). [Andrew Gierth wrote a
- patch for part of this a while back, which Russ has. Marco d'Itri
- expressed some interest in working on this.]
-
-* Various parts of INN are using write or writev; they should all use
- xwrite or xwritev instead. Even for writes that are unlikely to ever be
- partial, on some systems system calls aren't restartable and xwrite and
- xwritev properly handle EINTR returns.
-
-* Apparently on Solaris open can also be interrupted by a signal; we may
- need to have an xopen wrapper that checks for EINTR and retries.
-
-* tradspool has a few annoying problems. Deleted newsgroups never have
- their last articles expired, and there is no way of forcibly
- resynchronizing the articles stored on disk with what overview knows
- about unless tradindexed is used. Some sort of utility program to take
- care of these and to do things like analyze the tradspool.map file
- should be provided.
-
-* Rewrite inndstart as a helper program that only binds the relevant
- sockets and then returns them to innd. Since file descriptors are
- shared by child processes, this can be done with a program spawned by
- innd. This may have gotten more complicated with IPv6. Drop
- startinnfeed entirely in favor of recommending people use ulimit in the
- news init script.
-
-* contrib/mkbuf and contrib/reset-cnfs.c should be combined into a utility
- for creating and clearing cycbuffs, perhaps combined with cnfsheadconf,
- and the whole thing moved into storage/cnfs rather than frontends (along
- with cnfsstat). pullart.c may also stand to be merged into the same
- utility (cnfs-util might not be a bad name).
-
-
-Documentation Projects
-
-* Add man pages for all libinn interfaces. There should be a subdirectory
- of doc/pod for this since there will be a lot of them; installing them
- as libinn_<section>.3 seems to make the most sense (so, for example,
- error handling routines would be documented in libinn_error.3).
-
-* Better documentation of and support for UUCP feeds. send-uucp is now
- easier to use, but there's still a paucity of documentation covering the
- whole theory and mechanisms of UUCP feeding.
-
-* Everything installed by INN should have a man page. Currently, there
- are several binaries and configuration files that don't have man pages.
- (In some cases, the best thing to do with the configuration file may be
- to merge it into another one or find a way to eliminate it.)
-
-* Document the internal formats of the various overview methods, CNFS,
- timehash, and timecaf. A lot of this documentation already exists in
- various forms, but it needs to be cleaned up and collected in one place
- for each format, preferrably as a man page.
-
-* Add documentation for slave servers. [Russ has articles from
- inn-workers that can be used as a beginning.]
-
-* Write complete documentation for all of our extensions to RFC 977 or RFC
- 1036, preferrably in a format that could be suitable for future
- inclusion into new revisions of the RFCs.
-
-* Audit readers.conf.5 against perm.c for missing options ("include" at
- least is missing from the documentation).
-
-* The distributions file is undocumented.
-
-
-Code Cleanup Projects
-
-* Eliminate everything in the LEGACY section of config.h.
-
-* Move all compile-time configuration in config.h either into a separate
- header (such as inn/options.h) or turn it into a configuration file
- directive or a command-line option. In particular, the rnews
- configuration should probably be an rnews-specific section of inn.conf.
-
-* Move include/paths.h to include/inn/paths.h and change _PATH as a prefix
- to INN_PATH to move the identifiers out of the C reserved namespace.
- Check to be sure we still need all of the #defines and look at adding
- anything needed by innfeed (and eliminating the separate innfeed header
- serving the same purpose).
-
-* Move include/nntp.h to include/inn/nntp.h and at the same time look at
- standardizing the names of all of the #defines it provides, including
- the message class. [Russ has a start on this.]
-
-* Get rid of GetTimeInfo and TIMEINFO. All the struct is is a struct
- timeval plus time zone information. All of the parts of INN that deal
- with time zone information are isolated in lib/date.c. The rest of INN
- uses GetTimeInfo where a plain call to time would often work fine, or
- at most gettimeofday, and there's no reason to compute the time zone
- everywhere. Plus, it makes the code more readable to use standard
- functions and data types.
-
-* putman.sh should be merged into support/install-sh (which would mean
- giving up any pretext of using the standard install-sh script, but that
- should be fine).
-
-* Use vectors or cvectors everywhere that argify and friends are currently
- used and eliminate the separate implementation in nnrpd/misc.c.
-
-* Break up the remainder of libinn.h into multiple inn/* include files for
- specific functions (such as memory management, wildmat, date handling,
- NNTP commands, etc.), with an inn/util.h header to collect the remaining
- random utilities. Consider adding some sort of prefix, like inn_, to all
- functions that aren't part of some other logical set with its own prefix.
-
-* Break the CNFS and tradspool code into multiple source files to make it
- easier to understand the logical divisions of the code and consider
- doing the same with the other overview and storage methods.
-
-* Examine the (mostly socket) code that currently should probably be
- compiled with -fno-strict-aliasing on gcc and move the relevant casts
- to within function calls. [Russ knows about this.]
-
-* Clean up the use of #ifdef for sockets and IPv6, perhaps involving
- addition of more to include/portable/socket.h.
-
-
-Needed Bug Fixes
-
-* tradspool currently uses stdio to write out tradspool.map, which can
- cause problems if more than 256 file descriptors are in use for other
- things (such as incoming connections or tradindexed overview cache).
- It should use write() instead.
-
-* LIST NEWSGROUPS should probably only list newsgroups that are marked in
- the active file as valid groups.
-
-* INN's startup script should be sure to clean out old lock files and PID
- files for innfeed. Be careful, though, since innfeed may still be
- running, spawned from a previous innd.
-
-* makedbz should be more robust in the presence of malformed history
- lines, discarding with them or otherwise dealing with them.
-
-* CNFS, if the cycbuff is larger than 2GB and it doesn't have large file
- support, reports a mysterious file not found error because it assumes
- all errors from stat are the result of the cycbuff not being found.
-
-* Some servers reject some IHAVE, TAKETHIS, or CHECK commands with 500
- syntax errors (particularly for long message IDs), and innfeed doesn't
- handle this particularly well at the moment. It really should have an
- error handler for this case. [Sven Paulus has a preliminary patch that
- needs testing.]
-
-* Editing the active file by hand can currently munge it fairly badly even
- if the server is throttled unless you reload active before restarting
- the server. This could be avoidable for at least that particular case
- by checking the mtime of active before and after the server was
- throttled.
-
-* innreport silently discards news.notice entries about most of the errors
- innfeed generates. It should ideally generate some summary, or at least
- note that some error has occurred and the logs should be examined.
-
-* INN's message ID parser should be more forgiving about surrounding
- whitespace. Right now, it will reject messages with a trailing space in
- the Message-ID header.
-
-* nnrpd doesn't check the message ID of a posted article for syntactic
- validity before remailing it to the moderator, since normally it relies
- on innd to check the message ID. The message ID checking code from
- innd/art.c should be moved into lib so that nnrpd can use it as well.
-
-* Currently, if the list of newsgroups on an Xref slave is out of sync
- with the newsgroups on the master, receiving an article crossposted to
- one of the groups that doesn't exist on the slave will cause the slave
- to throttle. This isn't the best behavior; the server should either
- optionally create the missing newsgroup or just ignore that crossposted
- group (and modify Xref accordingly?).
-
-* Handling of compressed batches needs to be thoroughly reviewed by
- someone who understands how they're supposed to work. It's not clear
- that _PATH_GZIP is being used correctly at the moment and that
- compressed batch handling will work right now on systems that don't have
- gzip installed (but that do have uncompress).
-
-* innfeed's statistics don't add up properly all the time. All of the
- article dispositions don't add up to the offered count like they should.
- Some article handling must not be recorded properly.
-
-* innd's counting of article size doesn't always work properly, and it can
- accept articles that are larger than its configured limit. It's not
- clear exactly where this is happening.
-
-* If a channel feed exits immediately, innd respawns it immediately,
- causing thrashing of the system and a huge spew of errors in syslog. It
- should mark the channel as dormant for some period of time before
- respawning it, perhaps only if it's already died multiple times in a
- short interval.
-
-* ctlinnd begin <site-name> was causing innd to core dump.
-
-* Handling of innfeed's dropped batches needs looking at. There are three
- places where articles can fall between the cracks: an innfeed.togo file
- written by innd when the feed can't be spawned, a batch file named after
- the feed name which can be created under similar circumstances, and the
- dropped files written by innfeed itself. procbatch can clean these up,
- but has to be run by hand.
-
-* When using tradspool, groups are not immediately added to tradspool.map
- when created, making innfeed unable to find the articles until after
- some period of time. Part of the problem here is that tradspool only
- updates tradspool.map on a lazy basis, when it sees an article in that
- group, since there is no storage hook for creation of a new group.
-
-* nntpget doesn't handle long lines in messages.
-
-* WP feeds break if there are spaces in the Path header, and the inn.conf
- parser doesn't check for this case and will allow people to configure
- their server that way. (It's not clear that the latter is actually a
- bug, given the new USEFOR attempt to allow folding of Path headers, but
- the space needs to be removed for WP feeds.)
-
-* Error handling in the history backend needs to be reviewed, since it
- currently is always printing out errno regardless of whether it's
- meaningful. The error handling needs to record errno if it's useful and
- the reporting function should only print it out if it's useful for that
- error.
-
-* innd returns 437 for articles that were accepted but filed in the junk
- group. It should probably return the appropriate 2xx status code in
- that case instead.
-
-* Someone should go through the BUGS sections of all of the manpages and
- fix those for which the current behavior is unacceptable.
-
-
-Requested New Features
-
-* Consider implementing the HEADERS command as discussed rather
- extensively in news.software.nntp. [Greg Andruk has a preliminary
- patch.]
-
-* There have been a few requests for the ability to programmatically set
- the subject of the report generated by news.daily, with escapes that are
- filled in by the various pieces of information that might be useful.
-
-* A bulk cancel command using the MODE CANCEL interface. Possibly through
- ctlinnd, although it may be a bit afield of what ctlinnd is currently
- for.
-
-* Sven Paulus's patch for nnrpd volume reports should be integrated. See
- <ftp://ftp.tin.org/pub/news/servers/inn/unofficial-patches/
- patch-inn-2.2.x-artstat+list+overstat>.
-
-* Lots of people encrypt X-Trace in various ways. Should that be offered
- as a standard option? The first data element should probably remain
- unencrypted so that the O flag in newsfeeds doesn't break.
-
- Should there also be an option not to generate X-Trace? And this whole
- area may change if USEFOR ever standardizes poster trace information;
- it's been proposed to put it in the path tail instead. The current
- USEFOR trend as of January, 2001 appears to be towards an Injector-Info
- header with this information, allowing a token or an injecting hostname.
- For a token, one really wants it to be hierarchically structured for
- spam filtering even if it's encrypted (in other words, to get a "group"
- of clients, one could just match the first n bytes of the token instead
- of the whole thing).
-
- Olaf Titz suggests:
-
- This can be done by formatting the (rest of) the header in a way
- that fields are always a multiple of 8 bytes and applying a 64 bit
- block cipher in ECB mode on it. But then we would be better off
- using binary fields, as the timestamp is 9 bytes and an IP address
- 10-12 bytes.
-
- Combining the timestamp and PID into one block, adding an
- authenticated user field and omitting the redundant formatted time
- would give the following format:
-
- X-Trace: g212.hadiko.de [395109AA000016FF] [AC14302A00000000] [...]
- time | pid ip |reserved user
-
-* ctlinnd flushlogs currently renames all of the log files. It would be
- nice to support the method of log rotation that most other daemons
- support, namely to move the logs aside and then tell innd to reopen its
- log files. Ideally, that behavior would be triggered with a SIGHUP.
- scanlogs would have to be modified to handle this.
-
- The best way to support this seems to be to leave scanlogs as is by
- default, but also add two additional modes. One would flush all the
- logs and prepare for the syslog logs to be rotated, and the other would
- do all the work needed after the logs have been rotated. That way, if
- someone wanted to plug in a separate log rotation handler, they could do
- so and just call scanlogs on either side of it. The reporting portions
- of scanlogs should be in a separate program.
-
-* Several people have Perl interfaces to pieces of INN that should ideally
- be part of the INN source tree in some fashion. Greg Andruk has a bunch
- of stuff that Russ has copies of, for example.
-
-* Investigate using the new, stricter date parsing code in libinn for
- nnrpd rather than the extremely lenient parsedate routine.
-
-* There are various available patches for Cancel-Lock and an Internet
- draft; support should be added to INN for both generation and
- verification (definitely optional and not on by default at this point).
-
-* It would be nice to be able to reload inn.conf (although difficult, due
- to the amount of data that's generated from it and stashed in various
- places). This will need to wait for the new configuration parsing
- library and an inn.conf parser that uses it.
-
-* remembertrash currently rejects and remembers articles with syntax
- errors as well as things like unwanted newsgroups and unwanted
- distributions, which means that if a peer sends you a bunch of mangled
- articles, you'll then also reject the correct versions of the articles
- from other peers. This should probably be rethought.
-
-* Additional limits for readers.conf: Limit on concurrent parallel reader
- streams, limit on KB/second download (preliminary support for this is
- already in), and a limit on maximum posted articles per day (tied in
- with the backoff stuff?). These should be per-IP or per-user, but
- possibly also per-access group. (Consider pulling the -H, -T, -X, and
- -i code out from innd and using it here.)
-
-* timecaf should have more configurable parameters (at the least, how
- frequently to switch to a new CAF file should be an option).
- storage.conf should really be extended to allow method-specific
- configuration for things like this (and to allow the cycbuff.conf file
- to be merged into storage.conf).
-
-* Allow generation of arbitrary additional information that could go in
- overview by using embedded Perl or Python code. This might be a cleaner
- way to do the keywords code, which really wants Perl's regex engine
- ideally. It would also let one do something like doing MD5 hashes of
- each article and putting that in the overview if you care a lot about
- making sure that articles aren't corrupted.
-
-* Allow some way of accepting articles regardless of the Date header, even
- if it's far into the future. Some people are running into articles that
- are dated years into the future for some reason that they still want to
- store on the server.
-
-* There was a request to make --program-suffix and the other name
- transformation options to autoconf work. The standard GNU package does
- this with really ugly sed commands in the Makefile rules; we could
- probably do better, perhaps by substituting the autoconf results into
- support/install-sh.
-
-* INN currently uses hash tables to store the active file internally. It
- would be worth trying ternary search trees to see if they're faster; the
- data structure is simpler, performance may be comparable for hits and
- significantly better for misses, sizing and resizing becomes a non-issue,
- and the space penalty isn't too bad. A generic implementation is already
- available in libinn. (An even better place to use ternary search trees
- may be the configuration parser.)
-
-* Provide an innshellvars equivalent for Python.
-
-* inncheck should check the syntax of all the various files that are
- returned by LIST commands, since having those files present with the
- wrong syntax could result in non-compliant responses from the server.
- Possibly the server should also refuse to send malformatted lines to
- the client.
-
-* ctlinnd reload incoming.conf could return a count of the hosts that
- failed, or even better a list of them. This would make pruning old
- stuff out of incoming.conf much easier.
-
-* nnrpd could use sendfile(2), if available, to send articles directly
- to the socket (for those storage methods where to-wire conversion is
- not needed). This would need to be added to the storage API.
-
-* Somebody should look at keeping the "newsgroups" file more accurate
- (e.g. newgroups for existing groups should change description, better
- checkgroups handling, checking for duplicates)
-
-* The by-domain statistics innreport generates for nnrpd count all local
- connections (those with no "." in the hostname) in with the errors as
- just "?". The host2dom function could be updated to group these as
- something like "Local".
-
-* news.daily could detect if expire segfaults and unpause the server.
-
-* When using SSL, track the amount of data that's been transferred to the
- client and periodically renegotiate the session key.
-
-* When using SSL, use SSL_get_peer to get a verified client certificate,
- if available, and use it to create an additional header line when
- posting articles (X-Auth-Poster?). This header could use:
-
- X509_NAME_oneline(X509_get_subject_name(peer),...)
-
- for the full distinguished name, or
-
- X509_name_get_text_by_NID(X509_get_subject_name(peer),
- NID_commonName, ...)
-
- for the client's "common name" alone.
-
-* When using SSL, use the server's key to generate an HMAC of the body of
- the message (and most headers?), then include that digest in the
- headers. This allows a news administrator to determine if a complaint
- about the content of a message is fradulent since the message was
- changed after transmission.
-
-
-General Projects
-
-* All the old packages in unoff-contrib should be reviewed for integration
- into INN.
-
-* It may be better for INN on SysV-derived systems to use poll rather than
- select. The semantics are better, and on some systems (such as Solaris)
- select is limited to 1024 file descriptors whereas poll can handle any
- number. Unfortunately, the API is drastically different between the
- two and poll isn't portable, so supporting both cleanly would require a
- bit of thought.
-
-* Currently only innd and innfeed increase their file descriptor limits.
- Other parts of INN, notably makehistory, may benefit from doing the same
- thing if they can without root privileges.
-
-* The Tcl filtering support code has undergone serious bitrot and needs
- some work to fix it and make it work with modern versions of Tcl and the
- current version of INN. It also lacks a lot of the functionality of the
- Perl and Python filters, if anyone cares.
-
-* Revisit support for aliased groups and what nnrpd does with them.
- Should posts to the alias automatically be redirected to the real group?
- Regardless, the error return should provide useful information about
- where to post instead. Also, the new overview API, for at least some of
- the overview methods, truncated the group status at one character and
- lost the name of the group to which a group is aliased; that needs to be
- fixed.
-
-* More details as to why a message ID is bad would be useful to return to
- the user, particularly for rnews, inews, etc. innd also rejects message
- IDs with trailing spaces, which can be hard to check.
-
-* Support putting the active file and history file in different
- directories without hand-editing a bunch of files.
-
-* nnrpd's NNTP command parsing interacts poorly with AUTHINFO and
- passwords containing spaces. The correct solution isn't clear; check
- with the current NNTP RFC draft and how existing clients handle it?
-
-* frontends/pullnews and contrib/backupfeed solve the same problem; the
- best ideas of both should be unified into one script.
-
-* actsyncd could stand a rewrite and cleaner handling of both
- configuration and syncing against multiple sources which are canonical
- for different sets of groups.
-
-* send-nntp and nntpsend basically do the same thing; send-nntp could
- probably be removed (possibly with some extra support in nntpsend for
- doing simpler things).
-
-
-Long-Term Projects
-
-* Look at turning header parsing into a library of some sort. Lots of INN
- does this, but different parts of INN need subtly different things, so
- the best best API is unclear.
-
-* INN's header handling needs to be checked against the current USEFOR
- draft. This may want wait until after we have a header parsing library.
-
-* The innd filter should be able to specify additional or replacement
- groups into which an article should be filed, or even spool the article
- to a local disk file rather than storing it. (See the stuff that the
- nnrpd filter can already do.)
-
-* Add authentication via SASL to nnrpd. This is a boatload of additional
- issues, particularly if we want to add authentication methods like
- Kerberos that require their own separate libraries (although we should
- use Cyrus's SASL libraries, which will simplify a lot of that).
- [Jeffrey Vinocur is working on a standard for this.]
-
-* When articles expire out of a storage method with self-expire
- functionality, the overview and history entries for those articles
- should also be expired immediately. Otherwise, things like the GROUP
- command don't give the correct results. This will likely require a
- callback that can be passed to CNFS that is called to do the overview
- and history cleanup for each article overwritten. It will also require
- the new history API.
-
-* Feed control, namely allowing your peers to set policy on what articles
- you feed them (not just newsgroups but max article size and perhaps even
- filter properties like "non-binary"). Every site does this a bit
- differently. Some people have web interfaces, some people use GUP, some
- people roll their own alternate things. It would really be nice to have
- some good way of doing this as part of INN. It's worth considering an
- NNTP extension for this purpose, although the first step is to build a
- generic interface that an NNTP extension, a web page, etc. could all
- use. (An alternate way of doing this would be to extend IHAVE to pass
- the list of newsgroups as part of the command, although this doesn't
- seem as generally useful.)
-
-* Traffic classification as an extension of filtering. The filter should
- be able to label traffic as binary (e.g.) without rejecting it, and
- newsfeeds should be extended to allow feeding only non-binary articles
- (e.g.) to a peer.
-
-* External authenticators should also be able to do things like return a
- list of groups that a person is allowed to read or post to. Currently,
- maintaining a set of users and a set of groups, each of which some
- subset of the users is allowed to access, is far too difficult. For a
- good starting list of additional functionality that should be made
- available, look at everything the Perl authentication hooks can do.
- This should probably wait for the configuration file parsing rewrite.
-
-* Allow nnrpd to spawn long-running helper processes. Not only would this
- be useful for handling authentication (so that the auth hooks could work
- without execing a program on every connection), but it may allow for
- other architectures for handling requests (such as a pool of helpers
- that deal only with overview requests). More than that, nnrpd should
- *be* a long-running helper process that innd can feed open file
- descriptors to. [Aidan Culley has ideas along these lines.]
-
-* The tradspool storage method requires assigning a number to every
- newsgroup (for use in a token). Currently this is maintained in a
- separate tradspool.map file, but it would be much better to keep that
- information in the active file where it can't drop out of sync. A code
- assigned to each newsgroup would be useful for other things as well,
- such as hashing the directories for the tradindexed overview. For use
- for that purpose, though, the active file would have to be extended to
- include removed groups, since they'd need to be kept in the active file
- to reserve their numbers until the last articles expired.
-
-* The locking of the active file leaves something to be desired; in
- general, the locking in INN (for the active file, the history file,
- spool updates, overview updates, and the like) needs a thorough
- inspection and some cleanup. A good place to start would be tracing
- through the pause and throttle code and write up a clear description of
- what gets locked where and what is safely restarted and what isn't.
- Long term, there needs to be a library locking routine used by
- *everything* that needs to write to the history file, active file, etc.
- and that keeps track of the PID of the process locking things and is
- accessible via ctlinnd.
-
-* There is a fundamental problem with the current design of the
- control.ctl file. It combines two things: A database of hierarchies,
- their maintainers, and related information, and a list of which
- hierarchies the local server should honor. These should be separated
- out into the database (which could mostly be updated from a remote
- source like ftp.isc.org and then combined with local additions) and a
- configured list of hierarchies (or sub-hierarchies within hierarchies)
- that control messages should be honored for. This should be reasonably
- simple although correct handling of checkgroups could get a mite tricky.
-
-* Possible NNTP extension: Compression of the protocol, using gzip,
- bzip2, or some other technique. Particularly useful for long lists like
- the active file information or the overview information, but possibly
- useful in general for other things.
-
-* Install wizards. Configuring INN is currently very complex even for an
- experienced news admin, and there are several fairly standard
- configurations that shouldn't be nearly that complicated to get running
- out of the box. A little interactive Perl script asking some simple
- questions could probably get a lot of cases easily right.
-
-* One ideally wants to be able to easily convert between different
- overview formats or storage methods, refiling articles in place. This
- should be possible once we have a history API that allows changing the
- storage location of an article in-place.
-
-* Set up the infrastructure required so that INN can use alloca. This
- would significantly decrease the number of calls to malloc needed and
- would be a lot more convenient.
-
-* A serious investigation into whether INN could use a garbage collector
- is probably a good idea. The network buffers probably need to be
- handled with decidated code, but there are a lot of other incidental
- allocations and deallocations that may be much more efficient and safer
- using a garbage collector.
-
-* Look at integrating asprintf and vasprintf. Russ already tried this
- once and couldn't see a good way of doing it (particularly vasprintf)
- without hooking deep into an sprintf implementation, because the simple
- hack of calling vsnprintf first, allocating that much memory, and then
- calling it again on the new buffer doesn't work for vasprintf (you can't
- reprocess the arguments).
-
-* Support building in a separate directory than the source tree. It may
- be best to just support this via lndir rather than try to do it in
- configure, but it would be ideal to add support for this to the autoconf
- system. Unfortunately, the standard method requires letting configure
- generate all of the makefiles, which would make running configure and
- config.status take much longer than it does currently.
-
-* Look at adding some kind of support for MODE CANCEL via network sockets
- and fixing up the protocol so that it could possibly be standardized
- (the easiest thing to do would probably be to change it into a CANCEL
- command). If we want to get to the point where INN can accept and even
- propagate such feeds from dedicated spam filters or the like, there must
- also be some mechanism of negotiating policy in order to decide what
- cancels the server wants to be fed.
-
-* The "possibly signed" char data type is one of the inherent flaws of C.
- Some other projects have successfully gotten completely away from this
- by declaring all of their strings to be unsigned char, defining a macro
- like U that casts strings to unsigned char for use with literal strings,
- and always using unsigned char everywhere. Unfortunately, this also
- requires wrappering all of the standard libc string functions, since
- they're prototyped as taking char rather than unsigned char. The
- benefits include cleaner and consistent handling of characters over 127,
- better warnings from the compiler, consistent behavior across platforms
- with different notions about the signedness of char, and the elimination
- of warnings from the <ctype.h> macros on platforms like Solaris where
- those macros can't handle signed characters. We should look at doing
- this for INN.
-
-* It would clean up a lot of code considerably if we could just use mmap
- semantics regardless of whether the system has mmap. It may be possible
- to emulate mmap on systems that don't have it by reading the entirety of
- the file into memory and setting the flags that require things to call
- mmap_flush and mmap_invalidate on a regular basis, but it's not clear
- where to stash the file descriptor that corresponds to the mapped file.
-
-* Figure out some Samba library that we can link against for the Samba
- authenticator so that we can get all the Samba code back out of INN's
- source tree; we don't want to maintain it.
-
-* Consider replacing the awkward access: parameter in readers.conf with
- separate commands (e.g. "allow_newnews: true") or otherwise cleaning up
- the interaction between access: and read:/post:. Note that at least
- allownewnews: can be treated as a setting for overriding inn.conf and
- should be very easy to add.
-
-* Add a localport: parameter (similar to localaddress:) to readers.conf
- auth groups. With those two parameters (and ssl_required:) we
- essentially eliminate the need to run multiple instances of nnrpd just to
- use different configurations.
-
-* Various things may break when trying to use data written while compiled
- with large file support using a server that wasn't so compiled (and vice
- versa). The main one is the history file, but tradindexed is also
- affected and buffindexed has been reported to have problems with this
- as well. Ideally, all of INN's data files should be as portable as
- possible.
-
-
-Complete Code Reorganization
-
-At some point, we should probably abandon and archive the current CVS
-repository, reimport all of the current source files, and start with a
-fresh repository with a better revision control system such as Subversion.
-A better revision control system would let us rename and move things
-around arbitrarily, something CVS doesn't handle at all well. Should this
-ever be done, we should consider doing all of the following at the same
-time:
-
-* Don't include any generated files in the CVS tree. Maintainers should
- have autoconf and friends, pod2text and pod2man, and bison around anyway.
- This would save a bunch of extra check-ins, remove the danger of the
- generated files getting out of sync, and drastically reduce the
- repository size in the case of configure.
-
-* Don't include any of the generated man pages in the CVS tree, as an
- additional case of the above. All of the documentation should be in POD
- and we can generate the man pages as part of the snapshot process.
-
-* storage should be reserved just for article storage; the overview
- methods should be in a separate overview tree.
-
-* The split between frontends and backends is highly non-intuitive. Some
- better organization scheme should be arrived at. Perhaps something
- related to incoming and outgoing, with programs like cnfsstat moved into
- the storage directory with the other storage-related code?
-
-* Add a separate utils directory for things like convdate, shlock,
- shrinkfile, and the like. Some of the scripts may possibly want to go
- into that directory too.
-
-* The lib directory possibly should be split so that it contains only code
- always compiled and part of INN, and the various replacements for
- possibly missing system routines are in a separate directory (such as
- replace). These should possibly be separate libraries; there are things
- that currently link against libinn that only need the portability
- pieces.
-
-* The doc directory really should be broken down further by type of
- documentation or section or something; it's getting a bit unwieldy.
-
-* Untabify and reformat all of the code according to a consistent coding
- style which would then be enforced for all future check-ins.
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS)
-
-ALL = auth_smb ckpasswd domain ident radius $(KRB5_AUTH)
-
-LIBSMB = smbval/smbvalid.a
-
-LIBAUTH = libauth.o
-
-SOURCES = auth_krb5.c auth_smb.c ckpasswd.c domain.c ident.c libauth.c \
- radius.c
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- if [ x"$(KRB5_AUTH)" != x ] ; then \
- $(LI_XPUB) auth_krb5 $(D)$(PATHAUTHPASSWD)/auth_krb5 ; \
- fi
- for F in auth_smb ckpasswd radius ; do \
- $(LI_XPUB) $$F $D$(PATHAUTHPASSWD)/$$F ; \
- done
- for F in domain ident ; do \
- $(LI_XPUB) $$F $D$(PATHAUTHRESOLV)/$$F ; \
- done
-
-clobber clean distclean:
- rm -f *.o $(ALL)
- rm -rf .libs
- cd smbval && $(MAKE) clean
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES) ../lib/*.c ../include/*.h
-
-profiled:
- $(MAKEPROFILING) all
-
-
-## Compilation rules.
-
-LINK = $(LIBLD) $(LDFLAGS) -o $@
-CKLIBS = $(CRYPTLIB) $(SHADOWLIB) $(PAMLIB) $(DBMLIB)
-
-auth_krb5: auth_krb5.o $(LIBAUTH) $(LIBINN)
- $(LINK) auth_krb5.o $(LIBAUTH) $(KRB5LIB) $(LIBINN) $(LIBS)
-
-auth_smb: auth_smb.o $(LIBSMB) $(LIBAUTH) $(LIBINN)
- $(LINK) auth_smb.o $(LIBSMB) $(LIBAUTH) $(LIBINN) $(LIBS)
-
-ckpasswd: ckpasswd.o $(LIBAUTH) $(LIBINN)
- $(LINK) ckpasswd.o $(LIBAUTH) $(CKLIBS) $(LIBINN) $(LIBS)
-
-domain: domain.o $(LIBAUTH) $(LIBINN)
- $(LINK) domain.o $(LIBAUTH) $(LIBINN) $(LIBS)
-
-ident: ident.o $(LIBAUTH) $(LIBINN)
- $(LINK) ident.o $(LIBAUTH) $(LIBINN) $(LIBS)
-
-radius: radius.o $(LIBAUTH) $(LIBINN)
- $(LINK) radius.o $(LIBAUTH) $(LIBINN) $(LIBS)
-
-auth_krb5.o: auth_krb5.c
- $(CC) $(CFLAGS) $(KRB5INC) -c auth_krb5.c
-
-ckpasswd.o: ckpasswd.c
- $(CC) $(CFLAGS) $(DBMINC) -c ckpasswd.c
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSMB): ; (cd smbval ; $(MAKE))
-$(LIBAUTH): libauth.h libauth.c
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-auth_krb5.o: auth_krb5.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- libauth.h ../include/portable/socket.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h
-auth_smb.o: auth_smb.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h libauth.h \
- ../include/portable/socket.h ../include/config.h smbval/valid.h
-ckpasswd.o: ckpasswd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/inn/qio.h \
- ../include/inn/vector.h ../include/libinn.h libauth.h \
- ../include/portable/socket.h ../include/config.h
-domain.o: domain.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h \
- libauth.h ../include/portable/socket.h ../include/config.h
-ident.o: ident.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h \
- libauth.h ../include/portable/socket.h ../include/config.h
-libauth.o: libauth.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h libauth.h ../include/portable/socket.h \
- ../include/config.h ../include/inn/messages.h ../include/inn/defines.h
-radius.o: radius.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/md5.h ../include/inn/messages.h \
- ../include/libinn.h ../include/nntp.h ../include/paths.h \
- ../include/conffile.h libauth.h ../include/portable/socket.h
+++ /dev/null
-/* $Id: auth_krb5.c 7462 2005-12-12 01:06:54Z eagle $
-**
-** Check an username and password against Kerberos v5.
-**
-** Based on nnrpkrb5auth by Christopher P. Lindsey <lindsey@mallorn.com>
-** See <http://www.mallorn.com/tools/nnrpkrb5auth>
-**
-** This program takes a username and password pair from nnrpd and checks
-** checks their validity against a Kerberos v5 KDC by attempting to obtain a
-** TGT. With the -i <instance> command line option, appends /<instance> to
-** the username prior to authentication.
-**
-** Special thanks to Von Welch <vwelch@vwelch.com> for giving me the initial
-** code on which the Kerberos V authentication is based many years ago, and
-** for introducing me to Kerberos back in '96.
-**
-** Also, thanks to Graeme Mathieson <graeme@mathie.cx> for his inspiration
-** through the pamckpasswd program.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libauth.h"
-#ifdef HAVE_ET_COM_ERR_H
-# include <et/com_err.h>
-#else
-# include <com_err.h>
-#endif
-
-/* krb5_get_in_tkt_with_password is deprecated. */
-#define KRB5_DEPRECATED 1
-#include <krb5.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-/*
- * Default life of the ticket we are getting. Since we are just checking
- * to see if the user can get one, it doesn't need a long lifetime.
- */
-#define KRB5_DEFAULT_LIFE 60 * 5 /* 5 minutes */
-
-
-/*
-** Check the username and password by attempting to get a TGT. Returns 1 on
-** success and 0 on failure. Errors are reported via com_err.
-*/
-static int
-krb5_check_password (char *principal_name, char *password)
-{
- krb5_context kcontext;
- krb5_creds creds;
- krb5_principal user_principal;
- krb5_data *user_realm;
- krb5_principal service_principal;
- krb5_timestamp now;
- krb5_address **addrs = (krb5_address **) NULL; /* Use default */
- long lifetime = KRB5_DEFAULT_LIFE;
- int options = 0;
-
- /* TGT service name for convenience */
- krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
-
- krb5_preauthtype *preauth = NULL;
-
- krb5_error_code code;
-
- /* Our return code - 1 is success */
- int result = 0;
-
- /* Initialize our Kerberos state */
- code = krb5_init_context (&kcontext);
- if (code) {
- com_err (message_program_name, code, "initializing krb5 context");
- return 0;
- }
-
-#ifdef HAVE_KRB5_INIT_ETS
- /* Initialize krb5 error tables */
- krb5_init_ets (kcontext);
-#endif
-
- /* Get current time */
- code = krb5_timeofday (kcontext, &now);
- if (code) {
- com_err (message_program_name, code, "getting time of day");
- return 0;
- }
-
- /* Set up credentials to be filled in */
- memset (&creds, 0, sizeof(creds));
-
- /* From here on, goto cleanup to exit */
-
- /* Parse the username into a krb5 principal */
- if (!principal_name) {
- com_err (message_program_name, 0, "passed NULL principal name");
- goto cleanup;
- }
-
- code = krb5_parse_name (kcontext, principal_name, &user_principal);
- if (code) {
- com_err (message_program_name, code,
- "parsing user principal name %.100s", principal_name);
- goto cleanup;
- }
-
- creds.client = user_principal;
-
- /* Get the user's realm for building service principal */
- user_realm = krb5_princ_realm (kcontext, user_principal);
-
- /*
- * Build the service name into a principal. Right now this is
- * a TGT for the user's realm.
- */
- code = krb5_build_principal_ext (kcontext,
- &service_principal,
- user_realm->length,
- user_realm->data,
- tgtname.length,
- tgtname.data,
- user_realm->length,
- user_realm->data,
- 0 /* terminator */);
- if (code) {
- com_err(message_program_name, code, "building service principal name");
- goto cleanup;
- }
-
- creds.server = service_principal;
-
- creds.times.starttime = 0; /* Now */
- creds.times.endtime = now + lifetime;
- creds.times.renew_till = 0; /* Unrenewable */
-
- /* DO IT */
- code = krb5_get_in_tkt_with_password (kcontext,
- options,
- addrs,
- NULL,
- preauth,
- password,
- 0,
- &creds,
- 0);
-
- /* We are done with password at this point... */
-
- if (code) {
- /* FAILURE - Parse a few common errors here */
- switch (code) {
- case KRB5KRB_AP_ERR_BAD_INTEGRITY:
- com_err (message_program_name, 0, "bad password for %.100s",
- principal_name);
- break;
- case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
- com_err (message_program_name, 0, "unknown user \"%.100s\"",
- principal_name);
- break;
- default:
- com_err (message_program_name, code,
- "checking Kerberos password for %.100s", principal_name);
- }
- result = 0;
- } else {
- /* SUCCESS */
- result = 1;
- }
-
- /* Cleanup */
- cleanup:
- krb5_free_cred_contents (kcontext, &creds);
-
- return result;
-}
-
-int
-main (int argc, char *argv[])
-{
- struct auth_info *authinfo;
- char *new_user;
-
- message_program_name = "auth_krb5";
-
- /* Retrieve the username and passwd from nnrpd. */
- authinfo = get_auth_info(stdin);
-
- /* Must have a username/password, and no '@' in the address. @ checking
- is there to prevent authentication against another Kerberos realm; there
- should be a -r <realm> commandline option to make this check unnecessary
- in the future. */
- if (authinfo == NULL)
- die("no authentication information from nnrpd");
- if (authinfo->username[0] == '\0')
- die("null username");
- if (strchr(authinfo->username, '@') != NULL)
- die("username contains @, not allowed");
-
- /* May need to prepend instance name if -i option was given. */
- if (argc > 1) {
- if (argc == 3 && strcmp(argv[1], "-i") == 0) {
- new_user = concat(authinfo->username, "/", argv[2], (char *) 0);
- free(authinfo->username);
- authinfo->username = new_user;
- } else {
- die("error parsing command-line options");
- }
- }
-
- if (krb5_check_password(authinfo->username, authinfo->password)) {
- printf("User:%s\r\n", authinfo->username);
- exit(0);
- } else {
- die("failure validating password");
- }
-}
+++ /dev/null
-/*
- * Samba authenticator.
- * usage: auth_smb <server> [<backup_server>] <domain>
- *
- * Heavily based on:
- * pam_smb -- David Airlie 1998-2000 v1.1.6 <airlied@samba.org>
- * http://www.csn.ul.ie/~airlied
- *
- * Written 2000 October by Krischan Jodies <krischan@jodies.cx>
- *
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "inn/messages.h"
-
-#include "libauth.h"
-#include "smbval/valid.h"
-
-int
-main(int argc, char *argv[])
-{
- struct auth_info *authinfo;
- int result;
- char *server, *backup, *domain;
-
- message_program_name = "auth_smb";
-
- if ((argc > 4) || (argc < 3))
- die("wrong number of arguments"
- " (auth_smb <server> [<backup-server>] <domain>");
-
- authinfo = get_auth_info(stdin);
- if (authinfo == NULL)
- die("no user information provided by nnrpd");
-
- /* Got a username and password. Now check to see if they're valid. */
- server = argv[1];
- backup = (argc > 3) ? argv[2] : argv[1];
- domain = (argc > 3) ? argv[3] : argv[2];
- result = Valid_User(authinfo->username, authinfo->password, server,
- backup, domain);
-
- /* Analyze the result. */
- switch (result) {
- case NTV_NO_ERROR:
- printf("User:%s\n", authinfo->username);
- exit(0);
- break;
- case NTV_SERVER_ERROR:
- die("server error");
- break;
- case NTV_PROTOCOL_ERROR:
- die("protocol error");
- break;
- case NTV_LOGON_ERROR:
- die("logon error");
- break;
- default:
- die("unknown error");
- break;
- }
-
- /* Never reached. */
- return 1;
-}
+++ /dev/null
-/* $Id: ckpasswd.c 7565 2006-08-28 02:42:54Z eagle $
-**
-** The default username/password authenticator.
-**
-** This program is intended to be run by nnrpd and handle usernames and
-** passwords. It can authenticate against a regular flat file (the type
-** managed by htpasswd), a DBM file, the system password file or shadow file,
-** or PAM.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "inn/vector.h"
-#include "libinn.h"
-
-#include "libauth.h"
-
-#if HAVE_CRYPT_H
-# include <crypt.h>
-#endif
-#include <fcntl.h>
-#include <pwd.h>
-#include <grp.h>
-
-#if defined(HAVE_DBM) || defined(HAVE_BDB_DBM)
-# if HAVE_NDBM_H
-# include <ndbm.h>
-# elif HAVE_BDB_DBM
-# define DB_DBM_HSEARCH 1
-# include <db.h>
-# elif HAVE_GDBM_NDBM_H
-# include <gdbm-ndbm.h>
-# elif HAVE_DB1_NDBM_H
-# include <db1/ndbm.h>
-# endif
-# define OPT_DBM "d:"
-#else
-# define OPT_DBM ""
-#endif
-
-#if HAVE_GETSPNAM
-# include <shadow.h>
-# define OPT_SHADOW "s"
-#else
-# define OPT_SHADOW ""
-#endif
-
-#if HAVE_PAM
-# if HAVE_PAM_PAM_APPL_H
-# include <pam/pam_appl.h>
-# else
-# include <security/pam_appl.h>
-# endif
-#endif
-
-
-/*
-** The PAM conversation function.
-**
-** Since we already have all the information and can't ask the user
-** questions, we can't quite follow the real PAM protocol. Instead, we just
-** return the password in response to every question that PAM asks. There
-** appears to be no generic way to determine whether the message in question
-** is indeed asking for the password....
-**
-** This function allocates an array of struct pam_response to return to the
-** PAM libraries that's never freed. For this program, this isn't much of an
-** issue, since it will likely only be called once and then the program will
-** exit. This function uses malloc and strdup instead of xmalloc and xstrdup
-** intentionally so that the PAM conversation will be closed cleanly if we
-** run out of memory rather than simply terminated.
-**
-** appdata_ptr contains the password we were given.
-*/
-#if HAVE_PAM
-static int
-pass_conv(int num_msg, const struct pam_message **msgm UNUSED,
- struct pam_response **response, void *appdata_ptr)
-{
- int i;
-
- *response = malloc(num_msg * sizeof(struct pam_response));
- if (*response == NULL)
- return PAM_CONV_ERR;
- for (i = 0; i < num_msg; i++) {
- (*response)[i].resp = strdup((char *)appdata_ptr);
- (*response)[i].resp_retcode = 0;
- }
- return PAM_SUCCESS;
-}
-#endif /* HAVE_PAM */
-
-
-/*
-** Authenticate a user via PAM.
-**
-** Attempts to authenticate a user with PAM, returning true if the user
-** successfully authenticates and false otherwise. Note that this function
-** doesn't attempt to handle any remapping of the authenticated user by the
-** PAM stack, but just assumes that the authenticated user was the same as
-** the username given.
-**
-** Right now, all failures are handled via die. This may be worth revisiting
-** in case we want to try other authentication methods if this fails for a
-** reason other than the system not having PAM support.
-*/
-#if !HAVE_PAM
-static bool
-auth_pam(char *username UNUSED, char *password UNUSED)
-{
- return false;
-}
-#else
-static bool
-auth_pam(const char *username, char *password)
-{
- pam_handle_t *pamh;
- struct pam_conv conv;
- int status;
-
- conv.conv = pass_conv;
- conv.appdata_ptr = password;
- status = pam_start("nnrpd", username, &conv, &pamh);
- if (status != PAM_SUCCESS)
- die("pam_start failed: %s", pam_strerror(pamh, status));
- status = pam_authenticate(pamh, PAM_SILENT);
- if (status != PAM_SUCCESS)
- die("pam_authenticate failed: %s", pam_strerror(pamh, status));
- status = pam_acct_mgmt(pamh, PAM_SILENT);
- if (status != PAM_SUCCESS)
- die("pam_acct_mgmt failed: %s", pam_strerror(pamh, status));
- status = pam_end(pamh, status);
- if (status != PAM_SUCCESS)
- die("pam_end failed: %s", pam_strerror(pamh, status));
-
- /* If we get to here, the user successfully authenticated. */
- return true;
-}
-#endif /* HAVE_PAM */
-
-
-/*
-** Try to get a password out of a dbm file. The dbm file should have the
-** username for the key and the crypted password as the value. The crypted
-** password, if found, is returned as a newly allocated string; otherwise,
-** NULL is returned.
-*/
-#if !(defined(HAVE_DBM) || defined(HAVE_BDB_DBM))
-static char *
-password_dbm(char *user UNUSED, const char *file UNUSED)
-{
- return NULL;
-}
-#else
-static char *
-password_dbm(char *name, const char *file)
-{
- datum key, value;
- DBM *database;
- char *password;
-
- database = dbm_open(file, O_RDONLY, 0600);
- if (database == NULL)
- return NULL;
- key.dptr = name;
- key.dsize = strlen(name);
- value = dbm_fetch(database, key);
- if (value.dptr == NULL) {
- dbm_close(database);
- return NULL;
- }
- password = xmalloc(value.dsize + 1);
- strlcpy(password, value.dptr, value.dsize + 1);
- dbm_close(database);
- return password;
-}
-#endif /* HAVE_DBM || HAVE_BDB_DBM */
-
-
-/*
-** Try to get a password out of the system /etc/shadow file. The crypted
-** password, if found, is returned as a newly allocated string; otherwise,
-** NULL is returned.
-*/
-#if !HAVE_GETSPNAM
-static char *
-password_shadow(const char *user UNUSED)
-{
- return NULL;
-}
-#else
-static char *
-password_shadow(const char *user)
-{
- struct spwd *spwd;
-
- spwd = getspnam(user);
- if (spwd != NULL)
- return xstrdup(spwd->sp_pwdp);
- return NULL;
-}
-#endif /* HAVE_GETSPNAM */
-
-
-/*
-** Try to get a password out of a file. The crypted password, if found, is
-** returned as a newly allocated string; otherwise, NULL is returned.
-*/
-static char *
-password_file(const char *username, const char *file)
-{
- QIOSTATE *qp;
- char *line, *password;
- struct cvector *info = NULL;
-
- qp = QIOopen(file);
- if (qp == NULL)
- return NULL;
- for (line = QIOread(qp); line != NULL; line = QIOread(qp)) {
- if (*line == '#' || *line == '\n')
- continue;
- info = cvector_split(line, ':', info);
- if (info->count < 2 || strcmp(info->strings[0], username) != 0)
- continue;
- password = xstrdup(info->strings[1]);
- QIOclose(qp);
- cvector_free(info);
- return password;
- }
- if (QIOtoolong(qp))
- die("line too long in %s", file);
- if (QIOerror(qp))
- sysdie("error reading %s", file);
- QIOclose(qp);
- cvector_free(info);
- return NULL;
-}
-
-
-/*
-** Try to get a password out of the system password file. The crypted
-** password, if found, is returned as a newly allocated string; otherwise,
-** NULL is returned.
-*/
-static char *
-password_system(const char *username)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(username);
- if (pwd != NULL)
- return xstrdup(pwd->pw_passwd);
- return NULL;
-}
-
-
-/*
-** Try to get the name of a user's primary group out of the system group
-** file. The group, if found, is returned as a newly allocated string;
-** otherwise, NULL is returned. If the username is not found, NULL is
-** returned.
-*/
-static char *
-group_system(const char *username)
-{
- struct passwd *pwd;
- struct group *gr;
-
- pwd = getpwnam(username);
- if (pwd == NULL)
- return NULL;
- gr = getgrgid(pwd->pw_gid);
- if (gr == NULL)
- return NULL;
- return xstrdup(gr->gr_name);
-}
-
-
-/*
-** Output username (and group, if desired) in correct return format.
-*/
-static void
-output_user(const char *username, bool wantgroup)
-{
- if (wantgroup) {
- char *group = group_system(username);
- if (group == NULL)
- die("group info for user %s not available", username);
- printf("User:%s@%s\n", username, group);
- }
- else
- printf("User:%s\n", username);
-}
-
-
-/*
-** Main routine.
-**
-** We handle the variences between systems with #if blocks above, so that
-** this code can look fairly clean.
-*/
-int
-main(int argc, char *argv[])
-{
- enum authtype { AUTH_NONE, AUTH_SHADOW, AUTH_FILE, AUTH_DBM };
-
- int opt;
- enum authtype type = AUTH_NONE;
- bool wantgroup = false;
- const char *filename = NULL;
- struct auth_info *authinfo = NULL;
- char *password = NULL;
-
- message_program_name = "ckpasswd";
-
- while ((opt = getopt(argc, argv, "gf:u:p:" OPT_DBM OPT_SHADOW)) != -1) {
- switch (opt) {
- case 'g':
- if (type == AUTH_DBM || type == AUTH_FILE)
- die("-g option is incompatible with -d or -f");
- wantgroup = true;
- break;
- case 'd':
- if (type != AUTH_NONE)
- die("only one of -s, -f, or -d allowed");
- if (wantgroup)
- die("-g option is incompatible with -d or -f");
- type = AUTH_DBM;
- filename = optarg;
- break;
- case 'f':
- if (type != AUTH_NONE)
- die("only one of -s, -f, or -d allowed");
- if (wantgroup)
- die("-g option is incompatible with -d or -f");
- type = AUTH_FILE;
- filename = optarg;
- break;
- case 's':
- if (type != AUTH_NONE)
- die("only one of -s, -f, or -d allowed");
- type = AUTH_SHADOW;
- break;
- case 'u':
- if (authinfo == NULL) {
- authinfo = xmalloc(sizeof(struct auth_info));
- authinfo->password = NULL;
- }
- authinfo->username = optarg;
- break;
- case 'p':
- if (authinfo == NULL) {
- authinfo = xmalloc(sizeof(struct auth_info));
- authinfo->username = NULL;
- }
- authinfo->password = optarg;
- break;
- default:
- exit(1);
- }
- }
- if (argc != optind)
- die("extra arguments given");
- if (authinfo != NULL && authinfo->username == NULL)
- die("-u option is required if -p option is given");
- if (authinfo != NULL && authinfo->password == NULL)
- die("-p option is required if -u option is given");
-
- /* Unless a username or password was given on the command line, assume
- we're being run by nnrpd. */
- if (authinfo == NULL)
- authinfo = get_auth_info(stdin);
- if (authinfo == NULL)
- die("no authentication information from nnrpd");
- if (authinfo->username[0] == '\0')
- die("null username");
-
- /* Run the appropriate authentication routines. */
- switch (type) {
- case AUTH_SHADOW:
- password = password_shadow(authinfo->username);
- if (password == NULL)
- password = password_system(authinfo->username);
- break;
- case AUTH_FILE:
- password = password_file(authinfo->username, filename);
- break;
- case AUTH_DBM:
- password = password_dbm(authinfo->username, filename);
- break;
- case AUTH_NONE:
- if (auth_pam(authinfo->username, authinfo->password)) {
- output_user(authinfo->username, wantgroup);
- exit(0);
- }
- password = password_system(authinfo->username);
- break;
- }
-
- if (password == NULL)
- die("user %s unknown", authinfo->username);
- if (strcmp(password, crypt(authinfo->password, password)) != 0)
- die("invalid password for user %s", authinfo->username);
-
- /* The password matched. */
- output_user(authinfo->username, wantgroup);
- exit(0);
-}
+++ /dev/null
-/* $Id: domain.c 7141 2005-03-17 11:42:46Z vinocur $
-**
-** Domain authenticator.
-**
-** Compares the domain of the client connection to the first argument given
-** on the command line, and returns the host portion of the connecting host
-** as the user if it matches.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "libauth.h"
-
-int
-main(int argc, char *argv[])
-{
- char *p, *host;
- struct res_info *res;
-
- if (argc != 2)
- die("Usage: domain <domain>");
- message_program_name = "domain";
-
- /* Read the connection information from stdin. */
- res = get_res_info(stdin);
- if (res == NULL)
- die("did not get ClientHost data from nnrpd");
- host = res->clienthostname;
-
- /* Check the host against the provided domain. Allow the domain to be
- specified both with and without a leading period; if without, make sure
- that there is a period right before where it matches in the host. */
- p = strstr(host, argv[1]);
- if (p == host)
- die("host %s matches the domain exactly", host);
- if (p == NULL || (argv[1][0] != '.' && p != host && *(p - 1) != '.'))
- die("host %s didn't match domain %s", host, argv[1]);
-
- /* Peel off the portion of the host before where the provided domain
- matches and return it as the user. */
- if (argv[1][0] != '.')
- p--;
- *p = '\0';
- printf("User:%s\n", host);
- return 0;
-}
+++ /dev/null
-/* $Id: ident.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Ident authenticator.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <netdb.h>
-#include <signal.h>
-#include <syslog.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "libauth.h"
-
-#define IDENT_PORT 113
-
-static void out(int sig UNUSED) {
- exit(1);
-}
-
-int main(int argc, char *argv[])
-{
- struct servent *s;
- char buf[2048];
- struct res_info *res;
- struct sockaddr_in *lsin, *csin;
-#ifdef HAVE_INET6
- struct sockaddr_storage *lss;
- struct sockaddr_in6 *lsin6, *csin6;
-#endif
- int sock;
- int opt;
- int truncate_domain = 0;
- char *iter;
- char *p;
- unsigned int got;
- int lport, cport, identport;
- char *endstr;
-
- message_program_name = "ident";
-
- xsignal_norestart(SIGALRM,out);
- alarm(15);
-
- s = getservbyname("ident", "tcp");
- if (!s)
- identport = IDENT_PORT;
- else
- identport = ntohs(s->s_port);
-
- while ((opt = getopt(argc, argv, "p:t")) != -1) {
- switch (opt) {
- case 'p':
- for (iter = optarg; *iter; iter++)
- if (*iter < '0' || *iter > '9')
- break;
- if (*iter) {
- /* not entirely numeric */
- s = getservbyname(optarg, "tcp");
- if (s == NULL)
- die("cannot getsrvbyname(%s, tcp)", optarg);
- identport = s->s_port;
- } else
- identport = atoi(optarg);
- break;
- case 't':
- truncate_domain = 1;
- break;
- }
- }
-
- /* read the connection info from stdin */
- res = get_res_info(stdin);
- if (res == NULL)
- die("did not get client information from nnrpd");
-
-#ifdef HAVE_INET6
- lss = (struct sockaddr_storage *)(res->local);
- lsin6 = (struct sockaddr_in6 *)(res->local);
- csin6 = (struct sockaddr_in6 *)(res->client);
- if( lss->ss_family == AF_INET6 )
- {
- lport = ntohs( lsin6->sin6_port );
- lsin6->sin6_port = 0;
- cport = ntohs( csin6->sin6_port );
- csin6->sin6_port = htons( identport );
- sock = socket(PF_INET6, SOCK_STREAM, 0);
- } else
-#endif
- {
- lsin = (struct sockaddr_in *)(res->local);
- lport = htons( lsin->sin_port );
- lsin->sin_port = 0;
- csin = (struct sockaddr_in *)(res->client);
- cport = htons( csin->sin_port );
- csin->sin_port = htons( identport );
- sock = socket(PF_INET, SOCK_STREAM, 0);
- }
- if (sock < 0)
- sysdie("cannot create socket");
- if (bind(sock, res->local, SA_LEN(res->local)) < 0)
- sysdie("cannot bind socket");
- if (connect(sock, res->client, SA_LEN(res->local)) < 0) {
- if (errno != ECONNREFUSED)
- sysdie("cannot connect to ident server");
- else
- sysdie("client host does not accept ident connections");
- }
- free_res_info(res);
-
- /* send the request out */
- snprintf(buf, sizeof(buf), "%d , %d\r\n", cport, lport);
- opt = xwrite(sock, buf, strlen(buf));
- if (opt < 0)
- sysdie("cannot write to ident server");
-
- /* get the answer back */
- got = 0;
- do {
- opt = read(sock, buf+got, sizeof(buf)-got);
- if (opt < 0)
- sysdie("cannot read from ident server");
- else if (!opt)
- die("end of file from ident server before response");
- while (opt--)
- if (buf[got] != '\n')
- got++;
- } while (buf[got] != '\n');
- buf[got] = '\0';
- if (buf[got-1] == '\r')
- buf[got-1] = '\0';
-
- /* buf now contains the entire ident response. */
- if (!(iter = strchr(buf, ':')))
- /* malformed response */
- die("malformed response \"%s\" from ident server", buf);
- iter++;
-
- while (*iter && ISWHITE(*iter))
- iter++;
- endstr = iter;
- while (*endstr && *endstr != ':' && !ISWHITE(*endstr))
- endstr++;
- if (!*endstr)
- /* malformed response */
- die("malformed response \"%s\" from ident server", buf);
- if (*endstr != ':') {
- *endstr++ = '\0';
- while (*endstr != ':')
- endstr++;
- }
-
- *endstr = '\0';
-
- if (strcmp(iter, "ERROR") == 0)
- die("ident server reported an error");
- else if (strcmp(iter, "USERID") != 0)
- die("ident server returned \"%s\", not USERID", iter);
-
- /* skip the operating system */
- if (!(iter = strchr(endstr+1, ':')))
- exit(1);
-
- /* everything else is username */
- iter++;
- while (*iter && ISWHITE(*iter))
- iter++;
- if (!*iter || *iter == '[')
- /* null, or encrypted response */
- die("ident response is null or encrypted");
- if ((truncate_domain == 1) && ((p = strchr(iter, '@')) != NULL))
- *p = '\0';
- printf("User:%s\n", iter);
-
- exit(0);
-}
+++ /dev/null
-/* $Id: libauth.c 7500 2006-03-20 01:52:44Z eagle $
-**
-** Common code for authenticators and resolvers.
-**
-** Collects common code to read information from nnrpd that should be done
-** the same for all authenticators, and common code to get information about
-** the incoming connection.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-
-#include "libauth.h"
-#include "inn/messages.h"
-
-#define NAMESTR "ClientAuthname: "
-#define PASSSTR "ClientPassword: "
-
-#define CLIHOST "ClientHost: "
-#define CLIIP "ClientIP: "
-#define CLIPORT "ClientPort: "
-#define LOCIP "LocalIP: "
-#define LOCPORT "LocalPort: "
-
-#ifdef HAVE_INET6
-# include <netdb.h>
-#endif
-
-/* Main loop. If res != NULL, expects to get resolver info from nnrpd, and
- writes it into the struct. If auth != NULL, expects to get authentication
- info from nnrpd, and writes it into the struct. */
-
-static bool
-get_connection_info(FILE *stream, struct res_info *res, struct auth_info *auth)
-{
- char buff[SMBUF];
- size_t length;
- char *cip = NULL, *sip = NULL, *cport = NULL, *sport = NULL;
-#ifdef HAVE_INET6
- struct addrinfo *r, hints;
-#else
- struct sockaddr_in *loc_sin, *cli_sin;
-#endif
-
- /* Zero fields first (anything remaining NULL after is missing data) */
- if (res != NULL) {
- res->clienthostname = NULL;
- res->client = NULL;
- res->local = NULL;
- }
- if (auth != NULL) {
- auth->username = NULL;
- auth->password = NULL;
- }
-
- /* Read input from nnrpd a line at a time, stripping \r\n. */
- while (fgets(buff, sizeof(buff), stream) != NULL) {
- length = strlen(buff);
- if (length == 0 || buff[length - 1] != '\n')
- goto error;
- buff[length - 1] = '\0';
- if (length > 1 && buff[length - 2] == '\r')
- buff[length - 2] = '\0';
-
- /* Parse */
- if (strncmp(buff, ".", 2) == 0)
- break;
- else if (auth != NULL && strncmp(buff, NAMESTR, strlen(NAMESTR)) == 0)
- auth->username = xstrdup(buff + strlen(NAMESTR));
- else if (auth != NULL && strncmp(buff, PASSSTR, strlen(PASSSTR)) == 0)
- auth->password = xstrdup(buff + strlen(PASSSTR));
- else if (res != NULL && strncmp(buff, CLIHOST, strlen(CLIHOST)) == 0)
- res->clienthostname = xstrdup(buff + strlen(CLIHOST));
- else if (res != NULL && strncmp(buff, CLIIP, strlen(CLIIP)) == 0)
- cip = xstrdup(buff + strlen(CLIIP));
- else if (res != NULL && strncmp(buff, CLIPORT, strlen(CLIPORT)) == 0)
- cport = xstrdup(buff + strlen(CLIPORT));
- else if (res != NULL && strncmp(buff, LOCIP, strlen(LOCIP)) == 0)
- sip = xstrdup(buff + strlen(LOCIP));
- else if (res != NULL && strncmp(buff, LOCPORT, strlen(LOCPORT)) == 0)
- sport = xstrdup(buff + strlen(LOCPORT));
- else {
- /**** We just ignore excess fields for now ****/
-
- /* warn("libauth: unexpected data from nnrpd: \"%s\"", buff); */
- /* goto error; */
- }
- }
-
- /* If some field is missing, free the rest and error out. */
- if (auth != NULL && (auth->username == NULL || auth->password == NULL)) {
- warn("libauth: requested authenticator data not sent by nnrpd");
- goto error;
- }
- if (res != NULL && (res->clienthostname == NULL || cip == NULL ||
- cport == NULL || sip == NULL || sport == NULL)) {
- warn("libauth: requested resolver data not sent by nnrpd");
- goto error;
- }
-
- /* Generate sockaddrs from IP and port strings */
- if (res != NULL) {
-#ifdef HAVE_INET6
- /* sockaddr_in6 may be overkill for PF_INET case, but oh well */
- res->client = xcalloc(1, sizeof(struct sockaddr_in6));
- res->local = xcalloc(1, sizeof(struct sockaddr_in6));
-
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
-
- hints.ai_family = strchr( cip, ':' ) != NULL ? PF_INET6 : PF_INET;
- if( getaddrinfo( cip, cport, &hints, &r ) != 0)
- goto error;
- if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
- goto error;
- memcpy( res->client, r->ai_addr, r->ai_addrlen );
- freeaddrinfo( r );
-
- hints.ai_family = strchr( sip, ':' ) != NULL ? PF_INET6 : PF_INET;
- if( getaddrinfo( sip, sport, &hints, &r ) != 0)
- goto error;
- if( r->ai_addrlen > sizeof(struct sockaddr_in6) )
- goto error;
- memcpy( res->local, r->ai_addr, r->ai_addrlen );
- freeaddrinfo( r );
-#else
- res->client = xcalloc(1, sizeof(struct sockaddr_in));
- res->local = xcalloc(1, sizeof(struct sockaddr_in));
-
- cli_sin = (struct sockaddr_in *)(res->client);
- loc_sin = (struct sockaddr_in *)(res->local);
- cli_sin->sin_family = AF_INET;
- if (!inet_aton(cip, &cli_sin->sin_addr))
- goto error;
- cli_sin->sin_port = htons( atoi(cport) );
-
- loc_sin->sin_family = AF_INET;
- if (!inet_aton(sip, &loc_sin->sin_addr))
- goto error;
- loc_sin->sin_port = htons( atoi(sport) );
-
-# ifdef HAVE_SOCKADDR_LEN
- cli_sin->sin_len = sizeof(struct sockaddr_in);
- loc_sin->sin_len = sizeof(struct sockaddr_in);
-# endif
-#endif
-
- free(sip);
- free(sport);
- free(cip);
- free(cport);
- }
-
- return true;
-
-error:
- if (auth != NULL && auth->username != NULL) free(auth->username);
- if (auth != NULL && auth->password != NULL) free(auth->password);
- if (res != NULL && res->clienthostname != NULL) free(res->clienthostname);
- if (res != NULL && res->client != NULL) free(res->client);
- if (res != NULL && res->local != NULL) free(res->local);
- if (sip != NULL) free(sip);
- if (sport != NULL) free(sport);
- if (cip != NULL) free(cip);
- if (cport != NULL) free(cport);
- return false;
-}
-
-
-/* Wrappers to read information from nnrpd, returning an allocated struct on
- success. */
-
-struct res_info *
-get_res_info(FILE *stream) {
- struct res_info *res = xmalloc(sizeof(struct res_info));
-
- if(get_connection_info(stream, res, NULL))
- return res;
-
- free(res);
- return NULL;
-}
-
-
-struct auth_info *
-get_auth_info(FILE *stream) {
- struct auth_info *auth = xmalloc(sizeof(struct auth_info));
-
- if(get_connection_info(stream, NULL, auth))
- return auth;
-
- free(auth);
- return NULL;
-}
-
-void
-free_res_info(struct res_info *res) {
- if(res == NULL)
- return;
- if(res->client != NULL) free(res->client);
- if(res->local != NULL) free(res->local);
- if(res->clienthostname != NULL) free(res->clienthostname);
- free(res);
-}
-
-void
-free_auth_info(struct auth_info *auth) {
- if(auth == NULL)
- return;
- if(auth->username != NULL) free(auth->username);
- if(auth->password != NULL) free(auth->password);
- free(auth);
-}
-
+++ /dev/null
-/*
-**
-** Common headers for authenticators and resolvers.
-**
-*/
-
-#include "config.h"
-#include "portable/socket.h"
-
-/* Holds the resolver information from nnrpd. */
-struct res_info {
- struct sockaddr *client;
- struct sockaddr *local;
- char *clienthostname;
-};
-
-/* Holds the authentication information from nnrpd. */
-struct auth_info {
- char *username;
- char *password;
-};
-
-/*
- * Reads connection information from a file descriptor (normally stdin, when
- * talking to nnrpd) and returns a new res_info or auth_info struct, or
- * returns NULL on failure. Note that the fields will never be NULL; if the
- * corresponding information is missing, it is an error (which will be
- * logged and NULL will be returned). The client is responsible for freeing
- * the struct and its fields; this can be done by calling the appropriate
- * destruction function below.
- */
-
-extern struct auth_info *get_auth_info(FILE *);
-extern struct res_info *get_res_info (FILE *);
-
-extern void free_auth_info(struct auth_info*);
-extern void free_res_info (struct res_info*);
-
-
+++ /dev/null
-/* $Id: radius.c 7745 2008-04-06 10:18:54Z iulius $
-**
-** Authenticate a user against a remote radius server.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#if HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/md5.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "conffile.h"
-
-#include "libauth.h"
-
-#define RADIUS_LOCAL_PORT NNTP_PORT
-
-#define AUTH_VECTOR_LEN 16
-
-typedef struct _auth_req {
- unsigned char code;
- unsigned char id;
- unsigned short length;
- unsigned char vector[AUTH_VECTOR_LEN];
- unsigned char data[NNTP_STRLEN*2];
- int datalen;
-} auth_req;
-
-typedef struct _rad_config_t {
- char *secret; /* pseudo encryption thingy secret that radius uses */
-
- char *radhost; /* parameters for talking to the remote radius sever */
- int radport;
- char *lochost;
- int locport;
-
- char *prefix, *suffix; /* futz with the username, if necessary */
- int ignore_source;
-
- struct _rad_config_t *next; /* point to any additional servers */
-} rad_config_t;
-
-typedef struct _sending_t {
- auth_req req;
- int reqlen;
- struct sockaddr_in sinr;
- struct _sending_t *next;
-} sending_t;
-
-#define RADlbrace 1
-#define RADrbrace 2
-#define RADserver 10
-#define RADhost 11
-#define RADsecret 12
-#define RADport 13
-#define RADlochost 14
-#define RADlocport 15
-#define RADprefix 16
-#define RADsuffix 17
-#define RADsource 18
-
-static CONFTOKEN radtoks[] = {
- { RADlbrace, "{" },
- { RADrbrace, "}" },
- { RADserver, "server" },
- { RADhost, "radhost:" },
- { RADsecret, "secret:" },
- { RADport, "radport:" },
- { RADlochost, "lochost:" },
- { RADlocport, "locport:" },
- { RADprefix, "prefix:" },
- { RADsuffix, "suffix:" },
- { RADsource, "ignore-source:" },
- { 0, 0 }
-};
-
-static rad_config_t *get_radconf(void)
-{
- rad_config_t *new;
-
- new = xcalloc(1, sizeof(rad_config_t));
- new->next = NULL;
-
- return new;
-}
-
-static int read_config(char *authfile, rad_config_t *radconf)
-{
- int inbrace;
- rad_config_t *radconfig=NULL;
- CONFFILE *file;
- CONFTOKEN *token;
- char *server;
- int type;
- char *iter;
-
- if ((file = CONFfopen(authfile)) == NULL)
- sysdie("cannot open config file %s", authfile);
-
- inbrace = 0;
- while ((token = CONFgettoken(radtoks, file)) != NULL) {
- if (!inbrace) {
- if (token->type != RADserver)
- die("expected server keyword on line %d", file->lineno);
- if ((token = CONFgettoken(0, file)) == NULL)
- die("expected server name on line %d", file->lineno);
- server = xstrdup(token->name);
- if ((token = CONFgettoken(radtoks, file)) == NULL
- || token->type != RADlbrace)
- die("expected { on line %d", file->lineno);
- inbrace = 1;
-
- if (radconfig == NULL)
- radconfig = radconf;
- else {
- radconfig->next = get_radconf();
- radconfig = radconfig->next;
- }
- }
- else {
- type = token->type;
- if (type == RADrbrace)
- inbrace = 0;
- else {
- if ((token = CONFgettoken(0, file)) == NULL)
- die("keyword with no value on line %d", file->lineno);
- iter = token->name;
-
- /* what are we setting? */
- switch(type) {
- case RADsecret:
- if (radconfig->secret) continue;
- radconfig->secret = xstrdup(iter);
- break;
- case RADhost:
- if (radconfig->radhost) continue;
- radconfig->radhost = xstrdup(iter);
- break;
- case RADport:
- if (radconfig->radport) continue;
- radconfig->radport = atoi(iter);
- break;
- case RADlochost:
- if (radconfig->lochost) continue;
- radconfig->lochost = xstrdup(iter);
- break;
- case RADlocport:
- if (radconfig->locport) continue;
- radconfig->locport = atoi(iter);
- break;
- case RADprefix:
- if (radconfig->prefix) continue;
- radconfig->prefix = xstrdup(iter);
- break;
- case RADsuffix:
- if (radconfig->suffix) continue;
- radconfig->suffix = xstrdup(iter);
- break;
- case RADsource:
- if (!strcasecmp(iter, "true"))
- radconfig->ignore_source = 1;
- else if (!strcasecmp(iter, "false"))
- radconfig->ignore_source = 0;
- else
- die("expected true or false after ignore-source on line %d",
- file->lineno);
- break;
- default:
- die("unknown keyword on line %d", file->lineno);
- }
- }
- }
- }
-
- CONFfclose(file);
-
- if (!radconf->radhost)
- die("no radius host specified");
- else if (!radconf->secret)
- die("no shared secret with radius host specified");
-
- return(0);
-}
-
-#define PW_AUTH_UDP_PORT 1645
-
-#define PW_AUTHENTICATION_REQUEST 1
-#define PW_AUTHENTICATION_ACK 2
-#define PW_AUTHENTICATION_REJECT 3
-
-#define PW_USER_NAME 1
-#define PW_PASSWORD 2
-
-#define PW_SERVICE_TYPE 6
-#define PW_SERVICE_AUTH_ONLY 8
-
-#define RAD_NAS_IP_ADDRESS 4 /* IP address */
-#define RAD_NAS_PORT 5 /* Integer */
-
-static void req_copyto (auth_req to, sending_t *from)
-{
- to = from->req;
-}
-
-static void req_copyfrom (sending_t *to, auth_req from)
-{
- to->req = from;
-}
-
-static int rad_auth(rad_config_t *radconfig, char *uname, char *pass)
-{
- auth_req req;
- int i, j, jlen, passstart;
- unsigned char secbuf[128];
- char hostname[SMBUF];
- unsigned char digest[MD5_DIGESTSIZE];
- struct timeval seed;
- struct sockaddr_in sinl;
- int sock;
- struct hostent *hent;
- int passlen;
- time_t now, end;
- struct timeval tmout;
- int got;
- fd_set rdfds;
- uint32_t nvalue;
- socklen_t slen;
- int authtries= 3; /* number of times to try reaching the radius server */
- rad_config_t *config;
- sending_t *reqtop, *sreq, *new;
- int done;
-
- /* set up the linked list */
- config = radconfig;
-
- if (config == NULL) {
- warn("no configuration file");
- return(-2);
- } else {
- /* setting sreq to NULL guarantees reqtop will be properly set later */
- sreq = NULL;
- reqtop = NULL;
- }
-
- while (config != NULL){
- new = xmalloc(sizeof(sending_t));
- new->next = NULL;
-
- if (sreq == NULL){
- reqtop = new;
- sreq = new;
- } else {
- sreq->next = new;
- sreq = sreq->next;
- }
- req_copyto(req, sreq);
-
- /* first, build the sockaddrs */
- memset(&sinl, '\0', sizeof(sinl));
- memset(&sreq->sinr, '\0', sizeof(sreq->sinr));
- sinl.sin_family = AF_INET;
- sreq->sinr.sin_family = AF_INET;
- if (config->lochost == NULL) {
- if (gethostname(hostname, sizeof(hostname)) != 0) {
- syswarn("cannot get local hostname");
- return(-2);
- }
- config->lochost = xstrdup(hostname);
- }
- if (config->lochost) {
- if (inet_aton(config->lochost, &sinl.sin_addr) != 1) {
- if ((hent = gethostbyname(config->lochost)) == NULL) {
- warn("cannot gethostbyname lochost %s", config->lochost);
- return(-2);
- }
- memcpy(&sinl.sin_addr.s_addr, hent->h_addr,
- sizeof(struct in_addr));
- }
- }
- if (inet_aton(config->radhost, &sreq->sinr.sin_addr) != 1) {
- if ((hent = gethostbyname(config->radhost)) == NULL) {
- warn("cannot gethostbyname radhost %s", config->radhost);
- return(-2);
- }
- memcpy(&sreq->sinr.sin_addr.s_addr, hent->h_addr_list[0],
- sizeof(struct in_addr));
- }
-
- if (config->radport)
- sreq->sinr.sin_port = htons(config->radport);
- else
- sreq->sinr.sin_port = htons(PW_AUTH_UDP_PORT);
-
- /* seed the random number generator for the auth vector */
- gettimeofday(&seed, 0);
- srandom((unsigned) seed.tv_sec+seed.tv_usec);
- /* build the visible part of the auth vector randomly */
- for (i = 0; i < AUTH_VECTOR_LEN; i++)
- req.vector[i] = random() % 256;
- strlcpy((char *) secbuf, config->secret, sizeof(secbuf));
- memcpy(secbuf+strlen(config->secret), req.vector, AUTH_VECTOR_LEN);
- md5_hash(secbuf, strlen(config->secret)+AUTH_VECTOR_LEN, digest);
- /* fill in the auth_req data */
- req.code = PW_AUTHENTICATION_REQUEST;
- req.id = 0;
-
- /* bracket the username in the configured prefix/suffix */
- req.data[0] = PW_USER_NAME;
- req.data[1] = 2;
- req.data[2] = '\0';
- if (config->prefix) {
- req.data[1] += strlen(config->prefix);
- strlcat((char *) &req.data[2], config->prefix, sizeof(req.data) - 2);
- }
- req.data[1] += strlen(uname);
- strlcat((char *)&req.data[2], uname, sizeof(req.data) - 2);
- if (!strchr(uname, '@') && config->suffix) {
- req.data[1] += strlen(config->suffix);
- strlcat((char *)&req.data[2], config->suffix, sizeof(req.data) - 2);
- }
- req.datalen = req.data[1];
-
- /* set the password */
- passstart = req.datalen;
- req.data[req.datalen] = PW_PASSWORD;
- /* Null pad the password */
- passlen = (strlen(pass) + 15) / 16;
- passlen *= 16;
- req.data[req.datalen+1] = passlen+2;
- strlcpy((char *)&req.data[req.datalen+2], pass,
- sizeof(req.data) - req.datalen - 2);
- passlen -= strlen(pass);
- while (passlen--)
- req.data[req.datalen+passlen+2+strlen(pass)] = '\0';
- req.datalen += req.data[req.datalen+1];
-
- /* Add NAS_PORT and NAS_IP_ADDRESS into request */
- if ((nvalue = config->locport) == 0)
- nvalue = RADIUS_LOCAL_PORT;
- req.data[req.datalen++] = RAD_NAS_PORT;
- req.data[req.datalen++] = sizeof(nvalue) + 2;
- nvalue = htonl(nvalue);
- memcpy(req.data + req.datalen, &nvalue, sizeof(nvalue));
- req.datalen += sizeof(nvalue);
- req.data[req.datalen++] = RAD_NAS_IP_ADDRESS;
- req.data[req.datalen++] = sizeof(struct in_addr) + 2;
- memcpy(req.data + req.datalen, &sinl.sin_addr.s_addr,
- sizeof(struct in_addr));
- req.datalen += sizeof(struct in_addr);
-
- /* we're only doing authentication */
- req.data[req.datalen] = PW_SERVICE_TYPE;
- req.data[req.datalen+1] = 6;
- req.data[req.datalen+2] = (PW_SERVICE_AUTH_ONLY >> 24) & 0x000000ff;
- req.data[req.datalen+3] = (PW_SERVICE_AUTH_ONLY >> 16) & 0x000000ff;
- req.data[req.datalen+4] = (PW_SERVICE_AUTH_ONLY >> 8) & 0x000000ff;
- req.data[req.datalen+5] = PW_SERVICE_AUTH_ONLY & 0x000000ff;
- req.datalen += req.data[req.datalen+1];
-
- /* filled in the data, now we know what the actual length is. */
- req.length = 4+AUTH_VECTOR_LEN+req.datalen;
-
- /* "encrypt" the password */
- for (i = 0; i < req.data[passstart+1]-2; i += sizeof(HASH)) {
- jlen = sizeof(HASH);
- if (req.data[passstart+1]-(unsigned)i-2 < sizeof(HASH))
- jlen = req.data[passstart+1]-i-2;
- for (j = 0; j < jlen; j++)
- req.data[passstart+2+i+j] ^= digest[j];
- if (jlen == sizeof(HASH)) {
- /* Recalculate the digest from the HASHed previous */
- strlcpy((char *) secbuf, config->secret, sizeof(secbuf));
- memcpy(secbuf+strlen(config->secret), &req.data[passstart+2+i],
- sizeof(HASH));
- md5_hash(secbuf, strlen(config->secret)+sizeof(HASH), digest);
- }
- }
- sreq->reqlen = req.length;
- req.length = htons(req.length);
-
- req_copyfrom(sreq, req);
-
- /* Go to the next record in the list */
- config = config->next;
- }
-
- /* YAYY! The auth_req is ready to go! Build the reply socket and send out
- * the message. */
-
- /* now, build the sockets */
- if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- syswarn("cannot build reply socket");
- return(-1);
- }
- if (bind(sock, (struct sockaddr*) &sinl, sizeof(sinl)) < 0) {
- syswarn("cannot bind reply socket");
- close(sock);
- return(-1);
- }
-
- for(done = 0; authtries > 0 && !done; authtries--) {
- for (config = radconfig, sreq = reqtop; sreq != NULL && !done;
- config = config->next, sreq = sreq->next){
- req_copyto(req, sreq);
-
- /* send out the packet and wait for reply. */
- if (sendto(sock, (char *)&req, sreq->reqlen, 0,
- (struct sockaddr*) &sreq->sinr,
- sizeof (struct sockaddr_in)) < 0) {
- syswarn("cannot send auth_reg");
- close(sock);
- return(-1);
- }
-
- /* wait 5 seconds maximum for a radius reply. */
- now = time(0);
- end = now+5;
- tmout.tv_sec = 6;
- tmout.tv_usec = 0;
- FD_ZERO(&rdfds);
- /* store the old vector to verify next checksum */
- memcpy(secbuf+sizeof(req.vector), req.vector, sizeof(req.vector));
- FD_SET(sock, &rdfds);
- got = select(sock+1, &rdfds, 0, 0, &tmout);
- if (got < 0) {
- syswarn("cannot not select");
- break;
- } else if (got == 0) {
- /* timer ran out */
- now = time(0);
- tmout.tv_sec = end - now + 1;
- tmout.tv_usec = 0;
- continue;
- }
- slen = sizeof(sinl);
- if ((jlen = recvfrom(sock, (char *)&req, sizeof(req)-sizeof(int), 0,
- (struct sockaddr*) &sinl, &slen)) < 0) {
- syswarn("cannot recvfrom");
- break;
- }
- if (!config->ignore_source) {
- if (sinl.sin_addr.s_addr != sreq->sinr.sin_addr.s_addr ||
- (sinl.sin_port != sreq->sinr.sin_port)) {
- warn("received unexpected UDP packet from %s:%d",
- inet_ntoa(sinl.sin_addr), ntohs(sinl.sin_port));
- continue;
- }
- }
- sreq->reqlen = ntohs(req.length);
- if (jlen < 4+AUTH_VECTOR_LEN || jlen != sreq->reqlen) {
- warn("received badly-sized packet");
- continue;
- }
- /* verify the checksum */
- memcpy(((char*)&req)+sreq->reqlen, config->secret, strlen(config->secret));
- memcpy(secbuf, req.vector, sizeof(req.vector));
- memcpy(req.vector, secbuf+sizeof(req.vector), sizeof(req.vector));
- md5_hash((unsigned char *)&req, strlen(config->secret)+sreq->reqlen,
- digest);
- if (memcmp(digest, secbuf, sizeof(HASH)) != 0) {
- warn("checksum didn't match");
- continue;
- }
- /* FINALLY! Got back a known-good packet. See if we're in. */
- close(sock);
- return (req.code == PW_AUTHENTICATION_ACK) ? 0 : -1;
- done = 1;
- req_copyfrom(sreq, req);
- break;
- }
- }
- if (authtries == 0)
- warn("cannot talk to remote radius server %s:%d",
- inet_ntoa(sreq->sinr.sin_addr), ntohs(sreq->sinr.sin_port));
- return(-2);
-}
-
-#define RAD_HAVE_HOST 1
-#define RAD_HAVE_PORT 2
-#define RAD_HAVE_PREFIX 4
-#define RAD_HAVE_SUFFIX 8
-#define RAD_HAVE_LOCHOST 16
-#define RAD_HAVE_LOCPORT 32
-
-int main(int argc, char *argv[])
-{
- int opt;
- int havefile, haveother;
- struct auth_info *authinfo;
- rad_config_t radconfig;
- int retval;
- char *radius_config;
-
- message_program_name = "radius";
-
- if (!innconf_read(NULL))
- exit(1);
-
- memset(&radconfig, '\0', sizeof(rad_config_t));
- haveother = havefile = 0;
-
- while ((opt = getopt(argc, argv, "f:h")) != -1) {
- switch (opt) {
- case 'f':
- if (haveother)
- die("-f flag after another flag");
- if (!havefile) {
- /* override the standard config completely if the user
- * specifies an alternate config file */
- memset(&radconfig, '\0', sizeof(rad_config_t));
- havefile = 1;
- }
- read_config(optarg, &radconfig);
- break;
- case 'h':
- printf("Usage: radius [-f config]\n");
- exit(0);
- }
- }
- if (argc != optind)
- exit(2);
- if (!havefile) {
- radius_config = concatpath(innconf->pathetc, _PATH_RADIUS_CONFIG);
- read_config(radius_config, &radconfig);
-
- free(radius_config);
- }
-
- authinfo = get_auth_info(stdin);
- if (authinfo == NULL)
- die("failed getting auth info");
- if (authinfo->username[0] == '\0')
- die("empty username");
-
- /* got username and password, check that they're valid */
-
- retval = rad_auth(&radconfig, authinfo->username, authinfo->password);
- if (retval == -1)
- die("user %s password doesn't match", authinfo->username);
- else if (retval == -2)
- /* couldn't talk to the radius server.. output logged above. */
- exit(1);
- else if (retval != 0)
- die("unexpected return code from authentication function: %d",
- retval);
-
- /* radius password matches! */
- printf("User:%s\n", authinfo->username);
- exit(0);
-}
+++ /dev/null
-## $Id: Makefile 5789 2002-09-29 23:34:26Z rra $
-
-include ../../Makefile.global
-
-top = ../..
-CFLAGS = $(GCFLAGS)
-
-ALL = smbvalid.a
-
-SOURCES = rfcnb-io.c rfcnb-util.c session.c smbdes.c \
- smbencrypt.c smblib-util.c smblib.c valid.c
-
-OBJECTS = $(SOURCES:.c=.o)
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-smbvalid.a: $(OBJECTS)
- ar rc $@ $(OBJECTS)
- $(RANLIB) $@
-
-clobber clean distclean:
- rm -f *.o smbvalid.a
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-rfcnb-io.o: rfcnb-io.c ../../include/config.h \
- ../../include/inn/defines.h ../../include/clibrary.h rfcnb-priv.h \
- rfcnb-error.h rfcnb-common.h byteorder.h rfcnb-util.h rfcnb-io.h
-rfcnb-util.o: rfcnb-util.c ../../include/config.h \
- ../../include/inn/defines.h ../../include/clibrary.h rfcnb-priv.h \
- rfcnb-error.h rfcnb-common.h byteorder.h rfcnb-util.h rfcnb-io.h
-session.o: session.c ../../include/config.h \
- ../../include/inn/defines.h ../../include/clibrary.h rfcnb-priv.h \
- rfcnb-error.h rfcnb-common.h byteorder.h rfcnb-util.h
-smbdes.o: smbdes.c
-smbencrypt.o: smbencrypt.c ../../include/config.h \
- ../../include/inn/defines.h ../../include/clibrary.h smblib-priv.h \
- smblib-common.h byteorder.h
-smblib-util.o: smblib-util.c ../../include/config.h \
- ../../include/inn/defines.h ../../include/clibrary.h smblib-priv.h \
- smblib-common.h byteorder.h rfcnb.h rfcnb-error.h rfcnb-common.h
-smblib.o: smblib.c ../../include/config.h ../../include/inn/defines.h \
- ../../include/clibrary.h smblib-priv.h smblib-common.h byteorder.h \
- rfcnb.h rfcnb-error.h rfcnb-common.h
-valid.o: valid.c ../../include/config.h ../../include/inn/defines.h \
- smblib-priv.h smblib-common.h byteorder.h valid.h
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- SMB Byte handling
- Copyright (C) Andrew Tridgell 1992-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- This file implements macros for machine independent short and
- int manipulation
-*/
-
-#undef CAREFUL_ALIGNMENT
-
-/* we know that the 386 can handle misalignment and has the "right"
- byteorder */
-#ifdef __i386__
-#define CAREFUL_ALIGNMENT 0
-#endif
-
-#ifndef CAREFUL_ALIGNMENT
-#define CAREFUL_ALIGNMENT 1
-#endif
-
-#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
-#define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
-#define SCVAL(buf,pos,val) (CVAL(buf,pos) = (val))
-
-
-#if CAREFUL_ALIGNMENT
-#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
-#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
-#define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8)
-#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
-#define SVALS(buf,pos) ((int16)SVAL(buf,pos))
-#define IVALS(buf,pos) ((int32)IVAL(buf,pos))
-#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16)(val)))
-#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32)(val)))
-#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16)(val)))
-#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32)(val)))
-#else
-/* this handles things for architectures like the 386 that can handle
- alignment errors */
-/*
- WARNING: This section is dependent on the length of int16 and int32
- being correct
-*/
-#define SVAL(buf,pos) (*(uint16 *)((char *)(buf) + (pos)))
-#define IVAL(buf,pos) (*(uint32 *)((char *)(buf) + (pos)))
-#define SVALS(buf,pos) (*(int16 *)((char *)(buf) + (pos)))
-#define IVALS(buf,pos) (*(int32 *)((char *)(buf) + (pos)))
-#define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16)(val))
-#define SIVAL(buf,pos,val) IVAL(buf,pos)=((uint32)(val))
-#define SSVALS(buf,pos,val) SVALS(buf,pos)=((int16)(val))
-#define SIVALS(buf,pos,val) IVALS(buf,pos)=((int32)(val))
-#endif
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Common Structures etc Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* A data structure we need */
-
-typedef struct RFCNB_Pkt {
-
- char * data; /* The data in this portion */
- int len;
- struct RFCNB_Pkt *next;
-
-} RFCNB_Pkt;
-
-void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt);
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Error Response Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Error responses */
-
-#define RFCNBE_Bad -1 /* Bad response */
-#define RFCNBE_OK 0
-
-/* these should follow the spec ... is there one ?*/
-
-#define RFCNBE_NoSpace 1 /* Could not allocate space for a struct */
-#define RFCNBE_BadName 2 /* Could not translate a name */
-#define RFCNBE_BadRead 3 /* Read sys call failed */
-#define RFCNBE_BadWrite 4 /* Write Sys call failed */
-#define RFCNBE_ProtErr 5 /* Protocol Error */
-#define RFCNBE_ConGone 6 /* Connection dropped */
-#define RFCNBE_BadHandle 7 /* Handle passed was bad */
-#define RFCNBE_BadSocket 8 /* Problems creating socket */
-#define RFCNBE_ConnectFailed 9 /* Connect failed */
-#define RFCNBE_CallRejNLOCN 10 /* Call rejected, not listening on CN */
-#define RFCNBE_CallRejNLFCN 11 /* Call rejected, not listening for CN */
-#define RFCNBE_CallRejCNNP 12 /* Call rejected, called name not present */
-#define RFCNBE_CallRejInfRes 13/* Call rejetced, name ok, no resources */
-#define RFCNBE_CallRejUnSpec 14/* Call rejected, unspecified error */
-#define RFCNBE_BadParam 15/* Bad parameters passed ... */
-#define RFCNBE_Timeout 16/* IO Timed out */
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NEtBIOS implementation
-
- Version 1.0
- RFCNB IO Routines ...
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/uio.h>
-
-#include "rfcnb-priv.h"
-#include "rfcnb-util.h"
-#include "rfcnb-io.h"
-
-int RFCNB_Timeout = 0; /* Timeout in seconds ... */
-
-/* Discard the rest of an incoming packet as we do not have space for it
- in the buffer we allocated or were passed ... */
-
-int RFCNB_Discard_Rest(struct RFCNB_Con *con, int len)
-
-{ char temp[100]; /* Read into here */
- int rest, this_read, bytes_read;
-
- /* len is the amount we should read */
-
- rest = len;
-
- while (rest > 0) {
-
- this_read = (rest > sizeof(temp)?sizeof(temp):rest);
-
- bytes_read = read(con -> fd, temp, this_read);
-
- if (bytes_read <= 0) { /* Error so return */
-
- if (bytes_read < 0)
- RFCNB_errno = RFCNBE_BadRead;
- else
- RFCNB_errno = RFCNBE_ConGone;
-
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- rest = rest - bytes_read;
-
- }
-
- return(0);
-
-}
-
-
-/* Send an RFCNB packet to the connection.
-
- We just send each of the blocks linked together ...
-
- If we can, try to send it as one iovec ...
-
-*/
-
-int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
-
-{ int len_sent, tot_sent, this_len;
- struct RFCNB_Pkt *pkt_ptr;
- char *this_data;
- int i;
- struct iovec io_list[10]; /* We should never have more */
- /* If we do, this will blow up ...*/
-
- /* Try to send the data ... We only send as many bytes as len claims */
- /* We should try to stuff it into an IOVEC and send as one write */
-
-
- pkt_ptr = pkt;
- len_sent = tot_sent = 0; /* Nothing sent so far */
- i = 0;
-
- while ((pkt_ptr != NULL) & (i < 10)) { /* Watch that magic number! */
-
- this_len = pkt_ptr -> len;
- this_data = pkt_ptr -> data;
- if ((tot_sent + this_len) > len)
- this_len = len - tot_sent; /* Adjust so we don't send too much */
-
- /* Now plug into the iovec ... */
-
- io_list[i].iov_len = this_len;
- io_list[i].iov_base = this_data;
- i++;
-
- tot_sent += this_len;
-
- if (tot_sent == len) break; /* Let's not send too much */
-
- pkt_ptr = pkt_ptr -> next;
-
- }
-
- /* Set up an alarm if timeouts are set ... */
-
- if (RFCNB_Timeout > 0)
- alarm(RFCNB_Timeout);
-
- if ((len_sent = writev(con -> fd, io_list, i)) < 0) { /* An error */
-
- con -> rfc_errno = errno;
- if (errno == EINTR) /* We were interrupted ... */
- RFCNB_errno = RFCNBE_Timeout;
- else
- RFCNB_errno = RFCNBE_BadWrite;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- if (len_sent < tot_sent) { /* Less than we wanted */
- if (errno == EINTR) /* We were interrupted */
- RFCNB_errno = RFCNBE_Timeout;
- else
- RFCNB_errno = RFCNBE_BadWrite;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
- }
-
- if (RFCNB_Timeout > 0)
- alarm(0); /* Reset that sucker */
-
- return(len_sent);
-
-}
-
-/* Read an RFCNB packet off the connection.
-
- We read the first 4 bytes, that tells us the length, then read the
- rest. We should implement a timeout, but we don't just yet
-
-*/
-
-
-int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len)
-
-{ int read_len, pkt_len;
- char hdr[RFCNB_Pkt_Hdr_Len]; /* Local space for the header */
- struct RFCNB_Pkt *pkt_frag;
- int more, this_time, offset, frag_len, this_len;
- bool seen_keep_alive = true;
-
- /* Read that header straight into the buffer */
-
- if (len < RFCNB_Pkt_Hdr_Len) { /* What a bozo */
-
- RFCNB_errno = RFCNBE_BadParam;
- return(RFCNBE_Bad);
-
- }
-
- /* We discard keep alives here ... */
-
- if (RFCNB_Timeout > 0)
- alarm(RFCNB_Timeout);
-
- while (seen_keep_alive) {
-
- if ((read_len = read(con -> fd, hdr, sizeof(hdr))) < 0) { /* Problems */
- if (errno == EINTR)
- RFCNB_errno = RFCNBE_Timeout;
- else
- RFCNB_errno = RFCNBE_BadRead;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- /* Now we check out what we got */
-
- if (read_len == 0) { /* Connection closed, send back eof? */
-
- if (errno == EINTR)
- RFCNB_errno = RFCNBE_Timeout;
- else
- RFCNB_errno = RFCNBE_ConGone;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- if (RFCNB_Pkt_Type(hdr) != RFCNB_SESSION_KEEP_ALIVE) {
- seen_keep_alive = false;
- }
-
- }
-
- /* What if we got less than or equal to a hdr size in bytes? */
-
- if (read_len < sizeof(hdr)) { /* We got a small packet */
-
- /* Now we need to copy the hdr portion we got into the supplied packet */
-
- memcpy(pkt -> data, hdr, read_len); /*Copy data */
-
- return(read_len);
-
- }
-
- /* Now, if we got at least a hdr size, alloc space for rest, if we need it */
-
- pkt_len = RFCNB_Pkt_Len(hdr);
-
- /* Now copy in the hdr */
-
- memcpy(pkt -> data, hdr, sizeof(hdr));
-
- /* Get the rest of the packet ... first figure out how big our buf is? */
- /* And make sure that we handle the fragments properly ... Sure should */
- /* use an iovec ... */
-
- if (len < pkt_len) /* Only get as much as we have space for */
- more = len - RFCNB_Pkt_Hdr_Len;
- else
- more = pkt_len;
-
- this_time = 0;
-
- /* We read for each fragment ... */
-
- if (pkt -> len == read_len){ /* If this frag was exact size */
- pkt_frag = pkt -> next; /* Stick next lot in next frag */
- offset = 0; /* then we start at 0 in next */
- }
- else {
- pkt_frag = pkt; /* Otherwise use rest of this frag */
- offset = RFCNB_Pkt_Hdr_Len; /* Otherwise skip the header */
- }
-
- frag_len = pkt_frag -> len;
-
- if (more <= frag_len) /* If len left to get less than frag space */
- this_len = more; /* Get the rest ... */
- else
- this_len = frag_len - offset;
-
- while (more > 0) {
-
- if ((this_time = read(con -> fd, (pkt_frag -> data) + offset, this_len)) <= 0) { /* Problems */
-
- if (errno == EINTR) {
-
- RFCNB_errno = RFCNB_Timeout;
-
- }
- else {
- if (this_time < 0)
- RFCNB_errno = RFCNBE_BadRead;
- else
- RFCNB_errno = RFCNBE_ConGone;
- }
-
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- read_len = read_len + this_time; /* How much have we read ... */
-
- /* Now set up the next part */
-
- if (pkt_frag -> next == NULL) break; /* That's it here */
-
- pkt_frag = pkt_frag -> next;
- this_len = pkt_frag -> len;
- offset = 0;
-
- more = more - this_time;
-
- }
-
- if (read_len < (pkt_len + sizeof(hdr))) { /* Discard the rest */
-
- return(RFCNB_Discard_Rest(con, (pkt_len + sizeof(hdr)) - read_len));
-
- }
-
- if (RFCNB_Timeout > 0)
- alarm(0); /* Reset that sucker */
-
- return(read_len + sizeof(RFCNB_Hdr));
-}
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB IO Routines Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-int RFCNB_Put_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
-
-int RFCNB_Get_Pkt(struct RFCNB_Con *con, struct RFCNB_Pkt *pkt, int len);
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Defines we need */
-
-typedef unsigned short uint16;
-
-#define GLOBAL extern
-
-#include <netinet/in.h>
-
-#include "rfcnb-error.h"
-#include "rfcnb-common.h"
-#include "byteorder.h"
-
-#define RFCNB_Default_Port 139
-
-#define RFCNB_MAX_STATS 1
-
-/* Protocol defines we need */
-
-#define RFCNB_SESSION_MESSAGE 0
-#define RFCNB_SESSION_REQUEST 0x81
-#define RFCNB_SESSION_ACK 0x82
-#define RFCNB_SESSION_REJ 0x83
-#define RFCNB_SESSION_RETARGET 0x84
-#define RFCNB_SESSION_KEEP_ALIVE 0x85
-
-/* Structures */
-
-typedef struct redirect_addr * redirect_ptr;
-
-struct redirect_addr {
-
- struct in_addr ip_addr;
- int port;
- redirect_ptr next;
-
-};
-
-typedef struct RFCNB_Con {
-
- int fd; /* File descripter for TCP/IP connection */
- int rfc_errno; /* last error */
- int timeout; /* How many milli-secs before IO times out */
- int redirects; /* How many times we were redirected */
- struct redirect_addr *redirect_list; /* First is first address */
- struct redirect_addr *last_addr;
-
-} RFCNB_Con;
-
-typedef char RFCNB_Hdr[4]; /* The header is 4 bytes long with */
- /* char[0] as the type, char[1] the */
- /* flags, and char[2..3] the length */
-
-/* Macros to extract things from the header. These are for portability
- between architecture types where we are worried about byte order */
-
-#define RFCNB_Pkt_Hdr_Len 4
-#define RFCNB_Pkt_Sess_Len 72
-#define RFCNB_Pkt_Retarg_Len 10
-#define RFCNB_Pkt_Nack_Len 5
-#define RFCNB_Pkt_Type_Offset 0
-#define RFCNB_Pkt_Flags_Offset 1
-#define RFCNB_Pkt_Len_Offset 2 /* Length is 2 bytes plus a flag bit */
-#define RFCNB_Pkt_N1Len_Offset 4
-#define RFCNB_Pkt_Called_Offset 5
-#define RFCNB_Pkt_N2Len_Offset 38
-#define RFCNB_Pkt_Calling_Offset 39
-#define RFCNB_Pkt_Error_Offset 4
-#define RFCNB_Pkt_IP_Offset 4
-#define RFCNB_Pkt_Port_Offset 8
-
-/* The next macro isolates the length of a packet, including the bit in the
- flags */
-
-#define RFCNB_Pkt_Len(p) (PVAL(p, 3) | (PVAL(p, 2) << 8) | \
- ((PVAL(p, RFCNB_Pkt_Flags_Offset) & 0x01) << 16))
-
-#define RFCNB_Put_Pkt_Len(p, v) ((p)[1] = (((v) >> 16) & 1)); \
- ((p)[2] = (((v) >> 8) & 0xFF)); \
- ((p)[3] = ((v) & 0xFF));
-
-#define RFCNB_Pkt_Type(p) (CVAL(p, RFCNB_Pkt_Type_Offset))
-
-/* Static variables */
-
-/* Only declare this if not defined */
-
-#ifndef RFCNB_ERRNO
-extern int RFCNB_errno;
-extern int RFCNB_saved_errno; /* Save this from point of error */
-#endif
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Utility Routines ...
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <errno.h>
-#include <netdb.h>
-
-#include "rfcnb-priv.h"
-#include "rfcnb-util.h"
-#include "rfcnb-io.h"
-
-#ifndef INADDR_NONE
-# define INADDR_NONE -1
-#endif
-
-extern void (*Prot_Print_Routine)(); /* Pointer to protocol print routine */
-
-/* Convert name and pad to 16 chars as needed */
-/* Name 1 is a C string with null termination, name 2 may not be */
-/* If SysName is true, then put a <00> on end, else space> */
-
-void RFCNB_CvtPad_Name(char *name1, char *name2)
-
-{ char c, c1, c2;
- int i, len;
-
- len = strlen(name1);
-
- for (i = 0; i < 16; i++) {
-
- if (i >= len) {
-
- c1 = 'C'; c2 = 'A'; /* CA is a space */
-
- } else {
-
- c = name1[i];
- c1 = (char)((int)c/16 + (int)'A');
- c2 = (char)((int)c%16 + (int)'A');
- }
-
- name2[i*2] = c1;
- name2[i*2+1] = c2;
-
- }
-
- name2[32] = 0; /* Put in the nll ...*/
-
-}
-
-/* Get a packet of size n */
-
-struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n)
-
-{ RFCNB_Pkt *pkt;
-
- if ((pkt = (struct RFCNB_Pkt *)malloc(sizeof(struct RFCNB_Pkt))) == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(NULL);
-
- }
-
- pkt -> next = NULL;
- pkt -> len = n;
-
- if (n == 0) return(pkt);
-
- if ((pkt -> data = (char *)malloc(n)) == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- free(pkt);
- return(NULL);
-
- }
-
- return(pkt);
-
-}
-
-/* Free up a packet */
-
-void RFCNB_Free_Pkt(struct RFCNB_Pkt *pkt)
-
-{ struct RFCNB_Pkt *pkt_next; char *data_ptr;
-
- while (pkt != NULL) {
-
- pkt_next = pkt -> next;
-
- data_ptr = pkt -> data;
-
- if (data_ptr != NULL)
- free(data_ptr);
-
- free(pkt);
-
- pkt = pkt_next;
-
- }
-
-}
-
-/* Resolve a name into an address */
-
-int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP)
-
-{ int addr; /* Assumes IP4, 32 bit network addresses */
- struct hostent *hp;
-
- /* Use inet_addr to try to convert the address */
-
- if ((addr = inet_addr(host)) == INADDR_NONE) { /* Oh well, a good try :-) */
-
- /* Now try a name look up with gethostbyname */
-
- if ((hp = gethostbyname(host)) == NULL) { /* Not in DNS */
-
- /* Try NetBIOS name lookup, how the hell do we do that? */
-
- RFCNB_errno = RFCNBE_BadName; /* Is this right? */
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
- else { /* We got a name */
-
- memcpy((void *)Dest_IP, (void *)hp -> h_addr_list[0], sizeof(struct in_addr));
-
- }
- }
- else { /* It was an IP address */
-
- memcpy((void *)Dest_IP, (void *)&addr, sizeof(struct in_addr));
-
- }
-
- return 0;
-
-}
-
-/* Disconnect the TCP connection to the server */
-
-int RFCNB_Close(int socket)
-
-{
-
- close(socket);
-
- /* If we want to do error recovery, here is where we put it */
-
- return 0;
-
-}
-
-/* Connect to the server specified in the IP address.
- Not sure how to handle socket options etc. */
-
-int RFCNB_IP_Connect(struct in_addr Dest_IP, int port)
-
-{ struct sockaddr_in Socket;
- int fd;
-
- /* Create a socket */
-
- if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Handle the error */
-
- RFCNB_errno = RFCNBE_BadSocket;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
- }
-
- memset(&Socket, 0, sizeof(Socket));
- memcpy((char *)&Socket.sin_addr, (char *)&Dest_IP, sizeof(Dest_IP));
-
- Socket.sin_port = htons(port);
- Socket.sin_family = PF_INET;
-
- /* Now connect to the destination */
-
- if (connect(fd, (struct sockaddr *)&Socket, sizeof(Socket)) < 0) { /* Error */
-
- close(fd);
- RFCNB_errno = RFCNBE_ConnectFailed;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
- }
-
- return(fd);
-
-}
-
-/* handle the details of establishing the RFCNB session with remote
- end
-
-*/
-
-int RFCNB_Session_Req(struct RFCNB_Con *con,
- char *Called_Name,
- char *Calling_Name,
- bool *redirect,
- struct in_addr *Dest_IP,
- int * port)
-
-{ char *sess_pkt;
-
- /* Response packet should be no more than 9 bytes, make 16 jic */
-
- char resp[16];
- int len;
- struct RFCNB_Pkt *pkt, res_pkt;
-
- /* We build and send the session request, then read the response */
-
- pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Sess_Len);
-
- if (pkt == NULL) {
-
- return(RFCNBE_Bad); /* Leave the error that RFCNB_Alloc_Pkt gives) */
-
- }
-
- sess_pkt = pkt -> data; /* Get pointer to packet proper */
-
- sess_pkt[RFCNB_Pkt_Type_Offset] = RFCNB_SESSION_REQUEST;
- RFCNB_Put_Pkt_Len(sess_pkt, RFCNB_Pkt_Sess_Len-RFCNB_Pkt_Hdr_Len);
- sess_pkt[RFCNB_Pkt_N1Len_Offset] = 32;
- sess_pkt[RFCNB_Pkt_N2Len_Offset] = 32;
-
- RFCNB_CvtPad_Name(Called_Name, (sess_pkt + RFCNB_Pkt_Called_Offset));
- RFCNB_CvtPad_Name(Calling_Name, (sess_pkt + RFCNB_Pkt_Calling_Offset));
-
- /* Now send the packet */
-
- if ((len = RFCNB_Put_Pkt(con, pkt, RFCNB_Pkt_Sess_Len)) < 0) {
-
- return(RFCNBE_Bad); /* Should be able to write that lot ... */
-
- }
-
- res_pkt.data = resp;
- res_pkt.len = sizeof(resp);
- res_pkt.next = NULL;
-
- if ((len = RFCNB_Get_Pkt(con, &res_pkt, sizeof(resp))) < 0) {
-
- return(RFCNBE_Bad);
-
- }
-
- /* Now analyze the packet ... */
-
- switch (RFCNB_Pkt_Type(resp)) {
-
- case RFCNB_SESSION_REJ: /* Didnt like us ... too bad */
-
- /* Why did we get rejected ? */
-
- switch (CVAL(resp,RFCNB_Pkt_Error_Offset)) {
-
- case 0x80:
- RFCNB_errno = RFCNBE_CallRejNLOCN;
- break;
- case 0x81:
- RFCNB_errno = RFCNBE_CallRejNLFCN;
- break;
- case 0x82:
- RFCNB_errno = RFCNBE_CallRejCNNP;
- break;
- case 0x83:
- RFCNB_errno = RFCNBE_CallRejInfRes;
- break;
- case 0x8F:
- RFCNB_errno = RFCNBE_CallRejUnSpec;
- break;
- default:
- RFCNB_errno = RFCNBE_ProtErr;
- break;
- }
-
- return(RFCNBE_Bad);
- break;
-
- case RFCNB_SESSION_ACK: /* Got what we wanted ... */
-
- return(0);
- break;
-
- case RFCNB_SESSION_RETARGET: /* Go elsewhere */
-
- *redirect = true; /* Copy port and ip addr */
-
- memcpy(Dest_IP, (resp + RFCNB_Pkt_IP_Offset), sizeof(struct in_addr));
- *port = SVAL(resp, RFCNB_Pkt_Port_Offset);
-
- return(0);
- break;
-
- default: /* A protocol error */
-
- RFCNB_errno = RFCNBE_ProtErr;
- return(RFCNBE_Bad);
- break;
- }
-}
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Utility Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-void RFCNB_CvtPad_Name(char *name1, char *name2);
-
-struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
-
-int RFCNB_Name_To_IP(char *host, struct in_addr *Dest_IP);
-
-int RFCNB_Close(int socket);
-
-int RFCNB_IP_Connect(struct in_addr Dest_IP, int port);
-
-int RFCNB_Session_Req(struct RFCNB_Con *con,
- char *Called_Name,
- char *Calling_Name,
- bool *redirect,
- struct in_addr *Dest_IP,
- int * port);
-
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- RFCNB Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Error responses */
-
-#include "rfcnb-error.h"
-#include "rfcnb-common.h"
-
-/* Defines we need */
-
-#define RFCNB_Default_Port 139
-
-/* Definition of routines we define */
-
-void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
- int port);
-
-int RFCNB_Send(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
-
-int RFCNB_Recv(void *Con_Handle, struct RFCNB_Pkt *Data, int Length);
-
-int RFCNB_Hangup(void *con_Handle);
-
-void *RFCNB_Listen();
-
-struct RFCNB_Pkt *RFCNB_Alloc_Pkt(int n);
+++ /dev/null
-/* UNIX RFCNB (RFC1001/RFC1002) NetBIOS implementation
-
- Version 1.0
- Session Routines ...
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-
-int RFCNB_errno = 0;
-int RFCNB_saved_errno = 0;
-#define RFCNB_ERRNO
-
-#include "rfcnb-priv.h"
-#include "rfcnb-io.h"
-#include "rfcnb-util.h"
-
-int RFCNB_Stats[RFCNB_MAX_STATS];
-
-void (*Prot_Print_Routine)() = NULL; /* Pointer to print routine */
-
-/* Set up a session with a remote name. We are passed Called_Name as a
- string which we convert to a NetBIOS name, ie space terminated, up to
- 16 characters only if we need to. If Called_Address is not empty, then
- we use it to connect to the remote end, but put in Called_Name ... Called
- Address can be a DNS based name, or a TCP/IP address ...
-*/
-
-void *RFCNB_Call(char *Called_Name, char *Calling_Name, char *Called_Address,
- int port)
-
-{ struct RFCNB_Con *con;
- struct in_addr Dest_IP;
- int Client;
- bool redirect; struct redirect_addr *redir_addr;
- char *Service_Address;
-
- /* Now, we really should look up the port in /etc/services ... */
-
- if (port == 0) port = RFCNB_Default_Port;
-
- /* Create a connection structure first */
-
- if ((con = (struct RFCNB_Con *)malloc(sizeof(struct RFCNB_Con))) == NULL) { /* Error in size */
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(NULL);
-
- }
-
- con -> fd = -0; /* no descriptor yet */
- con -> rfc_errno = 0; /* no error yet */
- con -> timeout = 0; /* no timeout */
- con -> redirects = 0;
- con -> redirect_list = NULL; /* Fix bug still in version 0.50 */
-
- /* Resolve that name into an IP address */
-
- Service_Address = Called_Name;
- if (strcmp(Called_Address, "") != 0) { /* If the Called Address = "" */
- Service_Address = Called_Address;
- }
-
- if ((errno = RFCNB_Name_To_IP(Service_Address, &Dest_IP)) < 0) { /* Error */
-
- /* No need to modify RFCNB_errno as it was done by RFCNB_Name_To_IP */
-
- return(NULL);
-
- }
-
- /* Now connect to the remote end */
-
- redirect = true; /* Fudge this one so we go once through */
-
- while (redirect) { /* Connect and get session info etc */
-
- redirect = false; /* Assume all OK */
-
- /* Build the redirect info. First one is first addr called */
- /* And tack it onto the list of addresses we called */
-
- if ((redir_addr = (struct redirect_addr *)malloc(sizeof(struct redirect_addr))) == NULL) { /* Could not get space */
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(NULL);
-
- }
-
- memcpy((char *)&(redir_addr -> ip_addr), (char *)&Dest_IP, sizeof(Dest_IP));
- redir_addr -> port = port;
- redir_addr -> next = NULL;
-
- if (con -> redirect_list == NULL) { /* Stick on head */
-
- con -> redirect_list = con -> last_addr = redir_addr;
-
- } else {
-
- con -> last_addr -> next = redir_addr;
- con -> last_addr = redir_addr;
-
- }
-
- /* Now, make that connection */
-
- if ((Client = RFCNB_IP_Connect(Dest_IP, port)) < 0) { /* Error */
-
- /* No need to modify RFCNB_errno as it was done by RFCNB_IP_Connect */
-
- return(NULL);
-
- }
-
- con -> fd = Client;
-
- /* Now send and handle the RFCNB session request */
- /* If we get a redirect, we will comeback with redirect true
- and a new IP address in DEST_IP */
-
- if ((errno = RFCNB_Session_Req(con,
- Called_Name,
- Calling_Name,
- &redirect, &Dest_IP, &port)) < 0) {
-
- /* No need to modify RFCNB_errno as it was done by RFCNB_Session.. */
-
- return(NULL);
-
- }
-
- if (redirect) {
-
- /* We have to close the connection, and then try again */
-
- (con -> redirects)++;
-
- RFCNB_Close(con -> fd); /* Close it */
-
- }
- }
-
- return(con);
-
-}
-
-/* We send a packet to the other end ... for the moment, we treat the
- data as a series of pointers to blocks of data ... we should check the
- length ... */
-
-int RFCNB_Send(struct RFCNB_Con *Con_Handle, struct RFCNB_Pkt *udata, int Length)
-
-{ struct RFCNB_Pkt *pkt; char *hdr;
- int len;
-
- /* Plug in the header and send the data */
-
- pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
-
- if (pkt == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- pkt -> next = udata; /* The user data we want to send */
-
- hdr = pkt -> data;
-
- /* Following crap is for portability across multiple UNIX machines */
-
- *(hdr + RFCNB_Pkt_Type_Offset) = RFCNB_SESSION_MESSAGE;
- RFCNB_Put_Pkt_Len(hdr, Length);
-
-#ifdef RFCNB_DEBUG
-
- fprintf(stderr, "Sending packet: ");
-
-#endif
-
- if ((len = RFCNB_Put_Pkt(Con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
-
- /* No need to change RFCNB_errno as it was done by put_pkt ... */
-
- return(RFCNBE_Bad); /* Should be able to write that lot ... */
-
- }
-
- /* Now we have sent that lot, let's get rid of the RFCNB Header and return */
-
- pkt -> next = NULL;
-
- RFCNB_Free_Pkt(pkt);
-
- return(len);
-
-}
-
-/* We pick up a message from the internet ... We have to worry about
- non-message packets ... */
-
-int RFCNB_Recv(void *con_Handle, struct RFCNB_Pkt *Data, int Length)
-
-{ struct RFCNB_Pkt *pkt;
- int ret_len;
-
- if (con_Handle == NULL){
-
- RFCNB_errno = RFCNBE_BadHandle;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- /* Now get a packet from below. We allocate a header first */
-
- /* Plug in the header and send the data */
-
- pkt = RFCNB_Alloc_Pkt(RFCNB_Pkt_Hdr_Len);
-
- if (pkt == NULL) {
-
- RFCNB_errno = RFCNBE_NoSpace;
- RFCNB_saved_errno = errno;
- return(RFCNBE_Bad);
-
- }
-
- pkt -> next = Data; /* Plug in the data portion */
-
- if ((ret_len = RFCNB_Get_Pkt(con_Handle, pkt, Length + RFCNB_Pkt_Hdr_Len)) < 0) {
-
-#ifdef RFCNB_DEBUG
- fprintf(stderr, "Bad packet return in RFCNB_Recv... \n");
-#endif
-
- return(RFCNBE_Bad);
-
- }
-
- /* We should check that we go a message and not a keep alive */
-
- pkt -> next = NULL;
-
- RFCNB_Free_Pkt(pkt);
-
- return(ret_len);
-
-}
-
-/* We just disconnect from the other end, as there is nothing in the RFCNB */
-/* protocol that specifies any exchange as far as I can see */
-
-int RFCNB_Hangup(struct RFCNB_Con *con_Handle)
-
-{
-
- if (con_Handle != NULL) {
- RFCNB_Close(con_Handle -> fd); /* Could this fail? */
- free(con_Handle);
- }
-
- return 0;
-
-
-}
-
-/* Set TCP_NODELAY on the socket */
-
-int RFCNB_Set_Sock_NoDelay(struct RFCNB_Con *con_Handle, bool yn)
-
-{
-
- return(setsockopt(con_Handle -> fd, IPPROTO_TCP, TCP_NODELAY,
- (char *)&yn, sizeof(yn)));
-
-}
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
-
- a partial implementation of DES designed for use in the
- SMB authentication protocol
-
- Copyright (C) Andrew Tridgell 1997
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-
-/* NOTES:
-
- This code makes no attempt to be fast! In fact, it is a very
- slow implementation
-
- This code is NOT a complete DES implementation. It implements only
- the minimum necessary for SMB authentication, as used by all SMB
- products (including every copy of Microsoft Windows95 ever sold)
-
- In particular, it can only do a unchained forward DES pass. This
- means it is not possible to use this code for encryption/decryption
- of data, instead it is only useful as a "hash" algorithm.
-
- There is no entry point into this code that allows normal DES operation.
-
- I believe this means that this code does not come under ITAR
- regulations but this is NOT a legal opinion. If you are concerned
- about the applicability of ITAR regulations to this code then you
- should confirm it for yourself (and maybe let me know if you come
- up with a different answer to the one above)
-*/
-
-
-
-static int perm1[56] = {57, 49, 41, 33, 25, 17, 9,
- 1, 58, 50, 42, 34, 26, 18,
- 10, 2, 59, 51, 43, 35, 27,
- 19, 11, 3, 60, 52, 44, 36,
- 63, 55, 47, 39, 31, 23, 15,
- 7, 62, 54, 46, 38, 30, 22,
- 14, 6, 61, 53, 45, 37, 29,
- 21, 13, 5, 28, 20, 12, 4};
-
-static int perm2[48] = {14, 17, 11, 24, 1, 5,
- 3, 28, 15, 6, 21, 10,
- 23, 19, 12, 4, 26, 8,
- 16, 7, 27, 20, 13, 2,
- 41, 52, 31, 37, 47, 55,
- 30, 40, 51, 45, 33, 48,
- 44, 49, 39, 56, 34, 53,
- 46, 42, 50, 36, 29, 32};
-
-static int perm3[64] = {58, 50, 42, 34, 26, 18, 10, 2,
- 60, 52, 44, 36, 28, 20, 12, 4,
- 62, 54, 46, 38, 30, 22, 14, 6,
- 64, 56, 48, 40, 32, 24, 16, 8,
- 57, 49, 41, 33, 25, 17, 9, 1,
- 59, 51, 43, 35, 27, 19, 11, 3,
- 61, 53, 45, 37, 29, 21, 13, 5,
- 63, 55, 47, 39, 31, 23, 15, 7};
-
-static int perm4[48] = { 32, 1, 2, 3, 4, 5,
- 4, 5, 6, 7, 8, 9,
- 8, 9, 10, 11, 12, 13,
- 12, 13, 14, 15, 16, 17,
- 16, 17, 18, 19, 20, 21,
- 20, 21, 22, 23, 24, 25,
- 24, 25, 26, 27, 28, 29,
- 28, 29, 30, 31, 32, 1};
-
-static int perm5[32] = { 16, 7, 20, 21,
- 29, 12, 28, 17,
- 1, 15, 23, 26,
- 5, 18, 31, 10,
- 2, 8, 24, 14,
- 32, 27, 3, 9,
- 19, 13, 30, 6,
- 22, 11, 4, 25};
-
-
-static int perm6[64] ={ 40, 8, 48, 16, 56, 24, 64, 32,
- 39, 7, 47, 15, 55, 23, 63, 31,
- 38, 6, 46, 14, 54, 22, 62, 30,
- 37, 5, 45, 13, 53, 21, 61, 29,
- 36, 4, 44, 12, 52, 20, 60, 28,
- 35, 3, 43, 11, 51, 19, 59, 27,
- 34, 2, 42, 10, 50, 18, 58, 26,
- 33, 1, 41, 9, 49, 17, 57, 25};
-
-
-static int sc[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
-
-static int sbox[8][4][16] = {
- {{14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
- {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
- {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
- {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}},
-
- {{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
- {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
- {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
- {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}},
-
- {{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
- {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
- {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
- {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}},
-
- {{7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
- {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
- {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
- {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}},
-
- {{2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
- {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
- {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
- {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}},
-
- {{12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
- {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
- {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
- {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}},
-
- {{4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
- {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
- {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
- {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}},
-
- {{13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
- {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
- {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
- {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}}};
-
-static void permute(char *out, char *in, int *p, int n)
-{
- int i;
- for (i=0;i<n;i++)
- out[i] = in[p[i]-1];
-}
-
-static void lshift(char *d, int count, int n)
-{
- char out[64];
- int i;
- for (i=0;i<n;i++)
- out[i] = d[(i+count)%n];
- for (i=0;i<n;i++)
- d[i] = out[i];
-}
-
-static void concat(char *out, char *in1, char *in2, int l1, int l2)
-{
- while (l1--)
- *out++ = *in1++;
- while (l2--)
- *out++ = *in2++;
-}
-
-static void xor(char *out, char *in1, char *in2, int n)
-{
- int i;
- for (i=0;i<n;i++)
- out[i] = in1[i] ^ in2[i];
-}
-
-static void dohash(char *out, char *in, char *key)
-{
- int i, j, k;
- char pk1[56];
- char c[28];
- char d[28];
- char cd[56];
- char ki[16][48];
- char pd1[64];
- char l[32], r[32];
- char rl[64];
-
- permute(pk1, key, perm1, 56);
-
- for (i=0;i<28;i++)
- c[i] = pk1[i];
- for (i=0;i<28;i++)
- d[i] = pk1[i+28];
-
- for (i=0;i<16;i++) {
- lshift(c, sc[i], 28);
- lshift(d, sc[i], 28);
-
- concat(cd, c, d, 28, 28);
- permute(ki[i], cd, perm2, 48);
- }
-
- permute(pd1, in, perm3, 64);
-
- for (j=0;j<32;j++) {
- l[j] = pd1[j];
- r[j] = pd1[j+32];
- }
-
- for (i=0;i<16;i++) {
- char er[48];
- char erk[48];
- char b[8][6];
- char cb[32];
- char pcb[32];
- char r2[32];
-
- permute(er, r, perm4, 48);
-
- xor(erk, er, ki[i], 48);
-
- for (j=0;j<8;j++)
- for (k=0;k<6;k++)
- b[j][k] = erk[j*6 + k];
-
- for (j=0;j<8;j++) {
- int m, n;
- m = (b[j][0]<<1) | b[j][5];
-
- n = (b[j][1]<<3) | (b[j][2]<<2) | (b[j][3]<<1) | b[j][4];
-
- for (k=0;k<4;k++)
- b[j][k] = (sbox[j][m][n] & (1<<(3-k)))?1:0;
- }
-
- for (j=0;j<8;j++)
- for (k=0;k<4;k++)
- cb[j*4+k] = b[j][k];
- permute(pcb, cb, perm5, 32);
-
- xor(r2, l, pcb, 32);
-
- for (j=0;j<32;j++)
- l[j] = r[j];
-
- for (j=0;j<32;j++)
- r[j] = r2[j];
- }
-
- concat(rl, r, l, 32, 32);
-
- permute(out, rl, perm6, 64);
-}
-
-static void str_to_key(unsigned char *str,unsigned char *key)
-{
- int i;
-
- key[0] = str[0]>>1;
- key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
- key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
- key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
- key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
- key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
- key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
- key[7] = str[6]&0x7F;
- for (i=0;i<8;i++) {
- key[i] = (key[i]<<1);
- }
-}
-
-
-static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key)
-{
- int i;
- char outb[64];
- char inb[64];
- char keyb[64];
- unsigned char key2[8];
-
- str_to_key(key, key2);
-
- for (i=0;i<64;i++) {
- inb[i] = (in[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
- keyb[i] = (key2[i/8] & (1<<(7-(i%8)))) ? 1 : 0;
- outb[i] = 0;
- }
-
- dohash(outb, inb, keyb);
-
- for (i=0;i<8;i++) {
- out[i] = 0;
- }
-
- for (i=0;i<64;i++) {
- if (outb[i])
- out[i/8] |= (1<<(7-(i%8)));
- }
-}
-
-void E_P16(unsigned char *p14,unsigned char *p16)
-{
- unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
- smbhash(p16, sp8, p14);
- smbhash(p16+8, sp8, p14+7);
-}
-
-void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
-{
- smbhash(p24, c8, p21);
- smbhash(p24+8, c8, p21+7);
- smbhash(p24+16, c8, p21+14);
-}
-
-void cred_hash1(unsigned char *out,unsigned char *in,unsigned char *key)
-{
- unsigned char buf[8];
-
- smbhash(buf, in, key);
- smbhash(out, buf, key+9);
-}
-
-void cred_hash2(unsigned char *out,unsigned char *in,unsigned char *key)
-{
- unsigned char buf[8];
- static unsigned char key2[8];
-
- smbhash(buf, in, key);
- key2[0] = key[7];
- smbhash(out, buf, key2);
-}
-
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- SMB parameters and setup
- Copyright (C) Andrew Tridgell 1992-1997
- Modified by Jeremy Allison 1995.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#include "smblib-priv.h"
-
-typedef unsigned char uchar;
-
-void strupper(char *s);
-
-/*
- This implements the X/Open SMB password encryption
- It takes a password, a 8 byte "crypt key" and puts 24 bytes of
- encrypted password into p24 */
-void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24)
-{
- uchar p14[15], p21[21];
-
- memset(p21,'\0',21);
- memset(p14,'\0',14);
- strlcpy((char *) p14, (char *) passwd, sizeof(p14));
-
- strupper((char *)p14);
- E_P16(p14, p21);
- E_P24(p21, c8, p24);
-}
-
-void strupper(char *s)
-{
- while (*s)
- {
- {
- if (CTYPE(islower, *s))
- *s = toupper(*s);
- s++;
- }
- }
-}
+++ /dev/null
-/* UNIX SMBlib NetBIOS implementation
-
- Version 1.0
- SMBlib Common Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* Error CLASS codes and etc ... */
-
-#define SMBC_SUCCESS 0
-#define SMBC_ERRDOS 0x01
-#define SMBC_ERRSRV 0x02
-#define SMBC_ERRHRD 0x03
-#define SMBC_ERRCMD 0xFF
-
-/* Define the protocol types ... */
-
-#define SMB_P_Unknown -1 /* Hmmm, is this smart? */
-#define SMB_P_Core 0
-#define SMB_P_CorePlus 1
-#define SMB_P_DOSLanMan1 2
-#define SMB_P_LanMan1 3
-#define SMB_P_DOSLanMan2 4
-#define SMB_P_LanMan2 5
-#define SMB_P_DOSLanMan2_1 6
-#define SMB_P_LanMan2_1 7
-#define SMB_P_NT1 8
-
-/* SMBlib return codes */
-/* We want something that indicates whether or not the return code was a */
-/* remote error, a local error in SMBlib or returned from lower layer ... */
-/* Wonder if this will work ... */
-/* SMBlibE_Remote = 1 indicates remote error */
-/* SMBlibE_ values < 0 indicate local error with more info available */
-/* SMBlibE_ values >1 indicate local from SMBlib code errors? */
-
-#define SMBlibE_Success 0
-#define SMBlibE_Remote 1 /* Remote error, get more info from con */
-#define SMBlibE_BAD -1
-#define SMBlibE_LowerLayer 2 /* Lower layer error */
-#define SMBlibE_NotImpl 3 /* Function not yet implemented */
-#define SMBlibE_ProtLow 4 /* Protocol negotiated does not support req */
-#define SMBlibE_NoSpace 5 /* No space to allocate a structure */
-#define SMBlibE_BadParam 6 /* Bad parameters */
-#define SMBlibE_NegNoProt 7 /* None of our protocols was liked */
-#define SMBlibE_SendFailed 8 /* Sending an SMB failed */
-#define SMBlibE_RecvFailed 9 /* Receiving an SMB failed */
-#define SMBlibE_GuestOnly 10 /* Logged in as guest */
-#define SMBlibE_CallFailed 11 /* Call remote end failed */
-#define SMBlibE_ProtUnknown 12 /* Protocol unknown */
-#define SMBlibE_NoSuchMsg 13 /* Keep this up to date */
+++ /dev/null
-/* UNIX SMBlib NetBIOS implementation
-
- Version 1.0
- SMBlib private Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "smblib-common.h"
-#include <sys/types.h>
-#include <unistd.h>
-
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-
-#include "byteorder.h" /* Hmmm ... hot good */
-
-#define SMB_DEF_IDF 0x424D53FF /* "\377SMB" */
-
-/* The protocol commands and constants we need */
-#define SMBnegprot 0x72 /* negotiate protocol */
-#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */
-#define SMBdialectID 0x02 /* a dialect id */
-
-typedef unsigned short WORD;
-typedef unsigned short UWORD;
-typedef unsigned int ULONG;
-typedef unsigned char BYTE;
-typedef unsigned char UCHAR;
-
-/* Some macros to allow access to actual packet data so that we */
-/* can change the underlying representation of packets. */
-/* */
-/* The current formats vying for attention are a fragment */
-/* approach where the SMB header is a fragment linked to the */
-/* data portion with the transport protocol (rfcnb or whatever) */
-/* being linked on the front. */
-/* */
-/* The other approach is where the whole packet is one array */
-/* of bytes with space allowed on the front for the packet */
-/* headers. */
-
-#define SMB_Hdr(p) (char *)(p -> data)
-
-/* SMB Hdr def for File Sharing Protocol? From MS and Intel, */
-/* Intel PN 138446 Doc Version 2.0, Nov 7, 1988. This def also */
-/* applies to LANMAN1.0 as well as the Core Protocol */
-/* The spec states that wct and bcc must be present, even if 0 */
-
-/* We define these as offsets into a char SMB[] array for the */
-/* sake of portability */
-
-/* NOTE!. Some of the lenght defines, SMB_<protreq>_len do not include */
-/* the data that follows in the SMB packet, so the code will have to */
-/* take that into account. */
-
-#define SMB_hdr_idf_offset 0 /* 0xFF,'SMB' 0-3 */
-#define SMB_hdr_com_offset 4 /* BYTE 4 */
-#define SMB_hdr_rcls_offset 5 /* BYTE 5 */
-#define SMB_hdr_reh_offset 6 /* BYTE 6 */
-#define SMB_hdr_err_offset 7 /* WORD 7 */
-#define SMB_hdr_reb_offset 9 /* BYTE 9 */
-#define SMB_hdr_flg_offset 9 /* same as reb ...*/
-#define SMB_hdr_res_offset 10 /* 7 WORDs 10 */
-#define SMB_hdr_res0_offset 10 /* WORD 10 */
-#define SMB_hdr_flg2_offset 10 /* WORD */
-#define SMB_hdr_res1_offset 12 /* WORD 12 */
-#define SMB_hdr_res2_offset 14
-#define SMB_hdr_res3_offset 16
-#define SMB_hdr_res4_offset 18
-#define SMB_hdr_res5_offset 20
-#define SMB_hdr_res6_offset 22
-#define SMB_hdr_tid_offset 24
-#define SMB_hdr_pid_offset 26
-#define SMB_hdr_uid_offset 28
-#define SMB_hdr_mid_offset 30
-#define SMB_hdr_wct_offset 32
-
-#define SMB_hdr_len 33 /* 33 byte header? */
-
-#define SMB_hdr_axc_offset 33 /* AndX Command */
-#define SMB_hdr_axr_offset 34 /* AndX Reserved */
-#define SMB_hdr_axo_offset 35 /* Offset from start to WCT of AndX cmd */
-
-/* Format of the Negotiate Protocol SMB */
-
-#define SMB_negp_bcc_offset 33
-#define SMB_negp_buf_offset 35 /* Where the buffer starts */
-#define SMB_negp_len 35 /* plus the data */
-
-/* Format of the Negotiate Response SMB, for CoreProtocol, LM1.2 and */
-/* NT LM 0.12. wct will be 1 for CoreProtocol, 13 for LM 1.2, and 17 */
-/* for NT LM 0.12 */
-
-#define SMB_negrCP_idx_offset 33 /* Response to the neg req */
-#define SMB_negrCP_bcc_offset 35
-#define SMB_negrLM_idx_offset 33 /* dialect index */
-#define SMB_negrLM_sec_offset 35 /* Security mode */
-#define SMB_sec_user_mask 0x01 /* 0 = share, 1 = user */
-#define SMB_sec_encrypt_mask 0x02 /* pick out encrypt */
-#define SMB_negrLM_mbs_offset 37 /* max buffer size */
-#define SMB_negrLM_mmc_offset 39 /* max mpx count */
-#define SMB_negrLM_mnv_offset 41 /* max number of VCs */
-#define SMB_negrLM_rm_offset 43 /* raw mode support bit vec*/
-#define SMB_negrLM_sk_offset 45 /* session key, 32 bits */
-#define SMB_negrLM_st_offset 49 /* Current server time */
-#define SMB_negrLM_sd_offset 51 /* Current server date */
-#define SMB_negrLM_stz_offset 53 /* Server Time Zone */
-#define SMB_negrLM_ekl_offset 55 /* encryption key length */
-#define SMB_negrLM_res_offset 57 /* reserved */
-#define SMB_negrLM_bcc_offset 59 /* bcc */
-#define SMB_negrLM_len 61 /* 61 bytes ? */
-#define SMB_negrLM_buf_offset 61 /* Where the fun begins */
-
-#define SMB_negrNTLM_idx_offset 33 /* Selected protocol */
-#define SMB_negrNTLM_sec_offset 35 /* Security more */
-#define SMB_negrNTLM_mmc_offset 36 /* Different format above */
-#define SMB_negrNTLM_mnv_offset 38 /* Max VCs */
-#define SMB_negrNTLM_mbs_offset 40 /* MBS now a long */
-#define SMB_negrNTLM_mrs_offset 44 /* Max raw size */
-#define SMB_negrNTLM_sk_offset 48 /* Session Key */
-#define SMB_negrNTLM_cap_offset 52 /* Capabilities */
-#define SMB_negrNTLM_stl_offset 56 /* Server time low */
-#define SMB_negrNTLM_sth_offset 60 /* Server time high */
-#define SMB_negrNTLM_stz_offset 64 /* Server time zone */
-#define SMB_negrNTLM_ekl_offset 66 /* Encrypt key len */
-#define SMB_negrNTLM_bcc_offset 67 /* Bcc */
-#define SMB_negrNTLM_len 69
-#define SMB_negrNTLM_buf_offset 69
-
-/* Offsets for Delete file */
-
-#define SMB_delet_sat_offset 33 /* search attribites */
-#define SMB_delet_bcc_offset 35 /* bcc */
-#define SMB_delet_buf_offset 37
-#define SMB_delet_len 37
-
-/* Offsets for SESSION_SETUP_ANDX for both LM and NT LM protocols */
-
-#define SMB_ssetpLM_mbs_offset 37 /* Max buffer Size, allow for AndX */
-#define SMB_ssetpLM_mmc_offset 39 /* max multiplex count */
-#define SMB_ssetpLM_vcn_offset 41 /* VC number if new VC */
-#define SMB_ssetpLM_snk_offset 43 /* Session Key */
-#define SMB_ssetpLM_pwl_offset 47 /* password length */
-#define SMB_ssetpLM_res_offset 49 /* reserved */
-#define SMB_ssetpLM_bcc_offset 53 /* bcc */
-#define SMB_ssetpLM_len 55 /* before data ... */
-#define SMB_ssetpLM_buf_offset 55
-
-#define SMB_ssetpNTLM_mbs_offset 37 /* Max Buffer Size for NT LM 0.12 */
- /* and above */
-#define SMB_ssetpNTLM_mmc_offset 39 /* Max Multiplex count */
-#define SMB_ssetpNTLM_vcn_offset 41 /* VC Number */
-#define SMB_ssetpNTLM_snk_offset 43 /* Session key */
-#define SMB_ssetpNTLM_cipl_offset 47 /* Case Insensitive PW Len */
-#define SMB_ssetpNTLM_cspl_offset 49 /* Unicode pw len */
-#define SMB_ssetpNTLM_res_offset 51 /* reserved */
-#define SMB_ssetpNTLM_cap_offset 55 /* server capabilities */
-#define SMB_ssetpNTLM_bcc_offset 59 /* bcc */
-#define SMB_ssetpNTLM_len 61 /* before data */
-#define SMB_ssetpNTLM_buf_offset 61
-
-#define SMB_ssetpr_axo_offset 35 /* Offset of next response ... */
-#define SMB_ssetpr_act_offset 37 /* action, bit 0 = 1 => guest */
-#define SMB_ssetpr_bcc_offset 39 /* bcc */
-#define SMB_ssetpr_buf_offset 41 /* Native OS etc */
-
-/* The following two arrays need to be in step! */
-/* We must make it possible for callers to specify these ... */
-
-extern const char *SMB_Prots[];
-extern int SMB_Types[];
-
-typedef struct SMB_Connect_Def * SMB_Handle_Type;
-
-struct SMB_Connect_Def {
-
- SMB_Handle_Type Next_Con, Prev_Con; /* Next and previous conn */
- int protocol; /* What is the protocol */
- int prot_IDX; /* And what is the index */
- void *Trans_Connect; /* The connection */
-
- /* All these strings should be malloc'd */
-
- char service[80], username[80], password[80], desthost[80], sock_options[80];
- char address[80], myname[80];
-
- int gid; /* Group ID, do we need it? */
- int mid; /* Multiplex ID? We might need one per con */
- int pid; /* Process ID */
-
- int uid; /* Authenticated user id. */
-
- /* It is pretty clear that we need to bust some of */
- /* these out into a per TCon record, as there may */
- /* be multiple TCon's per server, etc ... later */
-
- int port; /* port to use in case not default, this is a TCPism! */
-
- int max_xmit; /* Max xmit permitted by server */
- int Security; /* 0 = share, 1 = user */
- int Raw_Support; /* bit 0 = 1 = Read Raw supported, 1 = 1 Write raw */
- bool encrypt_passwords; /* false = don't */
- int MaxMPX, MaxVC, MaxRaw;
- unsigned int SessionKey, Capabilities;
- int SvrTZ; /* Server Time Zone */
- int Encrypt_Key_Len;
- char Encrypt_Key[80], Domain[80], PDomain[80], OSName[80], LMType[40];
- char Svr_OS[80], Svr_LMType[80], Svr_PDom[80];
-
-};
-
-#define SMBLIB_DEFAULT_OSNAME "UNIX of some type"
-#define SMBLIB_DEFAULT_LMTYPE "SMBlib LM2.1 minus a bit"
-#define SMBLIB_MAX_XMIT 65535
-
-/* global Variables for the library */
-
-#ifndef SMBLIB_ERRNO
-extern int SMBlib_errno;
-extern int SMBlib_SMB_Error; /* last Error */
-#endif
-
-/* From smbdes.c. */
-void E_P16(unsigned char *, unsigned char *);
-void E_P24(unsigned char *, unsigned char *, unsigned char *);
-
-/* From smblib-util.c. */
-void SMB_Get_My_Name(char *name, int len);
-
-/* From smbencrypt.c. */
-void SMBencrypt(unsigned char *passwd, unsigned char *, unsigned char *);
+++ /dev/null
-/* UNIX SMBlib NetBIOS implementation
-
- Version 1.0
- SMBlib Utility Routines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "smblib-priv.h"
-#include "rfcnb.h"
-
-/* The following two arrays need to be in step! */
-/* We must make it possible for callers to specify these ... */
-
-const char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
- "MICROSOFT NETWORKS 1.03",
- "MICROSOFT NETWORKS 3.0",
- "DOS LANMAN1.0",
- "LANMAN1.0",
- "DOS LM1.2X002",
- "LM1.2X002",
- "DOS LANMAN2.1",
- "LANMAN2.1",
- "Samba",
- "NT LM 0.12",
- "NT LANMAN 1.0",
- NULL};
-
-int SMB_Types[] = {SMB_P_Core,
- SMB_P_CorePlus,
- SMB_P_DOSLanMan1,
- SMB_P_DOSLanMan1,
- SMB_P_LanMan1,
- SMB_P_DOSLanMan2,
- SMB_P_LanMan2,
- SMB_P_LanMan2_1,
- SMB_P_LanMan2_1,
- SMB_P_NT1,
- SMB_P_NT1,
- SMB_P_NT1,
- -1};
-
-/* Figure out what protocol was accepted, given the list of dialect strings */
-/* We offered, and the index back from the server. We allow for a user */
-/* supplied list, and assume that it is a subset of our list */
-
-int SMB_Figure_Protocol(const char *dialects[], int prot_index)
-
-{ int i;
-
- if (dialects == SMB_Prots) { /* The jobs is easy, just index into table */
-
- return(SMB_Types[prot_index]);
- }
- else { /* Search through SMB_Prots looking for a match */
-
- for (i = 0; SMB_Prots[i] != NULL; i++) {
-
- if (strcmp(dialects[prot_index], SMB_Prots[i]) == 0) { /* A match */
-
- return(SMB_Types[i]);
-
- }
-
- }
-
- /* If we got here, then we are in trouble, because the protocol was not */
- /* One we understand ... */
-
- return(SMB_P_Unknown);
-
- }
-
-}
-
-
-/* Negotiate the protocol we will use from the list passed in Prots */
-/* we return the index of the accepted protocol in NegProt, -1 indicates */
-/* none acceptible, and our return value is 0 if ok, <0 if problems */
-
-int SMB_Negotiate(SMB_Handle_Type Con_Handle, const char *Prots[])
-{
- struct RFCNB_Pkt *pkt;
- int prots_len, i, pkt_len, prot, alloc_len;
- char *p;
-
- /* Figure out how long the prot list will be and allocate space for it */
-
- prots_len = 0;
-
- for (i = 0; Prots[i] != NULL; i++) {
-
- prots_len = prots_len + strlen(Prots[i]) + 2; /* Account for null etc */
-
- }
-
- /* The -1 accounts for the one byte smb_buf we have because some systems */
- /* don't like char msg_buf[] */
-
- pkt_len = SMB_negp_len + prots_len;
-
- /* Make sure that the pkt len is long enough for the max response ... */
- /* Which is a problem, because the encryption key len eec may be long */
-
- if (pkt_len < (SMB_hdr_wct_offset + (19 * 2) + 40)) {
-
- alloc_len = SMB_hdr_wct_offset + (19 * 2) + 40;
-
- }
- else {
-
- alloc_len = pkt_len;
-
- }
-
- pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(alloc_len);
-
- if (pkt == NULL) {
-
- SMBlib_errno = SMBlibE_NoSpace;
- return(SMBlibE_BAD);
-
- }
-
- /* Now plug in the bits we need */
-
- memset(SMB_Hdr(pkt), 0, SMB_negp_len);
- SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
- *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBnegprot;
- SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
- *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 0;
-
- SSVAL(SMB_Hdr(pkt), SMB_negp_bcc_offset, prots_len);
-
- /* Now copy the prot strings in with the right stuff */
-
- p = (char *)(SMB_Hdr(pkt) + SMB_negp_buf_offset);
-
- for (i = 0; Prots[i] != NULL; i++) {
-
- *p = SMBdialectID;
- strcpy(p + 1, Prots[i]);
- p = p + strlen(Prots[i]) + 2; /* Adjust len of p for null plus dialectID */
-
- }
-
- /* Now send the packet and sit back ... */
-
- if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
-
-
-#ifdef DEBUG
- fprintf(stderr, "Error sending negotiate protocol\n");
-#endif
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = -SMBlibE_SendFailed; /* Failed, check lower layer errno */
- return(SMBlibE_BAD);
-
- }
-
- /* Now get the response ... */
-
- if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, alloc_len) < 0) {
-
-#ifdef DEBUG
- fprintf(stderr, "Error receiving response to negotiate\n");
-#endif
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = -SMBlibE_RecvFailed; /* Failed, check lower layer errno */
- return(SMBlibE_BAD);
-
- }
-
- if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
-
-#ifdef DEBUG
- fprintf(stderr, "SMB_Negotiate failed with errorclass = %i, Error Code = %i\n",
- CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset),
- SVAL(SMB_Hdr(pkt), SMB_hdr_err_offset));
-#endif
-
- SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_Remote;
- return(SMBlibE_BAD);
-
- }
-
- if (SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset) == 0xFFFF) {
-
-#ifdef DEBUG
- fprintf(stderr, "None of our protocols was accepted ... ");
-#endif
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_NegNoProt;
- return(SMBlibE_BAD);
-
- }
-
- /* Now, unpack the info from the response, if any and evaluate the proto */
- /* selected. We must make sure it is one we like ... */
-
- Con_Handle -> prot_IDX = prot = SVAL(SMB_Hdr(pkt), SMB_negrCP_idx_offset);
- Con_Handle -> protocol = SMB_Figure_Protocol(Prots, prot);
-
- if (Con_Handle -> protocol == SMB_P_Unknown) { /* No good ... */
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_ProtUnknown;
- return(SMBlibE_BAD);
-
- }
-
- switch (CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset)) {
-
- case 0x01: /* No more info ... */
-
- break;
-
- case 13: /* Up to and including LanMan 2.1 */
-
- Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrLM_sec_offset);
- Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
- Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
-
- Con_Handle -> max_xmit = SVAL(SMB_Hdr(pkt), SMB_negrLM_mbs_offset);
- Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrLM_mmc_offset);
- Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrLM_mnv_offset);
- Con_Handle -> Raw_Support = SVAL(SMB_Hdr(pkt), SMB_negrLM_rm_offset);
- Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrLM_sk_offset);
- Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrLM_stz_offset);
- Con_Handle -> Encrypt_Key_Len = SVAL(SMB_Hdr(pkt), SMB_negrLM_ekl_offset);
-
- p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset);
- fprintf(stderr, "%p", (char *)(SMB_Hdr(pkt) + SMB_negrLM_buf_offset));
- memcpy(Con_Handle->Encrypt_Key, p, 8);
-
- p = (SMB_Hdr(pkt) + SMB_negrLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
-
- strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
-
- break;
-
- case 17: /* NT LM 0.12 and LN LM 1.0 */
-
- Con_Handle -> Security = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_sec_offset);
- Con_Handle -> encrypt_passwords = ((Con_Handle -> Security & SMB_sec_encrypt_mask) != 0x00);
- Con_Handle -> Security = Con_Handle -> Security & SMB_sec_user_mask;
-
- Con_Handle -> max_xmit = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mbs_offset);
- Con_Handle -> MaxMPX = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mmc_offset);
- Con_Handle -> MaxVC = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_mnv_offset);
- Con_Handle -> MaxRaw = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_mrs_offset);
- Con_Handle -> SessionKey = IVAL(SMB_Hdr(pkt), SMB_negrNTLM_sk_offset);
- Con_Handle -> SvrTZ = SVAL(SMB_Hdr(pkt), SMB_negrNTLM_stz_offset);
- Con_Handle -> Encrypt_Key_Len = CVAL(SMB_Hdr(pkt), SMB_negrNTLM_ekl_offset);
-
- p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset );
- memcpy(Con_Handle -> Encrypt_Key, p, 8);
- p = (SMB_Hdr(pkt) + SMB_negrNTLM_buf_offset + Con_Handle -> Encrypt_Key_Len);
-
- strncpy(p, Con_Handle -> Svr_PDom, sizeof(Con_Handle -> Svr_PDom) - 1);
-
- break;
-
- default:
-
-#ifdef DEBUG
- fprintf(stderr, "Unknown NegProt response format ... Ignored\n");
- fprintf(stderr, " wct = %i\n", CVAL(SMB_Hdr(pkt), SMB_hdr_wct_offset));
-#endif
-
- break;
- }
-
-#ifdef DEBUG
- fprintf(stderr, "Protocol selected is: %i:%s\n", prot, Prots[prot]);
-#endif
-
- RFCNB_Free_Pkt(pkt);
- return(0);
-
-}
-
-/* Get our hostname */
-
-void SMB_Get_My_Name(char *name, int len)
-
-{
- if (gethostname(name, len) < 0) { /* Error getting name */
-
- strncpy(name, "unknown", len);
-
- /* Should check the error */
-
-#ifdef DEBUG
- fprintf(stderr, "gethostname in SMB_Get_My_Name returned error:");
- perror("");
-#endif
-
- }
-
- /* only keep the portion up to the first "." */
-
-
-}
+++ /dev/null
-/* UNIX SMBlib NetBIOS implementation
-
- Version 1.0
- SMBlib Routines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <signal.h>
-
-int SMBlib_errno;
-int SMBlib_SMB_Error;
-#define SMBLIB_ERRNO
-typedef unsigned char uchar;
-#include "smblib-priv.h"
-
-#include "rfcnb.h"
-
-/* Initialize the SMBlib package */
-
-int SMB_Init()
-
-{
- signal(SIGPIPE, SIG_IGN); /* Ignore these ... */
-
- return 0;
-
-}
-
-int SMB_Term()
-
-{
-
- return 0;
-
-}
-
-/* SMB_Connect_Server: Connect to a server, but don't negotiate protocol */
-/* or anything else ... */
-
-SMB_Handle_Type SMB_Connect_Server(SMB_Handle_Type Con_Handle,
- char *server, char *NTdomain)
-
-{ SMB_Handle_Type con;
- char called[80], calling[80], *address;
- int i;
-
- /* Get a connection structure if one does not exist */
-
- con = Con_Handle;
-
- if (Con_Handle == NULL) {
-
- if ((con = (struct SMB_Connect_Def *)malloc(sizeof(struct SMB_Connect_Def))) == NULL) {
-
-
- SMBlib_errno = SMBlibE_NoSpace;
- return NULL;
- }
-
- }
-
- /* Init some things ... */
-
- strlcpy(con->service, "", sizeof(con->service));
- strlcpy(con->username, "", sizeof(con->username));
- strlcpy(con->password, "", sizeof(con->password));
- strlcpy(con->sock_options, "", sizeof(con->sock_options));
- strlcpy(con->address, "", sizeof(con->address));
- strlcpy(con->desthost, server, sizeof(con->desthost));
- strlcpy(con->PDomain, NTdomain, sizeof(con->PDomain));
- strlcpy(con->OSName, SMBLIB_DEFAULT_OSNAME, sizeof(con->OSName));
- strlcpy(con->LMType, SMBLIB_DEFAULT_LMTYPE, sizeof(con->LMType));
-
- SMB_Get_My_Name(con -> myname, sizeof(con -> myname));
-
- con -> port = 0; /* No port selected */
-
- /* Get some things we need for the SMB Header */
-
- con -> pid = getpid();
- con -> mid = con -> pid; /* This will do for now ... */
- con -> uid = 0; /* Until we have done a logon, no uid ... */
- con -> gid = getgid();
-
- /* Now connect to the remote end, but first upper case the name of the
- service we are going to call, sine some servers want it in uppercase */
-
- for (i=0; i < strlen(server); i++)
- called[i] = toupper(server[i]);
-
- called[strlen(server)] = 0; /* Make it a string */
-
- for (i=0; i < strlen(con -> myname); i++)
- calling[i] = toupper(con -> myname[i]);
-
- calling[strlen(con -> myname)] = 0; /* Make it a string */
-
- if (strcmp(con -> address, "") == 0)
- address = con -> desthost;
- else
- address = con -> address;
-
- con -> Trans_Connect = RFCNB_Call(called,
- calling,
- address, /* Protocol specific */
- con -> port);
-
- /* Did we get one? */
-
- if (con -> Trans_Connect == NULL) {
-
- if (Con_Handle == NULL) {
- Con_Handle = NULL;
- free(con);
- }
- SMBlib_errno = -SMBlibE_CallFailed;
- return NULL;
-
- }
-
- return(con);
-
-}
-
-/* Logon to the server. That is, do a session setup if we can. We do not do */
-/* Unicode yet! */
-
-int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
- char *PassWord)
-
-{ struct RFCNB_Pkt *pkt;
- int param_len, pkt_len, pass_len;
- char *p, pword[128];
-
- /* First we need a packet etc ... but we need to know what protocol has */
- /* been negotiated to figure out if we can do it and what SMB format to */
- /* use ... */
-
- if (Con_Handle -> protocol < SMB_P_LanMan1) {
-
- SMBlib_errno = SMBlibE_ProtLow;
- return(SMBlibE_BAD);
-
- }
-
- strlcpy(pword, PassWord, sizeof(pword));
- if (Con_Handle -> encrypt_passwords)
- {
- pass_len=24;
- SMBencrypt((uchar *) PassWord, (uchar *)Con_Handle -> Encrypt_Key,(uchar *)pword);
- }
- else
- pass_len=strlen(pword);
-
-
- /* Now build the correct structure */
-
- if (Con_Handle -> protocol < SMB_P_NT1) {
-
- param_len = strlen(UserName) + 1 + pass_len + 1 +
- strlen(Con_Handle -> PDomain) + 1 +
- strlen(Con_Handle -> OSName) + 1;
-
- pkt_len = SMB_ssetpLM_len + param_len;
-
- pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
-
- if (pkt == NULL) {
-
- SMBlib_errno = SMBlibE_NoSpace;
- return(SMBlibE_BAD); /* Should handle the error */
-
- }
-
- memset(SMB_Hdr(pkt), 0, SMB_ssetpLM_len);
- SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
- *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
- SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
- *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 10;
- *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
- SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
-
- SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mbs_offset, SMBLIB_MAX_XMIT);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_mmc_offset, 2);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_vcn_offset, Con_Handle -> pid);
- SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_snk_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_pwl_offset, pass_len + 1);
- SIVAL(SMB_Hdr(pkt), SMB_ssetpLM_res_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpLM_bcc_offset, param_len);
-
- /* Now copy the param strings in with the right stuff */
-
- p = (char *)(SMB_Hdr(pkt) + SMB_ssetpLM_buf_offset);
-
- /* Copy in password, then the rest. Password has a null at end */
-
- memcpy(p, pword, pass_len);
-
- p = p + pass_len + 1;
-
- strcpy(p, UserName);
- p = p + strlen(UserName);
- *p = 0;
-
- p = p + 1;
-
- strcpy(p, Con_Handle -> PDomain);
- p = p + strlen(Con_Handle -> PDomain);
- *p = 0;
- p = p + 1;
-
- strcpy(p, Con_Handle -> OSName);
- p = p + strlen(Con_Handle -> OSName);
- *p = 0;
-
- }
- else {
-
- /* We don't admit to UNICODE support ... */
-
- param_len = strlen(UserName) + 1 + pass_len +
- strlen(Con_Handle -> PDomain) + 1 +
- strlen(Con_Handle -> OSName) + 1 +
- strlen(Con_Handle -> LMType) + 1;
-
- pkt_len = SMB_ssetpNTLM_len + param_len;
-
- pkt = (struct RFCNB_Pkt *)RFCNB_Alloc_Pkt(pkt_len);
-
- if (pkt == NULL) {
-
- SMBlib_errno = SMBlibE_NoSpace;
- return(-1); /* Should handle the error */
-
- }
-
- memset(SMB_Hdr(pkt), 0, SMB_ssetpNTLM_len);
- SIVAL(SMB_Hdr(pkt), SMB_hdr_idf_offset, SMB_DEF_IDF); /* Plunk in IDF */
- *(SMB_Hdr(pkt) + SMB_hdr_com_offset) = SMBsesssetupX;
- SSVAL(SMB_Hdr(pkt), SMB_hdr_pid_offset, Con_Handle -> pid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_tid_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_mid_offset, Con_Handle -> mid);
- SSVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset, Con_Handle -> uid);
- *(SMB_Hdr(pkt) + SMB_hdr_wct_offset) = 13;
- *(SMB_Hdr(pkt) + SMB_hdr_axc_offset) = 0xFF; /* No extra command */
- SSVAL(SMB_Hdr(pkt), SMB_hdr_axo_offset, 0);
-
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mbs_offset, SMBLIB_MAX_XMIT);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_mmc_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_vcn_offset, 0);
- SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_snk_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cipl_offset, pass_len);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cspl_offset, 0);
- SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_res_offset, 0);
- SIVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_cap_offset, 0);
- SSVAL(SMB_Hdr(pkt), SMB_ssetpNTLM_bcc_offset, param_len);
-
- /* Now copy the param strings in with the right stuff */
-
- p = (char *)(SMB_Hdr(pkt) + SMB_ssetpNTLM_buf_offset);
-
- /* Copy in password, then the rest. Password has no null at end */
-
- memcpy(p, pword, pass_len);
-
- p = p + pass_len;
-
- strcpy(p, UserName);
- p = p + strlen(UserName);
- *p = 0;
-
- p = p + 1;
-
- strcpy(p, Con_Handle -> PDomain);
- p = p + strlen(Con_Handle -> PDomain);
- *p = 0;
- p = p + 1;
-
- strcpy(p, Con_Handle -> OSName);
- p = p + strlen(Con_Handle -> OSName);
- *p = 0;
- p = p + 1;
-
- strcpy(p, Con_Handle -> LMType);
- p = p + strlen(Con_Handle -> LMType);
- *p = 0;
-
- }
-
- /* Now send it and get a response */
-
- if (RFCNB_Send(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0){
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_SendFailed;
- return(SMBlibE_BAD);
-
- }
-
- /* Now get the response ... */
-
- if (RFCNB_Recv(Con_Handle -> Trans_Connect, pkt, pkt_len) < 0) {
-
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_RecvFailed;
- return(SMBlibE_BAD);
-
- }
-
- /* Check out the response type ... */
-
- if (CVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset) != SMBC_SUCCESS) { /* Process error */
-
- SMBlib_SMB_Error = IVAL(SMB_Hdr(pkt), SMB_hdr_rcls_offset);
- RFCNB_Free_Pkt(pkt);
- SMBlib_errno = SMBlibE_Remote;
- return(SMBlibE_BAD);
-
- }
-/** @@@ mdz: check for guest login { **/
- if (SVAL(SMB_Hdr(pkt), SMB_ssetpr_act_offset) & 0x1)
- {
- /* do we allow guest login? NO! */
- return(SMBlibE_BAD);
-
- }
- /** @@@ mdz: } **/
-
-
- /* Now pick up the UID for future reference ... */
-
- Con_Handle -> uid = SVAL(SMB_Hdr(pkt), SMB_hdr_uid_offset);
- RFCNB_Free_Pkt(pkt);
-
- return(0);
-
-}
-
-
-/* Disconnect from the server, and disconnect all tree connects */
-
-int SMB_Discon(SMB_Handle_Type Con_Handle, bool KeepHandle)
-
-{
-
- /* We just disconnect the connection for now ... */
-
- RFCNB_Hangup(Con_Handle -> Trans_Connect);
-
- if (!KeepHandle)
- free(Con_Handle);
-
- return(0);
-
-}
+++ /dev/null
-/* UNIX SMBlib NetBIOS implementation
-
- Version 1.0
- SMBlib Defines
-
- Copyright (C) Richard Sharpe 1996
-
-*/
-
-/*
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "smblib-common.h"
-
-/* Just define all the entry points */
-
-/* Initialize the library. */
-
-int SMB_Init(void);
-
-/* Connect to a server, but do not do a tree con etc ... */
-
-void *SMB_Connect_Server(void *Con, char *server, char *NTdomain);
-
-/* Negotiate a protocol */
-
-int SMB_Negotiate(void *Con_Handle, char *Prots[]);
-
-/* Disconnect from server. Has flag to specify whether or not we keep the */
-/* handle. */
-
-int SMB_Discon(void *Con, bool KeepHandle);
-
-/* Log on to a server. */
-
-int SMB_Logon_Server(SMB_Handle_Type Con_Handle, char *UserName,
- char *PassWord);
+++ /dev/null
-#include <sys/types.h>
-#include <unistd.h>
-#include <syslog.h>
-#include "config.h"
-#include "smblib-priv.h"
-#include "smblib.h"
-#include "valid.h"
-
-int Valid_User(char *USERNAME,char *PASSWORD,char *SERVER,char *BACKUP, char *DOMAIN)
-{
- char *SMB_Prots[] = {"PC NETWORK PROGRAM 1.0",
- "MICROSOFT NETWORKS 1.03",
- "MICROSOFT NETWORKS 3.0",
- "LANMAN1.0",
- "LM1.2X002",
- "Samba",
- "NT LM 0.12",
- "NT LANMAN 1.0",
- NULL};
- SMB_Handle_Type con;
-
- SMB_Init();
- con = SMB_Connect_Server(NULL, SERVER, DOMAIN);
- if (con == NULL) { /* Error ... */
- con = SMB_Connect_Server(NULL, BACKUP, DOMAIN);
- if (con == NULL) {
- return(NTV_SERVER_ERROR);
- }
- }
- if (SMB_Negotiate(con, SMB_Prots) < 0) { /* An error */
- SMB_Discon(con,0);
- return(NTV_PROTOCOL_ERROR);
- }
- /* Test for a server in share level mode do not authenticate against it */
- if (con -> Security == 0)
- {
- SMB_Discon(con,0);
- return(NTV_PROTOCOL_ERROR);
- }
-
- if (SMB_Logon_Server(con, USERNAME, PASSWORD) < 0) {
- SMB_Discon(con,0);
- return(NTV_LOGON_ERROR);
- }
-
- SMB_Discon(con,0);
- return(NTV_NO_ERROR);
-}
+++ /dev/null
-#ifndef _VALID_H_
-#define _VALID_H_
-/* SMB User verification function */
-
-#define NTV_NO_ERROR 0
-#define NTV_SERVER_ERROR 1
-#define NTV_PROTOCOL_ERROR 2
-#define NTV_LOGON_ERROR 3
-
-int Valid_User(char *USERNAME,char *PASSWORD,char *SERVER, char *BACKUP, char *DOMAIN);
-
-#endif
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-# @(#) $Id: actmerge.in 2674 1999-11-15 06:28:29Z rra $
-# @(#) Under RCS control in /usr/local/news/src/inn/local/RCS/actmerge.sh,v
-#
-# actmerge - merge two active files
-#
-# usage:
-# actmerge [-s] ign1 ign2 host1 host2
-#
-# -s - write status on stderr even if no fatal error
-# ign1 - ignore file for host1
-# ign2 - ignore file for host2
-# host1 - 1st active file or host
-# host2 - 2nd active file or host
-#
-# The merge of two active files are sent to stdout. The status is
-# written to stderr.
-
-# By: Landon Curt Noll chongo@toad.com (chongo was here /\../\)
-#
-# Copyright (c) Landon Curt Noll, 1996.
-# All rights reserved.
-#
-# Permission to use and modify is hereby granted so long as this
-# notice remains. Use at your own risk. No warranty is implied.
-
-# preset vars
-#
-
-# Our lock file
-LOCK=${LOCKS}/LOCK.actmerge
-# where actsync is located
-ACTSYNC=${PATHBIN}/actsync
-# exit value of actsync if unable to get an active file
-NOSYNC=127
-# args used by actsync a fetch of an active file
-FETCH="-b 0 -d 0 -g 0 -o aK -p 0 -q 12 -s 0 -t 0 -v 2"
-# args used to merge two active files
-MERGE="-b 0 -d 0 -g 0 -m -o aK -p 0 -q 12 -s 0 -t 0 -v 3"
-# unless -q
-QUIET=true
-
-# parse args
-#
-if [ $# -gt 1 ]; then
- if [ X"-s" = X"$1" ]; then
- QUIET=
- shift
- fi
-fi
-if [ $# -ne 4 ]; then
- echo "usage: $0 ign1 ign2 host1 host2" 1>&2
- exit 1
-fi
-ign1="$1"
-if [ ! -s "$ign1" ]; then
- echo "$0: host1 ignore file not found or empty: $ign1" 1>&2
- exit 2
-fi
-ign2="$2"
-if [ ! -s "$ign2" ]; then
- echo "$0: host2 ignore file not found or empty: $ign2" 1>&2
- exit 3
-fi
-host1="$3"
-host2="$4"
-
-
-# Lock out others
-#
-trap 'rm -f ${LOCK}; exit 1' 0 1 2 3 15
-shlock -p $$ -f ${LOCK} || {
- echo "$0: Locked by `cat ${LOCK}`" 1>&2
- exit 4
-}
-
-# setup
-#
-tmp="$TMPDIR/.merge$$"
-act1="$TMPDIR/.act1$$"
-act2="$TMPDIR/.act2$$"
-trap "rm -f $tmp ${LOCK} $act1 $act2; exit" 0 1 2 3 15
-rm -f "$tmp"
-touch "$tmp"
-chmod 0600 "$tmp"
-rm -f "$act1"
-touch "$act1"
-chmod 0600 "$act1"
-rm -f "$act2"
-touch "$act2"
-chmod 0600 "$act2"
-
-# try to fetch the first active file
-#
-echo "=-= fetching $host1" >>$tmp
-eval "$ACTSYNC -i $ign1 $FETCH /dev/null $host1 > $act1 2>>$tmp"
-status=$?
-if [ "$status" -ne 0 ]; then
-
- # We failed on our first try, so we will trice knock 3 times after
- # waiting 5 minutes.
- #
- for loop in 1 2 3; do
-
- # wait 5 minutes
- sleep 300
-
- # try #1
- eval "$ACTSYNC -i $ign1 $FETCH /dev/null $host1 > $act1 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
-
- # try #2
- eval "$ACTSYNC -i $ign1 $FETCH /dev/null $host1 > $act1 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
-
- # try #3
- eval "$ACTSYNC -i $ign1 $FETCH /dev/null $host1 > $act1 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
- done
-
- # give up
- #
- if [ "$status" -ne 0 ]; then
- echo "=-= `date` merge $host1 $host2 exit $status" 1>&2
- sed -e 's/^/ /' < "$tmp" 1>&2
- exit "$status"
- fi
-fi
-if [ ! -s "$act1" ]; then
- echo "$0: host1 active file not found or empty: $act1" 1>&2
- exit 5
-fi
-
-# try to fetch the second active file
-#
-echo "=-= fetching $host2" >>$tmp
-eval "$ACTSYNC -i $ign2 $FETCH /dev/null $host2 > $act2 2>>$tmp"
-status=$?
-if [ "$status" -ne 0 ]; then
-
- # We failed on our first try, so we will trice knock 3 times after
- # waiting 5 minutes.
- #
- for loop in 1 2 3; do
-
- # wait 5 minutes
- sleep 300
-
- # try #1
- eval "$ACTSYNC -i $ign2 $FETCH /dev/null $host2 > $act2 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
-
- # try #2
- eval "$ACTSYNC -i $ign2 $FETCH /dev/null $host2 > $act2 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
-
- # try #3
- eval "$ACTSYNC -i $ign2 $FETCH /dev/null $host2 > $act2 2>>$tmp"
- status=$?
- if [ "$status" -eq "$NOSYNC" ]; then
- break;
- fi
- done
-
- # give up
- #
- if [ "$status" -ne 0 ]; then
- echo "=-= `date` merge $host1 $host2 exit $status" 1>&2
- sed -e 's/^/ /' < "$tmp" 1>&2
- exit "$status"
- fi
-fi
-if [ ! -s "$act2" ]; then
- echo "$0: host2 active file not found or empty: $act2" 1>&2
- exit 6
-fi
-
-# merge the 2 active files to stdout
-#
-echo "=-= merging $host1 and $host2" >>$tmp
-eval "$ACTSYNC $MERGE $act1 $act2" 2>>$tmp
-status=$?
-if [ "$status" -ne 0 ]; then
- echo "=-= `date` merge $host1 $host2 exit $status" 1>&2
- sed -e 's/^/ /' < "$tmp" 1>&2
- exit "$status"
-fi
-
-# if not -q, send status to stderr
-#
-if [ -z "$QUIET" ]; then
- echo "=-= `date` merge $host1 $host2 successful" 1>&2
- sed -e 's/^/ /' < "$tmp" 1>&2
-fi
-
-# all done
-#
-rm -f "${LOCK}"
-exit 0
+++ /dev/null
-/* @(#) $Id: actsync.c 6372 2003-05-31 19:48:28Z rra $ */
-/* @(#) Under RCS control in /usr/local/news/src/inn/local/RCS/actsync.c,v */
-/*
- * actsync - sync or merge two active files
- *
- * usage:
- * actsync [-b hostid][-d hostid][-g max][-i ignore_file][-I][-k][-l hostid]
- * [-m][-n name][-o fmt][-p %][-q hostid][-s size]
- * [-t hostid][-T][-v verbose_lvl][-z sec]
- * [host1] host2
- *
- * -A use authentication to server
- * -b hostid ignore *.bork.bork.bork groups from: (def: -b 0)
- * 0 from neither host
- * 1 from host1
- * 2 from host2
- * 12 from host1 and host2
- * 21 from host1 and host2
- * -d hostid ignore groups with all numeric components (def: -d 0)
- * -g max ignore group >max levels (0=dont ignore) (def: -g 0)
- * -i ignore_file file with list/types of groups to ignore (def: no file)
- * -I hostid ignore_file applies only to hostid (def: -I 12)
- * -k keep host1 groups with errors (def: remove)
- * -l hostid flag =group problems as errors (def: -l 12)
- * -m merge, keep group not on host2 (def: sync)
- * -n name name given to ctlinnd newgroup commands (def: actsync)
- * -o fmt type of output: (def: -o c)
- * a output groups in active format
- * a1 like 'a', but output ignored non-err host1 grps
- * ak like 'a', keep host2 hi/low values on new groups
- * aK like 'a', use host2 hi/low values always
- * c output in ctlinnd change commands
- * x no output, safely exec ctlinnd commands
- * xi no output, safely exec commands interactively
- * -p % min % host1 lines unchanged allowed (def: -p 96)
- * -q hostid silence errors from a host (see -b) (def: -q 0)
- * -s size ignore names longer than size (0=no lim) (def: -s 0)
- * -t hostid ignore bad top level groups from:(see -b) (def: -t 2)
- * -T no new hierarchies (def: allow)
- * -v verbose_lvl verbosity level (def: -v 0)
- * 0 no debug or status reports
- * 1 summary if work done
- * 2 summary & actions (if exec output) only if done
- * 3 summary & actions (if exec output)
- * 4 debug output plus all -v 3 messages
- * -z sec sleep sec seconds per exec if -o x (def: -z 4)
- * host1 host to be changed (def: local server)
- * host2 reference host used in merge
- */
-/*
- * By: Landon Curt Noll chongo@toad.com (chongo was here /\../\)
- *
- * Copyright (c) Landon Curt Noll, 1996.
- * All rights reserved.
- *
- * Permission to use and modify is hereby granted so long as this
- * notice remains. Use at your own risk. No warranty is implied.
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <math.h>
-#include <sys/stat.h>
-#include <signal.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-
-static const char usage[] = "\
-Usage: actsync [-A][-b hostid][-d hostid][-i ignore_file][-I hostid][-k]\n\
- [-l hostid][-m][-n name][-o fmt][-p min_%_unchg][-q hostid]\n\
- [-s size][-t hostid][-T][-v verbose_lvl][-z sec]\n\
- [host1] host2\n\
-\n\
- -A use authentication to server\n\
- -b hostid ignore *.bork.bork.bork groups from: (def: -b 0)\n\
- 0 from neither host\n\
- 1 from host1\n\
- 2 from host2\n\
- 12 from host1 and host2\n\
- 21 from host1 and host2\n\
- -d hostid ignore grps with all numeric components (def: -d 0)\n\
- -g max ignore group >max levels (0=don't) (def: -g 0)\n\
- -i file file with groups to ignore (def: no file)\n\
- -I hostid ignore_file applies only to hostid (def: -I 12)\n\
- -k keep host1 groups with errors (def: remove)\n\
- -l hostid flag =group problems as errors (def: -l 12)\n\
- -m merge, keep group not on host2 (def: sync)\n\
- -n name name given to ctlinnd newgroup cmds (def: actsync)\n\
- -o fmt type of output: (def: -o c)\n\
- a output groups in active format\n\
- a1 like 'a', but output ignored non-err host1 grps\n\
- ak like 'a', keep host2 hi/low values on new groups\n\
- aK like 'a', use host2 hi/low values always\n\
- c output in ctlinnd change commands\n\
- x no output, safely exec ctlinnd commands\n\
- xi no output, safely exec commands interactively\n\
- -p % min % host1 lines unchanged allowed (def: -p 96)\n\
- -q hostid silence errors from a host (see -b) (def: -q 0)\n\
- -s size ignore names > than size (0=no lim) (def: -s 0)\n\
- -t hostid ignore bad top level grps from: (see -b)(def: -t 2)\n\
- -T no new hierarchies (def: allow)\n\
- -v level verbosity level (def: -v 0)\n\
- 0 no debug or status reports\n\
- 1 summary if work done\n\
- 2 summary & actions (if exec output) only if done\n\
- 3 summary & actions (if exec output)\n\
- 4 debug output plus all -v 3 messages\n\
- -z sec sleep sec seconds per exec if -o x (def: -z 4)\n\
-\n\
- host1 host to be changed (def: local server)\n\
- host2 reference host used in merge\n";
-
-
-/*
- * pat - internal ignore/check pattern
- *
- * A pattern, derived from an ignore file, will determine if a group
- * is will be checked if it is on both hosts or ignored altogether.
- *
- * The type related to the 4th field of an active file. Types may
- * currently be one of [ymjnx=]. If '=' is one of the types, an
- * optional equivalence pattern may be given in the 'epat' element.
- *
- * For example, to ignore "foo.bar.*", if it is junked or equated to
- * a group of the form "alt.*.foo.bar.*":
- *
- * x.pat = "foo.bar.*";
- * x.type = "j=";
- * x.epat = "alt.*.foo.bar.*";
- * x.ignore = 1;
- *
- * To further check "foo.bar.mod" if it is moderated:
- *
- * x.pat = "foo.bar.mod";
- * x.type = "m";
- * x.epat = NULL;
- * x.ignore = 0;
- *
- * The 'i' value means ignore, 'c' value means 'compare'. The last pattern
- * that matches a group determines the fate of the group. By default all
- * groups are included.
- */
-struct pat {
- char *pat; /* newsgroup pattern */
- int type_match; /* 1 => match only if group type matches */
- int y_type; /* 1 => match if a 'y' type group */
- int m_type; /* 1 => match if a 'm' type group */
- int n_type; /* 1 => match if a 'n' type group */
- int j_type; /* 1 => match if a 'j' type group */
- int x_type; /* 1 => match if a 'x' type group */
- int eq_type; /* 1 => match if a 'eq' type group */
- char *epat; /* =pattern to match, if non-NULL and = is in type */
- int ignore; /* 0 => check matching group, 1 => ignore it */
-};
-
-/* internal representation of an active line */
-struct grp {
- int ignore; /* ignore reason, 0 => not ignore (see below) */
- int hostid; /* HOSTID this group is from */
- int linenum; /* >0 => active line number, <=0 => not a line */
- int output; /* 1 => output to produce the merged active file */
- int remove; /* 1 => remove this group */
- char *name; /* newsgroup name */
- char *hi; /* high article string */
- char *low; /* low article string */
- char *type; /* newsgroup type string */
- char *outhi; /* output high article string */
- char *outlow; /* output low article string */
- char *outtype; /* output newsgroup type string */
-};
-
-/* structure used in the process of looking for =group type problems */
-struct eqgrp {
- int skip; /* 1 => skip this entry */
- struct grp *g; /* =group that is being examined */
- char *eq; /* current equivalence name */
-};
-
-/*
- * These ignore reasons are listed in order severity; from mild to severe.
- */
-#define NOT_IGNORED 0x0000 /* newsgroup has not been ignored */
-#define CHECK_IGNORE 0x0001 /* ignore file ignores this entry */
-#define CHECK_TYPE 0x0002 /* group type is ignored */
-#define CHECK_BORK 0x0004 /* group is a *.bork.bork.bork group */
-#define CHECK_HIER 0x0008 /* -T && new group's hierarchy does not exist */
-#define ERROR_LONGLOOP 0x0010 /* =name refers to long =grp chain or cycle */
-#define ERROR_EQLOOP 0x0020 /* =name refers to itself in some way */
-#define ERROR_NONEQ 0x0040 /* =name does not refer to a valid group */
-#define ERROR_DUP 0x0080 /* newsgroup is a duplicate of another */
-#define ERROR_EQNAME 0x0100 /* =name is a bad group name */
-#define ERROR_BADTYPE 0x0200 /* newsgroup type is invalid */
-#define ERROR_BADNAME 0x0400 /* newsgroup name is invalid */
-#define ERROR_FORMAT 0x0800 /* entry line is malformed */
-
-#define IS_IGNORE(ign) ((ign) & (CHECK_IGNORE|CHECK_TYPE|CHECK_BORK|CHECK_HIER))
-#define IS_ERROR(ign) ((ign) & ~(CHECK_IGNORE|CHECK_TYPE|CHECK_BORK|CHECK_HIER))
-
-#define NOHOST 0 /* neither host1 nor host2 */
-#define HOSTID1 1 /* entry from the first host */
-#define HOSTID2 2 /* entry from the second host */
-
-#define CHUNK 5000 /* number of elements to alloc at a time */
-
-#define TYPES "ymjnx=" /* group types (1st char of 4th active fld) */
-#define TYPECNT (sizeof(TYPES)-1)
-
-#define DEF_HI "0000000000" /* default hi string value for new groups */
-#define DEF_LOW "0000000001" /* default low string value for new groups */
-#define WATER_LEN 10 /* string length of hi/low water mark */
-
-#define DEF_NAME "actsync" /* default name to use for ctlinnd newgroup */
-
-#define MIN_UNCHG (double)96.0 /* min % of host1 lines unchanged allowed */
-
-#define DEV_NULL "/dev/null" /* path to the bit bucket */
-#define CTLINND_NAME "ctlinnd" /* basename of ctlinnd command */
-#define CTLINND_TIME_OUT "-t30" /* seconds to wait before timeout */
-
-#define READ_SIDE 0 /* read side of a pipe */
-#define WRITE_SIDE 1 /* write side of a pipe */
-
-#define EQ_LOOP 16 /* give up if =eq loop/chain is this long */
-#define NOT_REACHED 127 /* exit value if unable to get active files */
-
-#define NEWGRP_EMPTY 0 /* no new group dir was found */
-#define NEWGRP_NOCHG 1 /* new group dir found but no hi/low change */
-#define NEWGRP_CHG 2 /* new group dir found but no hi/low change */
-
-/* -b macros */
-#define BORK_CHECK(hostid) \
- ((hostid == HOSTID1 && bork_host1_flag) || \
- (hostid == HOSTID2 && bork_host2_flag))
-
-/* -d macros */
-#define NUM_CHECK(hostid) \
- ((hostid == HOSTID1 && num_host1_flag) || \
- (hostid == HOSTID2 && num_host2_flag))
-
-/* -t macros */
-#define TOP_CHECK(hostid) \
- ((hostid == HOSTID1 && t_host1_flag) || \
- (hostid == HOSTID2 && t_host2_flag))
-
-/* -o output types */
-#define OUTPUT_ACTIVE 1 /* output in active file format */
-#define OUTPUT_CTLINND 2 /* output in ctlinnd change commands */
-#define OUTPUT_EXEC 3 /* no output, safely exec commands */
-#define OUTPUT_IEXEC 4 /* no output, exec commands interactively */
-
-/* -q macros */
-#define QUIET(hostid) \
- ((hostid == HOSTID1 && quiet_host1) || (hostid == HOSTID2 && quiet_host2))
-
-/* -v verbosity level */
-#define VER_MIN 0 /* minimum -v level */
-#define VER_NONE 0 /* no -v output */
-#define VER_SUMM_IF_WORK 1 /* output summary if actions were performed */
-#define VER_REPT_IF_WORK 2 /* output summary & actions only if performed */
-#define VER_REPORT 3 /* output summary & actions performed */
-#define VER_FULL 4 /* output all summary, actins and debug */
-#define VER_MAX 4 /* maximum -v level */
-#define D_IF_SUMM (v_flag >= VER_SUMM_IF_WORK) /* true => give summary always */
-#define D_REPORT (v_flag >= VER_REPT_IF_WORK) /* true => give reports */
-#define D_BUG (v_flag == VER_FULL) /* true => debug processing */
-#define D_SUMMARY (v_flag >= VER_REPORT) /* true => give summary always */
-
-/* flag and arg related defaults */
-int bork_host1_flag = 0; /* 1 => -b 1 or -b 12 or -b 21 given */
-int bork_host2_flag = 0; /* 1 => -b 2 or -b 12 or -b 21 given */
-int num_host1_flag = 0; /* 1 => -d 1 or -d 12 or -d 21 given */
-int num_host2_flag = 0; /* 1 => -d 2 or -d 12 or -d 21 given */
-char *ign_file = NULL; /* default ignore file */
-int ign_host1_flag = 1; /* 1 => -i ign_file applies to host1 */
-int ign_host2_flag = 1; /* 1 => -i ign_file applies to host2 */
-int g_flag = 0; /* ignore grps deeper than > g_flag, 0=>dont */
-int k_flag = 0; /* 1 => -k given */
-int l_host1_flag = HOSTID1; /* HOSTID1 => host1 =group error detection */
-int l_host2_flag = HOSTID2; /* HOSTID2 => host2 =group error detection */
-int m_flag = 0; /* 1 => merge active files, don't sync */
-const char *new_name = DEF_NAME; /* ctlinnd newgroup name */
-int o_flag = OUTPUT_CTLINND; /* default output type */
-double p_flag = MIN_UNCHG; /* min % host1 lines allowed to be unchanged */
-int host1_errs = 0; /* errors found in host1 active file */
-int host2_errs = 0; /* errors found in host2 active file */
-int quiet_host1 = 0; /* 1 => -q 1 or -q 12 or -q 21 given */
-int quiet_host2 = 0; /* 1 => -q 2 or -q 12 or -q 21 given */
-int s_flag = 0; /* max group size (length), 0 => do not check */
-int t_host1_flag = 0; /* 1 => -t 1 or -t 12 or -t 21 given */
-int t_host2_flag = 1; /* 1 => -t 2 or -d 12 or -t 21 given */
-int no_new_hier = 0; /* 1 => -T; no new hierarchies */
-int host2_hilow_newgrp = 0; /* 1 => use host2 hi/low on new groups */
-int host2_hilow_all = 0; /* 1 => use host2 hi/low on all groups */
-int host1_ign_print = 0; /* 1 => print host1 ignored groups too */
-int v_flag = 0; /* default verbosity level */
-int z_flag = 4; /* sleep z_flag sec per exec if -o x */
-int A_flag = 0;
-
-/* forward declarations */
-static struct grp *get_active(); /* get an active file from a remote host */
-static int bad_grpname(); /* test if string is a valid group name */
-static struct pat *get_ignore(); /* read in an ignore file */
-static void ignore(); /* ignore newsgroups given an ignore list */
-static int merge_cmp(); /* qsort compare for active file merge */
-static void merge_grps(); /* merge groups from active files */
-static int active_cmp(); /* qsort compare for active file output */
-static void output_grps(); /* output the merged groups */
-static void process_args(); /* process command line arguments */
-static void error_mark(); /* mark for removal, error grps from host */
-static int eq_merge_cmp(); /* qsort compare for =type grp processing */
-static int mark_eq_probs(); /* mark =type problems from a host */
-static int exec_cmd(); /* exec a ctlinnd command */
-static int new_top_hier(); /* see if we have a new top level */
-
-int
-main(argc, argv)
- int argc; /* arg count */
- char *argv[]; /* the args */
-{
- struct grp *grp; /* struct grp array for host1 & host2 */
- struct pat *ignor; /* ignore list from ignore file */
- int grplen; /* length of host1/host2 group array */
- int iglen; /* length of ignore list */
- char *host1; /* host to change */
- char *host2; /* comparison host */
-
- /* First thing, set up our identity. */
- message_program_name = "actsync";
-
- /* Read in default info from inn.conf. */
- if (!innconf_read(NULL))
- exit(1);
- process_args(argc, argv, &host1, &host2);
-
- /* obtain the active files */
- grp = get_active(host1, HOSTID1, &grplen, NULL, &host1_errs);
- grp = get_active(host2, HOSTID2, &grplen, grp, &host2_errs);
-
- /* ignore groups from both active files, if -i */
- if (ign_file != NULL) {
-
- /* read in the ignore file */
- ignor = get_ignore(ign_file, &iglen);
-
- /* ignore groups */
- ignore(grp, grplen, ignor, iglen);
- }
-
- /* compare groups from both hosts */
- merge_grps(grp, grplen, host1, host2);
-
- /* mark for removal, error groups from host1 if -e */
- if (! k_flag) {
-
- /* mark error groups for removal */
- error_mark(grp, grplen, HOSTID1);
- }
-
- /* output result of merge */
- output_grps(grp, grplen);
-
- /* all done */
- exit(0);
-}
-
-/*
- * process_args - process the command line arguments
- *
- * given:
- * argc arg count
- * argv the args
- * host1 name of first host (may be 2nd if -R)
- * host2 name of second host2 *may be 1st if -R)
- */
-static void
-process_args(argc, argv, host1, host2)
- int argc; /* arg count */
- char *argv[]; /* the arg array */
- char **host1; /* where to place name of host1 */
- char **host2; /* where to place name of host2 */
-{
- char *def_serv = NULL; /* name of default server */
- int i;
-
- /* parse args */
- while ((i = getopt(argc,argv,"Ab:d:g:i:I:kl:mn:o:p:q:s:t:Tv:z:")) != EOF) {
- switch (i) {
- case 'A':
- A_flag = 1;
- break;
- case 'b': /* -b {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- bork_host1_flag = 0;
- bork_host2_flag = 0;
- break;
- case 1:
- bork_host1_flag = 1;
- break;
- case 2:
- bork_host2_flag = 1;
- break;
- case 12:
- case 21:
- bork_host1_flag = 1;
- bork_host2_flag = 1;
- break;
- default:
- warn("-b option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 'd': /* -d {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- num_host1_flag = 0;
- num_host2_flag = 0;
- break;
- case 1:
- num_host1_flag = 1;
- break;
- case 2:
- num_host2_flag = 1;
- break;
- case 12:
- case 21:
- num_host1_flag = 1;
- num_host2_flag = 1;
- break;
- default:
- warn("-d option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 'g': /* -g max */
- g_flag = atoi(optarg);
- break;
- case 'i': /* -i ignore_file */
- ign_file = optarg;
- break;
- case 'I': /* -I {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- ign_host1_flag = 0;
- ign_host2_flag = 0;
- break;
- case 1:
- ign_host1_flag = 1;
- ign_host2_flag = 0;
- break;
- case 2:
- ign_host1_flag = 0;
- ign_host2_flag = 1;
- break;
- case 12:
- case 21:
- ign_host1_flag = 1;
- ign_host2_flag = 1;
- break;
- default:
- warn("-I option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 'k': /* -k */
- k_flag = 1;
- break;
- case 'l': /* -l {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- l_host1_flag = NOHOST;
- l_host2_flag = NOHOST;
- break;
- case 1:
- l_host1_flag = HOSTID1;
- l_host2_flag = NOHOST;
- break;
- case 2:
- l_host1_flag = NOHOST;
- l_host2_flag = HOSTID2;
- break;
- case 12:
- case 21:
- l_host1_flag = HOSTID1;
- l_host2_flag = HOSTID2;
- break;
- default:
- warn("-l option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 'm': /* -m */
- m_flag = 1;
- break;
- case 'n': /* -n name */
- new_name = optarg;
- break;
- case 'o': /* -o out_type */
- switch (optarg[0]) {
- case 'a':
- o_flag = OUTPUT_ACTIVE;
- switch (optarg[1]) {
- case '1':
- switch(optarg[2]) {
- case 'K': /* -o a1K */
- host1_ign_print = 1;
- host2_hilow_all = 1;
- host2_hilow_newgrp = 1;
- break;
- case 'k': /* -o a1k */
- host1_ign_print = 1;
- host2_hilow_newgrp = 1;
- break;
- default: /* -o a1 */
- host1_ign_print = 1;
- break;
- }
- break;
- case 'K':
- switch(optarg[2]) {
- case '1': /* -o aK1 */
- host1_ign_print = 1;
- host2_hilow_all = 1;
- host2_hilow_newgrp = 1;
- break;
- default: /* -o aK */
- host2_hilow_all = 1;
- host2_hilow_newgrp = 1;
- break;
- };
- break;
- case 'k':
- switch(optarg[2]) {
- case '1': /* -o ak1 */
- host1_ign_print = 1;
- host2_hilow_newgrp = 1;
- break;
- default: /* -o ak */
- host2_hilow_newgrp = 1;
- break;
- };
- break;
- case '\0': /* -o a */
- break;
- default:
- warn("-o type must be a, a1, ak, aK, ak1, or aK1");
- die("%s", usage);
- }
- break;
- case 'c':
- o_flag = OUTPUT_CTLINND;
- break;
- case 'x':
- if (optarg[1] == 'i') {
- o_flag = OUTPUT_IEXEC;
- } else {
- o_flag = OUTPUT_EXEC;
- }
- break;
- default:
- warn("-o type must be a, a1, ak, aK, ak1, aK1, c, x, or xi");
- die("%s", usage);
- }
- break;
- case 'p': /* -p %_min_host1_change */
- /* parse % into [0,100] */
- p_flag = atof(optarg);
- if (p_flag > (double)100.0) {
- p_flag = (double)100.0;
- } else if (p_flag < (double)0.0) {
- p_flag = (double)0.0;
- }
- break;
- case 'q': /* -q {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- quiet_host1 = 0;
- quiet_host2 = 0;
- break;
- case 1:
- quiet_host1 = 1;
- break;
- case 2:
- quiet_host2 = 1;
- break;
- case 12:
- case 21:
- quiet_host1 = 1;
- quiet_host2 = 1;
- break;
- default:
- warn("-q option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 's': /* -s size */
- s_flag = atoi(optarg);
- break;
- case 't': /* -t {0|1|2|12|21} */
- switch (atoi(optarg)) {
- case 0:
- t_host1_flag = NOHOST;
- t_host2_flag = NOHOST;
- break;
- case 1:
- t_host1_flag = HOSTID1;
- t_host2_flag = NOHOST;
- break;
- case 2:
- t_host1_flag = NOHOST;
- t_host2_flag = HOSTID2;
- break;
- case 12:
- case 21:
- t_host1_flag = HOSTID1;
- t_host2_flag = HOSTID2;
- break;
- default:
- warn("-t option must be 0, 1, 2, 12, or 21");
- die("%s", usage);
- }
- break;
- case 'T': /* -T */
- no_new_hier = 1;
- break;
- case 'v': /* -v verbose_lvl */
- v_flag = atoi(optarg);
- if (v_flag < VER_MIN || v_flag > VER_MAX) {
- warn("-v level must be >= %d and <= %d", VER_MIN, VER_MAX);
- die("%s", usage);
- }
- break;
- case 'z': /* -z sec */
- z_flag = atoi(optarg);
- break;
- default:
- warn("unknown flag");
- die("%s", usage);
- }
- }
-
- /* process the remaining args */
- argc -= optind;
- argv += optind;
- *host1 = NULL;
- switch (argc) {
- case 1:
- /* assume host1 is the local server */
- *host2 = argv[0];
- break;
- case 2:
- *host1 = argv[0];
- *host2 = argv[1];
- break;
- default:
- warn("expected 1 or 2 host args, found %d", argc);
- die("%s", usage);
- }
-
- /* determine default host name if needed */
- if (*host1 == NULL || strcmp(*host1, "-") == 0) {
- def_serv = innconf->server;
- *host1 = def_serv;
- }
- if (*host2 == NULL || strcmp(*host2, "-") == 0) {
- def_serv = innconf->server;
- *host2 = def_serv;
- }
- if (*host1 == NULL || *host2 == NULL)
- die("unable to determine default server name");
- if (D_BUG && def_serv != NULL)
- warn("STATUS: using default server: %s", def_serv);
-
- /* processing done */
- return;
-}
-
-/*
- * get_active - get an active file from a host
- *
- * given:
- * host host to contact or file to read, NULL => local server
- * hostid HOST_ID of host
- * len pointer to length of grp return array
- * grp existing host array to add, or NULL
- * errs count of lines that were found to have some error
- *
- * returns;
- * Pointer to an array of grp structures describing each active entry.
- * Does not return on fatal error.
- *
- * If host starts with a '/' or '.', then it is assumed to be a local file.
- * In that case, the local file is opened and read.
- */
-static struct grp *
-get_active(host, hostid, len, grp, errs)
- char *host; /* the host to contact */
- int hostid; /* HOST_ID of host */
- int *len; /* length of returned grp array in elements */
- struct grp* grp; /* existing group array or NULL */
- int *errs; /* line error count */
-{
- FILE *active; /* stream for fetched active data */
- FILE *FromServer; /* stream from server */
- FILE *ToServer; /* stream to server */
- QIOSTATE *qp; /* QIO active state */
- char buff[8192+1]; /* QIO buffer */
- char *line; /* the line just read */
- struct grp *ret; /* array of groups to return */
- struct grp *cur; /* current grp entry being formed */
- int max; /* max length of ret */
- int cnt; /* number of entries read */
- int ucnt; /* number of entries to be used */
- int namelen; /* length of newsgroup name */
- int is_file; /* 1 => host is actually a filename */
- int num_check; /* true => check for all numeric components */
- char *rhost;
- int rport;
- char *p;
- int i;
-
- /* firewall */
- if (len == NULL)
- die("internal error #1: len is NULL");
- if (errs == NULL)
- die("internal error #2: errs in NULL");
- if (D_BUG)
- warn("STATUS: obtaining active file from %s", host);
-
- /* setup return array if needed */
- if (grp == NULL) {
- ret = xmalloc(CHUNK * sizeof(struct grp));
- max = CHUNK;
- *len = 0;
-
- /* or prep to use the existing array */
- } else {
- ret = grp;
- max = ((*len + CHUNK-1)/CHUNK)*CHUNK;
- }
-
- /* check for host being a filename */
- if (host != NULL && (host[0] == '/' || host[0] == '.')) {
-
- /* note that host is actually a file */
- is_file = 1;
-
- /* setup to read the local file quickly */
- if ((qp = QIOopen(host)) == NULL)
- sysdie("cannot open active file");
-
- /* case: host is a hostname or NULL (default server) */
- } else {
-
- /* note that host is actually a hostname or NULL */
- is_file = 0;
-
- /* prepare remote host variables */
- if ((p = strchr(host, ':')) != NULL) {
- rport = atoi(p + 1);
- *p = '\0';
- rhost = xstrdup(host);
- *p = ':';
- } else {
- rhost = xstrdup(host);
- rport = NNTP_PORT;
- }
-
- /* open a connection to the server */
- buff[0] = '\0';
- if (NNTPconnect(rhost, rport, &FromServer, &ToServer, buff) < 0)
- die("cannot connect to server: %s",
- buff[0] ? buff : strerror(errno));
-
- if (A_flag && NNTPsendpassword(rhost, FromServer, ToServer) < 0)
- die("cannot authenticate to server");
-
- free(rhost);
-
- /* get the active data from the server */
- active = CAlistopen(FromServer, ToServer, NULL);
- if (active == NULL)
- sysdie("cannot retrieve data");
-
- /* setup to read the retrieved data quickly */
- if ((qp = QIOfdopen((int)fileno(active))) == NULL)
- sysdie("cannot read temp file");
- }
-
- /* scan server's output, processing appropriate lines */
- num_check = NUM_CHECK(hostid);
- for (cnt=0, ucnt=0; (line = QIOread(qp)) != NULL; ++(*len), ++cnt) {
-
- /* expand return array if needed */
- if (*len >= max) {
- max += CHUNK;
- ret = xrealloc(ret, sizeof(struct grp) * max);
- }
-
- /* setup the next return element */
- cur = &ret[*len];
- cur->ignore = NOT_IGNORED;
- cur->hostid = hostid;
- cur->linenum = cnt+1;
- cur->output = 0;
- cur->remove = 0;
- cur->name = NULL;
- cur->hi = NULL;
- cur->low = NULL;
- cur->type = NULL;
- cur->outhi = NULL;
- cur->outlow = NULL;
- cur->outtype = NULL;
-
- /* obtain a copy of the current line */
- cur->name = xstrdup(line);
-
- /* get the group name */
- if ((p = strchr(cur->name, ' ')) == NULL) {
- if (!QUIET(hostid))
- warn("line %d from %s is malformed, skipping line", cnt + 1,
- host);
-
- /* don't form an entry for this group */
- --(*len);
- continue;
- }
- *p = '\0';
- namelen = p - cur->name;
-
- /* find the other 3 fields, ignore if not found */
- cur->hi = p+1;
- if ((p = strchr(p + 1, ' ')) == NULL) {
- if (!QUIET(hostid))
- warn("skipping malformed line %d (field 2) from %s", cnt + 1,
- host);
-
- /* don't form an entry for this group */
- --(*len);
- continue;
- }
- *p = '\0';
- cur->low = p+1;
- if ((p = strchr(p + 1, ' ')) == NULL) {
- if (!QUIET(hostid))
- warn("skipping malformed line %d (field 3) from %s", cnt + 1,
- host);
-
- /* don't form an entry for this group */
- --(*len);
- continue;
- }
- *p = '\0';
- cur->type = p+1;
- if ((p = strchr(p + 1, ' ')) != NULL) {
- if (!QUIET(hostid))
- warn("skipping line %d from %s, it has more than 4 fields",
- cnt + 1, host);
-
- /* don't form an entry for this group */
- --(*len);
- continue;
- }
-
- /* check for bad group name */
- if (bad_grpname(cur->name, num_check)) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has a bad newsgroup name",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADNAME;
- continue;
- }
-
- /* check for long name if requested */
- if (s_flag > 0 && strlen(cur->name) > (size_t)s_flag) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has a name that is too long",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADNAME;
- continue;
- }
-
- /* look for only a bad top level element if the proper -t was given */
- if (TOP_CHECK(hostid)) {
-
- /* look for a '.' in the name */
- if (strcmp(cur->name, "junk") != 0 &&
- strcmp(cur->name, "control") != 0 &&
- strcmp(cur->name, "to") != 0 &&
- strcmp(cur->name, "test") != 0 &&
- strcmp(cur->name, "general") != 0 &&
- strchr(cur->name, '.') == NULL) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s is an invalid top level name",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADNAME;
- continue;
- }
- }
-
- /* look for *.bork.bork.bork groups if the proper -b was given */
- if (BORK_CHECK(cur->hostid)) {
- int elmlen; /* length of element */
- char *q; /* beyond end of element */
-
- /* scan the name backwards */
- q = &(cur->name[namelen]);
- for (p = &(cur->name[namelen-1]); p >= cur->name; --p) {
- /* if '.', see if this is a bork element */
- if (*p == '.') {
- /* see if the bork element is short enough */
- elmlen = q-p;
- if (3*elmlen <= q-cur->name) {
- /* look for a triple match */
- if (strncmp(p,p-elmlen,elmlen) == 0 &&
- strncmp(p,p-(elmlen*2),elmlen) == 0) {
- /* found a *.bork.bork.bork group */
- cur->ignore |= CHECK_BORK;
- break;
- }
- }
- /* note the end of a new element */
- q = p;
- }
- }
- }
-
- /*
- * check for bad chars in the hi water mark
- */
- for (p=cur->hi, i=0; *p && isascii(*p) && isdigit((int)*p); ++p, ++i) {
- }
- if (*p) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has non-digits in hi water",
- cnt + 1, cur->name, cur->hi);
- cur->ignore |= ERROR_FORMAT;
- continue;
- }
-
- /*
- * check for excessive hi water length
- */
- if (i > WATER_LEN) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s hi water len: %d < %d",
- cnt + 1, cur->name, cur->hi, i, WATER_LEN);
- cur->ignore |= ERROR_FORMAT;
- continue;
- }
-
- /*
- * if the hi water length is too small, malloc and resize
- */
- if (i != WATER_LEN) {
- p = xmalloc(WATER_LEN + 1);
- memcpy(p, cur->hi, ((i > WATER_LEN) ? WATER_LEN : i)+1);
- }
-
- /*
- * check for bad chars in the low water mark
- */
- for (p=cur->low, i=0; *p && isascii(*p) && isdigit((int)*p); ++p, ++i) {
- }
- if (*p) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has non-digits in low water",
- cnt + 1, cur->name, cur->low);
- cur->ignore |= ERROR_FORMAT;
- continue;
- }
-
- /*
- * check for excessive low water length
- */
- if (i > WATER_LEN) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s low water len: %d < %d",
- cnt + 1, cur->name, cur->hi, i, WATER_LEN);
- cur->ignore |= ERROR_FORMAT;
- continue;
- }
-
- /*
- * if the low water length is too small, malloc and resize
- */
- if (i != WATER_LEN) {
- p = xmalloc(WATER_LEN + 1);
- memcpy(p, cur->low, ((i > WATER_LEN) ? WATER_LEN : i)+1);
- }
-
- /* check for a bad group type */
- switch (cur->type[0]) {
- case 'y':
- /* of COURSE: collabra has incompatible flags. but it */
- /* looks like they can be fixed easily enough. */
- if (cur->type[1] == 'g') {
- cur->type[1] = '\0';
- }
- case 'm':
- case 'j':
- case 'n':
- case 'x':
- if (cur->type[1] != '\0') {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has a bad newsgroup type",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADTYPE;
- }
- break;
- case '=':
- if (cur->type[1] == '\0') {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has an empty =group name",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADTYPE;
- }
- break;
- default:
- if (!QUIET(hostid))
- warn("line %d <%s> from %s has an unknown newsgroup type",
- cnt + 1, cur->name, host);
- cur->ignore |= ERROR_BADTYPE;
- break;
- }
- if (cur->ignore & ERROR_BADTYPE) {
- continue;
- }
-
- /* if an = type, check for bad = name */
- if (cur->type[0] == '=' && bad_grpname(&(cur->type[1]), num_check)) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s is equivalenced to a bad name:"
- " <%s>", cnt+1, cur->name, host,
- (cur->type) ? cur->type : "NULL");
- cur->ignore |= ERROR_EQNAME;
- continue;
- }
-
- /* if an = type, check for long = name if requested */
- if (cur->type[0] == '=' && s_flag > 0 &&
- strlen(&(cur->type[1])) > (size_t)s_flag) {
- if (!QUIET(hostid))
- warn("line %d <%s> from %s is equivalenced to a long name:"
- " <%s>", cnt+1, cur->name, host,
- (cur->type) ? cur->type : "NULL");
- cur->ignore |= ERROR_EQNAME;
- continue;
- }
-
- /* count this entry which will be used */
- ++ucnt;
- }
- if (D_BUG)
- warn("STATUS: read %d groups, will merge %d groups from %s",
- cnt, ucnt, host);
-
- /* count the errors */
- *errs = cnt - ucnt;
- if (D_BUG)
- warn("STATUS: found %d line errors from %s", *errs, host);
-
- /* determine why we stopped */
- if (QIOerror(qp))
- sysdie("cannot read temp file for %s at line %d", host, cnt);
- else if (QIOtoolong(qp))
- sysdie("line %d from host %s is too long", cnt, host);
-
- /* all done */
- if (is_file) {
- QIOclose(qp);
- } else {
- CAclose();
- fprintf(ToServer, "quit\r\n");
- fclose(ToServer);
- fgets(buff, sizeof buff, FromServer);
- fclose(FromServer);
- }
- return ret;
-}
-
-/*
- * bad_grpname - test if the string is a valid group name
- *
- * Newsgroup names must consist of only alphanumeric chars and
- * characters from the following regular expression:
- *
- * [.+-_]
- *
- * One cannot have two '.'s in a row. The first character must be
- * alphanumeric. The character following a '.' must be alphanumeric.
- * The name cannot end in a '.' character.
- *
- * If we are checking for all numeric compnents, (see num_chk) then
- * a component cannot be all numeric. I.e,. there must be a non-numeric
- * character in the name, there must be a non-numeric character between
- * the start and the first '.', there must be a non-numeric character
- * between two '.'s anmd there must be a non-numeric character between
- * the last '.' and the end.
- *
- * given:
- * name newsgroup name to check
- * num_chk true => all numeric newsgroups components are invalid
- * false => do not check for numeric newsgroups
- *
- * returns:
- * 0 group is ok
- * 1 group is bad
- */
-static int
-bad_grpname(name, num_chk)
- char *name; /* newsgroup name to check */
- int num_chk; /* true => check for numeric newsgroup */
-{
- char *p;
- int non_num; /* true => found a non-numeric, non-. character */
- int level; /* group levels (.'s) */
-
- /* firewall */
- if (name == NULL) {
- return 1;
- }
-
- /* must start with a alpha numeric ascii character */
- if (!isascii(name[0])) {
- return 1;
- }
- /* set non_num as needed */
- if (isalpha((int)name[0])) {
- non_num = true;
- } else if ((int)isdigit((int)name[0])) {
- non_num = false;
- } else {
- return 1;
- }
-
- /* scan each char */
- level = 0;
- for (p=name+1; *p; ++p) {
-
- /* name must contain ASCII chars */
- if (!isascii(*p)) {
- return 1;
- }
-
- /* alpha chars are ok */
- if (isalpha((int)*p)) {
- non_num = true;
- continue;
- }
-
- /* numeric chars are ok */
- if (isdigit((int)*p)) {
- continue;
- }
-
- /* +, - and _ are ok */
- if (*p == '+' || *p == '-' || *p == '_') {
- non_num = true;
- continue;
- }
-
- /* check for the '.' case */
- if (*p == '.') {
- /*
- * look for groups that are too deep, if requested by -g
- */
- if (g_flag > 0 && ++level > g_flag) {
- /* we are too deep */
- return 1;
- }
-
- /*
- * A '.' is ok as long as the next character is alphanumeric.
- * This imples that '.' cannot before a previous '.' and
- * that it cannot be at the end.
- *
- * If we are checking for all numeric compnents, then
- * '.' is ok if we saw a non-numeric char before the
- * last '.', or before the beginning if no previous '.'
- * has been seen.
- */
- if ((!num_chk || non_num) && isascii(*(p+1)) && isalnum((int)*(p+1))) {
- ++p; /* '.' is ok, and so is the next char */
- if (isdigit((int)*p)) { /* reset non_num as needed */
- non_num = false;
- } else {
- non_num = true;
- }
- continue;
- }
- }
-
- /* this character must be invalid */
- return 1;
- }
- if (num_chk && !non_num) {
- /* last component is all numeric */
- return 1;
- }
-
- /* the name must be ok */
- return 0;
-}
-
-/*
- * get_ignore - get the ignore list from an ignore file
- *
- * given:
- * filename name of the ignore file to read
- * *len pointer to length of ignore return array
- *
- * returns:
- * returns a malloced ignore pattern array, changes len
- *
- * An ignore file is of the form:
- *
- * # this is a comment which is ignored
- * # comments begin at the first # character
- * # comments may follow text on the same line
- *
- * # blank lines are ignored too
- *
- * # lines are [ic] <spaces-tabs> pattern [<spaces-tabs> type] ...
- * i foo.* # ignore foo.* groups,
- * c foo.bar m # but check foo.bar if moderated
- * c foo.keep.* # and check foo.keep.*
- * i foo.keep.* j =alt.* # except when foo.keep.* is junked
- * # or equivalenced to an alt.* group
- *
- * The 'i' value means ignore, 'c' value means 'compare'. The last pattern
- * that matches a group determines the fate of the group. By default all
- * groups are included.
- *
- * NOTE: Only one '=name' is allowed per line.
- * "=" is considered to be equivalent to "=*".
- */
-static struct pat *
-get_ignore(filename, len)
- char *filename; /* name of the ignore file to read */
- int *len; /* length of return array */
-{
- QIOSTATE *qp; /* QIO ignore file state */
- char *line; /* the line just read */
- struct pat *ret; /* array of ignore patterns to return */
- struct pat *cur; /* current pattern entry being formed */
- int max; /* max length (in elements) of ret */
- int linenum; /* current line number */
- char *p;
- int i;
-
- /* firewall */
- if (filename == NULL)
- die("internal error #3: filename is NULL");
- if (len == NULL)
- die("internal error #4: len is NULL");
- if (D_BUG)
- warn("STATUS: reading ignore file %s", filename);
-
- /* setup return array */
- ret = xmalloc(CHUNK * sizeof(struct grp));
- max = CHUNK;
-
- /* setup to read the ignore file data quickly */
- if ((qp = QIOopen(filename)) == NULL)
- sysdie("cannot read ignore file %s", filename);
-
- /* scan server's output, displaying appropriate lines */
- *len = 0;
- for (linenum = 1; (line = QIOread(qp)) != NULL; ++linenum) {
-
- /* expand return array if needed */
- if (*len >= max) {
- max += CHUNK;
- ret = xrealloc(ret, sizeof(struct pat) * max);
- }
-
- /* remove any trailing comments */
- p = strchr(line, '#');
- if (p != NULL) {
- *p = '\0';
- }
-
- /* remove any trailing spaces and tabs */
- for (p = &line[strlen(line)-1];
- p >= line && (*p == ' ' || *p == '\t');
- --p) {
- *p = '\0';
- }
-
- /* ignore line if the remainder of the line is empty */
- if (line[0] == '\0') {
- continue;
- }
-
- /* ensure that the line starts with an i or c token */
- if ((line[0] != 'i' && line[0] != 'c') ||
- (line[1] != ' ' && line[1] != '\t'))
- die("first token is not i or c in line %d of %s", linenum,
- filename);
-
- /* ensure that the second newsgroup pattern token follows */
- p = strtok(line+2, " \t");
- if (p == NULL)
- die("did not find 2nd field in line %d of %s", linenum,
- filename);
-
- /* setup the next return element */
- cur = &ret[*len];
- cur->pat = NULL;
- cur->type_match = 0;
- cur->y_type = 0;
- cur->m_type = 0;
- cur->n_type = 0;
- cur->j_type = 0;
- cur->x_type = 0;
- cur->eq_type = 0;
- cur->epat = NULL;
- cur->ignore = (line[0] == 'i');
-
- /* obtain a copy of the newsgroup pattern token */
- cur->pat = xstrdup(p);
-
- /* process any other type tokens */
- for (p=strtok(NULL, " \t"), i=3;
- p != NULL;
- p=strtok(NULL, " \t"), ++i) {
-
- /* ensure that this next token is a valid type */
- switch (p[0]) {
- case 'y':
- case 'm':
- case 'j':
- case 'n':
- case 'x':
- if (p[1] != '\0') {
- warn("field %d on line %d of %s not a valid type",
- i, linenum, filename);
- die("valid types are a char from [ymnjx=] or =name");
- }
- break;
- case '=':
- break;
- default:
- warn("field %d on line %d of %s is not a valid type",
- i, linenum, filename);
- die("valid types are a char from [ymnjx=] or =name");
- }
-
- /* note that we have a type specific pattern */
- cur->type_match = 1;
-
- /* ensure that type is not a duplicate */
- if ((p[0] == 'y' && cur->y_type) ||
- (p[0] == 'm' && cur->m_type) ||
- (p[0] == 'n' && cur->n_type) ||
- (p[0] == 'j' && cur->j_type) ||
- (p[0] == 'x' && cur->x_type) ||
- (p[0] == '=' && cur->eq_type)) {
- warn("only one %c type allowed per line", p[0]);
- die("field %d on line %d of %s is a duplicate type",
- i, linenum, filename);
- }
-
- /* note what we have seen */
- switch (p[0]) {
- case 'y':
- cur->y_type = 1;
- break;
- case 'm':
- cur->m_type = 1;
- break;
- case 'j':
- cur->j_type = 1;
- break;
- case 'n':
- cur->n_type = 1;
- break;
- case 'x':
- cur->x_type = 1;
- break;
- case '=':
- cur->eq_type = 1;
- if (p[0] == '=' && p[1] != '\0')
- cur->epat = xstrdup(p + 1);
- break;
- }
-
- /* object if too many fields */
- if (i-3 > TYPECNT)
- die("too many fields on line %d of %s", linenum, filename);
- }
-
- /* count another pat element */
- ++(*len);
- }
-
- /* return the pattern array */
- return ret;
-}
-
-/*
- * ignore - ignore newsgroups given an ignore list
- *
- * given:
- * grp array of groups
- * grplen length of grp array in elements
- * igcl array of ignore
- * iglen length of igcl array in elements
- */
-static void
-ignore(grp, grplen, igcl, iglen)
- struct grp *grp; /* array of groups */
- int grplen; /* length of grp array in elements */
- struct pat *igcl; /* array of ignore patterns */
- int iglen; /* length of igcl array in elements */
-{
- struct grp *gp; /* current group element being examined */
- struct pat *pp; /* current pattern element being examined */
- int g; /* current group index number */
- int p; /* current pattern index number */
- int ign; /* 1 => ignore this group, 0 => check it */
- int icnt; /* groups ignored */
- int ccnt; /* groups to be checked */
-
- /* firewall */
- if (grp == NULL)
- die("internal error #5: grp is NULL");
- if (igcl == NULL)
- die("internal error $6: igcl is NULL");
- if (D_BUG)
- warn("STATUS: determining which groups to ignore");
-
- /* if nothing to do, return quickly */
- if (grplen <= 0 || iglen <= 0) {
- return;
- }
-
- /* examine each group */
- icnt = 0;
- ccnt = 0;
- for (g=0; g < grplen; ++g) {
-
- /* check the group to examine */
- gp = &grp[g];
- if (gp->ignore) {
- /* already ignored no need to examine */
- continue;
- }
-
- /* check group against all patterns */
- ign = 0;
- for (p=0, pp=igcl; p < iglen; ++p, ++pp) {
-
- /* if pattern has a specific type, check it first */
- if (pp->type_match) {
-
- /* specific type required, check for match */
- switch (gp->type[0]) {
- case 'y':
- if (! pp->y_type) continue; /* pattern does not apply */
- break;
- case 'm':
- if (! pp->m_type) continue; /* pattern does not apply */
- break;
- case 'n':
- if (! pp->n_type) continue; /* pattern does not apply */
- break;
- case 'j':
- if (! pp->j_type) continue; /* pattern does not apply */
- break;
- case 'x':
- if (! pp->x_type) continue; /* pattern does not apply */
- break;
- case '=':
- if (! pp->eq_type) continue; /* pattern does not apply */
- if (pp->epat != NULL && !uwildmat(&gp->type[1], pp->epat)) {
- /* equiv pattern doesn't match, patt does not apply */
- continue;
- }
- break;
- }
- }
-
- /* perform a match on group name */
- if (uwildmat(gp->name, pp->pat)) {
- /* this pattern fully matches, use the ignore value */
- ign = pp->ignore;
- }
- }
-
- /* if this group is to be ignored, note it */
- if (ign) {
- switch (gp->hostid) {
- case HOSTID1:
- if (ign_host1_flag) {
- gp->ignore |= CHECK_IGNORE;
- ++icnt;
- }
- break;
- case HOSTID2:
- if (ign_host2_flag) {
- gp->ignore |= CHECK_IGNORE;
- ++icnt;
- }
- break;
- default:
- die("newsgroup %s bad hostid: %d", gp->name, gp->hostid);
- }
- } else {
- ++ccnt;
- }
- }
- if (D_BUG)
- warn("STATUS: examined %d groups: %d ignored, %d to be checked",
- grplen, icnt, ccnt);
-}
-
-/*
- * merge_cmp - qsort compare function for later group merge
- *
- * given:
- * a group a to compare
- * b group b to compare
- *
- * returns:
- * >0 a > b
- * 0 a == b elements match (fatal error if a and b are different)
- * <0 a < b
- *
- * To speed up group comparison, we compare by the following items listed
- * in order of sorting:
- *
- * group name
- * hostid (host1 ahead of host2)
- * linenum (active file line number)
- */
-static int
-merge_cmp(arg_a, arg_b)
- const void *arg_a; /* first qsort compare arg */
- const void *arg_b; /* first qsort compare arg */
-{
- const struct grp *a = arg_a; /* group a to compare */
- const struct grp *b = arg_b; /* group b to compare */
- int i;
-
- /* firewall */
- if (a == b) {
- /* we guess this could happen */
- return(0);
- }
-
- /* compare group names */
- i = strcmp(a->name, b->name);
- if (i != 0) {
- return i;
- }
-
- /* compare hostid's */
- if (a->hostid != b->hostid) {
- if (a->hostid > b->hostid) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* compare active line numbers */
- if (a->linenum != b->linenum) {
- if (a->linenum > b->linenum) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* two different elements match, this should not happen! */
- die("two internal grp elements match!");
- /*NOTREACHED*/
-}
-
-/*
- * merge_grps - compare groups from both hosts
- *
- * given:
- * grp array of groups
- * grplen length of grp array in elements
- * host1 name of host with HOSTID1
- * host2 name of host with HOSTID2
- *
- * This routine will select which groups to output form a merged active file.
- */
-static void
-merge_grps(grp, grplen, host1, host2)
- struct grp *grp; /* array of groups */
- int grplen; /* length of grp array in elements */
- char *host1; /* name of host with HOSTID1 */
- char *host2; /* name of host with HOSTID2 */
-{
- int cur; /* current group index being examined */
- int nxt; /* next group index being examined */
- int outcnt; /* groups to output */
- int rmcnt; /* groups to remove */
- int h1_probs; /* =type problem groups from host1 */
- int h2_probs; /* =type problem groups from host2 */
-
- /* firewall */
- if (grp == NULL)
- die("internal error #7: grp is NULL");
-
- /* sort groups for the merge */
- if (D_BUG)
- warn("STATUS: sorting groups");
- qsort((char *)grp, grplen, sizeof(grp[0]), merge_cmp);
-
- /* mark =type problem groups from host2, if needed */
- h2_probs = mark_eq_probs(grp, grplen, l_host2_flag, host1, host2);
-
- /*
- * We will walk thru the sorted group array, looking for pairs
- * among the groups that we have not already ignored.
- *
- * If a host has duplicate groups, then the duplicates will
- * be next to each other.
- *
- * If both hosts have the name group, they will be next to each other.
- */
- if (D_BUG)
- warn("STATUS: merging groups");
- outcnt = 0;
- rmcnt = 0;
- for (cur=0; cur < grplen; cur=nxt) {
-
- /* determine the next group index */
- nxt = cur+1;
-
- /* skip if this group is ignored */
- if (grp[cur].ignore) {
- continue;
- }
- /* assert: cur is not ignored */
-
- /* check for duplicate groups from the same host */
- while (nxt < grplen) {
-
- /* mark the later as a duplicate */
- if (grp[cur].hostid == grp[nxt].hostid &&
- strcmp(grp[cur].name, grp[nxt].name) == 0) {
- grp[nxt].ignore |= ERROR_DUP;
- if (!QUIET(grp[cur].hostid))
- warn("lines %d and %d from %s refer to the same group",
- grp[cur].linenum, grp[nxt].linenum,
- ((grp[cur].hostid == HOSTID1) ? host1 : host2));
- ++nxt;
- } else {
- break;
- }
- }
- /* assert: cur is not ignored */
- /* assert: cur & nxt are not the same group from the same host */
-
- /* if nxt is ignored, look for the next non-ignored group */
- while (nxt < grplen && grp[nxt].ignore) {
- ++nxt;
- }
- /* assert: cur is not ignored */
- /* assert: nxt is not ignored or is beyond end */
- /* assert: cur & nxt are not the same group from the same host */
-
- /* case: cur and nxt are the same group */
- if (nxt < grplen && strcmp(grp[cur].name, grp[nxt].name) == 0) {
-
- /* assert: cur is HOSTID1 */
- if (grp[cur].hostid != HOSTID1)
- die("internal error #8: grp[%d].hostid: %d != %d",
- cur, grp[cur].hostid, HOSTID1);
-
- /*
- * Both hosts have the same group. Make host1 group type
- * match host2. (it may already)
- */
- grp[cur].output = 1;
- grp[cur].outhi = (host2_hilow_all ? grp[nxt].hi : grp[cur].hi);
- grp[cur].outlow = (host2_hilow_all ? grp[nxt].low : grp[cur].low);
- grp[cur].outtype = grp[nxt].type;
- ++outcnt;
-
- /* do not process nxt, skip to the one beyond */
- ++nxt;
-
- /* case: cur and nxt are different groups */
- } else {
-
- /*
- * if cur is host2, then host1 doesn't have it, so output it
- */
- if (grp[cur].hostid == HOSTID2) {
- grp[cur].output = 1;
- grp[cur].outhi = (host2_hilow_newgrp ? grp[cur].hi : DEF_HI);
- grp[cur].outlow = (host2_hilow_newgrp ? grp[cur].low : DEF_LOW);
- grp[cur].outtype = grp[cur].type;
- ++outcnt;
-
- /*
- * If cur is host1, then host2 doesn't have it.
- * Mark for removal if -m was not given.
- */
- } else {
- grp[cur].output = 1;
- grp[cur].outhi = grp[cur].hi;
- grp[cur].outlow = grp[cur].low;
- grp[cur].outtype = grp[cur].type;
- if (! m_flag) {
- grp[cur].remove = 1;
- ++rmcnt;
- }
- }
-
- /* if no more groups to examine, we are done */
- if (nxt >= grplen) {
- break;
- }
- }
- }
-
- /* mark =type problem groups from host1, if needed */
- h1_probs = mark_eq_probs(grp, grplen, l_host1_flag, host1, host2);
-
- /* all done */
- if (D_BUG) {
- warn("STATUS: sort-merge passed thru %d groups", outcnt);
- warn("STATUS: sort-merge marked %d groups for removal", rmcnt);
- warn("STATUS: marked %d =type error groups from host1", h1_probs);
- warn("STATUS: marked %d =type error groups from host2", h2_probs);
- }
- return;
-}
-
-/*
- * active_cmp - qsort compare function for active file style output
- *
- * given:
- * a group a to compare
- * b group b to compare
- *
- * returns:
- * >0 a > b
- * 0 a == b elements match (fatal error if a and b are different)
- * <0 a < b
- *
- * This sort will sort groups so that the lines that will we output
- * host1 lines followed by host2 lines. Thus, we will sort by
- * the following keys:
- *
- * hostid (host1 ahead of host2)
- * linenum (active file line number)
- */
-static int
-active_cmp(arg_a, arg_b)
- const void *arg_a; /* first qsort compare arg */
- const void *arg_b; /* first qsort compare arg */
-{
- const struct grp *a = arg_a; /* group a to compare */
- const struct grp *b = arg_b; /* group b to compare */
-
- /* firewall */
- if (a == b) {
- /* we guess this could happen */
- return(0);
- }
-
- /* compare hostid's */
- if (a->hostid != b->hostid) {
- if (a->hostid > b->hostid) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* compare active line numbers */
- if (a->linenum != b->linenum) {
- if (a->linenum > b->linenum) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* two different elements match, this should not happen! */
- die("two internal grp elements match!");
- /*NOTREACHED*/
-}
-
-/*
- * output_grps - output the result of the merge
- *
- * given:
- * grp array of groups
- * grplen length of grp array in elements
- */
-static void
-output_grps(grp, grplen)
- struct grp *grp; /* array of groups */
- int grplen; /* length of grp array in elements */
-{
- int add; /* number of groups added */
- int change; /* number of groups changed */
- int remove; /* number of groups removed */
- int no_new_dir; /* number of new groups with missing/empty dirs */
- int new_dir; /* number of new groupsm, non-empty dir no water chg */
- int water_change; /* number of new groups where hi&low water changed */
- int work; /* adds + changes + removals */
- int same; /* the number of groups the same */
- int ignore; /* host1 newsgroups to ignore */
- int not_done; /* exec errors and execs not performed */
- int rm_cycle; /* 1 => removals only, 0 => adds & changes only */
- int sleep_msg; /* 1 => -o x sleep message was given */
- int top_ignore; /* number of groups ignored because of no top level */
- int restore; /* host1 groups restored due to -o a1 */
- double host1_same; /* % of host1 that is the same */
- int i;
-
- /* firewall */
- if (grp == NULL)
- die("internal error #9: grp is NULL");
-
- /*
- * If -a1 was given, mark for output any host1 newsgroup that was
- * simply ignored due to the -i ign_file.
- */
- if (host1_ign_print) {
- restore = 0;
- for (i=0; i < grplen; ++i) {
- if (grp[i].hostid == HOSTID1 &&
- (grp[i].ignore == CHECK_IGNORE ||
- grp[i].ignore == CHECK_TYPE ||
- grp[i].ignore == (CHECK_IGNORE|CHECK_TYPE))) {
- /* force group to output and not be ignored */
- grp[i].ignore = 0;
- grp[i].output = 1;
- grp[i].remove = 0;
- grp[i].outhi = grp[i].hi;
- grp[i].outlow = grp[i].low;
- grp[i].outtype = grp[i].type;
- ++restore;
- }
- }
- if (D_BUG)
- warn("STATUS: restored %d host1 groups", restore);
- }
-
- /*
- * If -T, ignore new top level groups from host2
- */
- if (no_new_hier) {
- top_ignore = 0;
- for (i=0; i < grplen; ++i) {
- /* look at new newsgroups */
- if (grp[i].hostid == HOSTID2 &&
- grp[i].output != 0 &&
- new_top_hier(grp[i].name)) {
- /* no top level ignore this new group */
- grp[i].ignore |= CHECK_HIER;
- grp[i].output = 0;
- if (D_BUG)
- warn("ignore new newsgroup: %s, new hierarchy",
- grp[i].name);
- ++top_ignore;
- }
- }
- if (D_SUMMARY)
- warn("STATUS: ignored %d new newsgroups due to new hierarchy",
- top_ignore);
- }
-
- /* sort by active file order if active style output (-a) */
- if (o_flag == OUTPUT_ACTIVE) {
- if (D_BUG)
- warn("STATUS: sorting groups in output order");
- qsort((char *)grp, grplen, sizeof(grp[0]), active_cmp);
- }
-
- /*
- * Determine the % of lines from host1 active file that remain unchanged
- * ignoring any low/high water mark changes.
- *
- * Determine the number of old groups that will remain the same
- * the number of new groups that will be added.
- */
- add = 0;
- change = 0;
- remove = 0;
- same = 0;
- ignore = 0;
- no_new_dir = 0;
- new_dir = 0;
- water_change = 0;
- for (i=0; i < grplen; ++i) {
- /* skip non-output ... */
- if (grp[i].output == 0) {
- if (grp[i].hostid == HOSTID1) {
- ++ignore;
- }
- continue;
-
- /* case: group needs removal */
- } else if (grp[i].remove) {
- ++remove;
-
- /* case: group is from host2, so we need a newgroup */
- } else if (grp[i].hostid == HOSTID2) {
- ++add;
-
- /* case: group is from host1, but the type changed */
- } else if (grp[i].type != grp[i].outtype &&
- strcmp(grp[i].type,grp[i].outtype) != 0) {
- ++change;
-
- /* case: group did not change */
- } else {
- ++same;
- }
- }
- work = add+change+remove;
- if (same+work+host1_errs <= 0) {
- /* no lines, no work, no errors == nothing changed == 100% the same */
- host1_same = (double)100.0;
- } else {
- /* calculate % unchanged */
- host1_same = (double)100.0 *
- ((double)same / (double)(same+work+host1_errs));
- }
- if (D_BUG) {
- warn("STATUS: same=%d add=%d, change=%d, remove=%d",
- same, add, change, remove);
- warn("STATUS: ignore=%d, work=%d, err=%d",
- ignore, work, host1_errs);
- warn("STATUS: same+work+err=%d, host1_same=%.2f%%",
- same+work+host1_errs, host1_same);
- }
-
- /*
- * Bail out if we too few lines in host1 active file (ignoring
- * low/high water mark changes) remaining unchanged.
- *
- * We define change as:
- *
- * line errors from host1 active file
- * newsgroups to be added to host1
- * newsgroups to be removed from host1
- * newsgroups to be change in host1
- */
- if (host1_same < p_flag) {
- warn("HALT: lines unchanged: %.2f%% < min change limit: %.2f%%",
- host1_same, p_flag);
- warn(" No output or commands executed. Determine if the degree");
- warn(" of changes is okay and re-execute with a lower -p value");
- die(" or with the problem fixed.");
- }
-
- /*
- * look at all groups
- *
- * If we are not producing active file output, we must do removals
- * before we do any adds and changes.
- *
- * We recalculate the work stats in finer detail as well as noting how
- * many actions were successful.
- */
- add = 0;
- change = 0;
- remove = 0;
- same = 0;
- ignore = 0;
- work = 0;
- not_done = 0;
- sleep_msg = 0;
- rm_cycle = ((o_flag == OUTPUT_ACTIVE) ? 0 : 1);
- do {
- for (i=0; i < grplen; ++i) {
-
- /* if -o Ax, output ignored non-error groups too */
-
- /*
- * skip non-output ...
- *
- * but if '-a' and active output mode, then don't skip ignored,
- * non-error, non-removed groups from host1
- */
- if (grp[i].output == 0) {
- if (grp[i].hostid == HOSTID1) {
- ++ignore;
- }
- continue;
- }
-
- /* case: output active lines */
- if (o_flag == OUTPUT_ACTIVE) {
-
- /* case: group needs removal */
- if (grp[i].remove) {
- ++remove;
- ++work;
-
- /* case: group will be kept */
- } else {
-
- /* output in active file format */
- printf("%s %s %s %s\n",
- grp[i].name, grp[i].outhi, grp[i].outlow,
- grp[i].outtype);
-
- /* if -v level is high enough, do group accounting */
- if (D_IF_SUMM) {
-
- /* case: group is from host2, so we need a newgroup */
- if (grp[i].hostid == HOSTID2) {
- ++add;
- ++work;
-
- /* case: group is from host1, but the type changed */
- } else if (grp[i].type != grp[i].outtype &&
- strcmp(grp[i].type,grp[i].outtype) != 0) {
- ++change;
- ++work;
-
- /* case: group did not change */
- } else {
- ++same;
- }
- }
- }
-
- /* case: output ctlinnd commands */
- } else if (o_flag == OUTPUT_CTLINND) {
-
- /* case: group needs removal */
- if (grp[i].remove) {
-
- /* output rmgroup */
- if (rm_cycle) {
- printf("ctlinnd rmgroup %s\n", grp[i].name);
- ++remove;
- ++work;
- }
-
- /* case: group is from host2, so we need a newgroup */
- } else if (grp[i].hostid == HOSTID2) {
-
- /* output newgroup */
- if (! rm_cycle) {
- printf("ctlinnd newgroup %s %s %s\n",
- grp[i].name, grp[i].outtype, new_name);
- ++add;
- ++work;
- }
-
- /* case: group is from host1, but the type changed */
- } else if (grp[i].type != grp[i].outtype &&
- strcmp(grp[i].type,grp[i].outtype) != 0) {
-
- /* output changegroup */
- if (! rm_cycle) {
- printf("ctlinnd changegroup %s %s\n",
- grp[i].name, grp[i].outtype);
- ++change;
- ++work;
- }
-
- /* case: group did not change */
- } else {
- if (! rm_cycle) {
- ++same;
- }
- }
-
- /* case: exec ctlinnd commands */
- } else if (o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC) {
-
- /* warn about sleeping if needed and first time */
- if (o_flag == OUTPUT_EXEC && z_flag > 0 && sleep_msg == 0) {
- if (D_SUMMARY)
- warn("will sleep %d seconds before each fork/exec",
- z_flag);
- sleep_msg = 1;
- }
-
- /* case: group needs removal */
- if (grp[i].remove) {
-
- /* exec rmgroup */
- if (rm_cycle) {
- if (D_REPORT && o_flag == OUTPUT_EXEC)
- warn("rmgroup %s", grp[i].name);
- if (! exec_cmd(o_flag, "rmgroup",
- grp[i].name, NULL, NULL)) {
- ++not_done;
- } else {
- ++remove;
- ++work;
- }
- }
-
- /* case: group is from host2, so we need a newgroup */
- } else if (grp[i].hostid == HOSTID2) {
-
- /* exec newgroup */
- if (!rm_cycle) {
- if (D_REPORT && o_flag == OUTPUT_EXEC)
- warn("newgroup %s %s %s",
- grp[i].name, grp[i].outtype, new_name);
- if (! exec_cmd(o_flag, "newgroup", grp[i].name,
- grp[i].outtype, new_name)) {
- ++not_done;
- } else {
- ++add;
- ++work;
- }
- }
-
- /* case: group is from host1, but the type changed */
- } else if (grp[i].type != grp[i].outtype &&
- strcmp(grp[i].type,grp[i].outtype) != 0) {
-
- /* exec changegroup */
- if (!rm_cycle) {
- if (D_REPORT && o_flag == OUTPUT_EXEC)
- warn("changegroup %s %s",
- grp[i].name, grp[i].outtype);
- if (! exec_cmd(o_flag, "changegroup", grp[i].name,
- grp[i].outtype, NULL)) {
- ++not_done;
- } else {
- ++change;
- ++work;
- }
- }
-
- /* case: group did not change */
- } else {
- if (! rm_cycle) {
- ++same;
- }
- }
- }
- }
- } while (--rm_cycle >= 0);
-
- /* final accounting, if -v */
- if (D_SUMMARY || (D_IF_SUMM && (work > 0 || not_done > 0))) {
- warn("STATUS: %d group(s)", add+remove+change+same);
- warn("STATUS: %d group(s)%s added", add,
- ((o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC) ?
- "" : " to be"));
- warn("STATUS: %d group(s)%s removed", remove,
- ((o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC) ?
- "" : " to be"));
- warn("STATUS: %d group(s)%s changed", change,
- ((o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC) ?
- "" : " to be"));
- warn("STATUS: %d group(s) %s the same", same,
- ((o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC) ?
- "remain" : "are"));
- warn("STATUS: %.2f%% of lines unchanged", host1_same);
- warn("STATUS: %d group(s) ignored", ignore);
- if (o_flag == OUTPUT_EXEC || o_flag == OUTPUT_IEXEC)
- warn("STATUS: %d exec(s) not performed", not_done);
- }
-}
-
-/*
- * error_mark - mark for removal, error groups from a given host
- *
- * given:
- * grp array of groups
- * grplen length of grp array in elements
- * hostid host to mark error groups for removal
- */
-static void
-error_mark(grp, grplen, hostid)
- struct grp *grp; /* array of groups */
- int grplen; /* length of grp array in elements */
- int hostid; /* host to mark error groups for removal */
-{
- int i;
- int errcnt;
-
- /* firewall */
- if (grp == NULL)
- die("internal error #11: grp is NULL");
-
- /* loop thru groups, looking for error groups from a given host */
- errcnt = 0;
- for (i=0; i < grplen; ++i) {
-
- /* skip if not from hostid */
- if (grp[i].hostid != hostid) {
- continue;
- }
-
- /* mark for removal if an error group not already removed */
- if (IS_ERROR(grp[i].ignore)) {
-
- /* mark for removal */
- if (grp[i].output != 1 || grp[i].remove != 1) {
- grp[i].output = 1;
- grp[i].remove = 1;
- }
- ++errcnt;
- }
- }
-
- /* all done */
- if (D_SUMMARY || (D_IF_SUMM && errcnt > 0))
- warn("STATUS: marked %d error groups for removal", errcnt);
- return;
-}
-
-/*
- * eq_merge_cmp - qsort compare function for =type group processing
- *
- * given:
- * a =group a to compare
- * b =group b to compare
- *
- * returns:
- * >0 a > b
- * 0 a == b elements match (fatal error if a and b are different)
- * <0 a < b
- *
- * To speed up group comparison, we compare by the following items listed
- * in order of sorting:
- *
- * skip (non-skipped groups after skipped ones)
- * group equiv name
- * group name
- * hostid (host1 ahead of host2)
- * linenum (active file line number)
- */
-static int
-eq_merge_cmp(arg_a, arg_b)
- const void *arg_a; /* first qsort compare arg */
- const void *arg_b; /* first qsort compare arg */
-{
- const struct eqgrp *a = arg_a; /* group a to compare */
- const struct eqgrp *b = arg_b; /* group b to compare */
- int i;
-
- /* firewall */
- if (a == b) {
- /* we guess this could happen */
- return(0);
- }
-
- /* compare skip values */
- if (a->skip != b->skip) {
- if (a->skip > b->skip) {
- /* a is skipped, b is not */
- return 1;
- } else {
- /* b is skipped, a is not */
- return -1;
- }
- }
-
- /* compare the names the groups are equivalenced to */
- i = strcmp(a->eq, b->eq);
- if (i != 0) {
- return i;
- }
-
- /* compare the group names themselves */
- i = strcmp(a->g->name, b->g->name);
- if (i != 0) {
- return i;
- }
-
- /* compare hostid's */
- if (a->g->hostid != b->g->hostid) {
- if (a->g->hostid > b->g->hostid) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* compare active line numbers */
- if (a->g->linenum != b->g->linenum) {
- if (a->g->linenum > b->g->linenum) {
- return 1;
- } else {
- return -1;
- }
- }
-
- /* two different elements match, this should not happen! */
- die("two internal eqgrp elements match!");
-}
-
-/*
- * mark_eq_probs - mark =type groups from a given host that have problems
- *
- * given:
- * grp sorted array of groups
- * grplen length of grp array in elements
- * hostid host to mark error groups for removal, or NOHOST
- * host1 name of host with HOSTID1
- * host2 name of host with HOSTID2
- *
- * This function assumes that the grp array has been sorted by name.
- */
-static int
-mark_eq_probs(grp, grplen, hostid, host1, host2)
- struct grp *grp; /* array of groups */
- int grplen; /* length of grp array in elements */
- int hostid; /* host to mark error groups for removal */
- char *host1; /* name of host with HOSTID1 */
- char *host2; /* name of host with HOSTID2 */
-{
- struct eqgrp *eqgrp; /* =type pointer array */
- int eq_cnt; /* number of =type groups from host */
- int new_eq_cnt; /* number of =type groups remaining */
- int missing; /* =type groups equiv to missing groups */
- int cycled; /* =type groups equiv to themselves */
- int chained; /* =type groups in long chain or loop */
- int cmp; /* strcmp of two names */
- int step; /* equiv loop step */
- int i;
- int j;
-
- /* firewall */
- if (grp == NULL)
- die("internal error #12: grp is NULL");
- if (hostid == NOHOST) {
- /* nothing to detect, nothing else to do */
- return 0;
- }
-
- /* count the =type groups from hostid that are not in error */
- eq_cnt = 0;
- for (i=0; i < grplen; ++i) {
- if (grp[i].hostid == hostid &&
- ! IS_ERROR(grp[i].ignore) &&
- grp[i].type != NULL &&
- grp[i].type[0] == '=') {
- ++eq_cnt;
- }
- }
- if (D_BUG && hostid != NOHOST)
- warn("STATUS: host%d has %d =type groups", hostid, eq_cnt);
-
- /* if no groups, then there is nothing to do */
- if (eq_cnt == 0) {
- return 0;
- }
-
- /* setup the =group record array */
- eqgrp = xmalloc(eq_cnt * sizeof(eqgrp[0]));
- for (i=0, j=0; i < grplen && j < eq_cnt; ++i) {
- if (grp[i].hostid == hostid &&
- ! IS_ERROR(grp[i].ignore) &&
- grp[i].type != NULL &&
- grp[i].type[0] == '=') {
-
- /* initialize record */
- eqgrp[j].skip = 0;
- eqgrp[j].g = &grp[i];
- eqgrp[j].eq = &(grp[i].type[1]);
- ++j;
- }
- }
-
- /*
- * try to resolve =type groups in at least EQ_LOOP equiv links
- */
- new_eq_cnt = eq_cnt;
- missing = 0;
- cycled = 0;
- for (step=0; step < EQ_LOOP && new_eq_cnt >= 0; ++step) {
-
- /* sort the =group record array */
- qsort((char *)eqgrp, eq_cnt, sizeof(eqgrp[0]), eq_merge_cmp);
-
- /* look for the groups to which =type group point at */
- eq_cnt = new_eq_cnt;
- for (i=0, j=0; i < grplen && j < eq_cnt; ++i) {
-
- /* we will skip any group in error or from the wrong host */
- if (grp[i].hostid != hostid || IS_ERROR(grp[i].ignore)) {
- continue;
- }
-
- /* we will skip any skipped eqgrp's */
- if (eqgrp[j].skip) {
- /* try the same group against the next eqgrp */
- --i;
- ++j;
- continue;
- }
-
- /* compare the =name of the eqgrp with the name of the grp */
- cmp = strcmp(grp[i].name, eqgrp[j].eq);
-
- /* case: this group is pointed at by an eqgrp */
- if (cmp == 0) {
-
- /* see if we have looped around to the original group name */
- if (strcmp(grp[i].name, eqgrp[j].g->name) == 0) {
-
- /* note the detected loop */
- if (! QUIET(hostid))
- warn("%s from %s line %d =loops around to itself",
- eqgrp[j].g->name,
- ((eqgrp[j].g->hostid == HOSTID1) ? host1 : host2),
- eqgrp[j].g->linenum);
- eqgrp[j].g->ignore |= ERROR_EQLOOP;
-
- /* the =group is bad, so we don't need to bother with it */
- eqgrp[j].skip = 1;
- --new_eq_cnt;
- ++cycled;
- --i;
- ++j;
- continue;
- }
-
- /* if =group refers to a valid group, we are done with it */
- if (grp[i].type != NULL && grp[i].type[0] != '=') {
- eqgrp[j].skip = 1;
- --new_eq_cnt;
- /* otherwise note the equiv name */
- } else {
- eqgrp[j].eq = &(grp[i].type[1]);
- }
- --i;
- ++j;
-
- /* case: we missed the =name */
- } else if (cmp > 0) {
-
- /* mark the eqgrp in error */
- eqgrp[j].g->ignore |= ERROR_NONEQ;
- if (! QUIET(hostid))
- warn("%s from %s line %d not equiv to a valid group",
- eqgrp[j].g->name,
- ((eqgrp[j].g->hostid == HOSTID1) ? host1 : host2),
- eqgrp[j].g->linenum);
-
- /* =group is bad, so we don't need to bother with it anymore */
- eqgrp[j].skip = 1;
- --new_eq_cnt;
- ++missing;
- ++j;
- }
- }
-
- /* any remaining non-skipped eqgrps are bad */
- while (j < eq_cnt) {
-
- /* mark the eqgrp in error */
- eqgrp[j].g->ignore |= ERROR_NONEQ;
- if (! QUIET(hostid))
- warn("%s from %s line %d isn't equiv to a valid group",
- eqgrp[j].g->name,
- ((hostid == HOSTID1) ? host1 : host2),
- eqgrp[j].g->linenum);
-
- /* the =group is bad, so we don't need to bother with it anymore */
- eqgrp[j].skip = 1;
- --new_eq_cnt;
- ++missing;
- ++j;
- }
- }
-
- /* note groups that are in a long chain or loop */
- chained = new_eq_cnt;
- qsort((char *)eqgrp, eq_cnt, sizeof(eqgrp[0]), eq_merge_cmp);
- for (j=0; j < new_eq_cnt; ++j) {
-
- /* skip if already skipped */
- if (eqgrp[j].skip == 1) {
- continue;
- }
-
- /* mark as a long loop group */
- eqgrp[j].g->ignore |= ERROR_LONGLOOP;
- if (! QUIET(hostid))
- warn("%s from %s line %d in a long equiv chain or loop > %d",
- eqgrp[j].g->name,
- ((hostid == HOSTID1) ? host1 : host2),
- eqgrp[j].g->linenum, EQ_LOOP);
- }
-
- /* all done */
- if (D_BUG) {
- warn("%d =type groups from %s are not equiv to a valid group",
- missing, ((hostid == HOSTID1) ? host1 : host2));
- warn("%d =type groups from %s are equiv to themselves",
- cycled, ((hostid == HOSTID1) ? host1 : host2));
- warn("%d =type groups from %s are in a long chain or loop > %d",
- chained, ((hostid == HOSTID1) ? host1 : host2), EQ_LOOP);
- }
- free(eqgrp);
- return missing+cycled+chained;
-}
-
-/*
- * exec_cmd - exec a ctlinnd command in forked process
- *
- * given:
- * mode OUTPUT_EXEC or OUTPUT_IEXEC (interactive mode)
- * cmd "changegroup", "newgroup", "rmgroup"
- * grp name of group
- * type type of group or NULL
- * who newgroup creator or NULL
- *
- * returns:
- * 1 exec was performed
- * 0 exec was not performed
- */
-static int
-exec_cmd(mode, cmd, grp, type, who)
- int mode; /* OUTPUT_EXEC or OUTPUT_IEXEC (interactive mode) */
- char *cmd; /* changegroup, newgroup or rmgroup */
- char *grp; /* name of group to change, add, remove */
- char *type; /* type of group or NULL */
- char *who; /* newgroup creator or NULL */
-{
- FILE *ch_stream = NULL; /* stream from a child process */
- char buf[BUFSIZ+1]; /* interactive buffer */
- int pid; /* pid of child process */
- int io[2]; /* pair of pipe descriptors */
- int status; /* wait status */
- int exitval; /* exit status of the child */
- char *p;
-
- /* firewall */
- if (cmd == NULL || grp == NULL)
- die("internal error #13, cmd or grp is NULL");
-
- /* if interactive, ask the question */
- if (mode == OUTPUT_IEXEC) {
-
- /* ask the question */
- fflush(stdin);
- fflush(stdout);
- fflush(stderr);
- if (type == NULL) {
- printf("%s %s [yn]? ", cmd, grp);
- } else if (who == NULL) {
- printf("%s %s %s [yn]? ", cmd, grp, type);
- } else {
- printf("%s %s %s %s [yn]? ", cmd, grp, type, who);
- }
- fflush(stdout);
- buf[0] = '\0';
- buf[BUFSIZ] = '\0';
- p = fgets(buf, BUFSIZ, stdin);
- if (p == NULL) {
- /* EOF/ERROR on interactive input, silently stop processing */
- exit(43);
- }
-
- /* if non-empty line doesn't start with 'y' or 'Y', skip command */
- if (buf[0] != 'y' && buf[0] != 'Y' && buf[0] != '\n') {
- /* indicate nothing was done */
- return 0;
- }
- }
-
- /* build a pipe for output from child interactive mode */
- if (mode == OUTPUT_IEXEC) {
- if (pipe(io) < 0)
- sysdie("pipe create failed");
-
- /* setup a fake pipe to /dev/null for non-interactive mode */
- } else {
- io[READ_SIDE] = open(DEV_NULL, 0);
- if (io[READ_SIDE] < 0)
- sysdie("unable to open %s for reading", DEV_NULL);
- io[WRITE_SIDE] = open(DEV_NULL, 1);
- if (io[WRITE_SIDE] < 0)
- sysdie("unable to open %s for writing", DEV_NULL);
- }
-
- /* pause if in non-interactive mode so as to not busy-out the server */
- if (mode == OUTPUT_EXEC && z_flag > 0) {
- if (D_BUG)
- warn("sleeping %d seconds before fork/exec", z_flag);
- /* be sure they know what we are stalling */
- fflush(stderr);
- sleep(z_flag);
- }
-
- /* fork the child process */
- fflush(stdout);
- fflush(stderr);
- pid = fork();
- if (pid == -1)
- sysdie("fork failed");
-
- /* case: child process */
- if (pid == 0) {
-
- /*
- * prep file descriptors
- */
- fclose(stdin);
- close(io[READ_SIDE]);
- if (dup2(io[WRITE_SIDE], 1) < 0)
- sysdie("child: dup of write I/O pipe to stdout failed");
- if (dup2(io[WRITE_SIDE], 2) < 0)
- sysdie("child: dup of write I/O pipe to stderr failed");
-
- /* exec the ctlinnd command */
- p = concatpath(innconf->pathbin, _PATH_CTLINND);
- if (type == NULL) {
- execl(p,
- CTLINND_NAME, CTLINND_TIME_OUT, cmd, grp, (char *) 0);
- } else if (who == NULL) {
- execl(p,
- CTLINND_NAME, CTLINND_TIME_OUT, cmd, grp, type, (char *) 0);
- } else {
- execl(p,
- CTLINND_NAME, CTLINND_TIME_OUT, cmd, grp, type, who, (char *) 0);
- }
-
- /* child exec failed */
- sysdie("child process exec failed");
-
- /* case: parent process */
- } else {
-
- /* prep file descriptors */
- if (mode != OUTPUT_IEXEC) {
- close(io[READ_SIDE]);
- }
- close(io[WRITE_SIDE]);
-
- /* print a line from the child, if interactive */
- if (mode == OUTPUT_IEXEC) {
-
- /* read what the child says */
- buf[0] = '\0';
- buf[BUFSIZ] = '\0';
- ch_stream = fdopen(io[READ_SIDE], "r");
- if (ch_stream == NULL)
- sysdie("fdopen of pipe failed");
- p = fgets(buf, BUFSIZ, ch_stream);
-
- /* print what the child said, if anything */
- if (p != NULL) {
- if (buf[strlen(buf)-1] == '\n')
- buf[strlen(buf)-1] = '\0';
- warn(" %s", buf);
- }
- }
-
- /* look for abnormal child termination/status */
- errno = 0;
- while (wait(&status) < 0) {
- if (errno == EINTR) {
- /* just an interrupt, try to wait again */
- errno = 0;
- } else {
- sysdie("wait returned -1");
- }
- }
- if (mode == OUTPUT_IEXEC) {
- /* close the pipe now that we are done with reading it */
- fclose(ch_stream);
- }
- if (WIFSTOPPED(status)) {
- warn(" %s %s %s%s%s%s%s stopped",
- CTLINND_NAME, cmd, grp,
- (type ? "" : " "), (type ? type : ""),
- (who ? "" : " "), (who ? who : ""));
- /* assume no work was done */
- return 0;
- }
- if (WIFSIGNALED(status)) {
- warn(" %s %s %s%s%s%s%s killed by signal %d",
- CTLINND_NAME, cmd, grp,
- (type ? "" : " "), (type ? type : ""),
- (who ? "" : " "), (who ? who : ""), WTERMSIG(status));
- /* assume no work was done */
- return 0;
- }
- if (!WIFEXITED(status)) {
- warn(" %s %s %s%s%s%s%s returned unknown wait status: 0x%x",
- CTLINND_NAME, cmd, grp,
- (type ? "" : " "), (type ? type : ""),
- (who ? "" : " "), (who ? who : ""), status);
- /* assume no work was done */
- return 0;
- }
- exitval = WEXITSTATUS(status);
- if (exitval != 0) {
- warn(" %s %s %s%s%s%s%s exited with status: %d",
- CTLINND_NAME, cmd, grp,
- (type ? "" : " "), (type ? type : ""),
- (who ? "" : " "), (who ? who : ""), exitval);
- /* assume no work was done */
- return 0;
- }
- }
-
- /* all done */
- return 1;
-}
-
-/*
- * new_top_hier - determine if the newsgroup represents a new hierarchy
- *
- * Determine of the newsgroup name is a new hierarchy.
- *
- * given:
- * name name of newsgroup to check
- *
- * returns:
- * false hierarchy already exists
- * true hierarchy does not exist, name represents a new hierarchy
- *
- * NOTE: This function assumes that we are at the top of the news spool.
- */
-static int
-new_top_hier(name)
- char *name;
-{
- struct stat statbuf; /* stat of the hierarchy */
- int result; /* return result */
- char *dot;
-
- /*
- * temp change name to just the top level
- */
- dot = strchr(name, '.');
- if (dot != NULL) {
- *dot = '\0';
- }
-
- /*
- * determine if we can find this top level hierarchy directory
- */
- result = !(stat(name, &statbuf) >= 0 && S_ISDIR(statbuf.st_mode));
- /* restore name */
- if (dot != NULL) {
- *dot = '.';
- }
-
- /*
- * return the result
- */
- return result;
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-# @(#) $Id: actsyncd.in 6490 2003-10-18 05:49:04Z rra $
-# @(#) Under RCS control in /usr/local/news/src/inn/local/RCS/actsyncd.sh,v
-#
-# actsyncd - actsync daemon
-#
-# usage:
-# actsyncd [-x] config_file [debug_level [debug_outfmt]]
-#
-# -x xexec instead of reload
-# config_file name of file used to determine how to run actsync
-# debug_level force no action and use -v debug_level
-# debug_outfmt change -o a1 output to -o debug_outfmt for debug
-
-# By: Landon Curt Noll chongo@toad.com (chongo was here /\../\)
-#
-# Copyright (c) Landon Curt Noll, 1993.
-# All rights reserved.
-#
-# Permission to use and modify is hereby granted so long as this
-# notice remains. Use at your own risk. No warranty is implied.
-
-# preset vars
-#
-
-# Our lock file
-LOCK="${LOCKS}/LOCK.actsyncd"
-# where actsync is located
-ACTSYNC="${PATHBIN}/actsync"
-# exit value of actsync if unable to get an active file
-NOSYNC=127
-
-# parse args
-#
-if [ $# -gt 1 ]; then
- case $1 in
- -x|-r) shift ;; # no longer relevant
- esac
-fi
-case $# in
- 1) cfg="$1"; DEBUG=; DEBUG_FMT=; ;;
- 2) cfg="$1"; DEBUG="$2"; DEBUG_FMT=; ;;
- 3) cfg="$1"; DEBUG="$2"; DEBUG_FMT="$3"; ;;
- *) echo "usage: $0 [-x] config_file [debug_level [debug_outfmt]]" 1>&2;
- exit 1 ;;
-esac
-if [ ! -s "$cfg" ]; then
- echo "$0: config_file not found or empty: $ign" 1>&2
- exit 2
-fi
-
-# parse config_file
-#
-host="`sed -n -e 's/^host=[ ]*//p' $cfg | tail -1`"
-if [ -z "$host" ]; then
- echo "$0: no host specified in $cfg" 1>&2
- exit 3
-fi
-flags="`sed -n -e 's/^flags=[ ]*//p' $cfg | tail -1`"
-if [ -z "$flags" ]; then
- echo "$0: no flags specified in $cfg" 1>&2
- exit 4
-fi
-ign="`sed -n -e 's/^ignore_file=[ ]*//p' $cfg | tail -1`"
-if [ -z "$ign" ]; then
- echo "$0: no ignore file specified in $cfg" 1>&2
- exit 5
-fi
-ftp="`sed -n -e 's/^ftppath=[ ]*//p' $cfg | tail -1`"
-spool="`sed -n -e 's/^spool=[ ]*//p' $cfg | tail -1`"
-if [ -z "$spool" ]; then
- spool=$SPOOL
- #echo "$0: no spool directory specified in $cfg" 1>&2
- #exit 6
-fi
-if [ ! -f "$ign" ]; then
- ign="${PATHETC}/$ign"
-fi
-if [ ! -s "$ign" ]; then
- echo "$0: ignore_file not found or empty: $ign" 1>&2
- exit 7
-fi
-
-# force -o c mode (overrides any -o argument in the command line)
-#
-if [ -z "$DEBUG" ]; then
-
- # standard actsyncd output mode
- flags="$flags -o c"
-
-# DEBUG processing, if debug_level was given
-#
-else
-
- if [ ! -z "$ftp" ]; then
- echo "$0: cannot use DEBUG mode with ftp (yet)" >&2
- exit 88;
- fi
-
- # force -v level as needed
- flags="$flags -v $DEBUG"
-
- # force -o level but reject -o x modes
- if [ ! -z "$DEBUG_FMT" ]; then
- case "$DEBUG_FMT" in
- x*) echo "$0: do not use any of the -o x debug_outfmt modes!" 1>&2;
- exit 8 ;;
- *) flags="$flags -o $DEBUG_FMT" ;;
- esac
- fi
-
- # execute actsync directly
- echo "DEBUG: will execute $ACTSYNC -i $ign $flags $host" 1>&2
- eval "$ACTSYNC -i $ign $flags $host"
- status="$?"
- echo "DEBUG: exit status $status" 1>&2
- exit "$status"
-fi
-
-# Lock out others
-#
-shlock -p $$ -f "${LOCK}" || {
- echo "$0: Locked by `cat '${LOCK}'`" 1>&2
- exit 9
-}
-
-# setup
-#
-origdir=`pwd`
-workdir="${TMPDIR}/actsyncd"
-ctlinndcmds="cc_commands"
-out="sync.msg"
-cleanup="$SED -e 's/^/ /' < $out; cd ${origdir}; rm -rf '$workdir' '$LOCK'"
-trap "eval $cleanup; exit 123" 1 2 3 15
-
-set -e
-rm -rf "$workdir"
-mkdir "$workdir"
-cd "$workdir"
-set +e
-
-rm -f "$out"
-touch "$out"
-chmod 0644 "$out"
-
-# try to sync
-#
-# Try to sync off of the host. If unable to connect/sync then retry
-# up to 9 more times waiting 6 minutes between each try.
-#
-echo "=-= `date` for $host" >>$out 2>&1
-for loop in 1 2 3 4 5 6 7 8 9 10; do
-
- # get the active file to compare against
- status=0
- case $host in
- /*) cp $host active; status=$? ;;
- .*) cp $origdir/$host active; status=$? ;;
- *)
- if [ -z "$ftp" ]; then
- port=`expr "$host" : '.*:\(.*\)'`
- if [ -n "$port" ]; then
- port="-p $port"
- host=`expr "$host" : '\(.*\):.*'`
- fi
- echo "getlist -h $host $port" >>$out
- if getlist -h $host $port > active 2>>$out; then
- :
- else
- status=$NOSYNC
- fi
- else
- echo "$GETFTP ftp://$host/$ftp" >>$out
- $GETFTP ftp://$host/$ftp >>$out 2>&1
- status=$?
- if [ "$status" -ne 0 ]; then
- status=$NOSYNC
- else
- case "$ftp" in
- *.gz)
- echo "$GZIP -d active" >>$out
- if $GZIP -d active >>$out 2>&1; then
- :
- else
- status=1
- fi
- ;;
- *.Z)
- echo "$UNCOMPRESS active" >>$out
- if $UNCOMPRESS active >>$out 2>&1; then
- :
- else
- status=1
- fi
- ;;
- esac
- fi
- fi
- ;;
- esac
-
- if [ "$status" -ne "$NOSYNC" ]; then
-
- # detect bad status
- #
- if [ "$status" -ne 0 ]; then
- echo "FATAL: `date` for $host exit $status" >>$out
- eval $cleanup
- exit "$status"
- fi
-
- echo "$ACTSYNC -i $ign $flags ./active" >>$out
- eval "$ACTSYNC -i $ign $flags ./active >$ctlinndcmds 2>>$out"
-
- if [ $? -ne 0 ]; then
- echo "FATAL: `date` for $host actsync balked" >>$out
- eval $cleanup
- exit $?
- fi
-
- if [ ! -s $ctlinndcmds ]; then
- echo "No changes need to be made" >>$out
- else
- echo "=-= `date` for $host, updating active" >>$out
- echo "mod-active $ctlinndcmds" >>$out
- mod-active $ctlinndcmds >>$out 2>&1
-
- if [ $? -ne 0 ]; then
- echo "FATAL: `date` for $host mod-active FAILED" >>$out
- eval $cleanup
- exit 1
- fi
- fi
-
- # normal exit - all done
- #
- echo "=-= `date` for $host, end" >>$out
- eval $cleanup
- exit 0
- fi
-
- # failed to get the remote active file
- echo "=-= `date` for $host failed to connect/sync, retrying" >>$out
-
- # wait 6 minutes
- #
- sleep 360
-done
-
-# give up
-#
-echo "FATAL: `date` for $host failed to connect/sync 10 times" >>$out 2>&1
-eval $cleanup
-exit 1
+++ /dev/null
-/* $Id: archive.c 6138 2003-01-19 04:13:51Z rra $
-**
-** Read batchfiles on standard input and archive them.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#ifdef TM_IN_SYS_TIME
-# include <sys/time.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-
-static char *Archive = NULL;
-static char *ERRLOG = NULL;
-
-/*
-** Return a YYYYMM string that represents the current year/month
-*/
-static char *
-DateString(void)
-{
- static char ds[10];
- time_t now;
- struct tm *x;
-
- time(&now);
- x = localtime(&now);
- snprintf(ds, sizeof(ds), "%d%d", x->tm_year + 1900, x->tm_mon + 1);
-
- return ds;
-}
-
-
-/*
-** Try to make one directory. Return false on error.
-*/
-static bool
-MakeDir(char *Name)
-{
- struct stat Sb;
-
- if (mkdir(Name, GROUPDIR_MODE) >= 0)
- return true;
-
- /* See if it failed because it already exists. */
- return stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode);
-}
-
-
-/*
-** Given an entry, comp/foo/bar/1123, create the directory and all
-** parent directories needed. Return false on error.
-*/
-static bool
-MakeArchiveDirectory(char *Name)
-{
- char *p;
- char *save;
- bool made;
-
- if ((save = strrchr(Name, '/')) != NULL)
- *save = '\0';
-
- /* Optimize common case -- parent almost always exists. */
- if (MakeDir(Name)) {
- if (save)
- *save = '/';
- return true;
- }
-
- /* Try to make each of comp and comp/foo in turn. */
- for (p = Name; *p; p++)
- if (*p == '/' && p != Name) {
- *p = '\0';
- made = MakeDir(Name);
- *p = '/';
- if (!made) {
- if (save)
- *save = '/';
- return false;
- }
- }
-
- made = MakeDir(Name);
- if (save)
- *save = '/';
- return made;
-}
-
-
-/*
-** Copy a file. Return false if error.
-*/
-static bool
-Copy(char *src, char *dest)
-{
- FILE *in;
- FILE *out;
- size_t i;
- char *p;
- char buff[BUFSIZ];
-
- /* Open the output file. */
- if ((out = fopen(dest, "w")) == NULL) {
- /* Failed; make any missing directories and try again. */
- if ((p = strrchr(dest, '/')) != NULL) {
- if (!MakeArchiveDirectory(dest)) {
- syswarn("cannot mkdir for %s", dest);
- return false;
- }
- out = fopen(dest, "w");
- }
- if (p == NULL || out == NULL) {
- syswarn("cannot open %s for writing", dest);
- return false;
- }
- }
-
- /* Opening the input file is easier. */
- if ((in = fopen(src, "r")) == NULL) {
- syswarn("cannot open %s for reading", src);
- fclose(out);
- unlink(dest);
- return false;
- }
-
- /* Write the data. */
- while ((i = fread(buff, 1, sizeof buff, in)) != 0)
- if (fwrite(buff, 1, i, out) != i) {
- syswarn("cannot write to %s", dest);
- fclose(in);
- fclose(out);
- unlink(dest);
- return false;
- }
- fclose(in);
-
- /* Flush and close the output. */
- if (ferror(out) || fflush(out) == EOF) {
- syswarn("cannot flush %s", dest);
- unlink(dest);
- fclose(out);
- return false;
- }
- if (fclose(out) == EOF) {
- syswarn("cannot close %s", dest);
- unlink(dest);
- return false;
- }
-
- return true;
-}
-
-
-/*
-** Copy an article from memory into a file.
-*/
-static bool
-CopyArt(ARTHANDLE *art, char *dest, bool Concat)
-{
- FILE *out;
- const char *p;
- char *q, *article;
- size_t i;
- const char *mode = "w";
-
- if (Concat) mode = "a";
-
- /* Open the output file. */
- if ((out = fopen(dest, mode)) == NULL) {
- /* Failed; make any missing directories and try again. */
- if ((p = strrchr(dest, '/')) != NULL) {
- if (!MakeArchiveDirectory(dest)) {
- syswarn("cannot mkdir for %s", dest);
- return false;
- }
- out = fopen(dest, mode);
- }
- if (p == NULL || out == NULL) {
- syswarn("cannot open %s for writing", dest);
- return false;
- }
- }
-
- /* Copy the data. */
- article = xmalloc(art->len);
- for (i=0, q=article, p=art->data; p<art->data+art->len;) {
- if (&p[1] < art->data + art->len && p[0] == '\r' && p[1] == '\n') {
- p += 2;
- *q++ = '\n';
- i++;
- if (&p[1] < art->data + art->len && p[0] == '.' && p[1] == '.') {
- p += 2;
- *q++ = '.';
- i++;
- }
- if (&p[2] < art->data + art->len && p[0] == '.' && p[1] == '\r' && p[2] == '\n') {
- break;
- }
- } else {
- *q++ = *p++;
- i++;
- }
- }
- *q++ = '\0';
-
- /* Write the data. */
- if (Concat) {
- /* Write a separator... */
- fprintf(out, "-----------\n");
- }
- if (fwrite(article, i, 1, out) != 1) {
- syswarn("cannot write to %s", dest);
- fclose(out);
- if (!Concat) unlink(dest);
- free(article);
- return false;
- }
- free(article);
-
- /* Flush and close the output. */
- if (ferror(out) || fflush(out) == EOF) {
- syswarn("cannot flush %s", dest);
- if (!Concat) unlink(dest);
- fclose(out);
- return false;
- }
- if (fclose(out) == EOF) {
- syswarn("cannot close %s", dest);
- if (!Concat) unlink(dest);
- return false;
- }
-
- return true;
-}
-
-
-/*
-** Write an index entry. Ignore I/O errors; our caller checks for them.
-*/
-static void
-WriteArtIndex(ARTHANDLE *art, char *ShortName)
-{
- const char *p;
- int i;
- char Subject[BUFSIZ];
- char MessageID[BUFSIZ];
-
- Subject[0] = '\0'; /* default to null string */
- p = wire_findheader(art->data, art->len, "Subject");
- if (p != NULL) {
- for (i=0; *p != '\r' && *p != '\n' && *p != '\0'; i++) {
- Subject[i] = *p++;
- }
- Subject[i] = '\0';
- }
-
- MessageID[0] = '\0'; /* default to null string */
- p = wire_findheader(art->data, art->len, "Message-ID");
- if (p != NULL) {
- for (i=0; *p != '\r' && *p != '\n' && *p != '\0'; i++) {
- MessageID[i] = *p++;
- }
- MessageID[i] = '\0';
- }
-
- printf("%s %s %s\n",
- ShortName,
- MessageID[0] ? MessageID : "<none>",
- Subject[0] ? Subject : "<none>");
-}
-
-
-/*
-** Crack an Xref line apart into separate strings, each of the form "ng:artnum".
-** Return in "lenp" the number of newsgroups found.
-**
-** This routine blatantly stolen from tradspool.c
-*/
-static char **
-CrackXref(const char *xref, unsigned int *lenp) {
- char *p;
- char **xrefs;
- char *q;
- unsigned int len, xrefsize;
-
- len = 0;
- xrefsize = 5;
- xrefs = xmalloc(xrefsize * sizeof(char *));
-
- /* skip pathhost */
- if ((p = strchr(xref, ' ')) == NULL) {
- warn("cannot find pathhost in Xref header");
- return NULL;
- }
- /* skip next spaces */
- for (p++; *p == ' ' ; p++) ;
- while (true) {
- /* check for EOL */
- /* shouldn't ever hit null w/o hitting a \r\n first, but best to be paranoid */
- if (*p == '\n' || *p == '\r' || *p == 0) {
- /* hit EOL, return. */
- *lenp = len;
- return xrefs;
- }
- /* skip to next space or EOL */
- for (q=p; *q && *q != ' ' && *q != '\n' && *q != '\r' ; ++q) ;
-
- xrefs[len] = xstrndup(p, q - p);
-
- if (++len == xrefsize) {
- /* grow xrefs if needed. */
- xrefsize *= 2;
- xrefs = xrealloc(xrefs, xrefsize * sizeof(char *));
- }
-
- p = q;
- /* skip spaces */
- for ( ; *p == ' ' ; p++) ;
- }
-}
-
-
-/*
-** Crack an groups pattern parameter apart into separate strings
-** Return in "lenp" the number of patterns found.
-*/
-static char **
-CrackGroups(char *group, unsigned int *lenp) {
- char *p;
- char **groups;
- char *q;
- unsigned int len, grpsize;
-
- len = 0;
- grpsize = 5;
- groups = xmalloc(grpsize * sizeof(char *));
-
- /* skip leading spaces */
- for (p=group; *p == ' ' ; p++) ;
- while (true) {
- /* check for EOL */
- /* shouldn't ever hit null w/o hitting a \r\n first, but best to be paranoid */
- if (*p == '\n' || *p == '\r' || *p == 0) {
- /* hit EOL, return. */
- *lenp = len;
- return groups;
- }
- /* skip to next comma, space, or EOL */
- for (q=p; *q && *q != ',' && *q != ' ' && *q != '\n' && *q != '\r' ; ++q) ;
-
- groups[len] = xstrndup(p, q - p);
-
- if (++len == grpsize) {
- /* grow groups if needed. */
- grpsize *= 2;
- groups = xrealloc(groups, grpsize * sizeof(char *));
- }
-
- p = q;
- /* skip commas and spaces */
- for ( ; *p == ' ' || *p == ',' ; p++) ;
- }
-}
-
-
-int
-main(int ac, char *av[])
-{
- char *Name;
- char *p;
- FILE *F;
- int i;
- bool Flat;
- bool Redirect;
- bool Concat;
- char *Index;
- char buff[BUFSIZ];
- char *spool;
- char dest[BUFSIZ];
- char **groups, *q, *ng;
- char **xrefs;
- const char *xrefhdr;
- ARTHANDLE *art;
- TOKEN token;
- unsigned int numgroups, numxrefs;
- int j;
- char *base = NULL;
- bool doit;
-
- /* First thing, set up our identity. */
- message_program_name = "archive";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- Concat = false;
- Flat = false;
- Index = NULL;
- Redirect = true;
- umask(NEWSUMASK);
- ERRLOG = concatpath(innconf->pathlog, _PATH_ERRLOG);
- Archive = innconf->patharchive;
- groups = NULL;
- numgroups = 0;
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "a:cfi:p:r")) != EOF)
- switch (i) {
- default:
- die("usage error");
- break;
- case 'a':
- Archive = optarg;
- break;
- case 'c':
- Flat = true;
- Concat = true;
- break;
- case 'f':
- Flat = true;
- break;
- case 'i':
- Index = optarg;
- break;
- case 'p':
- groups = CrackGroups(optarg, &numgroups);
- break;
- case 'r':
- Redirect = false;
- break;
- }
-
- /* Parse arguments -- at most one, the batchfile. */
- ac -= optind;
- av += optind;
- if (ac > 2)
- die("usage error");
-
- /* Do file redirections. */
- if (Redirect)
- freopen(ERRLOG, "a", stderr);
- if (ac == 1 && freopen(av[0], "r", stdin) == NULL)
- sysdie("cannot open %s for input", av[0]);
- if (Index && freopen(Index, "a", stdout) == NULL)
- sysdie("cannot open %s for output", Index);
-
- /* Go to where the action is. */
- if (chdir(innconf->patharticles) < 0)
- sysdie("cannot chdir to %s", innconf->patharticles);
-
- /* Set up the destination. */
- strcpy(dest, Archive);
- Name = dest + strlen(dest);
- *Name++ = '/';
-
- if (!SMinit())
- die("cannot initialize storage manager: %s", SMerrorstr);
-
- /* Read input. */
- while (fgets(buff, sizeof buff, stdin) != NULL) {
- if ((p = strchr(buff, '\n')) == NULL) {
- warn("skipping %.40s: too long", buff);
- continue;
- }
- *p = '\0';
- if (buff[0] == '\0' || buff[0] == '#')
- continue;
-
- /* Check to see if this is a token... */
- if (IsToken(buff)) {
- /* Get a copy of the article. */
- token = TextToToken(buff);
- if ((art = SMretrieve(token, RETR_ALL)) == NULL) {
- warn("cannot retrieve %s", buff);
- continue;
- }
-
- /* Determine groups from the Xref header */
- xrefhdr = wire_findheader(art->data, art->len, "Xref");
- if (xrefhdr == NULL) {
- warn("cannot find Xref header");
- SMfreearticle(art);
- continue;
- }
-
- if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
- warn("bogus Xref header");
- SMfreearticle(art);
- continue;
- }
-
- /* Process each newsgroup... */
- if (base) {
- free(base);
- base = NULL;
- }
- for (i=0; (unsigned)i<numxrefs; i++) {
- /* Check for group limits... -p flag */
- if ((p=strchr(xrefs[i], ':')) == NULL) {
- warn("bogus Xref entry %s", xrefs[i]);
- continue; /* Skip to next xref */
- }
- if (numgroups > 0) {
- *p = '\0';
- ng = xrefs[i];
- doit = false;
- for (j=0; (unsigned)j<numgroups && !doit; j++) {
- if (uwildmat(ng, groups[j]) != 0) doit=true;
- }
- }
- else {
- doit = true;
- }
- *p = '/';
- if (doit) {
- p = Name;
- q = xrefs[i];
- while(*q) {
- *p++ = *q++;
- }
- *p='\0';
-
- if (!Flat) {
- for (p=Name; *p; p++) {
- if (*p == '.') {
- *p = '/';
- }
- }
- }
-
- if (Concat) {
- p = strrchr(Name, '/');
- q = DateString();
- p++;
- while (*q) {
- *p++ = *q++;
- }
- *p = '\0';
- }
-
- if (base && !Concat) {
- /* Try to link the file into the archive. */
- if (link(base, dest) < 0) {
-
- /* Make the archive directory. */
- if (!MakeArchiveDirectory(dest)) {
- syswarn("cannot mkdir for %s", dest);
- continue;
- }
-
- /* Try to link again; if that fails, make a copy. */
- if (link(base, dest) < 0) {
-#if defined(HAVE_SYMLINK)
- if (symlink(base, dest) < 0)
- syswarn("cannot symlink %s to %s",
- dest, base);
- else
-#endif /* defined(HAVE_SYMLINK) */
- if (!Copy(base, dest))
- continue;
- continue;
- }
- }
- } else {
- if (!CopyArt(art, dest, Concat))
- syswarn("copying %s to %s failed", buff, dest);
- base = xstrdup(dest);
- }
-
- /* Write index. */
- if (Index) {
- WriteArtIndex(art, Name);
- if (ferror(stdout) || fflush(stdout) == EOF)
- syswarn("cannot write index for %s", Name);
- }
- }
- }
-
- /* Free up the article storage space */
- SMfreearticle(art);
- art = NULL;
- /* Free up the xrefs storage space */
- for ( i=0; (unsigned)i<numxrefs; i++) free(xrefs[i]);
- free(xrefs);
- numxrefs = 0;
- xrefs = NULL;
- } else {
- warn("%s is not a token", buff);
- continue;
- }
- }
-
- /* close down the storage manager api */
- SMshutdown();
-
- /* If we read all our input, try to remove the file, and we're done. */
- if (feof(stdin)) {
- fclose(stdin);
- if (av[0])
- unlink(av[0]);
- exit(0);
- }
-
- /* Make an appropriate spool file. */
- p = av[0];
- if (p == NULL)
- spool = concatpath(innconf->pathoutgoing, "archive");
- else if (*p == '/')
- spool = concat(p, ".bch", (char *) 0);
- else
- spool = concat(innconf->pathoutgoing, "/", p, ".bch", (char *) 0);
- if ((F = xfopena(spool)) == NULL)
- sysdie("cannot spool to %s", spool);
-
- /* Write the rest of stdin to the spool file. */
- i = 0;
- if (fprintf(F, "%s\n", buff) == EOF) {
- syswarn("cannot start spool");
- i = 1;
- }
- while (fgets(buff, sizeof buff, stdin) != NULL)
- if (fputs(buff, F) == EOF) {
- syswarn("cannot write to spool");
- i = 1;
- break;
- }
- if (fclose(F) == EOF) {
- syswarn("cannot close spool");
- i = 1;
- }
-
- /* If we had a named input file, try to rename the spool. */
- if (p != NULL && rename(spool, av[0]) < 0) {
- syswarn("cannot rename spool");
- i = 1;
- }
-
- exit(i);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: batcher.c 6762 2004-05-17 04:24:53Z rra $
-**
-** Read batchfiles on standard input and spew out batches.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/timer.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-
-/*
-** Global variables.
-*/
-static bool BATCHopen;
-static bool STATprint;
-static double STATbegin;
-static double STATend;
-static char *Host;
-static char *InitialString;
-static char *Input;
-static char *Processor;
-static int ArtsInBatch;
-static int ArtsWritten;
-static int BATCHcount;
-static int MaxBatches;
-static int BATCHstatus;
-static long BytesInBatch = 60 * 1024;
-static long BytesWritten;
-static long MaxArts;
-static long MaxBytes;
-static sig_atomic_t GotInterrupt;
-static const char *Separator = "#! rnews %ld";
-static char *ERRLOG;
-
-/*
-** Start a batch process.
-*/
-static FILE *
-BATCHstart(void)
-{
- FILE *F;
- char buff[SMBUF];
-
- if (Processor && *Processor) {
- snprintf(buff, sizeof(buff), Processor, Host);
- F = popen(buff, "w");
- if (F == NULL)
- return NULL;
- }
- else
- F = stdout;
- BATCHopen = true;
- BATCHcount++;
- return F;
-}
-
-
-/*
-** Close a batch, return exit status.
-*/
-static int
-BATCHclose(FILE *F)
-{
- BATCHopen = false;
- if (F == stdout)
- return fflush(stdout) == EOF ? 1 : 0;
- return pclose(F);
-}
-
-
-/*
-** Update the batch file and exit.
-*/
-static void
-RequeueAndExit(off_t Cookie, char *line, long BytesInArt)
-{
- static char LINE1[] = "batcher %s times user %.3f system %.3f elapsed %.3f";
- static char LINE2[] ="batcher %s stats batches %d articles %d bytes %ld";
- char *spool;
- char buff[BIG_BUFFER];
- int i;
- FILE *F;
- double usertime;
- double systime;
-
- /* Do statistics. */
- STATend = TMRnow_double();
- if (GetResourceUsage(&usertime, &systime) < 0) {
- usertime = 0;
- systime = 0;
- }
-
- if (STATprint) {
- printf(LINE1, Host, usertime, systime, STATend - STATbegin);
- printf("\n");
- printf(LINE2, Host, BATCHcount, ArtsWritten, BytesWritten);
- printf("\n");
- }
-
- syslog(L_NOTICE, LINE1, Host, usertime, systime, STATend - STATbegin);
- syslog(L_NOTICE, LINE2, Host, BATCHcount, ArtsWritten, BytesWritten);
-
- /* Last batch exit okay? */
- if (BATCHstatus == 0) {
- if (feof(stdin) && Cookie != -1) {
- /* Yes, and we're all done -- remove input and exit. */
- fclose(stdin);
- if (Input)
- unlink(Input);
- exit(0);
- }
- }
-
- /* Make an appropriate spool file. */
- if (Input == NULL)
- spool = concatpath(innconf->pathoutgoing, Host);
- else
- spool = concat(Input, ".bch", (char *) 0);
- if ((F = xfopena(spool)) == NULL)
- sysdie("%s cannot open %s", Host, spool);
-
- /* If we can back up to where the batch started, do so. */
- i = 0;
- if (Cookie != -1 && fseeko(stdin, Cookie, SEEK_SET) == -1) {
- syswarn("%s cannot seek", Host);
- i = 1;
- }
-
- /* Write the line we had; if the fseeko worked, this will be an
- * extra line, but that's okay. */
- if (line && fprintf(F, "%s %ld\n", line, BytesInArt) == EOF) {
- syswarn("%s cannot write spool", Host);
- i = 1;
- }
-
- /* Write rest of stdin to spool. */
- while (fgets(buff, sizeof buff, stdin) != NULL)
- if (fputs(buff, F) == EOF) {
- syswarn("%s cannot write spool", Host);
- i = 1;
- break;
- }
- if (fclose(F) == EOF) {
- syswarn("%s cannot close spool", Host);
- i = 1;
- }
-
- /* If we had a named input file, try to rename the spool. */
- if (Input != NULL && rename(spool, Input) < 0) {
- syswarn("%s cannot rename spool", Host);
- i = 1;
- }
-
- exit(i);
- /* NOTREACHED */
-}
-
-
-/*
-** Mark that we got interrupted.
-*/
-static RETSIGTYPE
-CATCHinterrupt(int s)
-{
- GotInterrupt = true;
-
- /* Let two interrupts kill us. */
- xsignal(s, SIG_DFL);
-}
-
-
-int
-main(int ac, char *av[])
-{
- bool Redirect;
- FILE *F;
- const char *AltSpool;
- char *p;
- char *data;
- char line[BIG_BUFFER];
- char buff[BIG_BUFFER];
- int BytesInArt;
- long BytesInCB;
- off_t Cookie;
- size_t datasize;
- int i;
- int ArtsInCB;
- int length;
- TOKEN token;
- ARTHANDLE *art;
- char *artdata;
-
- /* Set defaults. */
- openlog("batcher", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "batcher";
- if (!innconf_read(NULL))
- exit(1);
- AltSpool = NULL;
- Redirect = true;
- umask(NEWSUMASK);
- ERRLOG = concatpath(innconf->pathlog, _PATH_ERRLOG);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "a:A:b:B:i:N:p:rs:S:v")) != EOF)
- switch (i) {
- default:
- die("usage error");
- break;
- case 'a':
- ArtsInBatch = atoi(optarg);
- break;
- case 'A':
- MaxArts = atol(optarg);
- break;
- case 'b':
- BytesInBatch = atol(optarg);
- break;
- case 'B':
- MaxBytes = atol(optarg);
- break;
- case 'i':
- InitialString = optarg;
- break;
- case 'N':
- MaxBatches = atoi(optarg);
- break;
- case 'p':
- Processor = optarg;
- break;
- case 'r':
- Redirect = false;
- break;
- case 's':
- Separator = optarg;
- break;
- case 'S':
- AltSpool = optarg;
- break;
- case 'v':
- STATprint = true;
- break;
- }
- if (MaxArts && ArtsInBatch == 0)
- ArtsInBatch = MaxArts;
- if (MaxBytes && BytesInBatch == 0)
- BytesInBatch = MaxBytes;
-
- /* Parse arguments. */
- ac -= optind;
- av += optind;
- if (ac != 1 && ac != 2)
- die("usage error");
- Host = av[0];
- if ((Input = av[1]) != NULL) {
- if (Input[0] != '/')
- Input = concatpath(innconf->pathoutgoing, av[1]);
- if (freopen(Input, "r", stdin) == NULL)
- sysdie("%s cannot open %s", Host, Input);
- }
-
- if (Redirect)
- freopen(ERRLOG, "a", stderr);
-
- /* Go to where the articles are. */
- if (chdir(innconf->patharticles) < 0)
- sysdie("%s cannot chdir to %s", Host, innconf->patharticles);
-
- /* Set initial counters, etc. */
- datasize = 8 * 1024;
- data = xmalloc(datasize);
- BytesInCB = 0;
- ArtsInCB = 0;
- Cookie = -1;
- GotInterrupt = false;
- xsignal(SIGHUP, CATCHinterrupt);
- xsignal(SIGINT, CATCHinterrupt);
- xsignal(SIGTERM, CATCHinterrupt);
- /* xsignal(SIGPIPE, CATCHinterrupt); */
- STATbegin = TMRnow_double();
-
- SMinit();
- F = NULL;
- while (fgets(line, sizeof line, stdin) != NULL) {
- /* Record line length in case we do an ftello. Not portable to
- * systems with non-Unix file formats. */
- length = strlen(line);
- Cookie = ftello(stdin) - length;
-
- /* Get lines like "name size" */
- if ((p = strchr(line, '\n')) == NULL) {
- warn("%s skipping %.40s: too long", Host, line);
- continue;
- }
- *p = '\0';
- if (line[0] == '\0' || line[0] == '#')
- continue;
- if ((p = strchr(line, ' ')) != NULL) {
- *p++ = '\0';
- /* Try to be forgiving of bad input. */
- BytesInArt = CTYPE(isdigit, (int)*p) ? atol(p) : -1;
- }
- else
- BytesInArt = -1;
-
- /* Strip of leading spool pathname. */
- if (line[0] == '/'
- && line[strlen(innconf->patharticles)] == '/'
- && strncmp(line, innconf->patharticles, strlen(innconf->patharticles)) == 0)
- p = line + strlen(innconf->patharticles) + 1;
- else
- p = line;
-
- /* Open the file. */
- if (IsToken(p)) {
- token = TextToToken(p);
- if ((art = SMretrieve(token, RETR_ALL)) == NULL) {
- if ((SMerrno != SMERR_NOENT) && (SMerrno != SMERR_UNINIT))
- warn("%s skipping %.40s: %s", Host, p, SMerrorstr);
- continue;
- }
- BytesInArt = -1;
- artdata = FromWireFmt(art->data, art->len, (size_t *)&BytesInArt);
- SMfreearticle(art);
- } else {
- warn("%s skipping %.40s: not token", Host, p);
- continue;
- }
-
- /* Have an open article, do we need to open a batch? This code
- * is here (rather then up before the while loop) so that we
- * can avoid sending an empty batch. The goto makes the code
- * a bit more clear. */
- if (F == NULL) {
- if (GotInterrupt) {
- RequeueAndExit(Cookie, (char *)NULL, 0L);
- }
- if ((F = BATCHstart()) == NULL) {
- syswarn("%s cannot start batch %d", Host, BATCHcount);
- break;
- }
- if (InitialString && *InitialString) {
- fprintf(F, "%s\n", InitialString);
- BytesInCB += strlen(InitialString) + 1;
- BytesWritten += strlen(InitialString) + 1;
- }
- goto SendIt;
- }
-
- /* We're writing a batch, see if adding the current article
- * would exceed the limits. */
- if ((ArtsInBatch > 0 && ArtsInCB + 1 >= ArtsInBatch)
- || (BytesInBatch > 0 && BytesInCB + BytesInArt >= BytesInBatch)) {
- if ((BATCHstatus = BATCHclose(F)) != 0) {
- if (BATCHstatus == -1)
- syswarn("%s cannot close batch %d", Host, BATCHcount);
- else
- syswarn("%s batch %d exit status %d", Host, BATCHcount,
- BATCHstatus);
- break;
- }
- ArtsInCB = 0;
- BytesInCB = 0;
-
- /* See if we can start a new batch. */
- if ((MaxBatches > 0 && BATCHcount >= MaxBatches)
- || (MaxBytes > 0 && BytesWritten + BytesInArt >= MaxBytes)
- || (MaxArts > 0 && ArtsWritten + 1 >= MaxArts)) {
- break;
- }
-
- if (GotInterrupt) {
- RequeueAndExit(Cookie, (char *)NULL, 0L);
- }
-
- if ((F = BATCHstart()) == NULL) {
- syswarn("%s cannot start batch %d", Host, BATCHcount);
- break;
- }
- }
-
- SendIt:
- /* Now we can start to send the article! */
- if (Separator && *Separator) {
- snprintf(buff, sizeof(buff), Separator, BytesInArt);
- BytesInCB += strlen(buff) + 1;
- BytesWritten += strlen(buff) + 1;
- if (fprintf(F, "%s\n", buff) == EOF || ferror(F)) {
- syswarn("%s cannot write separator", Host);
- break;
- }
- }
-
- /* Write the article. In case of interrupts, retry the read but not
- the fwrite because we can't check that reliably and portably. */
- if ((fwrite(artdata, 1, BytesInArt, F) != BytesInArt) || ferror(F))
- break;
-
- /* Update the counts. */
- BytesInCB += BytesInArt;
- BytesWritten += BytesInArt;
- ArtsInCB++;
- ArtsWritten++;
-
- if (GotInterrupt) {
- Cookie = -1;
- BATCHstatus = BATCHclose(F);
- RequeueAndExit(Cookie, line, BytesInArt);
- }
- }
-
- if (BATCHopen)
- BATCHstatus = BATCHclose(F);
- RequeueAndExit(Cookie, NULL, 0);
-
- return 0;
-}
+++ /dev/null
-/* $Id: buffchan.c 6163 2003-01-19 22:56:34Z rra $
-**
-** Buffered file exploder for innd.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-#include "map.h"
-
-/*
-** Hash functions for hashing sitenames.
-*/
-#define SITE_HASH(Name, p, j) \
- for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++
-#define SITE_SIZE 128
-#define SITE_BUCKET(j) &SITEtable[j & (SITE_SIZE - 1)]
-
-
-/*
-** Entry for a single active site.
-*/
-typedef struct _SITE {
- bool Dropped;
- const char *Name;
- int CloseLines;
- int FlushLines;
- time_t LastFlushed;
- time_t LastClosed;
- int CloseSeconds;
- int FlushSeconds;
- FILE *F;
- const char *Filename;
- char *Buffer;
-} SITE;
-
-
-/*
-** Site hashtable bucket.
-*/
-typedef struct _SITEHASH {
- int Size;
- int Used;
- SITE *Sites;
-} SITEHASH;
-
-
-/* Global variables. */
-static char *Format;
-static const char *Map;
-static int BufferMode;
-static int CloseEvery;
-static int FlushEvery;
-static int CloseSeconds;
-static int FlushSeconds;
-static sig_atomic_t GotInterrupt;
-static SITEHASH SITEtable[SITE_SIZE];
-static TIMEINFO Now;
-
-
-/*
-** Set up the site information. Basically creating empty buckets.
-*/
-static void
-SITEsetup(void)
-{
- SITEHASH *shp;
-
- for (shp = SITEtable; shp < ARRAY_END(SITEtable); shp++) {
- shp->Size = 3;
- shp->Sites = xmalloc(shp->Size * sizeof(SITE));
- shp->Used = 0;
- }
-}
-
-
-/*
-** Close a site
-*/
-static void
-SITEclose(SITE *sp)
-{
- FILE *F;
-
- if ((F = sp->F) != NULL) {
- if (fflush(F) == EOF || ferror(F)
- || fchmod((int)fileno(F), 0664) < 0
- || fclose(F) == EOF)
- syswarn("%s cannot close %s", sp->Name, sp->Filename);
- sp->F = NULL;
- }
-}
-
-/*
-** Close all open sites.
-*/
-static void
-SITEcloseall(void)
-{
- SITEHASH *shp;
- SITE *sp;
- int i;
-
- for (shp = SITEtable; shp < ARRAY_END(SITEtable); shp++)
- for (sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
- SITEclose(sp);
-}
-
-
-/*
-** Open the file for a site.
-*/
-static void SITEopen(SITE *sp)
-{
- int e;
-
- if ((sp->F = xfopena(sp->Filename)) == NULL
- && ((e = errno) != EACCES || chmod(sp->Filename, 0644) < 0
- || (sp->F = xfopena(sp->Filename)) == NULL)) {
- syswarn("%s cannot fopen %s", sp->Name, sp->Filename);
- if ((sp->F = fopen("/dev/null", "w")) == NULL)
- /* This really should not happen. */
- sysdie("%s cannot fopen /dev/null", sp->Name);
- }
- else if (fchmod((int)fileno(sp->F), 0444) < 0)
- syswarn("%s cannot fchmod %s", sp->Name, sp->Filename);
-
- if (BufferMode != '\0')
- setbuf(sp->F, sp->Buffer);
-
- /* Reset all counters. */
- sp->FlushLines = 0;
- sp->CloseLines = 0;
- sp->LastFlushed = Now.time;
- sp->LastClosed = Now.time;
- sp->Dropped = false;
-}
-
-
-/*
-** Find a site, possibly create if not found.
-*/
-static SITE *
-SITEfind(char *Name, bool CanCreate)
-{
- char *p;
- int i;
- unsigned int j;
- SITE *sp;
- SITEHASH *shp;
- char c;
- char buff[BUFSIZ];
-
- /* Look for site in the hash table. */
- SITE_HASH(Name, p, j);
- shp = SITE_BUCKET(j);
- for (c = *Name, sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
- if (c == sp->Name[0] && strcasecmp(Name, sp->Name) == 0)
- return sp;
- if (!CanCreate)
- return NULL;
-
- /* Adding a new site -- grow hash bucket if we need to. */
- if (shp->Used == shp->Size - 1) {
- shp->Size *= 2;
- shp->Sites = xrealloc(shp->Sites, shp->Size * sizeof(SITE));
- }
- sp = &shp->Sites[shp->Used++];
-
- /* Fill in the structure for the new site. */
- sp->Name = xstrdup(Name);
- snprintf(buff, sizeof(buff), Format, Map ? MAPname(Name) : sp->Name);
- sp->Filename = xstrdup(buff);
- if (BufferMode == 'u')
- sp->Buffer = NULL;
- else if (BufferMode == 'b')
- sp->Buffer = xmalloc(BUFSIZ);
- SITEopen(sp);
-
- return sp;
-}
-
-
-/*
-** Flush a site -- close and re-open the file.
-*/
-static void
-SITEflush(SITE *sp)
-{
- FILE *F;
-
- if ((F = sp->F) != NULL) {
- if (fflush(F) == EOF || ferror(F)
- || fchmod((int)fileno(F), 0664) < 0
- || fclose(F) == EOF)
- syswarn("%s cannot close %s", sp->Name, sp->Filename);
- sp->F = NULL;
- }
- if (!sp->Dropped)
- SITEopen(sp);
-}
-
-
-/*
-** Flush all open sites.
-*/
-static void
-SITEflushall(void)
-{
- SITEHASH *shp;
- SITE *sp;
- int i;
-
- for (shp = SITEtable; shp < ARRAY_END(SITEtable); shp++)
- for (sp = shp->Sites, i = shp->Used; --i >= 0; sp++)
- SITEflush(sp);
-}
-
-
-/*
-** Write data to a site.
-*/
-static void
-SITEwrite(char *name, char *text, size_t len)
-{
- SITE *sp;
-
- sp = SITEfind(name, true);
- if (sp->F == NULL)
- SITEopen(sp);
-
- if (fwrite(text, 1, len, sp->F) != len)
- syswarn("%s cannot write", sp->Name);
-
- /* Bump line count; see if time to close or flush. */
- if (CloseEvery && ++(sp->CloseLines) >= CloseEvery) {
- SITEflush(sp);
- return;
- }
- if (CloseSeconds && sp->LastClosed + CloseSeconds < Now.time) {
- SITEflush(sp);
- return;
- }
- if (FlushEvery && ++(sp->FlushLines) >= FlushEvery) {
- if (fflush(sp->F) == EOF || ferror(sp->F))
- syswarn("%s cannot flush %s", sp->Name, sp->Filename);
- sp->LastFlushed = Now.time;
- sp->FlushLines = 0;
- }
- else if (FlushSeconds && sp->LastFlushed + FlushSeconds < Now.time) {
- if (fflush(sp->F) == EOF || ferror(sp->F))
- syswarn("%s cannot flush %s", sp->Name, sp->Filename);
- sp->LastFlushed = Now.time;
- sp->FlushLines = 0;
- }
-}
-
-
-/*
-** Handle a command message.
-*/
-static void
-Process(char *p)
-{
- SITE *sp;
-
- if (*p == 'b' && strncmp(p, "begin", 5) == 0)
- /* No-op. */
- return;
-
- if (*p == 'f' && strncmp(p, "flush", 5) == 0) {
- for (p += 5; ISWHITE(*p); p++)
- continue;
- if (*p == '\0')
- SITEflushall();
- else if ((sp = SITEfind(p, false)) != NULL)
- SITEflush(sp);
- /*else
- fprintf(stderr, "buffchan flush %s unknown site\n", p);*/
- return;
- }
-
- if (*p == 'd' && strncmp(p, "drop", 4) == 0) {
- for (p += 4; ISWHITE(*p); p++)
- continue;
- if (*p == '\0')
- SITEcloseall();
- else if ((sp = SITEfind(p, false)) == NULL)
- warn("drop %s unknown site", p);
- else {
- SITEclose(sp);
- sp->Dropped = true;
- }
- return;
- }
-
- if (*p == 'r' && strncmp(p, "readmap", 7) == 0) {
- MAPread(Map);
- return;
- }
-
- /* Other command messages -- ignored. */
- warn("unknown message %s", p);
-}
-
-
-/*
-** Mark that we got a signal; let two signals kill us.
-*/
-static RETSIGTYPE
-CATCHinterrupt(int s)
-{
- GotInterrupt = true;
- xsignal(s, SIG_DFL);
-}
-
-
-int
-main(int ac, char *av[])
-{
- QIOSTATE *qp;
- int i;
- int Fields;
- char *p;
- char *next;
- char *line;
- char *Directory;
- bool Redirect;
- FILE *F;
- char *ERRLOG;
-
- /* First thing, set up our identity. */
- message_program_name = "buffchan";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- ERRLOG = concatpath(innconf->pathlog, _PATH_ERRLOG);
- Directory = NULL;
- Fields = 1;
- Format = NULL;
- Redirect = true;
- GotInterrupt = false;
- umask(NEWSUMASK);
-
- xsignal(SIGHUP, CATCHinterrupt);
- xsignal(SIGINT, CATCHinterrupt);
- xsignal(SIGQUIT, CATCHinterrupt);
- xsignal(SIGPIPE, CATCHinterrupt);
- xsignal(SIGTERM, CATCHinterrupt);
- xsignal(SIGALRM, CATCHinterrupt);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "bc:C:d:f:l:L:m:p:rs:u")) != EOF)
- switch (i) {
- default:
- die("usage error");
- break;
- case 'b':
- case 'u':
- BufferMode = i;
- break;
- case 'c':
- CloseEvery = atoi(optarg);
- break;
- case 'C':
- CloseSeconds = atoi(optarg);
- break;
- case 'd':
- Directory = optarg;
- if (Format == NULL)
- Format =xstrdup("%s");
- break;
- case 'f':
- Fields = atoi(optarg);
- break;
- case 'l':
- FlushEvery = atoi(optarg);
- break;
- case 'L':
- FlushSeconds = atoi(optarg);
- break;
- case 'm':
- Map = optarg;
- MAPread(Map);
- break;
- case 'p':
- if ((F = fopen(optarg, "w")) == NULL)
- sysdie("cannot fopen %s", optarg);
- fprintf(F, "%ld\n", (long)getpid());
- if (ferror(F) || fclose(F) == EOF)
- sysdie("cannot fclose %s", optarg);
- break;
- case 'r':
- Redirect = false;
- break;
- case 's':
- Format = optarg;
- break;
- }
- ac -= optind;
- av += optind;
- if (ac)
- die("usage error");
-
- /* Do some basic set-ups. */
- if (Redirect)
- freopen(ERRLOG, "a", stderr);
- if (Format == NULL) {
- Format = concatpath(innconf->pathoutgoing, "%s");
- }
- if (Directory && chdir(Directory) < 0)
- sysdie("cannot chdir to %s", Directory);
- SITEsetup();
-
- /* Read input. */
- for (qp = QIOfdopen((int)fileno(stdin)); !GotInterrupt ; ) {
- if ((line = QIOread(qp)) == NULL) {
- if (QIOerror(qp)) {
- syswarn("cannot read");
- break;
- }
- if (QIOtoolong(qp)) {
- warn("long line");
- QIOread(qp);
- continue;
- }
-
- /* Normal EOF. */
- break;
- }
-
- /* Command? */
- if (*line == EXP_CONTROL && *++line != EXP_CONTROL) {
- Process(line);
- continue;
- }
-
- /* Skip the right number of leading fields. */
- for (i = Fields, p = line; *p; p++)
- if (*p == ' ' && --i <= 0)
- break;
- if (*p == '\0')
- /* Nothing to write. Probably shouldn't happen. */
- continue;
-
- /* Add a newline, get the length of all leading fields. */
- *p++ = '\n';
- i = p - line;
-
- if (GetTimeInfo(&Now) < 0) {
- syswarn("cannot get time");
- break;
- }
-
- /* Rest of the line is space-separated list of filenames. */
- for (; *p; p = next) {
- /* Skip whitespace, get next word. */
- while (*p == ' ')
- p++;
- for (next = p; *next && *next != ' '; next++)
- continue;
- if (*next)
- *next++ = '\0';
-
- SITEwrite(p, line, i);
- }
-
- }
-
- SITEcloseall();
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: crosspost.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Parse input to add links for cross posted articles. Input format is one
-** line per article. Dots '.' are changed to '/'. Commas ',' or blanks
-** ' ' separate entries. Typically this is via a channel feed from innd
-** though an edit of the history file can also be used for recovery
-** purposes. Sample newsfeeds entry:
-**
-** # Create the links for cross posted articles
-** crosspost:*:Tc,Ap,WR:/usr/local/newsbin/crosspost
-**
-** WARNING: This no longer works with the current INN; don't use it
-** currently. It still exists in the source tree in case someone will
-** want to clean it up and make it useable again.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-
-
-static char *Dir;
-
-static int debug = false;
-static int syncfiles = true;
-
-static unsigned long STATTime = 0;
-static unsigned long STATMissing = 0; /* Source file missing */
-static unsigned long STATTooLong = 0; /* Name Too Long (src or dest) */
-static unsigned long STATLink = 0; /* Link done */
-static unsigned long STATLError = 0; /* Link problem */
-static unsigned long STATSymlink = 0; /* Symlink done */
-static unsigned long STATSLError = 0; /* Symlink problem */
-static unsigned long STATMkdir = 0; /* Mkdir done */
-static unsigned long STATMdError = 0; /* Mkdir problem */
-static unsigned long STATOError = 0; /* Other errors */
-
-#define MAXXPOST 256
-#define STATREFRESH 10800 /* 3 hours */
-
-/*
-** Write some statistics and reset all counters.
-*/
-void
-ProcessStats()
-{
- time_t Time;
-
- Time = time (NULL);
- syslog(L_NOTICE,
- "seconds %lu links %lu %lu symlinks %lu %lu mkdirs %lu %lu missing %lu toolong %lu other %lu",
- Time - STATTime, STATLink, STATLError, STATSymlink, STATSLError,
- STATMkdir, STATMdError, STATMissing, STATTooLong, STATOError);
-
- STATMissing = STATTooLong = STATLink = STATLError = 0;
- STATSymlink = STATSLError = STATMkdir = STATMdError = STATOError = 0;
- STATTime = Time;
-}
-
-/*
-** Try to make one directory. Return false on error.
-*/
-static bool
-MakeDir(Name)
- char *Name;
-{
- struct stat Sb;
-
- if (mkdir(Name, GROUPDIR_MODE) >= 0) {
- STATMkdir++;
- return true;
- }
-
- /* See if it failed because it already exists. */
- return stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode);
-}
-
-
-/*
-** Make spool directory. Return false on error.
-*/
-static bool
-MakeSpoolDir(Name)
- char *Name;
-{
- char *p;
- bool made;
-
- /* Optimize common case -- parent almost always exists. */
- if (MakeDir(Name))
- return true;
-
- /* Try to make each of comp and comp/foo in turn. */
- for (p = Name; *p; p++)
- if (*p == '/') {
- *p = '\0';
- made = MakeDir(Name);
- *p = '/';
- if (!made) {
- STATMdError++;
- return false;
- }
- }
-
- return MakeDir(Name);
-}
-
-
-/*
-** Process the input. Data can come from innd:
-** news/group/name/<number> [space news/group/<number>]...
-** or
-** news.group.name/<number>,[news.group.name/<number>]...
-*/
-static void
-ProcessIncoming(qp)
- QIOSTATE *qp;
-{
- char *p;
- int i;
- int nxp;
- int fd;
- int lnval ;
- char *names[MAXXPOST];
-
-
- for ( ; ; ) {
-
- if (time(NULL) - STATTime > STATREFRESH)
- ProcessStats();
-
- /* Read the first line of data. */
- if ((p = QIOread(qp)) == NULL) {
- if (QIOtoolong(qp)) {
- fprintf(stderr, "crosspost line too long\n");
- STATTooLong++;
- continue;
- }
- break;
- }
-
- for (i = 0; *p && (i < MAXXPOST); i++) { /* parse input into array */
- names[i] = p;
- for ( ; *p; p++) {
- if (*p == '.') *p++ = '/'; /* dot to slash translation */
- else if ((*p == ',') /* name separators */
- || (*p == ' ')
- || (*p == '\t')
- || (*p == '\n')) {
- *p++ = '\0';
- break;
- }
- }
- }
- nxp = i;
- if (debug) {
- for (i = 0; i < nxp; i++)
- fprintf(stderr, "crosspost: debug %d %s\n",
- i, names[i]);
- }
-
- if(syncfiles) fd = open(names[0], O_RDWR);
-
- for (i = 1; i < nxp; i++) {
- lnval = link(names[0], names[i]) ;
- if (lnval == 0) STATLink++;
- if (lnval < 0 && errno != EXDEV) { /* first try to link */
- int j;
- char path[SPOOLNAMEBUFF+2];
-
- for (j = 0; (path[j] = names[i][j]) != '\0' ; j++) ;
- for (j--; (j > 0) && (path[j] != '/'); j--) ;
- if (path[j] == '/') {
- path[j] = '\0';
- /* try making parent dir */
- if (MakeSpoolDir(path) == false) {
- fprintf(stderr, "crosspost cant mkdir %s\n",
- path);
- }
- else {
- /* 2nd try to link */
- lnval = link(names[0], names[i]) ;
- if (lnval == 0) STATLink++;
- if (lnval < 0 && errno == EXDEV) {
-#if !defined(HAVE_SYMLINK)
- fprintf(stderr, "crosspost cant link %s %s",
- names[0], names[i]);
- perror(" ");
-#else
- /* Try to make a symbolic link
- ** to the full pathname.
- */
- for (j = 0, p = Dir; (j < SPOOLNAMEBUFF) && *p; )
- path[j++] = *p++; /* copy spool dir */
- if (j < SPOOLNAMEBUFF) path[j++] = '/';
- for (p = names[0]; (j < SPOOLNAMEBUFF) && *p; )
- path[j++] = *p++; /* append path */
- path[j++] = '\0';
- if (symlink(path, names[i]) < 0) {
- fprintf(stderr,
- "crosspost cant symlink %s %s",
- path, names[i]);
- perror(" ");
- STATSLError++;
- }
- else
- STATSymlink++;
-#endif /* !defined(HAVE_SYMLINK) */
- } else if (lnval < 0) {
- if (lnval == ENOENT)
- STATMissing++;
- else {
- fprintf(stderr, "crosspost cant link %s %s",
- names[0], names[i]);
- perror(" ");
- STATLError++;
- }
- }
- }
- } else {
- fprintf(stderr, "crosspost bad path %s\n",
- names[i]);
- STATOError++;
- }
- } else if (lnval < 0) {
- int j;
- char path[SPOOLNAMEBUFF+2];
-
-#if !defined(HAVE_SYMLINK)
- fprintf(stderr, "crosspost cant link %s %s",
- names[0], names[i]);
- perror(" ");
-#else
- /* Try to make a symbolic link
- ** to the full pathname.
- */
- for (j = 0, p = Dir; (j < SPOOLNAMEBUFF) && *p; )
- path[j++] = *p++; /* copy spool dir */
- if (j < SPOOLNAMEBUFF) path[j++] = '/';
- for (p = names[0]; (j < SPOOLNAMEBUFF) && *p; )
- path[j++] = *p++; /* append path */
- path[j++] = '\0';
- if (symlink(path, names[i]) < 0) {
- fprintf(stderr,
- "crosspost cant symlink %s %s",
- path, names[i]);
- perror(" ");
- STATSLError++;
- }
- else
- STATSymlink++;
-#endif /* !defined(HAVE_SYMLINK) */
- }
- }
-
- if (syncfiles && (fd >= 0)) {
- fsync(fd);
- close(fd);
- }
- }
-
- if (QIOerror(qp))
- fprintf(stderr, "crosspost cant read %s\n", strerror(errno));
- QIOclose(qp);
-}
-
-
-static void
-Usage(void)
-{
- fprintf(stderr, "usage: crosspost [-D dir] [files...]\n");
- exit(1);
-}
-
-
-int
-main(ac, av)
- int ac;
- char *av[];
-{
- int i;
- QIOSTATE *qp;
-
- /* Set defaults. */
- if (ReadInnConf() < 0) exit(1);
- Dir = innconf->patharticles;
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "D:ds")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'D':
- Dir = optarg; /* specify spool path */
- break;
- case 'd':
- debug = true;
- break;
- case 's':
- syncfiles = false; /* do not fsync articles */
- break;
- }
- ac -= optind;
- av += optind;
-
- if (chdir(Dir) < 0) {
- fprintf(stderr, "crosspost cant chdir %s %s\n",
- Dir, strerror(errno));
- exit(1);
- }
- openlog("crosspost", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- STATTime = time (NULL);
- if (ac == 0)
- ProcessIncoming(QIOfdopen(STDIN_FILENO));
- else {
- for ( ; *av; av++)
- if (strcmp(*av, "-") == 0)
- ProcessIncoming(QIOfdopen(STDIN_FILENO));
- else if ((qp = QIOopen(*av)) == NULL)
- fprintf(stderr, "crosspost cant open %s %s\n",
- *av, strerror(errno));
- else
- ProcessIncoming(qp);
- }
-
- ProcessStats();
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: cvtbatch.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Read file list on standard input and spew out batchfiles.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-
-int
-main(int ac, char *av[]) {
- int i;
- QIOSTATE *qp;
- char *line;
- const char *text;
- char *format;
- char *p, *q;
- const char *r;
- bool Dirty;
- TOKEN token;
- ARTHANDLE *art;
- int len;
-
- /* First thing, set up our identity. */
- message_program_name = "cvtbatch";
- if (!innconf_read(NULL))
- exit(1);
-
- /* Parse JCL. */
- format = xstrdup("nm");
- while ((i = getopt(ac, av, "w:")) != EOF)
- switch (i) {
- default:
- die("usage error");
- break;
- case 'w':
- for (p = format = optarg; *p; p++) {
- switch (*p) {
- case FEED_BYTESIZE:
- case FEED_FULLNAME:
- case FEED_MESSAGEID:
- case FEED_NAME:
- continue;
- }
- warn("ignoring %c in -w flag", *p);
- }
- }
- ac -= optind;
- av += optind;
- if (ac)
- die("usage error");
-
- if (!SMinit())
- die("cannot initialize storage manager: %s", SMerrorstr);
-
- /* Loop over all input. */
- qp = QIOfdopen((int)fileno(stdin));
- while ((line = QIOread(qp)) != NULL) {
- for (p = line; *p; p++)
- if (ISWHITE(*p)) {
- *p = '\0';
- break;
- }
-
- if (!IsToken(line))
- continue;
- token = TextToToken(line);
- if ((art = SMretrieve(token, RETR_HEAD)) == NULL)
- continue;
- text = wire_findheader(art->data, art->len, "Message-ID");
- if (text == NULL) {
- SMfreearticle(art);
- continue;
- }
- len = art->len;
- for (r = text; r < art->data + art->len; r++) {
- if (*r == '\r' || *r == '\n')
- break;
- }
- if (r == art->data + art->len) {
- SMfreearticle(art);
- continue;
- }
- q = xmalloc(r - text + 1);
- memcpy(q, text, r - text);
- SMfreearticle(art);
- q[r - text] = '\0';
-
- /* Write the desired info. */
- for (Dirty = false, p = format; *p; p++) {
- switch (*p) {
- default:
- continue;
- case FEED_BYTESIZE:
- if (Dirty)
- putchar(' ');
- printf("%d", len);
- break;
- case FEED_FULLNAME:
- case FEED_NAME:
- if (Dirty)
- putchar(' ');
- printf("%s", line);
- break;
- case FEED_MESSAGEID:
- if (Dirty)
- putchar(' ');
- printf("%s", q);
- break;
- }
- Dirty = true;
- }
- free(q);
- if (Dirty)
- putchar('\n');
- }
-
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: filechan.c 6135 2003-01-19 01:15:40Z rra $
-**
-** An InterNetNews channel process that splits a funnel entry into
-** separate files. Originally from Robert Elz <kre@munnari.oz.au>.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-
-#include "map.h"
-
-int
-main(int ac, char *av[])
-{
- char buff[2048];
- char *p;
- char *next;
- int i;
- int fd;
- int Fields;
- const char *Directory;
- bool Map;
- FILE *F;
- struct stat Sb;
- uid_t uid;
- gid_t gid;
- uid_t myuid;
-
- /* First thing, set up our identity. */
- message_program_name = "filechan";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- Fields = 1;
- Directory = innconf->pathoutgoing;
- Map = false;
- myuid = geteuid();
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "d:f:m:p:")) != EOF)
- switch (i) {
- default:
- die("usage error");
- break;
- case 'd':
- Directory = optarg;
- break;
- case 'f':
- Fields = atoi(optarg);
- break;
- case 'm':
- Map = true;
- MAPread(optarg);
- break;
- case 'p':
- if ((F = fopen(optarg, "w")) == NULL)
- sysdie("cannot fopen %s", optarg);
- fprintf(F, "%ld\n", (long)getpid());
- if (ferror(F) || fclose(F) == EOF)
- sysdie("cannot fclose %s", optarg);
- break;
- }
-
- /* Move, and get owner of current directory. */
- if (chdir(Directory) < 0)
- sysdie("cannot chdir to %s", Directory);
- if (stat(".", &Sb) < 0)
- sysdie("cannot stat %s", Directory);
- uid = Sb.st_uid;
- gid = Sb.st_gid;
-
- /* Read input. */
- while (fgets(buff, sizeof buff, stdin) != NULL) {
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
-
- /* Skip the right number of leading fields. */
- for (i = Fields, p = buff; *p; p++)
- if (*p == ' ' && --i <= 0)
- break;
- if (*p == '\0')
- /* Nothing to write. Probably shouldn't happen. */
- continue;
-
- /* Add a newline, get the length of all leading fields. */
- *p++ = '\n';
- i = p - buff;
-
- /* Rest of the line is space-separated list of filenames. */
- for (; *p; p = next) {
- /* Skip whitespace, get next word. */
- while (*p == ' ')
- p++;
- for (next = p; *next && *next != ' '; next++)
- continue;
- if (*next)
- *next++ = '\0';
-
- if (Map)
- p = MAPname(p);
- fd = open(p, O_CREAT | O_WRONLY | O_APPEND, BATCHFILE_MODE);
- if (fd >= 0) {
- /* Try to lock it and set the ownership right. */
- inn_lock_file(fd, INN_LOCK_WRITE, true);
- if (myuid == 0 && uid != 0)
- chown(p, uid, gid);
-
- /* Just in case, seek to the end. */
- lseek(fd, 0, SEEK_END);
-
- errno = 0;
- if (write(fd, buff, i) != i)
- sysdie("write failed");
-
- close(fd);
- }
- }
- }
-
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: inndf.c 6677 2004-03-03 18:36:07Z hkehoe $
-**
-** Reports free kilobytes (not disk blocks) or free inodes.
-**
-** Written by Ian Dickinson <idickins@fore.com>
-** Wed Jul 26 10:11:38 BST 1995 (My birthday - 27 today!)
-**
-** inndf is a replacement for 'df | awk' in innwatch.ctl and for reporting
-** free space in other INN scripts. It doesn't sync, it forks less, and
-** it's generally less complicated.
-**
-** Usage: inndf [-i] <directory> [<directory> ...]
-** inndf -n
-** inndf -o
-**
-** Compile with -lserver (ie. /usr/lib/libserver.a) if you run Sun's Online
-** DiskSuite under SunOS 4.x. The wrapper functions there make the system
-** call transparent; they copy the f_spare values to the correct spots, so
-** f_blocks, f_bfree, f_bavail can exceed 2GB.
-**
-** Compile with -DHAVE_STATVFS for these systems:
-** System V Release 4.x
-** Solaris 2.x
-** HP-UX 10.x
-** OSF1
-**
-** Compile with -DHAVE_STATFS for these systems:
-** SunOS 4.x/Solaris 1.x
-** HP-UX 9.x
-** Linux
-** NeXTstep 3.x
-**
-** (Or even better, let autoconf take care of it.)
-**
-** Thanks to these folks for bug fixes and porting information:
-** Mahesh Ramachandran <rr@eel.ufl.edu>
-** Chuck Swiger <chuck@its.com>
-** Sang-yong Suh <sysuh@kigam.re.kr>
-** Swa Frantzen <Swa.Frantzen@Belgium.EU.net>
-** Brad Dickey <bdickey@haverford.edu>
-** Taso N. Devetzis <devetzis@snet.net>
-** Wei-Yeh Lee <weiyeh@columbia.edu>
-** Jeff Garzik <jeff.garzik@spinne.com>
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-
-/* The portability mess. Hide everything in macros so that the actual code
- is relatively clean. SysV uses statvfs, BSD uses statfs, and ULTRIX is
- just weird (and isn't worth checking for in configure).
-
- df_declare declares a variable of the appropriate type to pass to df_stat
- along with a path; df_stat will return true on success, false on failure.
- df_avail gives the number of free blocks, the size of those blocks given
- in df_bsize (which handles SysV's weird fragment vs. preferred block size
- thing). df_inodes returns the free inodes. */
-#if HAVE_STATVFS
-# include <sys/statvfs.h>
-# define df_stat(p, s) (statvfs((p), (s)) == 0)
-# define df_declare(s) struct statvfs s
-# define df_total(s) ((s).f_blocks)
-# define df_avail(s) ((s).f_bavail)
-# define df_scale(s) ((s).f_frsize == 0 ? (s).f_bsize : (s).f_frsize)
-# define df_files(s) ((s).f_files)
-# define df_favail(s) ((s).f_favail)
-#elif HAVE_STATFS
-# if HAVE_SYS_VFS_H
-# include <sys/vfs.h>
-# endif
-# if HAVE_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# if HAVE_SYS_MOUNT_H
-# include <sys/mount.h>
-# endif
-# ifdef __ultrix__
-# define df_stat(p, s) (statfs((p), (s)) >= 1)
-# define df_declare(s) struct fs_data s
-# define df_total(s) ((s).fd_btot)
-# define df_avail(s) ((s).fd_bfreen)
-# define df_scale(s) 1024
-# define df_files(s) ((s).fd_gtot)
-# define df_favail(s) ((s).fd_gfree)
-# else
-# define df_stat(p, s) (statfs((p), (s)) == 0)
-# define df_declare(s) struct statfs s
-# define df_total(s) ((s).f_blocks)
-# define df_avail(s) ((s).f_bavail)
-# define df_scale(s) ((s).f_bsize)
-# define df_files(s) ((s).f_files)
-# define df_favail(s) ((s).f_ffree)
-# endif
-#else
-# error "Platform not supported. Neither statvfs nor statfs available."
-#endif
-
-static const char usage[] = "\
-Usage: inndf [-i] [-f filename] [-F] <directory> [<directory> ...]\n\
- inndf -n\n\
- inndf -o\n\
-\n\
-The first form gives the free space in kilobytes (or the count of free\n\
-inodes if -i is given) in the file systems given by the arguments. If\n\
--f is given, the corresponding file should be a list of directories to\n\
-check in addition to the arguments. -F uses <pathetc>/filesystems as the\n\
-file and is otherwise the same.\n\
-\n\
-The second form gives the total count of overview records stored. The\n\
-third form gives the percentage space allocated to overview that's been\n\
-used (if the overview method used supports this query).";
-
-/*
-** Given a path, a flag saying whether to look at inodes instead of free
-** disk space, and a flag saying whether to format in columns, print out
-** the amount of free space or inodes on that file system. Returns the
-** percentage free, which may be printed out by the caller.
-*/
-static void
-printspace(const char *path, bool inode, bool fancy)
-{
- df_declare(info);
- unsigned long amount;
- double percent;
-
- if (df_stat(path, &info)) {
- if (inode) {
- amount = df_favail(info);
-
- /* This value is compared using the shell by innwatch, and some
- shells can't cope with anything larger than the maximum value
- of a signed long. ReiserFS returns 2^32 - 1, however, since it
- has no concept of inodes. So cap the returned value at the max
- value of a signed long. */
- if (amount > (1UL << 31) - 1)
- amount = (1UL << 31) - 1;
-
- /* 2.6 kernels show 0 available and used inodes, instead. */
- if (amount == 0 && df_files(info) == 0)
- amount = (1UL << 31) - 1;
- } else {
- /* Do the multiplication in floating point to try to retain
- accuracy if the free space in bytes would overflow an
- unsigned long. This should be safe until file systems larger
- than 4TB (which may not be much longer -- we should use long
- long instead if we have it).
-
- Be very careful about the order of casts here; it's too
- easy to cast back into an unsigned long a value that
- overflows, and one then gets silently wrong results. */
- amount = (unsigned long)
- (((double) df_avail(info) * df_scale(info)) / 1024.0);
- }
- } else {
- /* On error, free space is zero. */
- amount = 0;
- }
- printf(fancy ? "%10lu" : "%lu", amount);
- if (fancy) {
- printf(inode ? " inodes available " : " Kbytes available ");
- if (inode)
- percent = 100 * ((double) df_favail(info) / df_files(info));
- else
- percent = 100 * ((double) df_avail(info) / df_total(info));
- if (percent < 9.95)
- printf(" (%3.1f%%)", percent);
- else if (percent < 99.95)
- printf(" (%4.1f%%)", percent);
- else
- printf("(%5.1f%%)", percent);
- }
-}
-
-static void
-printspace_formatted(const char *path, bool inode)
-{
- printf("%-40s ", path);
- printspace(path, inode, true);
- printf("\n");
-}
-
-static char *
-readline(QIOSTATE *qp)
-{
- char *line, *p;
-
- for (line = QIOread(qp); line != NULL; line = QIOread(qp)) {
- p = strchr(line, '#');
- if (p != NULL)
- *p = '\0';
- for (; *line == ' ' || *line == '\t'; line++)
- ;
- if (*line != '\0') {
- for (p = line; *p != '\0' && *p != ' ' && *p != '\t'; p++)
- ;
- *p = '\0';
- return line;
- }
- }
- return NULL;
-}
-
-int
-main(int argc, char *argv[])
-{
- int option, i, count;
- unsigned long total;
- QIOSTATE *qp;
- char *active, *group, *line, *p;
- char *file = NULL;
- bool inode = false;
- bool overview = false;
- bool ovcount = false;
- bool use_filesystems = false;
-
- while ((option = getopt(argc, argv, "hinof:F")) != EOF) {
- switch (option) {
- default:
- die(usage);
- case 'h':
- printf("%s\n", usage);
- exit(0);
- case 'i':
- inode = true;
- break;
- case 'n':
- ovcount = true;
- break;
- case 'o':
- overview = true;
- break;
- case 'f':
- if (file != NULL)
- die("inndf: Only one of -f or -F may be given");
- file = xstrdup(optarg);
- break;
- case 'F':
- if (file != NULL)
- die("inndf: Only one of -f or -F may be given");
- if (!innconf_read(NULL))
- exit(1);
- file = concatpath(innconf->pathetc, INN_PATH_FILESYSTEMS);
- use_filesystems = true;
- break;
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc == 0 && !overview && !ovcount && file == NULL)
- die(usage);
-
- /* Set the program name now rather than earlier so that it doesn't get
- prepended to usage messages. */
- message_program_name = "inndf";
-
- /* If directories were specified, get statistics about them. If only
- one was given, just print out the number without the path or any
- explanatory text; this mode is used by e.g. innwatch. Otherwise,
- format things nicely. */
- if (argc == 1 && !overview && !ovcount && file == NULL) {
- printspace(argv[0], inode, false);
- printf("\n");
- } else {
- for (i = 0; i < argc; i++)
- printspace_formatted(argv[i], inode);
- if (file != NULL) {
- qp = QIOopen(file);
- if (qp == NULL) {
- if (!use_filesystems)
- sysdie("can't open %s", file);
- } else {
- line = readline(qp);
- while (line != NULL) {
- printspace_formatted(line, inode);
- line = readline(qp);
- }
- QIOclose(qp);
- }
- free(file);
- }
- }
-
- /* If we're going to be getting information from overview, do the icky
- initialization stuff. */
- if (overview || ovcount) {
- if (!use_filesystems)
- if (!innconf_read(NULL))
- exit(1);
- if (!OVopen(OV_READ))
- die("OVopen failed");
- }
-
- /* For the count, we have to troll through the active file and query the
- overview backend for each group. */
- if (ovcount) {
- active = concatpath(innconf->pathdb, _PATH_ACTIVE);
- qp = QIOopen(active);
- if (qp == NULL)
- sysdie("can't open %s", active);
-
- total = 0;
- group = QIOread(qp);
- while (group != NULL) {
- p = strchr(group, ' ');
- if (p != NULL)
- *p = '\0';
- if (OVgroupstats(group, NULL, NULL, &count, NULL))
- total += count;
- group = QIOread(qp);
- }
- QIOclose(qp);
- printf("%lu overview records stored\n", total);
- }
-
- /* Percentage used is simpler, but only some overview methods understand
- that query. */
- if (overview) {
- if (OVctl(OVSPACE, &count)) {
- if (count == -1)
- printf("Space used is meaningless for the %s method\n",
- innconf->ovmethod);
- else
- printf("%d%% overview space used\n", count);
- }
- }
- exit(0);
-}
+++ /dev/null
-/* $Id: innxbatch.c 6351 2003-05-19 02:00:06Z rra $
-**
-** Transmit batches to remote site, using the XBATCH command
-** Modelled after innxmit.c and nntpbatch.c
-**
-** Invocation:
-** innxbatch [options] <serverhost> <file> ...
-#ifdef FROMSTDIN
-** innxbatch -i <serverhost>
-#endif FROMSTDIN
-** will connect to serverhost's nntp port, and transfer the named files,
-** with an xbatch command for every file. Files that have been sent
-** successfully are unlink()ed. In case of any error, innxbatch terminates
-** and leaves any remaining files untouched, for later transmission.
-** Options:
-** -D increase debug level
-** -v report statistics to stdout
-#ifdef FROMSTDIN
-** -i read batch file names from stdin instead from command line.
-** For each successfully transmitted batch, an OK is printed on
-** stdout, to indicate that another file name is expected.
-#endif
-** -t Timeout for connection attempt
-** -T Timeout for batch transfers.
-** We do not use any file locking. At worst, a batch could be transmitted
-** twice in parallel by two independant invocations of innxbatch.
-** To prevent this, innxbatch should be invoked by a shell script that uses
-** shlock(1) to achieve mutual exclusion.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/timer.h"
-#include "libinn.h"
-#include "nntp.h"
-
-/*
-** Syslog formats - collected together so they remain consistent
-*/
-static char STAT1[] =
- "%s stats offered %lu accepted %lu refused %lu rejected %lu";
-static char STAT2[] = "%s times user %.3f system %.3f elapsed %.3f";
-static char CANT_CONNECT[] = "%s connect failed %s";
-static char CANT_AUTHENTICATE[] = "%s authenticate failed %s";
-static char XBATCH_FAIL[] = "%s xbatch failed %s";
-static char UNKNOWN_REPLY[] = "Unknown reply after sending batch -- %s";
-static char CANNOT_UNLINK[] = "cannot unlink %s: %m";
-/*
-** Global variables.
-*/
-static bool Debug = 0;
-static bool STATprint;
-static char *REMhost;
-static double STATbegin;
-static double STATend;
-static char *XBATCHname;
-static int FromServer;
-static int ToServer;
-static sig_atomic_t GotAlarm;
-static sig_atomic_t GotInterrupt;
-static sig_atomic_t JMPyes;
-static jmp_buf JMPwhere;
-static unsigned long STATaccepted;
-static unsigned long STAToffered;
-static unsigned long STATrefused;
-static unsigned long STATrejected;
-
-/*
-** Send a line to the server. \r\n will be appended
-*/
-static bool
-REMwrite(int fd, char *p)
-{
- int i;
- int err;
- char *dest;
- static char buff[NNTP_STRLEN];
-
- for (dest = buff, i = 0; p[i]; ) *dest++ = p[i++];
- *dest++ = '\r';
- *dest++ = '\n';
- *dest++ = '\0';
-
- for (dest = buff, i+=2; i; dest += err, i -= err) {
- err = write(fd, dest, i);
- if (err < 0) {
- syswarn("cannot write %s to %s", dest, REMhost);
- return false;
- }
- }
- if (Debug)
- fprintf(stderr, "> %s\n", p);
-
- return true;
-}
-
-/*
-** Print transfer statistics, clean up, and exit.
-*/
-static void
-ExitWithStats(int x)
-{
- static char QUIT[] = "quit";
- double usertime;
- double systime;
-
- REMwrite(ToServer, QUIT);
-
- STATend = TMRnow_double();
- if (GetResourceUsage(&usertime, &systime) < 0) {
- usertime = 0;
- systime = 0;
- }
-
- if (STATprint) {
- printf(STAT1,
- REMhost, STAToffered, STATaccepted, STATrefused, STATrejected);
- printf("\n");
- printf(STAT2, REMhost, usertime, systime, STATend - STATbegin);
- printf("\n");
- }
-
- syslog(L_NOTICE, STAT1,
- REMhost, STAToffered, STATaccepted, STATrefused, STATrejected);
- syslog(L_NOTICE, STAT2, REMhost, usertime, systime, STATend - STATbegin);
-
- exit(x);
- /* NOTREACHED */
-}
-
-
-/*
-** Clean up the NNTP escapes from a line.
-*/
-static char *
-REMclean(char *buff)
-{
- char *p;
-
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
-
- /* The dot-escape is only in text, not command responses. */
- return buff;
-}
-
-
-/*
-** Read a line of input, with timeout. We expect only answer lines, so
-** we ignore \r\n-->\n mapping and the dot escape.
-** Return true if okay, *or we got interrupted.*
-*/
-static bool
-REMread(char *start, int size)
-{
- char *p, *h;
- struct timeval t;
- fd_set rmask;
- int i;
-
- for (p = start; size; ) {
- FD_ZERO(&rmask);
- FD_SET(FromServer, &rmask);
- t.tv_sec = 10 * 60;
- t.tv_usec = 0;
- i = select(FromServer + 1, &rmask, NULL, NULL, &t);
- if (GotInterrupt) return true;
- if (i < 0) {
- if (errno == EINTR) continue;
- else return false;
- }
- if (i == 0 || !FD_ISSET(FromServer, &rmask)) return false;
- i = read(FromServer, p, size-1);
- if (GotInterrupt) return true;
- if (i <= 0) return false;
- h = p;
- p += i;
- size -= i;
- for ( ; h < p; h++) {
- if (h > start && '\n' == *h && '\r' == h[-1]) {
- *h = h[-1] = '\0';
- size = 0;
- }
- }
- }
-
- if (Debug)
- fprintf(stderr, "< %s\n", start);
-
- return true;
-}
-
-
-/*
-** Handle the interrupt.
-*/
-static void
-Interrupted(void)
-{
- warn("interrupted");
- ExitWithStats(1);
-}
-
-
-/*
-** Send a whole xbatch to the server. Uses the global variables
-** REMbuffer & friends
-*/
-static bool
-REMsendxbatch(int fd, char *buf, int size)
-{
- char *p;
- int i;
- int err;
-
- for (i = size, p = buf; i; p += err, i -= err) {
- err = write(fd, p, i);
- if (err < 0) {
- syswarn("cannot write xbatch to %s", REMhost);
- return false;
- }
- }
- if (GotInterrupt) Interrupted();
- if (Debug)
- fprintf(stderr, "> [%d bytes of xbatch]\n", size);
-
- /* What did the remote site say? */
- if (!REMread(buf, size)) {
- syswarn("no reply after sending xbatch");
- return false;
- }
- if (GotInterrupt) Interrupted();
-
- /* Parse the reply. */
- switch (atoi(buf)) {
- default:
- warn("unknown reply after sending batch -- %s", buf);
- syslog(L_ERROR, UNKNOWN_REPLY, buf);
- return false;
- /* NOTREACHED */
- break;
- case NNTP_RESENDIT_VAL:
- case NNTP_GOODBYE_VAL:
- syslog(L_NOTICE, XBATCH_FAIL, REMhost, buf);
- STATrejected++;
- return false;
- /* NOTREACHED */
- break;
- case NNTP_OK_XBATCHED_VAL:
- STATaccepted++;
- if (Debug) fprintf(stderr, "will unlink(%s)\n", XBATCHname);
- if (unlink(XBATCHname)) {
- /* probably another incarantion was faster, so avoid further duplicate
- * work
- */
- syswarn("cannot unlink %s", XBATCHname);
- syslog(L_NOTICE, CANNOT_UNLINK, XBATCHname);
- return false;
- }
- break;
- }
-
- /* Article sent */
- return true;
-}
-
-/*
-** Mark that we got interrupted.
-*/
-static RETSIGTYPE
-CATCHinterrupt(int s)
-{
- GotInterrupt = true;
-
- /* Let two interrupts kill us. */
- xsignal(s, SIG_DFL);
-}
-
-
-/*
-** Mark that the alarm went off.
-*/
-/* ARGSUSED0 */
-static RETSIGTYPE
-CATCHalarm(int s UNUSED)
-{
- GotAlarm = true;
- if (JMPyes)
- longjmp(JMPwhere, 1);
-}
-
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- warn("Usage: innxbatch [-Dv] [-t#] [-T#] host file ...");
-#ifdef FROMSTDIN
- warn(" innxbatch [-Dv] [-t#] [-T#] -i host");
-#endif
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- int i;
- char *p;
- FILE *From;
- FILE *To;
- char buff[NNTP_STRLEN];
- RETSIGTYPE (*old)(int) = NULL;
- unsigned int ConnectTimeout;
- unsigned int TotalTimeout;
- struct stat statbuf;
- int fd;
- int err;
- char *XBATCHbuffer = NULL;
- int XBATCHbuffersize = 0;
- int XBATCHsize;
-
- openlog("innxbatch", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "innxbatch";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- ConnectTimeout = 0;
- TotalTimeout = 0;
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "Dit:T:v")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- break;
- case 'D':
- Debug++;
- break;
-#ifdef FROMSTDIN
- case 'i':
- FromStdin = true;
- break;
-#endif
- case 't':
- ConnectTimeout = atoi(optarg);
- break;
- case 'T':
- TotalTimeout = atoi(optarg);
- break;
- case 'v':
- STATprint = true;
- break;
- }
- ac -= optind;
- av += optind;
-
- /* Parse arguments; host and filename. */
- if (ac < 2)
- Usage();
- REMhost = av[0];
- ac--;
- av++;
-
- /* Open a connection to the remote server. */
- if (ConnectTimeout) {
- GotAlarm = false;
- old = xsignal(SIGALRM, CATCHalarm);
- JMPyes = true;
- if (setjmp(JMPwhere))
- die("cannot connect to %s: timed out", REMhost);
- alarm(ConnectTimeout);
- }
- if (NNTPconnect(REMhost, NNTP_PORT, &From, &To, buff) < 0 || GotAlarm) {
- i = errno;
- warn("cannot connect to %s: %s", REMhost,
- buff[0] ? REMclean(buff): strerror(errno));
- if (GotAlarm)
- syslog(L_NOTICE, CANT_CONNECT, REMhost, "timeout");
- else
- syslog(L_NOTICE, CANT_CONNECT, REMhost,
- buff[0] ? REMclean(buff) : strerror(i));
- exit(1);
- }
-
- if (Debug)
- fprintf(stderr, "< %s\n", REMclean(buff));
- if (NNTPsendpassword(REMhost, From, To) < 0 || GotAlarm) {
- i = errno;
- syswarn("cannot authenticate with %s", REMhost);
- syslog(L_ERROR, CANT_AUTHENTICATE,
- REMhost, GotAlarm ? "timeout" : strerror(i));
- /* Don't send quit; we want the remote to print a message. */
- exit(1);
- }
- if (ConnectTimeout) {
- alarm(0);
- xsignal(SIGALRM, old);
- JMPyes = false;
- }
-
- /* We no longer need standard I/O. */
- FromServer = fileno(From);
- ToServer = fileno(To);
-
-#if defined(SOL_SOCKET) && defined(SO_SNDBUF) && defined(SO_RCVBUF)
- i = 24 * 1024;
- if (setsockopt(ToServer, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof i) < 0)
- perror("cant setsockopt(SNDBUF)");
- if (setsockopt(FromServer, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof i) < 0)
- perror("cant setsockopt(RCVBUF)");
-#endif /* defined(SOL_SOCKET) && defined(SO_SNDBUF) && defined(SO_RCVBUF) */
-
- GotInterrupt = false;
- GotAlarm = false;
-
- /* Set up signal handlers. */
- xsignal(SIGHUP, CATCHinterrupt);
- xsignal(SIGINT, CATCHinterrupt);
- xsignal(SIGTERM, CATCHinterrupt);
- xsignal(SIGPIPE, SIG_IGN);
- if (TotalTimeout) {
- xsignal(SIGALRM, CATCHalarm);
- alarm(TotalTimeout);
- }
-
- /* Start timing. */
- STATbegin = TMRnow_double();
-
- /* main loop over all specified files */
- for (XBATCHname = *av; ac && (XBATCHname = *av); av++, ac--) {
-
- if (Debug) fprintf(stderr, "will work on %s\n", XBATCHname);
-
- if (GotAlarm) {
- warn("timed out");
- ExitWithStats(1);
- }
- if (GotInterrupt) Interrupted();
-
- if ((fd = open(XBATCHname, O_RDONLY, 0)) < 0) {
- syswarn("cannot open %s, skipping", XBATCHname);
- continue;
- }
-
- if (fstat(fd, &statbuf)) {
- syswarn("cannot stat %s, skipping", XBATCHname);
- close(i);
- continue;
- }
-
- XBATCHsize = statbuf.st_size;
- if (XBATCHsize == 0) {
- warn("batch file %s is zero length, skipping", XBATCHname);
- close(i);
- unlink(XBATCHname);
- continue;
- } else if (XBATCHsize > XBATCHbuffersize) {
- XBATCHbuffersize = XBATCHsize;
- if (XBATCHbuffer) free(XBATCHbuffer);
- XBATCHbuffer = xmalloc(XBATCHsize);
- }
-
- err = 0; /* stupid compiler */
- for (i = XBATCHsize, p = XBATCHbuffer; i; i -= err, p+= err) {
- err = read(fd, p, i);
- if (err < 0) {
- syswarn("error reading %s, skipping", XBATCHname);
- break;
- } else if (0 == err) {
- syswarn("unexpected EOF reading %s, truncated", XBATCHname);
- XBATCHsize = p - XBATCHbuffer;
- break;
- }
- }
- close(fd);
- if (err < 0)
- continue;
-
- if (GotInterrupt) Interrupted();
-
- /* Offer the xbatch. */
- snprintf(buff, sizeof(buff), "xbatch %d", XBATCHsize);
- if (!REMwrite(ToServer, buff)) {
- syswarn("cannot offer xbatch to %s", REMhost);
- ExitWithStats(1);
- }
- STAToffered++;
- if (GotInterrupt) Interrupted();
-
- /* Does he want it? */
- if (!REMread(buff, (int)sizeof buff)) {
- syswarn("no reply to XBATCH %d from %s", XBATCHsize, REMhost);
- ExitWithStats(1);
- }
- if (GotInterrupt) Interrupted();
-
- /* Parse the reply. */
- switch (atoi(buff)) {
- default:
- warn("unknown reply to %s -- %s", XBATCHname, buff);
- ExitWithStats(1);
- /* NOTREACHED */
- break;
- case NNTP_RESENDIT_VAL:
- case NNTP_GOODBYE_VAL:
- /* Most likely out of space -- no point in continuing. */
- syslog(L_NOTICE, XBATCH_FAIL, REMhost, buff);
- ExitWithStats(1);
- /* NOTREACHED */
- case NNTP_CONT_XBATCH_VAL:
- if (!REMsendxbatch(ToServer, XBATCHbuffer, XBATCHsize))
- ExitWithStats(1);
- /* NOTREACHED */
- break;
- case NNTP_SYNTAX_VAL:
- case NNTP_BAD_COMMAND_VAL:
- warn("server %s seems not to understand XBATCH: %s", REMhost, buff);
- syslog(L_FATAL, XBATCH_FAIL, REMhost, buff);
- break;
- }
- }
- ExitWithStats(0);
- /* NOTREACHED */
- return 0;
-}
+++ /dev/null
-/* $Id: innxmit.c 6716 2004-05-16 20:26:56Z rra $
-**
-** Transmit articles to remote site.
-** Modified for NNTP streaming: 1996-01-03 Jerry Aguirre
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <setjmp.h>
-#include <signal.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "inn/timer.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "storage.h"
-
-#define OUTPUT_BUFFER_SIZE (16 * 1024)
-
-/* Streaming extensions to NNTP. This extension removes the lock-step
-** limitation of conventional NNTP. Article transfer is several times
-** faster. Negotiated and falls back to old mode if receiver refuses.
-*/
-
-/* max number of articles that can be streamed ahead */
-#define STNBUF 32
-
-/* Send "takethis" without "check" if this many articles were
-** accepted in a row.
-*/
-#define STNC 16
-
-/* typical number of articles to stream */
-/* must be able to fopen this many articles */
-#define STNBUFL (STNBUF/2)
-
-/* number of retries before requeueing to disk */
-#define STNRETRY 5
-
-struct stbufs { /* for each article we are procesing */
- char *st_fname; /* file name */
- char *st_id; /* message ID */
- int st_retry; /* retry count */
- int st_age; /* age count */
- ARTHANDLE *art; /* arthandle to read article contents */
- int st_hash; /* hash value to speed searches */
- long st_size; /* article size */
-};
-static struct stbufs stbuf[STNBUF]; /* we keep track of this many articles */
-static int stnq; /* current number of active entries in stbuf */
-static long stnofail; /* Count of consecutive successful sends */
-
-static int TryStream = true; /* Should attempt stream negotation? */
-static int CanStream = false; /* Result of stream negotation */
-static int DoCheck = true; /* Should check before takethis? */
-static char modestream[] = "mode stream";
-static char modeheadfeed[] = "mode headfeed";
-static long retries = 0;
-static int logRejects = false ; /* syslog the 437 responses. */
-
-
-
-/*
-** Syslog formats - collected together so they remain consistent
-*/
-static char STAT1[] =
- "%s stats offered %lu accepted %lu refused %lu rejected %lu missing %lu accsize %.0f rejsize %.0f";
-static char STAT2[] = "%s times user %.3f system %.3f elapsed %.3f";
-static char GOT_BADCOMMAND[] = "%s rejected %s %s";
-static char REJECTED[] = "%s rejected %s (%s) %s";
-static char REJ_STREAM[] = "%s rejected (%s) %s";
-static char CANT_CONNECT[] = "%s connect failed %s";
-static char CANT_AUTHENTICATE[] = "%s authenticate failed %s";
-static char IHAVE_FAIL[] = "%s ihave failed %s";
-
-static char CANT_FINDIT[] = "%s can't find %s";
-static char CANT_PARSEIT[] = "%s can't parse ID %s";
-static char UNEXPECTED[] = "%s unexpected response code %s";
-
-/*
-** Global variables.
-*/
-static bool AlwaysRewrite;
-static bool Debug;
-static bool DoRequeue = true;
-static bool Purging;
-static bool STATprint;
-static bool HeadersFeed;
-static char *BATCHname;
-static char *BATCHtemp;
-static char *REMhost;
-static double STATbegin;
-static double STATend;
-static FILE *BATCHfp;
-static int FromServer;
-static int ToServer;
-static struct history *History;
-static QIOSTATE *BATCHqp;
-static sig_atomic_t GotAlarm;
-static sig_atomic_t GotInterrupt;
-static sig_atomic_t JMPyes;
-static jmp_buf JMPwhere;
-static char *REMbuffer;
-static char *REMbuffptr;
-static char *REMbuffend;
-static unsigned long STATaccepted;
-static unsigned long STAToffered;
-static unsigned long STATrefused;
-static unsigned long STATrejected;
-static unsigned long STATmissing;
-static double STATacceptedsize;
-static double STATrejectedsize;
-
-
-/* Prototypes. */
-static ARTHANDLE *article_open(const char *path, const char *id);
-static void article_free(ARTHANDLE *);
-
-
-/*
-** Return true if the history file has the article expired.
-*/
-static bool
-Expired(char *MessageID) {
- return !HISlookup(History, MessageID, NULL, NULL, NULL, NULL);
-}
-
-
-/*
-** Flush and reset the site's output buffer. Return false on error.
-*/
-static bool
-REMflush(void)
-{
- int i;
-
- if (REMbuffptr == REMbuffer) return true; /* nothing buffered */
- i = xwrite(ToServer, REMbuffer, (int)(REMbuffptr - REMbuffer));
- REMbuffptr = REMbuffer;
- return i < 0 ? false : true;
-}
-
-/*
-** Return index to entry matching this message ID. Else return -1.
-** The hash is to speed up the search.
-** the protocol.
-*/
-static int
-stindex(char *MessageID, int hash) {
- int i;
-
- for (i = 0; i < STNBUF; i++) { /* linear search for ID */
- if ((stbuf[i].st_id) && (stbuf[i].st_id[0])
- && (stbuf[i].st_hash == hash)) {
- int n;
-
- if (strcasecmp(MessageID, stbuf[i].st_id)) continue;
-
- /* left of '@' is case sensitive */
- for (n = 0; (MessageID[n] != '@') && (MessageID[n] != '\0'); n++) ;
- if (strncmp(MessageID, stbuf[i].st_id, n)) continue;
- else break; /* found a match */
- }
- }
- if (i >= STNBUF) i = -1; /* no match found ? */
- return (i);
-}
-
-/* stidhash(): calculate a hash value for message IDs to speed comparisons */
-static int
-stidhash(char *MessageID) {
- char *p;
- int hash;
-
- hash = 0;
- for (p = MessageID + 1; *p && (*p != '>'); p++) {
- hash <<= 1;
- if (isascii((int)*p) && isupper((int)*p)) {
- hash += tolower(*p);
- } else {
- hash += *p;
- }
- }
- return hash;
-}
-
-/* stalloc(): save path, ID, and qp into one of the streaming mode entries */
-static int
-stalloc(char *Article, char *MessageID, ARTHANDLE *art, int hash) {
- int i;
-
- for (i = 0; i < STNBUF; i++) {
- if ((!stbuf[i].st_fname) || (stbuf[i].st_fname[0] == '\0')) break;
- }
- if (i >= STNBUF) { /* stnq says not full but can not find unused */
- syslog(L_ERROR, "stalloc: Internal error");
- return (-1);
- }
- if ((int)strlen(Article) >= SPOOLNAMEBUFF) {
- syslog(L_ERROR, "stalloc: filename longer than %d", SPOOLNAMEBUFF);
- return (-1);
- }
- /* allocate buffers on first use.
- ** If filename ever is longer than SPOOLNAMEBUFF then code will abort.
- ** If ID is ever longer than NNTP_STRLEN then other code would break.
- */
- if (!stbuf[i].st_fname)
- stbuf[i].st_fname = xmalloc(SPOOLNAMEBUFF);
- if (!stbuf[i].st_id)
- stbuf[i].st_id = xmalloc(NNTP_STRLEN);
- strlcpy(stbuf[i].st_fname, Article, SPOOLNAMEBUFF);
- strlcpy(stbuf[i].st_id, MessageID, NNTP_STRLEN);
- stbuf[i].art = art;
- stbuf[i].st_hash = hash;
- stbuf[i].st_retry = 0;
- stbuf[i].st_age = 0;
- stnq++;
- return i;
-}
-
-/* strel(): release for reuse one of the streaming mode entries */
-static void
-strel(int i) {
- if (stbuf[i].art) {
- article_free(stbuf[i].art);
- stbuf[i].art = NULL;
- }
- if (stbuf[i].st_id) stbuf[i].st_id[0] = '\0';
- if (stbuf[i].st_fname) stbuf[i].st_fname[0] = '\0';
- stnq--;
-}
-
-/*
-** Send a line to the server, adding the dot escape and \r\n.
-*/
-static bool
-REMwrite(char *p, int i, bool escdot) {
- int size;
-
- /* Buffer too full? */
- if (REMbuffend - REMbuffptr < i + 3) {
- if (!REMflush())
- return false;
- if (REMbuffend - REMbuffer < i + 3) {
- /* Line too long -- grow buffer. */
- size = i * 2;
- REMbuffer = xrealloc(REMbuffer, size);
- REMbuffend = &REMbuffer[size];
- }
- }
-
- /* Dot escape, text of the line, line terminator. */
- if (escdot && (*p == '.'))
- *REMbuffptr++ = '.';
- memcpy(REMbuffptr, p, i);
- REMbuffptr += i;
- *REMbuffptr++ = '\r';
- *REMbuffptr++ = '\n';
-
- return true;
-}
-
-
-/*
-** Print transfer statistics, clean up, and exit.
-*/
-static void
-ExitWithStats(int x)
-{
- static char QUIT[] = "quit";
- double usertime;
- double systime;
-
- if (!Purging) {
- REMwrite(QUIT, strlen(QUIT), false);
- REMflush();
- }
- STATend = TMRnow_double();
- if (GetResourceUsage(&usertime, &systime) < 0) {
- usertime = 0;
- systime = 0;
- }
-
- if (STATprint) {
- printf(STAT1, REMhost, STAToffered, STATaccepted, STATrefused,
- STATrejected, STATmissing, STATacceptedsize, STATrejectedsize);
- printf("\n");
- printf(STAT2, REMhost, usertime, systime, STATend - STATbegin);
- printf("\n");
- }
-
- syslog(L_NOTICE, STAT1, REMhost, STAToffered, STATaccepted, STATrefused,
- STATrejected, STATmissing, STATacceptedsize, STATrejectedsize);
- syslog(L_NOTICE, STAT2, REMhost, usertime, systime, STATend - STATbegin);
- if (retries)
- syslog(L_NOTICE, "%s %lu Streaming retries", REMhost, retries);
-
- if (BATCHfp != NULL && unlink(BATCHtemp) < 0 && errno != ENOENT)
- syswarn("cannot remove %s", BATCHtemp);
- sleep(1);
- SMshutdown();
- HISclose(History);
- exit(x);
- /* NOTREACHED */
-}
-
-
-/*
-** Close the batchfile and the temporary file, and rename the temporary
-** to be the batchfile.
-*/
-static void
-CloseAndRename(void)
-{
- /* Close the files, rename the temporary. */
- if (BATCHqp) {
- QIOclose(BATCHqp);
- BATCHqp = NULL;
- }
- if (ferror(BATCHfp)
- || fflush(BATCHfp) == EOF
- || fclose(BATCHfp) == EOF) {
- unlink(BATCHtemp);
- syswarn("cannot close %s", BATCHtemp);
- ExitWithStats(1);
- }
- if (rename(BATCHtemp, BATCHname) < 0) {
- syswarn("cannot rename %s", BATCHtemp);
- ExitWithStats(1);
- }
-}
-
-
-/*
-** Requeue an article, opening the temp file if we have to. If we get
-** a file write error, exit so that the original input is left alone.
-*/
-static void
-Requeue(const char *Article, const char *MessageID)
-{
- int fd;
-
- /* Temp file already open? */
- if (BATCHfp == NULL) {
- fd = mkstemp(BATCHtemp);
- if (fd < 0) {
- syswarn("cannot create a temporary file");
- ExitWithStats(1);
- }
- BATCHfp = fdopen(fd, "w");
- if (BATCHfp == NULL) {
- syswarn("cannot open %s", BATCHtemp);
- ExitWithStats(1);
- }
- }
-
- /* Called only to get the file open? */
- if (Article == NULL)
- return;
-
- if (MessageID != NULL)
- fprintf(BATCHfp, "%s %s\n", Article, MessageID);
- else
- fprintf(BATCHfp, "%s\n", Article);
- if (fflush(BATCHfp) == EOF || ferror(BATCHfp)) {
- syswarn("cannot requeue %s", Article);
- ExitWithStats(1);
- }
-}
-
-
-/*
-** Requeue an article then copy the rest of the batch file out.
-*/
-static void
-RequeueRestAndExit(char *Article, char *MessageID) {
- char *p;
-
- if (!AlwaysRewrite
- && STATaccepted == 0 && STATrejected == 0 && STATrefused == 0
- && STATmissing == 0) {
- warn("nothing sent -- leaving batchfile alone");
- ExitWithStats(1);
- }
-
- warn("rewriting batch file and exiting");
- if (CanStream) { /* streaming mode has a buffer of articles */
- int i;
-
- for (i = 0; i < STNBUF; i++) { /* requeue unacknowledged articles */
- if ((stbuf[i].st_fname) && (stbuf[i].st_fname[0] != '\0')) {
- if (Debug)
- fprintf(stderr, "stbuf[%d]= %s, %s\n",
- i, stbuf[i].st_fname, stbuf[i].st_id);
- Requeue(stbuf[i].st_fname, stbuf[i].st_id);
- if (Article == stbuf[i].st_fname) Article = NULL;
- strel(i); /* release entry */
- }
- }
- }
- Requeue(Article, MessageID);
-
- for ( ; BATCHqp; ) {
- if ((p = QIOread(BATCHqp)) == NULL) {
- if (QIOtoolong(BATCHqp)) {
- warn("skipping long line in %s", BATCHname);
- QIOread(BATCHqp);
- continue;
- }
- if (QIOerror(BATCHqp)) {
- syswarn("cannot read %s", BATCHname);
- ExitWithStats(1);
- }
-
- /* Normal EOF. */
- break;
- }
-
- if (fprintf(BATCHfp, "%s\n", p) == EOF
- || ferror(BATCHfp)) {
- syswarn("cannot requeue %s", p);
- ExitWithStats(1);
- }
- }
-
- CloseAndRename();
- ExitWithStats(1);
-}
-
-
-/*
-** Clean up the NNTP escapes from a line.
-*/
-static char *
-REMclean(char *buff) {
- char *p;
-
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
-
- /* The dot-escape is only in text, not command responses. */
- return buff;
-}
-
-
-/*
-** Read a line of input, with timeout. Also handle \r\n-->\n mapping
-** and the dot escape. Return true if okay, *or we got interrupted.*
-*/
-static bool
-REMread(char *start, int size) {
- static int count;
- static char buffer[BUFSIZ];
- static char *bp;
- char *p;
- char *q;
- char *end;
- struct timeval t;
- fd_set rmask;
- int i;
- char c;
-
- if (!REMflush())
- return false;
-
- for (p = start, end = &start[size - 1]; ; ) {
- if (count == 0) {
- /* Fill the buffer. */
- Again:
- FD_ZERO(&rmask);
- FD_SET(FromServer, &rmask);
- t.tv_sec = 10 * 60;
- t.tv_usec = 0;
- i = select(FromServer + 1, &rmask, NULL, NULL, &t);
- if (GotInterrupt)
- return true;
- if (i < 0) {
- if (errno == EINTR)
- goto Again;
- return false;
- }
- if (i == 0 || !FD_ISSET(FromServer, &rmask))
- return false;
- count = read(FromServer, buffer, sizeof buffer);
- if (GotInterrupt)
- return true;
- if (count <= 0)
- return false;
- bp = buffer;
- }
-
- /* Process next character. */
- count--;
- c = *bp++;
- if (c == '\n')
- break;
- if (p < end)
- *p++ = c;
- }
-
- /* We know we got \n; if previous char was \r, turn it into \n. */
- if (p > start && p < end && p[-1] == '\r')
- p[-1] = '\n';
- *p = '\0';
-
- /* Handle the dot escape. */
- if (*p == '.') {
- if (p[1] == '\n' && p[2] == '\0')
- /* EOF. */
- return false;
- for (q = &start[1]; (*p++ = *q++) != '\0'; )
- continue;
- }
- return true;
-}
-
-
-/*
-** Handle the interrupt.
-*/
-static void
-Interrupted(char *Article, char *MessageID) {
- warn("interrupted");
- RequeueRestAndExit(Article, MessageID);
-}
-
-
-/*
-** Returns the length of the headers.
-*/
-static int
-HeadersLen(ARTHANDLE *art, int *iscmsg) {
- const char *p;
- char lastchar = -1;
-
- /* from nnrpd/article.c ARTsendmmap() */
- for (p = art->data; p < (art->data + art->len); p++) {
- if (*p == '\r')
- continue;
- if (*p == '\n') {
- if (lastchar == '\n') {
- if (*(p-1) == '\r')
- p--;
- break;
- }
- if (*(p + 1) == 'C' && strncasecmp(p + 1, "Control: ", 9) == 0)
- *iscmsg = 1;
- }
- lastchar = *p;
- }
- return (p - art->data);
-}
-
-
-/*
-** Send a whole article to the server.
-*/
-static bool
-REMsendarticle(char *Article, char *MessageID, ARTHANDLE *art) {
- char buff[NNTP_STRLEN];
-
- if (!REMflush())
- return false;
- if (HeadersFeed) {
- struct iovec vec[3];
- char buf[20];
- int iscmsg = 0;
- int len = HeadersLen(art, &iscmsg);
-
- vec[0].iov_base = (char *) art->data;
- vec[0].iov_len = len;
- /* Add 14 bytes, which maybe will be the length of the Bytes header */
- snprintf(buf, sizeof(buf), "Bytes: %lu\r\n",
- (unsigned long) art->len + 14);
- vec[1].iov_base = buf;
- vec[1].iov_len = strlen(buf);
- if (iscmsg) {
- vec[2].iov_base = (char *) art->data + len;
- vec[2].iov_len = art->len - len;
- } else {
- vec[2].iov_base = (char *) "\r\n.\r\n";
- vec[2].iov_len = 5;
- }
- if (xwritev(ToServer, vec, 3) < 0)
- return false;
- } else
- if (xwrite(ToServer, art->data, art->len) < 0)
- return false;
- if (GotInterrupt)
- Interrupted(Article, MessageID);
- if (Debug) {
- fprintf(stderr, "> [ article %lu ]\n", (unsigned long) art->len);
- fprintf(stderr, "> .\n");
- }
-
- if (CanStream) return true; /* streaming mode does not wait for ACK */
-
- /* What did the remote site say? */
- if (!REMread(buff, (int)sizeof buff)) {
- syswarn("no reply after sending %s", Article);
- return false;
- }
- if (GotInterrupt)
- Interrupted(Article, MessageID);
- if (Debug)
- fprintf(stderr, "< %s", buff);
-
- /* Parse the reply. */
- switch (atoi(buff)) {
- default:
- warn("unknown reply after %s -- %s", Article, buff);
- if (DoRequeue)
- Requeue(Article, MessageID);
- break;
- case NNTP_BAD_COMMAND_VAL:
- case NNTP_SYNTAX_VAL:
- case NNTP_ACCESS_VAL:
- /* The receiving server is likely confused...no point in continuing */
- syslog(L_FATAL, GOT_BADCOMMAND, REMhost, MessageID, REMclean(buff));
- RequeueRestAndExit(Article, MessageID);
- /* NOTREACHED */
- case NNTP_RESENDIT_VAL:
- case NNTP_GOODBYE_VAL:
- Requeue(Article, MessageID);
- break;
- case NNTP_TOOKIT_VAL:
- STATaccepted++;
- STATacceptedsize += (double)art->len;
- break;
- case NNTP_REJECTIT_VAL:
- if (logRejects)
- syslog(L_NOTICE, REJECTED, REMhost,
- MessageID, Article, REMclean(buff));
- STATrejected++;
- STATrejectedsize += (double)art->len;
- break;
- }
-
- /* Article sent, or we requeued it. */
- return true;
-}
-\f
-
-/*
-** Get the Message-ID header from an open article.
-*/
-static char *
-GetMessageID(ARTHANDLE *art) {
- static char *buff;
- static int buffsize = 0;
- const char *p, *q;
-
- p = wire_findheader(art->data, art->len, "Message-ID");
- if (p == NULL)
- return NULL;
- for (q = p; q < art->data + art->len; q++) {
- if (*q == '\r' || *q == '\n')
- break;
- }
- if (q == art->data + art->len)
- return NULL;
- if (buffsize < q - p) {
- if (buffsize == 0)
- buff = xmalloc(q - p + 1);
- else
- buff = xrealloc(buff, q - p + 1);
- buffsize = q - p;
- }
- memcpy(buff, p, q - p);
- buff[q - p] = '\0';
- return buff;
-}
-\f
-
-/*
-** Mark that we got interrupted.
-*/
-static RETSIGTYPE
-CATCHinterrupt(int s) {
- GotInterrupt = true;
-
- /* Let two interrupts kill us. */
- xsignal(s, SIG_DFL);
-}
-
-
-/*
-** Mark that the alarm went off.
-*/
-static RETSIGTYPE
-CATCHalarm(int s UNUSED)
-{
- GotAlarm = true;
- if (JMPyes)
- longjmp(JMPwhere, 1);
-}
-
-/* check articles in streaming NNTP mode
-** return true on failure.
-*/
-static bool
-check(int i) {
- char buff[NNTP_STRLEN];
-
- /* send "check <ID>" to the other system */
- snprintf(buff, sizeof(buff), "check %s", stbuf[i].st_id);
- if (!REMwrite(buff, (int)strlen(buff), false)) {
- syswarn("cannot check article");
- return true;
- }
- STAToffered++;
- if (Debug) {
- if (stbuf[i].st_retry)
- fprintf(stderr, "> %s (retry %d)\n", buff, stbuf[i].st_retry);
- else
- fprintf(stderr, "> %s\n", buff);
- }
- if (GotInterrupt)
- Interrupted(stbuf[i].st_fname, stbuf[i].st_id);
-
- /* That all. Response is checked later by strlisten() */
- return false;
-}
-
-/* Send article in "takethis <id> streaming NNTP mode.
-** return true on failure.
-*/
-static bool
-takethis(int i) {
- char buff[NNTP_STRLEN];
-
- if (!stbuf[i].art) {
- warn("internal error: null article for %s in takethis",
- stbuf[i].st_fname);
- return true;
- }
- /* send "takethis <ID>" to the other system */
- snprintf(buff, sizeof(buff), "takethis %s", stbuf[i].st_id);
- if (!REMwrite(buff, (int)strlen(buff), false)) {
- syswarn("cannot send takethis");
- return true;
- }
- if (Debug)
- fprintf(stderr, "> %s\n", buff);
- if (GotInterrupt)
- Interrupted((char *)0, (char *)0);
- if (!REMsendarticle(stbuf[i].st_fname, stbuf[i].st_id, stbuf[i].art))
- return true;
- stbuf[i].st_size = stbuf[i].art->len;
- article_free(stbuf[i].art); /* should not need file again */
- stbuf[i].art = 0; /* so close to free descriptor */
- stbuf[i].st_age = 0;
- /* That all. Response is checked later by strlisten() */
- return false;
-}
-
-
-/* listen for responses. Process acknowledgments to remove items from
-** the queue. Also sends the articles on request. Returns true on error.
-** return true on failure.
-*/
-static bool
-strlisten(void)
-{
- int resp;
- int i;
- char *id, *p;
- char buff[NNTP_STRLEN];
- int hash;
-
- while(true) {
- if (!REMread(buff, (int)sizeof buff)) {
- syswarn("no reply to check");
- return true;
- }
- if (GotInterrupt)
- Interrupted((char *)0, (char *)0);
- if (Debug)
- fprintf(stderr, "< %s", buff);
-
- /* Parse the reply. */
- resp = atoi(buff);
- /* Skip the 1XX informational messages */
- if ((resp >= 100) && (resp < 200)) continue;
- switch (resp) { /* first time is to verify it */
- case NNTP_ERR_GOTID_VAL:
- case NNTP_OK_SENDID_VAL:
- case NNTP_OK_RECID_VAL:
- case NNTP_ERR_FAILID_VAL:
- case NNTP_RESENDID_VAL:
- if ((id = strchr(buff, '<')) != NULL) {
- p = strchr(id, '>');
- if (p) *(p+1) = '\0';
- hash = stidhash(id);
- i = stindex(id, hash); /* find table entry */
- if (i < 0) { /* should not happen */
- syslog(L_NOTICE, CANT_FINDIT, REMhost, REMclean(buff));
- return (true); /* can't find it! */
- }
- } else {
- syslog(L_NOTICE, CANT_PARSEIT, REMhost, REMclean(buff));
- return (true);
- }
- break;
- case NNTP_GOODBYE_VAL:
- /* Most likely out of space -- no point in continuing. */
- syslog(L_NOTICE, IHAVE_FAIL, REMhost, REMclean(buff));
- return true;
- /* NOTREACHED */
- default:
- syslog(L_NOTICE, UNEXPECTED, REMhost, REMclean(buff));
- if (Debug)
- fprintf(stderr, "Unknown reply \"%s\"",
- buff);
- return (true);
- }
- switch (resp) { /* now we take some action */
- case NNTP_RESENDID_VAL: /* remote wants it later */
- /* try again now because time has passed */
- if (stbuf[i].st_retry < STNRETRY) {
- if (check(i)) return true;
- stbuf[i].st_retry++;
- stbuf[i].st_age = 0;
- } else { /* requeue to disk for later */
- Requeue(stbuf[i].st_fname, stbuf[i].st_id);
- strel(i); /* release entry */
- }
- break;
- case NNTP_ERR_GOTID_VAL: /* remote doesn't want it */
- strel(i); /* release entry */
- STATrefused++;
- stnofail = 0;
- break;
-
- case NNTP_OK_SENDID_VAL: /* remote wants article */
- if (takethis(i)) return true;
- stnofail++;
- break;
-
- case NNTP_OK_RECID_VAL: /* remote received it OK */
- STATacceptedsize += (double) stbuf[i].st_size;
- strel(i); /* release entry */
- STATaccepted++;
- break;
-
- case NNTP_ERR_FAILID_VAL:
- STATrejectedsize += (double) stbuf[i].st_size;
- if (logRejects)
- syslog(L_NOTICE, REJ_STREAM, REMhost,
- stbuf[i].st_fname, REMclean(buff));
-/* XXXXX Caution THERE BE DRAGONS, I don't think this logs properly
- The message ID is returned in the peer response... so this is redundant
- stbuf[i].st_id, stbuf[i].st_fname, REMclean(buff)); */
- strel(i); /* release entry */
- STATrejected++;
- stnofail = 0;
- break;
- }
- break;
- }
- return (false);
-}
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- die("Usage: innxmit [-acdHlprs] [-t#] [-T#] host file");
-}
-
-
-/*
-** Open an article. If the argument is a token, retrieve the article via
-** the storage API. Otherwise, open the file and fake up an ARTHANDLE for
-** it. Only fill in those fields that we'll need. Articles not retrieved
-** via the storage API will have a type of TOKEN_EMPTY.
-*/
-static ARTHANDLE *
-article_open(const char *path, const char *id)
-{
- TOKEN token;
- ARTHANDLE *article;
- int fd, length;
- struct stat st;
- char *p;
-
- if (IsToken(path)) {
- token = TextToToken(path);
- article = SMretrieve(token, RETR_ALL);
- if (article == NULL) {
- if (SMerrno == SMERR_NOENT || SMerrno == SMERR_UNINIT)
- STATmissing++;
- else {
- warn("requeue %s: %s", path, SMerrorstr);
- Requeue(path, id);
- }
- }
- return article;
- } else {
- char *data;
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return NULL;
- if (fstat(fd, &st) < 0) {
- syswarn("requeue %s", path);
- Requeue(path, id);
- return NULL;
- }
- article = xmalloc(sizeof(ARTHANDLE));
- article->type = TOKEN_EMPTY;
- article->len = st.st_size;
- data = xmalloc(article->len);
- if (xread(fd, data, article->len) < 0) {
- syswarn("requeue %s", path);
- free(data);
- free(article);
- close(fd);
- Requeue(path, id);
- return NULL;
- }
- close(fd);
- p = memchr(data, '\n', article->len);
- if (p == NULL || p == data) {
- warn("requeue %s: cannot find headers", path);
- free(data);
- free(article);
- Requeue(path, id);
- return NULL;
- }
- if (p[-1] != '\r') {
- p = ToWireFmt(data, article->len, (size_t *)&length);
- free(data);
- data = p;
- article->len = length;
- }
- article->data = data;
- return article;
- }
-}
-
-
-/*
-** Free an article, using the type field to determine whether to free it
-** via the storage API.
-*/
-static void
-article_free(ARTHANDLE *article)
-{
- if (article->type == TOKEN_EMPTY) {
- free((char *)article->data);
- free(article);
- } else
- SMfreearticle(article);
-}
-
-
-int main(int ac, char *av[]) {
- static char SKIPPING[] = "Skipping \"%s\" --%s?\n";
- int i;
- char *p;
- ARTHANDLE *art;
- FILE *From;
- FILE *To;
- char buff[8192+128];
- char *Article;
- char *MessageID;
- RETSIGTYPE (*old)(int) = NULL;
- unsigned int ConnectTimeout;
- unsigned int TotalTimeout;
- int port = NNTP_PORT;
- bool val;
- char *path;
-
- openlog("innxmit", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "innxmit";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
-
- ConnectTimeout = 0;
- TotalTimeout = 0;
-
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "lacdHprst:T:vP:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'P':
- port = atoi(optarg);
- break;
- case 'a':
- AlwaysRewrite = true;
- break;
- case 'c':
- DoCheck = false;
- break;
- case 'd':
- Debug = true;
- break;
- case 'H':
- HeadersFeed = true;
- break;
- case 'l':
- logRejects = true ;
- break ;
- case 'p':
- AlwaysRewrite = true;
- Purging = true;
- break;
- case 'r':
- DoRequeue = false;
- break;
- case 's':
- TryStream = false;
- break;
- case 't':
- ConnectTimeout = atoi(optarg);
- break;
- case 'T':
- TotalTimeout = atoi(optarg);
- break;
- case 'v':
- STATprint = true;
- break;
- }
- ac -= optind;
- av += optind;
-
- /* Parse arguments; host and filename. */
- if (ac != 2)
- Usage();
- REMhost = av[0];
- BATCHname = av[1];
-
- if (chdir(innconf->patharticles) < 0)
- sysdie("cannot cd to %s", innconf->patharticles);
-
- val = true;
- if (!SMsetup(SM_PREOPEN,(void *)&val))
- die("cannot set up the storage manager");
- if (!SMinit())
- die("cannot initialize the storage manager: %s", SMerrorstr);
-
- /* Open the batch file and lock others out. */
- if (BATCHname[0] != '/') {
- BATCHname = concatpath(innconf->pathoutgoing, av[1]);
- }
- if (((i = open(BATCHname, O_RDWR)) < 0) || ((BATCHqp = QIOfdopen(i)) == NULL)) {
- syswarn("cannot open %s", BATCHname);
- SMshutdown();
- exit(1);
- }
- if (!inn_lock_file(QIOfileno(BATCHqp), INN_LOCK_WRITE, true)) {
-#if defined(EWOULDBLOCK)
- if (errno == EWOULDBLOCK) {
- SMshutdown();
- exit(0);
- }
-#endif /* defined(EWOULDBLOCK) */
- syswarn("cannot lock %s", BATCHname);
- SMshutdown();
- exit(1);
- }
-
- /* Get a temporary name in the same directory as the batch file. */
- p = strrchr(BATCHname, '/');
- *p = '\0';
- BATCHtemp = concatpath(BATCHname, "bchXXXXXX");
- *p = '/';
-
- /* Set up buffer used by REMwrite. */
- REMbuffer = xmalloc(OUTPUT_BUFFER_SIZE);
- REMbuffend = &REMbuffer[OUTPUT_BUFFER_SIZE];
- REMbuffptr = REMbuffer;
-
- /* Start timing. */
- STATbegin = TMRnow_double();
-
- if (!Purging) {
- /* Open a connection to the remote server. */
- if (ConnectTimeout) {
- GotAlarm = false;
- old = xsignal(SIGALRM, CATCHalarm);
- if (setjmp(JMPwhere)) {
- warn("cannot connect to %s: timed out", REMhost);
- SMshutdown();
- exit(1);
- }
- JMPyes = true;
- alarm(ConnectTimeout);
- }
- if (NNTPconnect(REMhost, port, &From, &To, buff) < 0 || GotAlarm) {
- i = errno;
- warn("cannot connect to %s: %s", REMhost,
- buff[0] ? REMclean(buff) : strerror(errno));
- if (GotAlarm)
- syslog(L_NOTICE, CANT_CONNECT, REMhost, "timeout");
- else
- syslog(L_NOTICE, CANT_CONNECT, REMhost,
- buff[0] ? REMclean(buff) : strerror(i));
- SMshutdown();
- exit(1);
- }
- if (Debug)
- fprintf(stderr, "< %s\n", REMclean(buff));
- if (NNTPsendpassword(REMhost, From, To) < 0 || GotAlarm) {
- i = errno;
- syswarn("cannot authenticate with %s", REMhost);
- syslog(L_ERROR, CANT_AUTHENTICATE,
- REMhost, GotAlarm ? "timeout" : strerror(i));
- /* Don't send quit; we want the remote to print a message. */
- SMshutdown();
- exit(1);
- }
- if (ConnectTimeout) {
- alarm(0);
- xsignal(SIGALRM, old);
- JMPyes = false;
- }
-
- /* We no longer need standard I/O. */
- FromServer = fileno(From);
- ToServer = fileno(To);
-
- if (TryStream) {
- if (!REMwrite(modestream, (int)strlen(modestream), false)) {
- syswarn("cannot negotiate %s", modestream);
- }
- if (Debug)
- fprintf(stderr, ">%s\n", modestream);
- /* Does he understand mode stream? */
- if (!REMread(buff, (int)sizeof buff)) {
- syswarn("no reply to %s", modestream);
- } else {
- if (Debug)
- fprintf(stderr, "< %s", buff);
-
- /* Parse the reply. */
- switch (atoi(buff)) {
- default:
- warn("unknown reply to %s -- %s", modestream, buff);
- CanStream = false;
- break;
- case NNTP_OK_STREAM_VAL: /* YES! */
- CanStream = true;
- break;
- case NNTP_AUTH_NEEDED_VAL: /* authentication refusal */
- case NNTP_BAD_COMMAND_VAL: /* normal refusal */
- CanStream = false;
- break;
- }
- }
- if (CanStream) {
- for (i = 0; i < STNBUF; i++) { /* reset buffers */
- stbuf[i].st_fname = 0;
- stbuf[i].st_id = 0;
- stbuf[i].art = 0;
- }
- stnq = 0;
- }
- }
- if (HeadersFeed) {
- if (!REMwrite(modeheadfeed, strlen(modeheadfeed), false))
- syswarn("cannot negotiate %s", modeheadfeed);
- if (Debug)
- fprintf(stderr, ">%s\n", modeheadfeed);
- if (!REMread(buff, sizeof buff)) {
- syswarn("no reply to %s", modeheadfeed);
- } else {
- if (Debug)
- fprintf(stderr, "< %s", buff);
-
- /* Parse the reply. */
- switch (atoi(buff)) {
- case 250: /* YES! */
- break;
- case NNTP_BAD_COMMAND_VAL: /* normal refusal */
- die("%s not allowed -- %s", modeheadfeed, buff);
- default:
- die("unknown reply to %s -- %s", modeheadfeed, buff);
- }
- }
- }
- }
-
- /* Set up signal handlers. */
- xsignal(SIGHUP, CATCHinterrupt);
- xsignal(SIGINT, CATCHinterrupt);
- xsignal(SIGTERM, CATCHinterrupt);
- xsignal(SIGPIPE, SIG_IGN);
- if (TotalTimeout) {
- xsignal(SIGALRM, CATCHalarm);
- alarm(TotalTimeout);
- }
-
- path = concatpath(innconf->pathdb, _PATH_HISTORY);
- History = HISopen(path, innconf->hismethod, HIS_RDONLY);
- free(path);
-
- /* Main processing loop. */
- GotInterrupt = false;
- GotAlarm = false;
- for (Article = NULL, MessageID = NULL; ; ) {
- if (GotAlarm) {
- warn("timed out");
- /* Don't resend the current article. */
- RequeueRestAndExit((char *)NULL, (char *)NULL);
- }
- if (GotInterrupt)
- Interrupted(Article, MessageID);
-
- if ((Article = QIOread(BATCHqp)) == NULL) {
- if (QIOtoolong(BATCHqp)) {
- warn("skipping long line in %s", BATCHname);
- QIOread(BATCHqp);
- continue;
- }
- if (QIOerror(BATCHqp)) {
- syswarn("cannot read %s", BATCHname);
- ExitWithStats(1);
- }
-
- /* Normal EOF -- we're done. */
- QIOclose(BATCHqp);
- BATCHqp = NULL;
- break;
- }
-
- /* Ignore blank lines. */
- if (*Article == '\0')
- continue;
-
- /* Split the line into possibly two fields. */
- if (Article[0] == '/'
- && Article[strlen(innconf->patharticles)] == '/'
- && strncmp(Article, innconf->patharticles, strlen(innconf->patharticles)) == 0)
- Article += strlen(innconf->patharticles) + 1;
- if ((MessageID = strchr(Article, ' ')) != NULL) {
- *MessageID++ = '\0';
- if (*MessageID != '<'
- || (p = strrchr(MessageID, '>')) == NULL
- || *++p != '\0') {
- warn("ignoring line %s %s...", Article, MessageID);
- continue;
- }
- }
-
- if (*Article == '\0') {
- if (MessageID)
- warn("empty file name for %s in %s", MessageID, BATCHname);
- else
- warn("empty file name, no message ID in %s", BATCHname);
- /* We could do a history lookup. */
- continue;
- }
-
- if (Purging && MessageID != NULL && !Expired(MessageID)) {
- Requeue(Article, MessageID);
- continue;
- }
-
- /* Drop articles with a message ID longer than NNTP_MSGID_MAXLEN to
- avoid overrunning buffers and throwing the server on the
- receiving end a blow from behind. */
- if (MessageID != NULL && strlen(MessageID) > NNTP_MSGID_MAXLEN) {
- warn("dropping article in %s: long message ID %s", BATCHname,
- MessageID);
- continue;
- }
-
- art = article_open(Article, MessageID);
- if (art == NULL)
- continue;
-
- if (Purging) {
- article_free(art);
- Requeue(Article, MessageID);
- continue;
- }
-
- /* Get the Message-ID from the article if we need to. */
- if (MessageID == NULL) {
- if ((MessageID = GetMessageID(art)) == NULL) {
- warn(SKIPPING, Article, "no message ID");
- article_free(art);
- continue;
- }
- }
- if (GotInterrupt)
- Interrupted(Article, MessageID);
-
- /* Offer the article. */
- if (CanStream) {
- int lim;
- int hash;
-
- hash = stidhash(MessageID);
- if (stindex(MessageID, hash) >= 0) { /* skip duplicates in queue */
- if (Debug)
- fprintf(stderr, "Skipping duplicate ID %s\n",
- MessageID);
- article_free(art);
- continue;
- }
- /* This code tries to optimize by sending a burst of "check"
- * commands before flushing the buffer. This should result
- * in several being sent in one packet reducing the network
- * overhead.
- */
- if (DoCheck && (stnofail < STNC)) lim = STNBUF;
- else lim = STNBUFL;
- if (stnq >= lim) { /* need to empty a buffer */
- while (stnq >= STNBUFL) { /* or several */
- if (strlisten()) {
- RequeueRestAndExit(Article, MessageID);
- }
- }
- }
- /* save new article in the buffer */
- i = stalloc(Article, MessageID, art, hash);
- if (i < 0) {
- article_free(art);
- RequeueRestAndExit(Article, MessageID);
- }
- if (DoCheck && (stnofail < STNC)) {
- if (check(i)) {
- RequeueRestAndExit((char *)NULL, (char *)NULL);
- }
- } else {
- STAToffered++ ;
- if (takethis(i)) {
- RequeueRestAndExit((char *)NULL, (char *)NULL);
- }
- }
- /* check for need to resend any IDs */
- for (i = 0; i < STNBUF; i++) {
- if ((stbuf[i].st_fname) && (stbuf[i].st_fname[0] != '\0')) {
- if (stbuf[i].st_age++ > stnq) {
- /* This should not happen but just in case ... */
- if (stbuf[i].st_retry < STNRETRY) {
- if (check(i)) /* resend check */
- RequeueRestAndExit((char *)NULL, (char *)NULL);
- retries++;
- stbuf[i].st_retry++;
- stbuf[i].st_age = 0;
- } else { /* requeue to disk for later */
- Requeue(stbuf[i].st_fname, stbuf[i].st_id);
- strel(i); /* release entry */
- }
- }
- }
- }
- continue; /* next article */
- }
- snprintf(buff, sizeof(buff), "ihave %s", MessageID);
- if (!REMwrite(buff, (int)strlen(buff), false)) {
- syswarn("cannot offer article");
- article_free(art);
- RequeueRestAndExit(Article, MessageID);
- }
- STAToffered++;
- if (Debug)
- fprintf(stderr, "> %s\n", buff);
- if (GotInterrupt)
- Interrupted(Article, MessageID);
-
- /* Does he want it? */
- if (!REMread(buff, (int)sizeof buff)) {
- syswarn("no reply to ihave");
- article_free(art);
- RequeueRestAndExit(Article, MessageID);
- }
- if (GotInterrupt)
- Interrupted(Article, MessageID);
- if (Debug)
- fprintf(stderr, "< %s", buff);
-
- /* Parse the reply. */
- switch (atoi(buff)) {
- default:
- warn("unknown reply to %s -- %s", Article, buff);
- if (DoRequeue)
- Requeue(Article, MessageID);
- break;
- case NNTP_BAD_COMMAND_VAL:
- case NNTP_SYNTAX_VAL:
- case NNTP_ACCESS_VAL:
- /* The receiving server is likely confused...no point in continuing */
- syslog(L_FATAL, GOT_BADCOMMAND, REMhost, MessageID, REMclean(buff));
- RequeueRestAndExit(Article, MessageID);
- /* NOTREACHED */
- case NNTP_AUTH_NEEDED_VAL:
- case NNTP_RESENDIT_VAL:
- case NNTP_GOODBYE_VAL:
- /* Most likely out of space -- no point in continuing. */
- syslog(L_NOTICE, IHAVE_FAIL, REMhost, REMclean(buff));
- RequeueRestAndExit(Article, MessageID);
- /* NOTREACHED */
- case NNTP_SENDIT_VAL:
- if (!REMsendarticle(Article, MessageID, art))
- RequeueRestAndExit(Article, MessageID);
- break;
- case NNTP_HAVEIT_VAL:
- STATrefused++;
- break;
-#if defined(NNTP_SENDIT_LATER)
- case NNTP_SENDIT_LATER_VAL:
- Requeue(Article, MessageID);
- break;
-#endif /* defined(NNTP_SENDIT_LATER) */
- }
-
- article_free(art);
- }
- if (CanStream) { /* need to wait for rest of ACKs */
- while (stnq > 0) {
- if (strlisten()) {
- RequeueRestAndExit((char *)NULL, (char *)NULL);
- }
- }
- }
-
- if (BATCHfp != NULL)
- /* We requeued something, so close the temp file. */
- CloseAndRename();
- else if (unlink(BATCHname) < 0 && errno != ENOENT)
- syswarn("cannot remove %s", BATCHtemp);
- ExitWithStats(0);
- /* NOTREACHED */
- return 0;
-}
+++ /dev/null
-/* $Id: map.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "libinn.h"
-#include "paths.h"
-
-#include "map.h"
-
-
-typedef struct _PAIR {
- char First;
- char *Key;
- char *Value;
-} PAIR;
-
-static PAIR *MAPdata;
-static PAIR *MAPend;
-
-
-/*
-** Free the map.
-*/
-void
-MAPfree(void)
-{
- PAIR *mp;
-
- for (mp = MAPdata; mp < MAPend; mp++) {
- free(mp->Key);
- free(mp->Value);
- }
- free(MAPdata);
- MAPdata = NULL;
-}
-
-
-/*
-** Read the map file.
-*/
-void
-MAPread(const char *name)
-{
- FILE *F;
- int i;
- PAIR *mp;
- char *p;
- char buff[BUFSIZ];
-
- if (MAPdata != NULL)
- MAPfree();
-
- /* Open file, count lines. */
- if ((F = fopen(name, "r")) == NULL) {
- fprintf(stderr, "Can't open %s, %s\n", name, strerror(errno));
- exit(1);
- }
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
- mp = MAPdata = xmalloc((i + 1) * sizeof(PAIR));
-
- /* Read each line; ignore blank and comment lines. */
- fseeko(F, 0, SEEK_SET);
- while (fgets(buff, sizeof buff, F) != NULL) {
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '\0'
- || buff[0] == '#'
- || (p = strchr(buff, ':')) == NULL)
- continue;
- *p++ = '\0';
- mp->First = buff[0];
- mp->Key = xstrdup(buff);
- mp->Value = xstrdup(p);
- mp++;
- }
- fclose(F);
- MAPend = mp;
-}
-
-
-/*
-** Look up a name in the map, return original value if not found.
-*/
-char *
-MAPname(char *p)
-{
- PAIR *mp;
- char c;
-
- for (c = *p, mp = MAPdata; mp < MAPend; mp++)
- if (c == mp->First && strcmp(p, mp->Key) == 0)
- return mp->Value;
- return p;
-}
+++ /dev/null
-/* $Id: map.h 5292 2002-03-10 08:59:54Z vinocur $
-**
-*/
-
-void MAPfree(void); /* free the map */
-void MAPread(const char *name); /* read the map file */
-char *MAPname(char *p); /* lookup in the map */
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# batch-active-update
-# Author: David Lawrence <tale@isc.org>
-
-# Reads a series of ctlinnd newgroup/rmgroup/changegroup commands, such as
-# is output by checkgroups and actsync, and efficiently handles them all at
-# once. Input can come from command line files or stdin, a la awk/sed.
-
-$oldact = $inn::active; # active file location
-$oldact = $inn::active; # active file location (same; shut up, perl -w)
-$newact = "$oldact.new$$"; # temporary name for new active file
-$actime = "$oldact.times"; # active.times file
-$pausemsg = 'batch active update, ok'; # message to be used for pausing?
-$diff_flags = ''; # Flags for diff(1); default chosen if null.
-
-$0 =~ s#^.*/##;
-
-die "$0: must run as $inn::newsuser user"
- unless $> == (getpwnam($inn::newsuser))[2];
-
-$debug = -t STDOUT ? 1 : 0;
-
-$| = 1; # show output as it happens (for an rsh/ssh pipe)
-
-# Guess at best flags for a condensed diff listing. The
-# checks for alternative operating systems is incomplete.
-unless ($diff_flags) {
- if (`diff -v 2>&1` =~ /GNU/) {
- $diff_flags = '-U0';
- } elsif ($^O =~ /^(dec_osf|solaris)$/) {
- $diff_flags = '-C0';
- } elsif ($^O eq 'nextstep') {
- $diff_flags = '-c0';
- } else {
- $diff_flags = '-c';
- }
-}
-
-print "reading list of groups to update\n" if $debug;
-
-$eval = "while (<OLDACT>) {\n";
-$eval .= " \$group = (split)[0];\n";
-
-while (<>) {
- if (/^\s*\S*ctlinnd newgroup (\S+) (\S)/) {
- $toadd{$1} = $2;
- } elsif (/^\s*\S*ctlinnd rmgroup (\S+)/) {
- $eval .= " next if \$group eq '$1';\n";
- } elsif (/^\s*\S*ctlinnd changegroup (\S+) (\S)/) {
- $eval .= " s/ \\S+\$/ $2/ if \$group eq '$1';\n";
- }
-}
-
-$eval .= " delete \$toadd{\$group};\n";
-$eval .= " if (!print(NEWACT \$_)) {\n";
-$eval .= " die \"\$0: writing \$newact failed (\$!), aborting\\n\";\n";
-$eval .= " }\n";
-$eval .= "}\n";
-
-&ctlinnd("pause $pausemsg");
-
-open(OLDACT, "< $oldact") || die "$0: open $oldact: $!\n";
-open(NEWACT, "> $newact") || die "$0: open $newact: $!\n";
-
-print "rewriting active file\n" if $debug;
-eval $eval;
-for (sort keys %toadd) {
- $add = "$_ 0000000000 0000000001 $toadd{$_}\n";
- if (!print( NEWACT $add)) {
- &ctlinnd("go $pausemsg");
- die "$0: writing $newact failed ($!), aborting\n";
- }
-}
-
-close(OLDACT) || warn "$0: close $oldact: $!\n";
-close(NEWACT) || warn "$0: close $newact: $!\n";
-
-if (!rename("$oldact", "$oldact.old")) {
- warn "$0: rename $oldact $oldact.old: $!\n";
-}
-
-if (!rename("$newact", "$oldact")) {
- die "$0: rename $newact $oldact: $!\n";
-}
-
-&ctlinnd("reload active 'updated from checkgroups'");
-system("diff $diff_flags $oldact.old $oldact");
-&ctlinnd("go $pausemsg");
-
-print "updating $actime\n" if $debug;
-if (open(TIMES, ">> $actime")) {
- $time = time;
- for (sort keys %toadd) {
- print TIMES "$_ $time checkgroups-update\n" || last;
- }
- close(TIMES) || warn "$0: close $actime: $!\n";
-} else {
- warn "$0: $actime not updated: $!\n";
-}
-
-exit 0;
-
-sub
-ctlinnd
-
-{
- local($command) = @_;
-
- print "ctlinnd $command\n" if $debug;
- if (system("$inn::newsbin/ctlinnd -s $command")) {
- die "$0: \"$command\" failed, aborting\n";
- }
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# news to mail channel backend
-#
-# INN gives us
-# @token@ addrs
-# for each article that needs to be mailed. We invoke sm on the
-# localhost to get the actual article and stuff
-# it down sendmail's throat.
-#
-# This program expect to find a file that maps listname to listaddrs,
-# @prefix@/etc/news2mail.cf
-# which must contain address mapping pairs such as
-#
-# big-red-ants@ucsd.edu big-red-ants-digest@ucsd.edu
-#
-# where the first token is the name fed to us from INN, and which is
-# also placed in the To: header of the outgoing mail. It's probably
-# the subscriber's list submittal address so that replies go to the
-# right place. The second token is the actual address sendmail ships
-# the article to.
-#
-# In the INN newsfeeds file, you need to have a channel feed:
-# n2m!:!*:Tc,Ac,Wn*:@prefix@/bin/news2mail
-# and a site for each of the various mailing lists you're feeding,
-# such as
-# big-red-ants@ucsd.edu:rec.pets.redants.*:Tm:n2m!
-#
-# Error handling is nearly nonexistent.
-#
-# - Brian Kantor, UCSD Aug 1998
-
-require 5.006;
-
-use FileHandle;
-use Sys::Syslog;
-use strict;
-
-my $cfFile = $inn::pathetc . "/news2mail.cf" ;
-my $sendmail = $inn::mta ;
-my $sm = $inn::pathbin . "/sm" ;
-my %maddr = ();
-
-#
-# the syslog calls are here but don't work on my system
-#
-openlog('news2mail', 'pid', 'mail');
-
-syslog('info', 'begin');
-
-#
-# load the list names and their mail addresses from cf file
-# #comments and blank lines are ignored
-#
-unless (open CF, "< $cfFile") {
- syslog('notice', 'CF open failed %m');
- die "bad CF";
- }
-
-while ( <CF> ) {
- next if /^#|^\s+$/;
- my ( $ln, $ma ) = split /\s+/;
- $maddr{ $ln } = $ma;
- }
-close CF;
-
-#
-# for each incoming line from the INN channel
-#
-while ( <STDIN> ) {
- chomp;
-
- syslog('info', $_);
-
- my ($token, $lnames) = split /\s+/, $_, 2;
- my @addrs = split /\s+/, $lnames;
-
- my @good = grep { defined $maddr{$_} } @addrs;
- my @bad = grep { !defined $maddr{$_} } @addrs;
-
- if (! @good) {
- syslog('notice', "unknown listname $_");
- next;
- }
-
- if (@bad) {
- syslog('info', 'skipping unknown lists: ', join(' ', @bad));
- }
- mailto($token, $lnames, @maddr{@good});
- }
-
-syslog ("info", "end") ;
-
-exit 0;
-
-sub mailto {
- my($t, $l, @a) = @_ ;
-
- my $sendmail = $inn::mta ;
- $sendmail =~ s!\s*%s!! ;
- my @command = (split (' ', $sendmail), '-ee', '-fnews', '-odq', @a);
-# @command[0] = '/usr/local/bin/debug';
-
- syslog('info', join(' ', @command));
-
- unless (open(SM, '|-', @command)) {
- syslog('notice', join(' ', '|', @command), 'failed!');
- die "bad $sendmail";
- }
-
- my $smgr = "$sm -q $t |";
-
- unless (open(SMGR, $smgr)) {
- syslog('notice', "$smgr failed!");
- die "bad $smgr";
- }
-
- # header
- while ( <SMGR> ) {
- chomp;
-
- # empty line signals end of header
- if ( /^$/ ) {
- print SM "To: $l\n\n";
- last;
- }
-
- #
- # skip unnecessary headers
- #
- next if /^NNTP-Posting-Date:/i;
- next if /^NNTP-Posting-Host:/i;
- next if /^X-Trace:/i;
- next if /^Xref:/i;
- next if /^Path:/i;
-
- #
- # convert Newsgroups header into X-Newsgroups
- #
- s/^Newsgroups:/X-Newsgroups:/i;
-
- print SM "$_\n";
- }
-
- # body
- while ( <SMGR> ) {
- print SM $_;
- }
-
- close(SMGR);
- close(SM);
- }
+++ /dev/null
-/* $Id: ninpaths.c 6362 2003-05-31 18:35:04Z rra $
-**
-** New inpaths reporting program.
-**
-** Idea, data structures and part of code based on inpaths 2.5
-** by Brian Reid, Landon Curt Noll
-**
-** This version written by Olaf Titz, Feb. 1997. Public domain.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <time.h>
-
-#define VERSION "3.1.1"
-
-#define MAXFNAME 1024 /* max length of file name */
-#define MAXLINE 1024 /* max length of Path line */
-#define HASH_TBL 65536 /* hash table size (power of two) */
-#define MAXHOST 128 /* max length of host name */
-#define HOSTF "%127s" /* scanf format for host name */
-#define RECLINE 120 /* dump file line length softlimit */
-
-/* structure used to tally the traffic between two hosts */
-struct trec {
- struct trec *rlink; /* next in chain */
- struct nrec *linkid; /* pointer to... */
- long tally; /* count */
-};
-
-/* structure to hold the information about a host */
-struct nrec {
- struct nrec *link; /* next in chain */
- struct trec *rlink; /* start of trec chain */
- char *id; /* host name */
- long no; /* identificator for dump file */
- long sentto; /* tally of articles sent from here */
-};
-
-struct nrec *hosthash[HASH_TBL];
-
-time_t starttime; /* Start time */
-double atimes=0.0; /* Sum of articles times wrt. starttime */
-long total=0, /* Total articles processed */
- sites=0; /* Total sites known */
-
-/* malloc and warn if out of mem */
-void *
-wmalloc(size_t s)
-{
- void *p=malloc(s);
- if (!p)
- fprintf(stderr, "warning: out of memory\n");
- return p;
-}
-
-/* Hash function due to Glenn Fowler / Landon Curt Noll / Phong Vo */
-int
-hash(const char *str)
-{
- unsigned long val;
- unsigned long c;
-
- for (val = 0; (c=(unsigned long)(*str)); ++str) {
- val *= 16777619; /* magic */
- val ^= c; /* more magic */
- }
- return (int)(val & (unsigned long)(HASH_TBL-1));
-}
-
-/* Look up a host in the hash table. Add if necessary. */
-struct nrec *
-hhost(const char *n)
-{
- struct nrec *h;
- int i=hash(n);
-
- for (h=hosthash[i]; h; h=h->link)
- if (!strcmp(n, h->id))
- return h;
- /* not there - allocate */
- h=wmalloc(sizeof(struct nrec));
- if (!h)
- return NULL;
- h->id=strdup(n);
- if (!h->id) {
- free(h); return NULL;
- }
- h->link=hosthash[i];
- h->rlink=NULL;
- h->no=h->sentto=0;
- hosthash[i]=h;
- sites++;
- return h;
-}
-
-/* Look up a tally record between hosts. Add if necessary. */
-struct trec *
-tallyrec(struct nrec *r, struct nrec *h)
-{
- struct trec *t;
- for (t=r->rlink; t; t=t->rlink)
- if (t->linkid==h)
- return t;
- t=wmalloc(sizeof(struct trec));
- if (!t)
- return NULL;
- t->rlink=r->rlink;
- t->linkid=h;
- t->tally=0;
- r->rlink=t;
- return t;
-}
-
-
-/* Dump file format:
- "!!NINP" <version> <starttime> <endtime> <sites> <total> <avgtime> "\n"
- followed by <sites> S-records,
- "!!NLREC\n"
- [3.0]
- followed by max. <sites>^2 L-records
- [3.1]
- followed by max. <sites> L-records
- "!!NEND" <nlrecs> "\n"
- starttime, endtime, avgtime as UNIX date
- the records are separated by space or \n
- an S-record is "site count"
- [3.0]
- an L-record is "sitea!siteb!count"
- [3.1]
- an L-record is ":sitea" { "!siteb,count" }...
- ",count" omitted if count==1
- where sitea and siteb are numbers of the S-records starting at 0
-*/
-
-int
-writedump(FILE *f)
-{
- int i, j;
- long n;
- struct nrec *h;
- struct trec *t;
-
- if (!total) {
- return -1;
- }
- fprintf(f, "!!NINP " VERSION " %lu %lu %ld %ld %ld\n",
- (unsigned long) starttime, (unsigned long) time(NULL), sites,
- total, (long)(atimes/total)+starttime);
- n=j=0;
- /* write the S-records (hosts), numbering them in the process */
- for (i=0; i<HASH_TBL; ++i)
- for (h=hosthash[i]; h; h=h->link) {
- h->no=n++;
- j+=fprintf(f, "%s %ld", h->id, h->sentto);
- if (j>RECLINE) {
- j=0;
- fprintf(f, "\n");
- } else {
- fprintf(f, " ");
- }
- }
- if (n!=sites)
- fprintf(stderr, "internal error: sites=%ld, dumped=%ld\n", sites, n);
-
- fprintf(f, "\n!!NLREC\n");
-
- n=j=0;
- /* write the L-records (links) */
- for (i=0; i<HASH_TBL; ++i)
- for (h=hosthash[i]; h; h=h->link)
- if ((t=h->rlink)) {
- j+=fprintf(f, ":%ld", h->no);
- for (; t; t=t->rlink) {
- j+=fprintf(f, "!%ld", t->linkid->no);
- if (t->tally>1)
- j+=fprintf(f, ",%ld", t->tally);
- n++;
- }
- if (j>RECLINE) {
- j=0;
- fprintf(f, "\n");
- }
- }
- fprintf(f, "\n!!NLEND %ld\n", n);
- return 0;
-}
-
-/* Write dump to a named file. Substitute %d in file name with system time. */
-
-void
-writedumpfile(const char *n)
-{
- char buf[MAXFNAME];
- FILE *d;
-
- if (n[0]=='-' && n[1]=='\0') {
- writedump(stdout);
- return;
- }
- snprintf(buf, sizeof(buf), n, time(0));
- d=fopen(buf, "w");
- if (d) {
- if (writedump(d)<0)
- unlink(buf);
- } else {
- perror("writedumpfile: fopen");
- }
-}
-
-/* Read a dump file. */
-
-int
-readdump(FILE *f)
-{
- int a, b;
- long i, m, l;
- unsigned long st, et, at;
- long sit, tot;
- struct nrec **n;
- struct trec *t;
- char c[MAXHOST];
- char v[16];
-
- #define formerr(i) {\
- fprintf(stderr, "dump file format error #%d\n", (i)); return -1; }
-
- if (fscanf(f, "!!NINP %15s %lu %lu %ld %ld %lu\n",
- v, &st, &et, &sit, &tot, &at)!=6)
- formerr(0);
-
- n=calloc(sit, sizeof(struct nrec *));
- if (!n) {
- fprintf(stderr, "error: out of memory\n");
- return -1;
- }
- for (i=0; i<sit; i++) {
- if (fscanf(f, HOSTF " %ld ", c, &l)!=2) {
- fprintf(stderr, "read %ld ", i);
- formerr(1);
- }
- n[i]=hhost(c);
- if (!n[i])
- return -1;
- n[i]->sentto+=l;
- }
- if ((fscanf(f, HOSTF "\n", c)!=1) ||
- strcmp(c, "!!NLREC"))
- formerr(2);
- m=0;
- if (!strncmp(v, "3.0", 3)) {
- /* Read 3.0-format L-records */
- while (fscanf(f, "%d!%d!%ld ", &a, &b, &l)==3) {
- t=tallyrec(n[a], n[b]);
- if (!t)
- return -1;
- t->tally+=l;
- ++m;
- }
- } else if (!strncmp(v, "3.1", 3)) {
- /* Read L-records */
- while (fscanf(f, " :%d", &a)==1) {
- while ((i=fscanf(f, "!%d,%ld", &b, &l))>0) {
- t=tallyrec(n[a], n[b]);
- if (i<2)
- l=1;
- if (!t)
- return -1;
- t->tally+=l;
- ++m;
- }
- }
- } else {
- fprintf(stderr, "version %s ", v);
- formerr(9);
- }
- if ((fscanf(f, "!!NLEND %ld\n", &i)!=1)
- || (i!=m))
- formerr(3);
-#ifdef DEBUG
- fprintf(stderr, " dumped start %s total=%ld atimes=%ld (%ld)\n",
- ctime(&st), tot, at, at-st);
-#endif
- /* Adjust the time average and total count */
- if ((unsigned long) starttime > st) {
- atimes+=(double)total*(starttime-st);
- starttime=st;
- }
- atimes+=(double)tot*(at-starttime);
- total+=tot;
-#ifdef DEBUG
- fprintf(stderr, " current start %s total=%ld atimes=%.0f (%.0f)\n\n",
- ctime(&starttime), total, atimes, atimes/total);
-#endif
- free(n);
- return 0;
-}
-
-/* Read dump from a file. */
-
-int
-readdumpfile(const char *n)
-{
- FILE *d;
- int i;
-
- if (n[0]=='-' && n[1]=='\0')
- return readdump(stdin);
-
- d=fopen(n, "r");
- if (d) {
- /* fprintf(stderr, "Reading dump file %s\n", n); */
- i=readdump(d);
- fclose(d);
- return i;
- } else {
- perror("readdumpfile: fopen");
- return -1;
- }
-}
-
-
-/* Process a Path line. */
-
-int
-pathline(char *c)
-{
- char *c2;
- struct nrec *h, *r;
- struct trec *t;
-
- r=NULL;
- while (*c) {
- for (c2=c; *c2 && *c2!='!'; c2++);
- if (c2-c>MAXHOST-1)
- /* looks broken, dont bother with rest */
- return 0;
- while (*c2=='!')
- *c2++='\0'; /* skip "!!" too */
- h=hhost(c);
- if (!h)
- return -1;
- ++h->sentto;
- if (r && r!=h) {
- t=tallyrec(r, h);
- if (!t)
- return -1;
- ++t->tally;
- }
- c=c2;
- r=h;
- }
- return 0;
-}
-
-/* Take Path lines from file (stdin used here). */
-
-void
-procpaths(FILE *f)
-{
- char buf[MAXLINE];
- char *c, *ce;
- int v=1; /* current line is valid */
-
- while (fgets(buf, sizeof(buf), f)) {
- c=buf;
- if (!strncmp(c, "Path: ", 6))
- c+=6;
- /* find end of line. Some broken newsreaders preload Path with
- a name containing spaces. Chop off those entries. */
- for (ce=c; *ce && !CTYPE(isspace, *ce); ++ce);
- if (!*ce) {
- /* bogus line */
- v=0;
- } else if (v) {
- /* valid line */
- for (; ce>c && *ce!='!'; --ce); /* ignore last element */
- *ce='\0';
- if (pathline(c)<0) /* process it */
- /* If an out of memory condition occurs while reading
- Path lines, stop reading and write the dump so far.
- INN will restart a fresh ninpaths. */
- return;
- /* update average age and grand total */
- atimes+=(time(0)-starttime);
- ++total;
- } else {
- /* next line is valid */
- v=1;
- }
- }
-}
-
-/* Output a report suitable for mailing. From inpaths 2.5 */
-
-void
-report(const char *hostname, int verbose)
-{
- double avgAge;
- int i, columns, needHost;
- long nhosts=0, nlinks=0;
- struct nrec *list, *relay;
- struct trec *rlist;
- char hostString[MAXHOST];
- time_t t0=time(0);
-
- if (!total) {
- fprintf(stderr, "report: no traffic\n");
- return;
- }
- /* mark own site to not report it */
- list=hhost(hostname);
- if (list)
- list->id[0]='\0';
-
- avgAge=((double)t0 - (atimes/total + (double)starttime)) /86400.0;
- printf("ZCZC begin inhosts %s %s %d %ld %3.1f\n",
- VERSION,hostname,verbose,total,avgAge);
- for (i=0; i<HASH_TBL-1; i++) {
- list = hosthash[i];
- while (list != NULL) {
- if (list->id[0] != 0 && list->rlink != NULL) {
- if (verbose > 0 || (100*list->sentto > total))
- printf("%ld\t%s\n",list->sentto, list->id);
- }
- list = list->link;
- }
- }
- printf("ZCZC end inhosts %s\n",hostname);
-
- printf("ZCZC begin inpaths %s %s %d %ld %3.1f\n",
- VERSION,hostname,verbose,total,avgAge);
- for (i=0; i<HASH_TBL-1; i++) {
- list = hosthash[i];
- while (list != NULL) {
- if (verbose > 1 || (100*list->sentto > total)) {
- if (list->id[0] != 0 && list->rlink != NULL) {
- columns = 3+strlen(list->id);
- snprintf(hostString,sizeof(hostString),"%s H ",list->id);
- needHost = 1;
- rlist = list->rlink;
- while (rlist != NULL) {
- if (
- (100*rlist->tally > total)
- || ((verbose > 1)&&(5000*rlist->tally>total))
- ) {
- if (needHost) printf("%s",hostString);
- needHost = 0;
- relay = rlist->linkid;
- if (relay->id[0] != 0) {
- if (columns > 70) {
- printf("\n%s",hostString);
- columns = 3+strlen(list->id);
- }
- printf("%ld Z %s U ", rlist->tally, relay->id);
- columns += 9+strlen(relay->id);
- }
- }
- rlist = rlist->rlink;
- ++nlinks;
- }
- if (!needHost) printf("\n");
- }
- }
- list = list->link;
- ++nhosts;
- }
- }
- printf("ZCZC end inpaths %s\n",hostname);
-#ifdef DEBUG
- fprintf(stderr, "Processed %ld hosts, %ld links.\n", nhosts, nlinks);
-#endif
-}
-
-extern char *optarg;
-
-int
-main(int argc, char *argv[])
-{
- int i;
- int pf=0, vf=2;
- char *df=NULL, *rf=NULL;
-
- for (i=0; i<HASH_TBL; i++)
- hosthash[i]=NULL;
- starttime=time(0);
-
- while ((i=getopt(argc, argv, "pd:u:r:v:"))!=EOF)
- switch (i) {
- case 'p':
- /* read Path lines from stdin */
- pf=1; break;
- case 'd':
- /* make a dump to the named file */
- df=optarg; break;
- case 'u':
- /* read dump from the named file */
- if (readdumpfile(optarg)<0)
- exit(1);
- break;
- case 'r':
- /* make a report for the named site */
- rf=optarg; break;
- case 'v':
- /* control report verbosity */
- vf=atoi(optarg); break;
- default:
- fprintf(stderr, "unknown option %c\n", i);
- }
-
- if (pf)
- procpaths(stdin);
- if (df)
- writedumpfile(df);
- if (rf)
- report(rf, vf);
- return 0;
-}
+++ /dev/null
-/* $Id: nntpget.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Connect to a remote site, and get news from it to offer to our local
-** server. Read list on stdin, or get it via NEWNEWS command. Writes
-** list of articles still needed to stdout.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-/*
-** All information about a site we are connected to.
-*/
-typedef struct _SITE {
- char *Name;
- int Rfd;
- int Wfd;
- char Buffer[BUFSIZ];
- char *bp;
- int Count;
-} SITE;
-
-
-/*
-** Global variables.
-*/
-static struct iovec SITEvec[2];
-static char SITEv1[] = "\r\n";
-static char READER[] = "mode reader";
-static unsigned long STATgot;
-static unsigned long STAToffered;
-static unsigned long STATsent;
-static unsigned long STATrejected;
-static struct history *History;
-
-\f
-
-/*
-** Read a line of input, with timeout.
-*/
-static bool
-SITEread(SITE *sp, char *start)
-{
- char *p;
- char *end;
- struct timeval t;
- fd_set rmask;
- int i;
- char c;
-
- for (p = start, end = &start[NNTP_STRLEN - 1]; ; ) {
- if (sp->Count == 0) {
- /* Fill the buffer. */
- Again:
- FD_ZERO(&rmask);
- FD_SET(sp->Rfd, &rmask);
- t.tv_sec = DEFAULT_TIMEOUT;
- t.tv_usec = 0;
- i = select(sp->Rfd + 1, &rmask, NULL, NULL, &t);
- if (i < 0) {
- if (errno == EINTR)
- goto Again;
- return false;
- }
- if (i == 0
- || !FD_ISSET(sp->Rfd, &rmask)
- || (sp->Count = read(sp->Rfd, sp->Buffer, sizeof sp->Buffer)) < 0)
- return false;
- if (sp->Count == 0)
- return false;
- sp->bp = sp->Buffer;
- }
-
- /* Process next character. */
- sp->Count--;
- c = *sp->bp++;
- if (c == '\n')
- break;
- if (p < end)
- *p++ = c;
- }
-
- /* If last two characters are \r\n, kill the \r as well as the \n. */
- if (p > start && p < end && p[-1] == '\r')
- p--;
- *p = '\0';
- return true;
-}
-
-
-/*
-** Send a line to the server, adding \r\n. Don't need to do dot-escape
-** since it's only for sending DATA to local site, and the data we got from
-** the remote site already is escaped.
-*/
-static bool
-SITEwrite(SITE *sp, const char *p, int i)
-{
- SITEvec[0].iov_base = (char *) p;
- SITEvec[0].iov_len = i;
- return xwritev(sp->Wfd, SITEvec, 2) >= 0;
-}
-
-
-static SITE *
-SITEconnect(char *host)
-{
- FILE *From;
- FILE *To;
- SITE *sp;
- int i;
-
- /* Connect and identify ourselves. */
- if (host)
- i = NNTPconnect(host, NNTP_PORT, &From, &To, (char *)NULL);
- else {
- host = innconf->server;
- if (host == NULL)
- die("no server specified and server not set in inn.conf");
- i = NNTPlocalopen(&From, &To, (char *)NULL);
- }
- if (i < 0)
- sysdie("cannot connect to %s", host);
-
- if (NNTPsendpassword(host, From, To) < 0)
- sysdie("cannot authenticate to %s", host);
-
- /* Build the structure. */
- sp = xmalloc(sizeof(SITE));
- sp->Name = host;
- sp->Rfd = fileno(From);
- sp->Wfd = fileno(To);
- sp->bp = sp->Buffer;
- sp->Count = 0;
- return sp;
-}
-
-
-/*
-** Send "quit" to a site, and get its reply.
-*/
-static void
-SITEquit(SITE *sp)
-{
- char buff[NNTP_STRLEN];
-
- SITEwrite(sp, "quit", 4);
- SITEread(sp, buff);
-}
-
-
-static bool
-HIShaveit(char *mesgid)
-{
- return HIScheck(History, mesgid);
-}
-
-
-static void
-Usage(const char *p)
-{
- warn("%s", p);
- fprintf(stderr, "Usage: nntpget"
- " [ -d dist -n grps [-f file | -t time -u file]] host\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- char buff[NNTP_STRLEN];
- char mesgid[NNTP_STRLEN];
- char tbuff[SMBUF];
- char *msgidfile = NULL;
- int msgidfd;
- const char *Groups;
- char *distributions;
- char *Since;
- char *path;
- int i;
- struct tm *gt;
- struct stat Sb;
- SITE *Remote;
- SITE *Local = NULL;
- FILE *F;
- bool Offer;
- bool Error;
- bool Verbose = false;
- char *Update;
- char *p;
-
- /* First thing, set up our identity. */
- message_program_name = "nntpget";
-
- /* Set defaults. */
- distributions = NULL;
- Groups = NULL;
- Since = NULL;
- Offer = false;
- Update = NULL;
- if (!innconf_read(NULL))
- exit(1);
-
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "d:f:n:t:ovu:")) != EOF)
- switch (i) {
- default:
- Usage("bad flag");
- /* NOTREACHED */
- case 'd':
- distributions = optarg;
- break;
- case 'u':
- Update = optarg;
- /* FALLTHROUGH */
- case 'f':
- if (Since)
- Usage("only one of -f, -t, or -u may be given");
- if (stat(optarg, &Sb) < 0)
- sysdie("cannot stat %s", optarg);
- gt = gmtime(&Sb.st_mtime);
- /* Y2K: NNTP Spec currently allows only two digit years. */
- snprintf(tbuff, sizeof(tbuff), "%02d%02d%02d %02d%02d%02d GMT",
- gt->tm_year % 100, gt->tm_mon + 1, gt->tm_mday,
- gt->tm_hour, gt->tm_min, gt->tm_sec);
- Since = tbuff;
- break;
- case 'n':
- Groups = optarg;
- break;
- case 'o':
- /* Open the history file. */
- path = concatpath(innconf->pathdb, _PATH_HISTORY);
- History = HISopen(path, innconf->hismethod, HIS_RDONLY);
- if (!History)
- sysdie("cannot open history");
- free(path);
- Offer = true;
- break;
- case 't':
- if (Since)
- Usage("only one of -t or -f may be given");
- Since = optarg;
- break;
- case 'v':
- Verbose = true;
- break;
- }
- ac -= optind;
- av += optind;
- if (ac != 1)
- Usage("no host given");
-
- /* Set up the scatter/gather vectors used by SITEwrite. */
- SITEvec[1].iov_base = SITEv1;
- SITEvec[1].iov_len = strlen(SITEv1);
-
- /* Connect to the remote server. */
- if ((Remote = SITEconnect(av[0])) == NULL)
- sysdie("cannot connect to %s", av[0]);
- if (!SITEwrite(Remote, READER, (int)strlen(READER))
- || !SITEread(Remote, buff))
- sysdie("cannot start reading");
-
- if (Since == NULL) {
- F = stdin;
- if (distributions || Groups)
- Usage("no -d or -n flags allowed when reading stdin");
- }
- else {
- /* Ask the server for a list of what's new. */
- if (Groups == NULL)
- Groups = "*";
- if (distributions)
- snprintf(buff, sizeof(buff), "NEWNEWS %s %s <%s>",
- Groups, Since, distributions);
- else
- snprintf(buff, sizeof(buff), "NEWNEWS %s %s", Groups, Since);
- if (!SITEwrite(Remote, buff, (int)strlen(buff))
- || !SITEread(Remote, buff))
- sysdie("cannot start list");
- if (buff[0] != NNTP_CLASS_OK) {
- SITEquit(Remote);
- die("protocol error from %s, got %s", Remote->Name, buff);
- }
-
- /* Create a temporary file. */
- msgidfile = concatpath(innconf->pathtmp, "nntpgetXXXXXX");
- msgidfd = mkstemp(msgidfile);
- if (msgidfd < 0)
- sysdie("cannot create a temporary file");
- F = fopen(msgidfile, "w+");
- if (F == NULL)
- sysdie("cannot open %s", msgidfile);
-
- /* Read and store the Message-ID list. */
- for ( ; ; ) {
- if (!SITEread(Remote, buff)) {
- syswarn("cannot read from %s", Remote->Name);
- fclose(F);
- SITEquit(Remote);
- exit(1);
- }
- if (strcmp(buff, ".") == 0)
- break;
- if (Offer && HIShaveit(buff))
- continue;
- if (fprintf(F, "%s\n", buff) == EOF || ferror(F)) {
- syswarn("cannot write %s", msgidfile);
- fclose(F);
- SITEquit(Remote);
- exit(1);
- }
- }
- if (fflush(F) == EOF) {
- syswarn("cannot flush %s", msgidfile);
- fclose(F);
- SITEquit(Remote);
- exit(1);
- }
- fseeko(F, 0, SEEK_SET);
- }
-
- if (Offer) {
- /* Connect to the local server. */
- if ((Local = SITEconnect((char *)NULL)) == NULL) {
- syswarn("cannot connect to local server");
- fclose(F);
- exit(1);
- }
- }
-
- /* Loop through the list of Message-ID's. */
- while (fgets(mesgid, sizeof mesgid, F) != NULL) {
- STATgot++;
- if ((p = strchr(mesgid, '\n')) != NULL)
- *p = '\0';
-
- if (Offer) {
- /* See if the local server wants it. */
- STAToffered++;
- snprintf(buff, sizeof(buff), "ihave %s", mesgid);
- if (!SITEwrite(Local, buff, (int)strlen(buff))
- || !SITEread(Local, buff)) {
- syswarn("cannot offer %s", mesgid);
- break;
- }
- if (atoi(buff) != NNTP_SENDIT_VAL)
- continue;
- }
-
- /* Try to get the article. */
- snprintf(buff, sizeof(buff), "article %s", mesgid);
- if (!SITEwrite(Remote, buff, (int)strlen(buff))
- || !SITEread(Remote, buff)) {
- syswarn("cannot get %s", mesgid);
- printf("%s\n", mesgid);
- break;
- }
- if (atoi(buff) != NNTP_ARTICLE_FOLLOWS_VAL) {
- if (Offer) {
- SITEwrite(Local, ".", 1);
- if (!SITEread(Local, buff)) {
- syswarn("no reply after %s", mesgid);
- break;
- }
- }
- continue;
- }
-
- if (Verbose)
- notice("%s...", mesgid);
-
- /* Read each line in the article and write it. */
- for (Error = false; ; ) {
- if (!SITEread(Remote, buff)) {
- syswarn("cannot read %s from %s", mesgid, Remote->Name);
- Error = true;
- break;
- }
- if (Offer) {
- if (!SITEwrite(Local, buff, (int)strlen(buff))) {
- syswarn("cannot send %s", mesgid);
- Error = true;
- break;
- }
- }
- else
- printf("%s\n", buff);
- if (strcmp(buff, ".") == 0)
- break;
- }
- if (Error) {
- printf("%s\n", mesgid);
- break;
- }
- STATsent++;
-
- /* How did the local server respond? */
- if (Offer) {
- if (!SITEread(Local, buff)) {
- syswarn("no reply after %s", mesgid);
- printf("%s\n", mesgid);
- break;
- }
- i = atoi(buff);
- if (i == NNTP_TOOKIT_VAL)
- continue;
- if (i == NNTP_RESENDIT_VAL) {
- printf("%s\n", mesgid);
- break;
- }
- syswarn("%s to %s", buff, mesgid);
- STATrejected++;
- }
- }
-
- /* Write rest of the list, close the input. */
- if (!feof(F))
- while (fgets(mesgid, sizeof mesgid, F) != NULL) {
- if ((p = strchr(mesgid, '\n')) != NULL)
- *p = '\0';
- printf("%s\n", mesgid);
- STATgot++;
- }
- fclose(F);
-
- /* Remove our temp file. */
- if (msgidfile && unlink(msgidfile) < 0)
- syswarn("cannot remove %s", msgidfile);
-
- /* All done. */
- SITEquit(Remote);
- if (Offer)
- SITEquit(Local);
-
- /* Update timestamp file? */
- if (Update) {
- if ((F = fopen(Update, "w")) == NULL)
- sysdie("cannot update %s", Update);
- fprintf(F, "got %ld offered %ld sent %ld rejected %ld\n",
- STATgot, STAToffered, STATsent, STATrejected);
- if (ferror(F) || fclose(F) == EOF)
- sysdie("cannot update %s", Update);
- }
-
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 5047 $
-## Send news via NNTP by running several innxmit processes in the background.
-## Usage:
-## nntpsend [-n][-p][-r][-s size][-S][-t timeout][-T limit][host fqdn]...
-## -a Always have innxmit rewrite the batchfile
-## -d debug mode, run innxmits with debug as well
-## -D same as -d except innxmits are not debugged
-## -p Run innxmit with -p to prune batch files
-## -r innxmit, don't requeue on unexpected error code
-## -s size limit the =n file to size bytes
-## -c disable message-ID checking in streaming mode
-## -t timeout innxmit timeout to make connection (def: 180)
-## -T limit innxmit connection transmit time limit (def: forever)
-## -P portnum port number to use
-## -l innxmit, log rejected articles
-## -N innxmit, disable streaming mode
-## -n do not lock for nntpsend, do not sleep between sets
-## -w delay wait delay seconds just before innxmit
-## host fqdn send to host and qualified domain (def: nntpsend.ctl)
-## If no "host fqdn" pairs appear on the command line, then ${CTLFILE}
-## file is read.
-
-PROGNAME=`basename $0`
-LOCK=${LOCKS}/LOCK.${PROGNAME}
-CTLFILE=${PATHETC}/${PROGNAME}.ctl
-LOG=${MOST_LOGS}/${PROGNAME}.log
-
-## Set defaults.
-A_FLAG=
-D_FLAG=
-NO_LOG_FLAG=
-P_FLAG=
-R_FLAG=
-S_FLAG=
-C_FLAG=
-L_FLAG=
-S2_FLAG=
-TRUNC_SIZE=
-T_FLAG=
-TIMELIMIT=
-PP_FLAG=
-NOLOCK=
-W_SECONDS=
-
-## Parse JCL.
-MORETODO=true
-while ${MORETODO} ; do
- case X"$1" in
- X-a)
- A_FLAG="-a"
- ;;
- X-d)
- D_FLAG="-d"
- NO_LOG_FLAG="true"
- ;;
- X-D)
- NO_LOG_FLAG="true"
- ;;
- X-l)
- L_FLAG="-l"
- ;;
- X-p)
- P_FLAG="-p"
- ;;
- X-r)
- R_FLAG="-r"
- ;;
- X-S)
- S_FLAG="-S"
- ;;
- X-N)
- S2_FLAG="-s"
- ;;
- X-c)
- C_FLAG="-c"
- ;;
- X-s)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- s" 1>&2
- exit 1
- fi
- TRUNC_SIZE="$2"
- shift
- ;;
- X-s*)
- TRUNC_SIZE="`echo $1 | ${SED} -e 's/-s//'`"
- ;;
- X-t)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- t" 1>&2
- exit 1
- fi
- T_FLAG="-t$2"
- shift
- ;;
- X-t*)
- T_FLAG="$1"
- ;;
- X-P)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- P" 1>&2
- exit 1
- fi
- PP_FLAG="-P$2"
- shift
- ;;
- X-P*)
- PP_FLAG="$1"
- ;;
- X-T)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- T" 1>&2
- exit 1
- fi
- TIMELIMIT="-T$2"
- shift
- ;;
- X-T*)
- TIMELIMIT="$1"
- ;;
- X-n)
- NOLOCK=true
- ;;
- X-w)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- w" 1>&2
- exit 1
- fi
- W_SECONDS="$2"
- shift
- ;;
- X--)
- shift
- MORETODO=false
- ;;
- X-*)
- echo "${PROGNAME}: illegal option -- $1" 1>&2
- exit 1
- ;;
- *)
- MORETODO=false
- ;;
- esac
- ${MORETODO} && shift
-done
-
-## grab the lock if not -n
-NNTPLOCK=${LOCKS}/LOCK.nntpsend
-if [ -z "${NOLOCK}" ]; then
- shlock -p $$ -f ${NNTPLOCK} || {
- # nothing to do
- exit 0
- }
-fi
-
-## Parse arguments; host/fqdn pairs.
-INPUT=${TMPDIR}/nntpsend$$
-cp /dev/null ${INPUT}
-while [ $# -gt 0 ]; do
- if [ $# -lt 2 ]; then
- echo "${PROGNAME}: Bad host/fqdn pair" 1>&2
- rm -f ${NNTPLOCK}
- exit 1
- fi
- echo "$1 $2" >>${INPUT}
- shift
- shift
-done
-
-## If nothing specified on the command line, read the control file.
-if [ ! -s ${INPUT} ] ; then
- if [ ! -r ${CTLFILE} ]; then
- echo "${PROGNAME}: cannot read ${CTLFILE}"
- rm -f ${NNTPLOCK}
- exit 1
- fi
- ${SED} -e 's/#.*//' -e '/^$/d' -e 's/::\([^:]*\)$/:max:\1/' \
- -e 's/:/ /g' <${CTLFILE} >${INPUT}
-fi
-
-## Go to where the action is.
-if [ ! -d ${BATCH} ]; then
- echo "${PROGNAME}: directory ${BATCH} not found" 1>&2
- rm -f ${NNTPLOCK}
- exit 1
-fi
-cd ${BATCH}
-
-## Set up log file.
-umask 002
-if [ -z "${NO_LOG_FLAG}" ]; then
- test ! -f ${LOG} && touch ${LOG}
- chmod 0660 ${LOG}
- exec >>${LOG} 2>&1
-fi
-PARENTPID=$$
-echo "${PROGNAME}: [${PARENTPID}] start"
-
-## Set up environment.
-export BATCH PROGNAME PARENTPID INNFLAGS
-
-## Loop over all sites.
-cat ${INPUT} | while read SITE HOST SIZE_ARG FLAGS; do
- ## Parse the input parameters.
- if [ -z "${SITE}" -o -z "${HOST}" ] ; then
- echo "Ignoring bad line: ${SITE} ${HOST} ${SIZE_ARG} ${FLAGS}" 1>&2
- continue
- fi
-
- ## give up early if we cannot even lock it
- ##
- ## NOTE: This lock is not nntpsend's lock but rather the
- ## lock that the parent shell of innxmit will use.
- ## Later on the child will take the lock from us.
- ##
- LOCK="${LOCKS}/LOCK.${SITE}"
- shlock -p $$ -f "${LOCK}" || continue
-
- ## Compute the specific parameters for this site.
- test "${SIZE_ARG}" = "max" && SIZE_ARG=
- if [ -n "${TRUNC_SIZE}" ]; then
- SIZE_ARG="${TRUNC_SIZE}"
- fi
- ## Parse the SIZE_ARG for either MaxSize-TruncSize or TruncSize
- case "${SIZE_ARG}" in
- *-*) MAXSIZE="`echo ${SIZE_ARG} | ${SED} -e 's/-.*//'`";
- SIZE="`echo ${SIZE_ARG} | ${SED} -e 's/^.*-//'`" ;;
- *) MAXSIZE="${SIZE_ARG}";
- SIZE="${SIZE_ARG}" ;;
- esac
- D_PARAM=
- R_PARAM=
- S_PARAM=
- S2_PARAM=
- C_PARAM=
- PP_PARAM=
- L_PARAM=
- TIMEOUT_PARAM=
- TIMELIMIT_PARAM=
- if [ -z "${FLAGS}" ]; then
- MORETODO=false
- else
- MORETODO=true
- set -- ${FLAGS}
- fi
- while ${MORETODO} ; do
- case "X$1" in
- X-a)
- ;;
- X-d)
- D_PARAM="-d"
- ;;
- X-c)
- C_PARAM="-c"
- ;;
- X-p)
- P_PARAM="-p"
- ;;
- X-r)
- R_PARAM="-r"
- ;;
- X-S)
- S_PARAM="-S"
- ;;
- X-s)
- S2_PARAM="-s"
- ;;
- X-l)
- L_PARAM="-l"
- ;;
- X-t)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- t" 1>&2
- rm -f "${NNTPLOCK}" "${LOCK}"
- exit 1
- fi
- TIMEOUT_PARAM="-t$2"
- shift
- ;;
- X-t*)
- TIMEOUT_PARAM="$1"
- ;;
- X-P)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- P" 1>&2
- rm -f "${NNTPLOCK}" "${LOCK}"
- exit 1
- fi
- PP_PARAM="-P$2"
- shift
- ;;
- X-P*)
- PP_PARAM="$1"
- ;;
- X-T)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- T" 1>&2
- rm -f "${NNTPLOCK}" "${LOCK}"
- exit 1
- fi
- TIMELIMIT_PARAM="-T$2"
- shift
- ;;
- X-T*)
- TIMELIMIT_PARAM="$1"
- ;;
- X-w)
- if [ -z "$2" ] ; then
- echo "${PROGNAME}: option requires an argument -- w" 1>&2
- rm -f "${NNTPLOCK}" "${LOCK}"
- exit 1
- fi
- W_SECONDS="$2"
- shift
- ;;
- *)
- MORETODO=false
- ;;
- esac
- ${MORETODO} && shift
- done
- if [ -z "${SIZE}" -o -n "${A_FLAG}" ]; then
- # rewrite batch file if we do not have a size limit
- INNFLAGS="-a"
- else
- # we have a size limit, let shrinkfile rewrite the file
- INNFLAGS=
- fi
- if [ -n "${D_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${D_FLAG}"
- else
- test -n "${D_PARAM}" && INNFLAGS="${INNFLAGS} ${D_PARAM}"
- fi
- if [ -n "${C_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${C_FLAG}"
- else
- test -n "${C_PARAM}" && INNFLAGS="${INNFLAGS} ${C_PARAM}"
- fi
- if [ -n "${P_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${P_FLAG}"
- else
- test -n "${P_PARAM}" && INNFLAGS="${INNFLAGS} ${P_PARAM}"
- fi
- if [ -n "${L_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${L_FLAG}"
- else
- test -n "${L_PARAM}" && INNFLAGS="${INNFLAGS} ${L_PARAM}"
- fi
- if [ -n "${R_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${R_FLAG}"
- else
- test -n "${R_PARAM}" && INNFLAGS="${INNFLAGS} ${R_PARAM}"
- fi
- if [ -n "${S_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${S_FLAG}"
- else
- test -n "${S_PARAM}" && INNFLAGS="${INNFLAGS} ${S_PARAM}"
- fi
- if [ -n "${S2_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${S2_FLAG}"
- else
- test -n "${S2_PARAM}" && INNFLAGS="${INNFLAGS} ${S2_PARAM}"
- fi
- if [ -n "${T_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${T_FLAG}"
- else
- test -n "${TIMEOUT_PARAM}" && INNFLAGS="${INNFLAGS} ${TIMEOUT_PARAM}"
- fi
- if [ -n "${PP_FLAG}" ]; then
- INNFLAGS="${INNFLAGS} ${PP_FLAG}"
- else
- test -n "${PP_PARAM}" && INNFLAGS="${INNFLAGS} ${PP_PARAM}"
- fi
- if [ -n "${TIMELIMIT}" ]; then
- INNFLAGS="${INNFLAGS} ${TIMELIMIT}"
- else
- test -n "${TIMELIMIT_PARAM}" \
- && INNFLAGS="${INNFLAGS} ${TIMELIMIT_PARAM}"
- fi
-
- ## Flush the buffers for the site now, rather than in the child.
- ## This helps pace the number of ctlinnd commands because the
- ## nntpsend process does not proceed until the site flush has
- ## been completed.
- ##
- # carry old unfinished work over to this task
- BATCHFILE="${SITE}=n"
- if [ -f "${SITE}.work" ] ; then
- cat ${SITE}.work >>"${BATCHFILE}"
- rm -f "${SITE}.work"
- fi
- # form BATCHFILE to hold the work for this site
- if [ -f "${SITE}" ]; then
- mv "${SITE}" "${SITE}.work"
- if ctlinnd -s -t30 flush ${SITE} ; then
- cat ${SITE}.work >>"${BATCHFILE}"
- rm -f ${SITE}.work
- else
- # flush failed, continue if we have any batchfile to work on
- echo "${PROGNAME}: bad flush for ${HOST} via ${SITE}"
- if [ -f "${BATCHFILE}" ]; then
- echo "${PROGNAME}: trying ${HOST} via ${SITE} anyway"
- else
- echo "${PROGNAME}: skipping ${HOST} via ${SITE}"
- rm -f ${LOCK}
- continue
- fi
- fi
- else
- # nothing to work on, so flush and move on
- ctlinnd -s -t30 flush ${SITE}
- echo "${PROGNAME}: file ${BATCH}/${SITE} for ${HOST} not found"
- if [ -f "${BATCHFILE}" ]; then
- echo "${PROGNAME}: trying ${HOST} via ${SITE} anyway"
- else
- echo "${PROGNAME}: skipping ${HOST} via ${SITE}"
- rm -f ${LOCK}
- continue
- fi
- fi
-
- ## Start sending this site in the background.
- export MAXSIZE SITE HOST PROGNAME PARENTPID SIZE TMPDIR LOCK BATCHFILE W_SECONDS
- sh -c '
- # grab the lock from the parent
- #
- # This is safe because only the parent will have locked
- # the site. We break the lock and reclaim it.
- rm -f ${LOCK}
- trap "rm -f ${LOCK} ; exit 1" 1 2 3 15
- shlock -p $$ -f ${LOCK} || {
- WHY="`cat ${LOCK}`"
- echo "${PROGNAME}: [${PARENTPID}:$$] ${SITE} locked ${WHY} `date`"
- exit
- }
- # process the site BATCHFILE
- if [ -f "${BATCHFILE}" ]; then
- test -n "${SIZE}" && shrinkfile -m${MAXSIZE} -s${SIZE} -v ${BATCHFILE}
- if [ -s ${BATCHFILE} ] ; then
- if [ -n "${W_SECONDS}" ] ; then
- echo "${PROGNAME}: [${PARENTPID}:$$] sleeping ${W_SECONDS} seconds before ${SITE}"
- sleep "${W_SECONDS}"
- fi
- echo "${PROGNAME}: [${PARENTPID}:$$] begin ${SITE} `date`"
- echo "${PROGNAME}: [${PARENTPID}:$$] innxmit ${INNFLAGS} ${HOST} ..."
- eval innxmit ${INNFLAGS} ${HOST} ${BATCH}/${BATCHFILE}
- echo "${PROGNAME}: [${PARENTPID}:$$] end ${SITE} `date`"
- else
- rm -f ${BATCHFILE}
- fi
- else
- echo "${PROGNAME}: file ${BATCH}/${BATCHFILE} for ${HOST} not found"
- fi
- rm -f ${LOCK}
- ' &
-done
-
-## release the nntpsend lock and clean up before we wait on child processes
-if [ -z "${NOLOCK}" ]; then
- rm -f ${NNTPLOCK}
-fi
-rm -f ${INPUT}
-
-## wait for child processes to finish
-wait
-
-## all done
-echo "${PROGNAME}: [${PARENTPID}] stop"
-exit 0
+++ /dev/null
-/* $Id: overchan.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Parse input to add to news overview database.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <errno.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-
-unsigned int NumArts;
-unsigned int StartTime;
-unsigned int TotOvTime;
-
-/*
- * Timer function (lifted from innd/timer.c).
- * This function is designed to report the number of milliseconds since
- * the first invocation. I wanted better resolution than time(), and
- * something easier to work with than gettimeofday()'s struct timeval's.
- */
-
-static unsigned gettime(void)
-{
- static int init = 0;
- static struct timeval start_tv;
- struct timeval tv;
-
- if (! init) {
- gettimeofday(&start_tv, NULL);
- init++;
- }
- gettimeofday(&tv, NULL);
- return((tv.tv_sec - start_tv.tv_sec) * 1000 + (tv.tv_usec - start_tv.tv_usec) / 1000);
-}
-
-/*
-** Process the input. Data comes from innd in the form:
-** @token@ data
-*/
-
-#define TEXT_TOKEN_LEN (2*sizeof(TOKEN)+2)
-static void ProcessIncoming(QIOSTATE *qp)
-{
- char *Data;
- char *p;
- TOKEN token;
- unsigned int starttime, endtime;
- time_t Time, Expires;
-
- for ( ; ; ) {
- /* Read the first line of data. */
- if ((Data = QIOread(qp)) == NULL) {
- if (QIOtoolong(qp)) {
- warn("line too long");
- continue;
- }
- break;
- }
-
- if (Data[0] != '@' || strlen(Data) < TEXT_TOKEN_LEN+2
- || Data[TEXT_TOKEN_LEN-1] != '@' || Data[TEXT_TOKEN_LEN] != ' ') {
- warn("malformed token %s", Data);
- continue;
- }
- token = TextToToken(Data);
- Data += TEXT_TOKEN_LEN+1; /* skip over token and space */
- for (p = Data; !ISWHITE(*p) ;p++) ;
- *p++ = '\0';
- Time = (time_t)atol(Data);
- for (Data = p; !ISWHITE(*p) ;p++) ;
- *p++ = '\0';
- Expires = (time_t)atol(Data);
- Data = p;
- NumArts++;
- starttime = gettime();
- if (OVadd(token, Data, strlen(Data), Time, Expires) == OVADDFAILED)
- syswarn("cannot write overview %s", Data);
- endtime = gettime();
- TotOvTime += endtime - starttime;
- }
- QIOclose(qp);
-}
-
-
-int main(int ac, char *av[])
-{
- QIOSTATE *qp;
- unsigned int now;
-
- /* First thing, set up our identity. */
- message_program_name = "overchan";
-
- /* Log warnings and fatal errors to syslog unless we were given command
- line arguments, since we're probably running under innd. */
- if (ac == 0) {
- openlog("overchan", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_handlers_warn(1, message_log_syslog_err);
- message_handlers_die(1, message_log_syslog_err);
- message_handlers_notice(1, message_log_syslog_notice);
- }
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- umask(NEWSUMASK);
- if (innconf->enableoverview && !innconf->useoverchan)
- warn("overchan is running while innd is creating overview data (you"
- " can ignore this message if you are running makehistory -F)");
-
- ac -= 1;
- av += 1;
-
- if (!OVopen(OV_WRITE))
- die("cannot open overview");
-
- StartTime = gettime();
- if (ac == 0)
- ProcessIncoming(QIOfdopen(STDIN_FILENO));
- else {
- for ( ; *av; av++)
- if (strcmp(*av, "-") == 0)
- ProcessIncoming(QIOfdopen(STDIN_FILENO));
- else if ((qp = QIOopen(*av)) == NULL)
- syswarn("cannot open %s", *av);
- else
- ProcessIncoming(qp);
- }
- OVclose();
- now = gettime();
- notice("timings %u arts %u of %u ms", NumArts, TotOvTime, now - StartTime);
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 2674 $
-## SH script to send IHAVE batches out.
-
-PROGNAME=`basename $0`
-LOG=${MOST_LOGS}/${PROGNAME}.log
-
-## How many Message-ID's per message.
-PERMESSAGE=1000
-
-## Go to where the action is, start logging
-cd $BATCH
-umask 002
-DEBUG=""
-if [ "X$1" = X-d ] ; then
- DEBUG="-d"
- shift
-else
- test ! -f ${LOG} && touch ${LOG}
- chmod 0660 ${LOG}
- exec >>${LOG} 2>&1
-fi
-
-echo "${PROGNAME}: [$$] begin `date`"
-
-## List of sitename:hostname pairs to send to
-if [ -n "$1" ] ; then
- LIST="$*"
-else
- echo "${PROGNAME}: [$$] no sites specified" >&2
- exit 1
-fi
-
-## Do the work...
-for SITE in ${LIST}; do
- case $SITE in
- *:*)
- HOST=`expr $SITE : '.*:\(.*\)'`
- SITE=`expr $SITE : '\(.*\):.*'`
- ;;
- *)
- HOST=$SITE
- ;;
- esac
- BATCHFILE=${SITE}.ihave.batch
- LOCK=${LOCKS}/LOCK.${SITE}.ihave
- trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
- shlock -p $$ -f ${LOCK} || {
- echo "${PROGNAME}: [$$] ${SITE}.ihave locked by `cat ${LOCK}`"
- continue
- }
-
- ## See if any data is ready for host.
- if [ -f ${SITE}.ihave.work ] ; then
- cat ${SITE}.ihave.work >>${BATCHFILE}
- rm -f ${SITE}.ihave.work
- fi
- if [ ! -f ${SITE}.ihave -o ! -s ${SITE}.ihave ] ; then
- if [ ! -f ${BATCHFILE} -o ! -s ${BATCHFILE} ] ; then
- rm -f ${LOCK}
- continue
- fi
- fi
- mv ${SITE}.ihave ${SITE}.ihave.work
- ctlinnd -s -t30 flush ${SITE}.ihave || continue
- cat ${SITE}.ihave.work >>${BATCHFILE}
- rm -f ${SITE}.ihave.work
- if [ ! -s ${BATCHFILE} ] ; then
- echo "${PROGNAME}: [$$] no articles for ${SITE}.ihave"
- rm -f ${BATCHFILE}
- continue
- fi
-
- echo "${PROGNAME}: [$$] begin ${SITE}.ihave"
-
- ## Write out the batchfile as a control message, in clumps.
- export SITE PERMESSAGE BATCHFILE
- while test -s ${BATCHFILE} ; do
- (
- echo Newsgroups: to.${SITE}
- echo Control: ihave `innconfval pathhost`
- echo Subject: cmsg ihave `innconfval pathhost`
- echo ''
- ${SED} -e ${PERMESSAGE}q <${BATCHFILE}
- ) | ${INEWS} -h
- ${SED} -e "1,${PERMESSAGE}d" <${BATCHFILE} >${BATCHFILE}.tmp
- mv ${BATCHFILE}.tmp ${BATCHFILE}
- done
- echo "${PROGNAME}: [$$] end ${SITE}.ihave"
- rm -f ${LOCK}
-done
-
-echo "${PROGNAME}: [$$] end `date`"
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 4115 $
-## SH script to send NNTP news out.
-
-PROGNAME=`basename $0`
-LOG=${MOST_LOGS}/${PROGNAME}.log
-
-## Go to where the action is, start logging
-cd $BATCH
-umask 002
-DEBUG=""
-if [ "X$1" = X-d ] ; then
- DEBUG="-d"
- shift
-else
- test ! -f ${LOG} && touch ${LOG}
- chmod 0660 ${LOG}
- exec >>${LOG} 2>&1
-fi
-
-echo "${PROGNAME}: [$$] begin `date`"
-
-## List of sitename:hostname pairs to send to
-if [ -n "$1" ] ; then
- LIST="$*"
-else
- echo "${PROGNAME}: [$$] no sites specified" >&2
- exit 1
-fi
-
-## Do the work...
-for SITE in ${LIST}; do
- case $SITE in
- *:*)
- HOST=`expr $SITE : '.*:\(.*\)'`
- SITE=`expr $SITE : '\(.*\):.*'`
- ;;
- *)
- HOST=$SITE
- ;;
- esac
- case $HOST in
- *@*)
- PORT=`expr $HOST : '\(.*\)@.*'`
- HOST=`expr $HOST : '.*@\(.*\)'`
- ;;
- *)
- PORT=119
- ;;
- esac
- BATCHFILE=${SITE}.nntp
- LOCK=${LOCKS}/LOCK.${SITE}
- trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
- shlock -p $$ -f ${LOCK} || {
- echo "${PROGNAME}: [$$] ${SITE} locked by `cat ${LOCK}`"
- continue
- }
-
- ## See if any data is ready for host.
- if [ -f ${SITE}.work ] ; then
- cat ${SITE}.work >>${BATCHFILE}
- rm -f ${SITE}.work
- fi
- if [ ! -f ${SITE} -o ! -s ${SITE} ] ; then
- if [ ! -f ${BATCHFILE} -o ! -s ${BATCHFILE} ] ; then
- rm -f ${LOCK}
- continue
- fi
- fi
- mv ${SITE} ${SITE}.work
- ctlinnd -s -t30 flush ${SITE} || continue
- cat ${SITE}.work >>${BATCHFILE}
- rm -f ${SITE}.work
- if [ ! -s ${BATCHFILE} ] ; then
- echo "${PROGNAME}: [$$] no articles for ${SITE}"
- rm -f ${BATCHFILE}
- continue
- fi
-
- echo "${PROGNAME}: [$$] begin ${SITE}"
- time innxmit ${DEBUG} -P ${PORT} ${HOST} ${BATCH}/${BATCHFILE}
- echo "${PROGNAME}: [$$] end ${SITE}"
- rm -f ${LOCK}
-done
-
-echo "${PROGNAME}: [$$] end `date`"
+++ /dev/null
-#!/usr/bin/perl -w
-# fixscript will replace this line with code to load innshellvars
-
-##############################################################################
-# send-uucp.pl create news batches from the outgoing files
-#
-# Author: Edvard Tuinder <ed@elm.net>
-#
-# Copyright (C) 1994 Edvard Tuinder - ELM Consultancy B.V.
-# Copyright (C) 1995-1997 Miquel van Smoorenburg - Cistron Internet Services
-#
-# Copyright (C) 2003 Marco d'Itri <md@linux.it>
-# Nearly rewritten. Added syslog support, real errors checking and more.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the Free
-# Software Foundation; either version 2 of the License, or (at your option)
-# any later version.
-##############################################################################
-
-use strict;
-use Sys::Syslog;
-
-# for compatibility with earlier versions of INN
-$inn::pathetc ||= '/etc/news';
-$inn::syslog_facility ||= 'news';
-$inn::uux ||= 'uux';
-
-# some default values
-my $MAXSIZE = 500000;
-my $MAXJOBS = 200;
-
-my %UNBATCHER = (
- compress => 'cunbatch',
- bzip2 => 'bunbatch',
- gzip => 'gunbatch',
-);
-
-my $UUX_FLAGS = '- -z -r -gd';
-my $BATCHER_FLAGS = '';
-
-##############################################################################
-my $config_file = $inn::pathetc . '/send-uucp.cf';
-my $lockfile = $inn::locks . '/LOCK.send-uucp';
-
-openlog('send-uucp', 'pid', $inn::syslog_facility);
-
-my @sitelist;
-if (@ARGV) {
- foreach my $site (@ARGV) {
- my @cfg = read_cf($config_file, $site);
- if (not @cfg) {
- logmsg("site $site not found in the configuration", 'err');
- next;
- }
- push @sitelist, @cfg;
- }
-} else {
- @sitelist = read_cf($config_file, undef);
-}
-
-if (not @sitelist) {
- logmsg('nothing to do', 'debug');
- exit 0;
-}
-
-chdir $inn::batch or logdie("Can't access $inn::batch: $!", 'crit');
-
-shlock($lockfile);
-
-run_site($_) foreach @sitelist;
-unlink $lockfile;
-exit 0;
-
-# lint food
-$inn::compress.$inn::locks.$inn::syslog_facility.$inn::have_uustat = 0 if 0;
-
-##############################################################################
-sub read_cf {
- my ($conf_file, $site_wanted) = @_;
-
- my $hour = (localtime time)[2];
-
- my @sites;
- open(CF, $conf_file) or logdie("cannot open $conf_file: $!", 'crit');
- while (<CF>) {
- chop;
- s/\s*\#.*$//;
- next if /^$/;
-
- my ($sitespec, $compress, $size, $time) = split(/\s+/);
- next if not $sitespec;
-
- my ($site, $host, $funnel) = split(/:/, $sitespec);
- $host = $site if not $host;
- $funnel = $site if not $funnel;
-
- $compress =~ s/_/ /g if $compress;
-
- if ($site_wanted) {
- if ($site eq $site_wanted) {
- push @sites, [$site, $host, $funnel, $compress, $size];
- last;
- }
- next;
- }
-
- if ($time) {
- foreach my $time (split(/,/, $time)) {
- next if $time != $hour;
- push @sites, [$site, $host, $funnel, $compress, $size];
- }
- } else {
- push @sites, [$site, $host, $funnel, $compress, $size];
- }
- }
- close CF;
- return @sites;
-}
-
-##############################################################################
-# count number of jobs in the UUCP queue for a given site
-sub count_jobs {
- my ($site) = @_;
-
- return 0 if not $inn::have_uustat;
- open(JOBS, "uustat -s $site 2> /dev/null |") or logdie("cannot fork: $!");
- my $count = grep(/ Executing rnews /, <JOBS>);
- close JOBS; # ignore errors, uustat may fail
- return $count;
-}
-
-# select the rnews label appropriate for the compressor program used
-sub unbatcher {
- my ($compressor) = @_;
-
- $compressor =~ s%.*/%%; # Do not keep the complete path.
- $compressor =~ s% .*%%; # Do not keep the optional parameters.
- return $UNBATCHER{$compressor} || 'cunbatch';
-}
-
-##############################################################################
-# batch articles for one site
-sub run_site {
- my ($cfg) = @_;
- my ($site, $host, $funnel, $compress, $size) = @$cfg;
-
- logmsg("checking site $site", 'debug');
- my $maxjobs = '';
- if ($MAXJOBS) {
- my $jobs = count_jobs($site);
- if ($jobs >= $MAXJOBS) {
- logmsg("too many jobs queued for $site");
- return;
- }
- $maxjobs = '-N ' . ($MAXJOBS - $jobs);
- }
-
- $compress ||= $inn::compress;
- $size ||= $MAXSIZE;
-
- # if exists a .work temp file left by a previous invocation, rename
- # it to .work.tmp, we'll append it to the current batch file once it
- # has been renamed and flushed.
- if (-f "$site.work") {
- rename("$site.work", "$site.work.tmp")
- or logdie("cannot rename $site.work: $!", 'crit');
- }
-
- if (not -f $site and not -f "$site.work.tmp") {
- logmsg("no batch file for site $site", 'err');
- return;
- }
-
- rename($site, "$site.work") or logdie("cannot rename $site: $!", 'crit');
- logmsg("Flushing $funnel for site $site", 'debug');
- ctlinnd('-t120', 'flush', $funnel);
-
- # append the old .work temp file to the current batch file if needed
- if (-f "$site.work.tmp") {
- my $err = '';
- open(OUT, ">>$site.work")
- or logdie("cannot open $site.work: $!", 'crit');
- open(IN, "$site.work.tmp")
- or logdie("cannot open $site.work.tmp: $!", 'crit');
- print OUT while <IN>;
- close IN;
- close OUT or logdie("cannot close $site.work: $!");;
- unlink "$site.work.tmp"
- or logmsg("cannot delete $site.work.tmp: $!", 'err');
- }
-
- if (not -s "$site.work") {
- logmsg("no articles for $site", 'debug');
- unlink "$site.work" or logmsg("cannot delete $site.work: $!", 'err');
- } else {
- if ($compress eq 'none') {
- system "batcher -b $size $maxjobs $BATCHER_FLAGS "
- . "-p\"$inn::uux $UUX_FLAGS %s!rnews\" $host $site.work";
- } else {
- system "batcher -b $size $maxjobs $BATCHER_FLAGS "
- . "-p\"{ echo '#! " . unbatcher($compress)
- . "' ; exec $compress; } | "
- . "$inn::uux $UUX_FLAGS %s!rnews\" $host $site.work";
- }
- logmsg("batched articles for $site", 'debug');
- }
-}
-
-##############################################################################
-sub logmsg {
- my ($msg, $lvl) = @_;
-
- syslog($lvl || 'notice', '%s', $msg);
-}
-
-sub logdie {
- my ($msg, $lvl) = @_;
-
- logmsg($msg, $lvl || 'err');
- unlink $lockfile;
- exit 1;
-}
-
-sub ctlinnd {
- my ($cmd, @args) = @_;
-
- my $st = system("$inn::newsbin/ctlinnd", '-s', $cmd, @args);
- logdie('Cannot run ctlinnd: ' . $!) if $st == -1;
- logdie('ctlinnd returned status ' . ($st & 255)) if $st > 0;
-}
-
-sub shlock {
- my $lockfile = shift;
-
- my $locktry = 0;
- while ($locktry < 60) {
- if (system("$inn::newsbin/shlock", '-p', $$, '-f', $lockfile) == 0) {
- return 1;
- }
- $locktry++;
- sleep 2;
- }
-
- my $lockreason;
- if (open(LOCKFILE, $lockfile)) {
- $lockreason = 'held by ' . (<LOCKFILE> || '?');
- close LOCKFILE;
- } else {
- $lockreason = $!;
- }
- logdie("Cannot get lock $lockfile: $lockreason");
- return undef;
-}
-
-__END__
-
-=head1 NAME
-
-send-uucp - Send Usenet articles via UUCP
-
-=head1 SYNOPSIS
-
-B<send-uucp> [I<SITE> ...]
-
-=head1 DESCRIPTION
-
-The B<send-uucp> program processes batch files written by innd(8) to send
-Usenet articles to UUCP sites. It reads a configuration file to control how
-it behaves with various sites. Normally, it's run periodically out of cron
-to put together batches and send them to remote UUCP sites.
-
-=head1 OPTIONS
-
-Any arguments provided to the program are interpreted as a list of sites
-specfied in F<send-uucp.cf> for which batches should be generated. If no
-arguments are supplied then batches will be generated for all sites listed
-in that configuration file.
-
-=head1 CONFIGURATION
-
-The sites to which articles are to be sent must be configured in the
-configuration file F<send-uucp.cf>. Each site is specified with a line of
-the form:
-
- site[:host[:funnel]] [compressor [maxsize [batchtime]]]
-
-=over 4
-
-=item I<site>
-
-The news site name being configured. This must match a site name
-from newsfeeds(5).
-
-=item I<host>
-
-The UUCP host name to which batches should be sent for this site.
-If omitted, the news site name will be used as the UUCP host name.
-
-=item I<funnel>
-
-In the case of a site configured as a funnel, B<send-uucp> needs to flush
-the channel (or exploder) being used as the target of the funnel instead of
-flushing the site. This is the way to tell B<send-uucp> the name of the
-channel or exploder to flush for this site. If not specified, default to
-flushing the site.
-
-=item I<compressor>
-
-The compression method to use for batches. This should be one of compress,
-gzip or none. Arguments for the compression command may be specified by
-using C<_> instead of spaces. For example, C<gzip_-9>. The default value is
-C<compress>.
-
-=item I<maxsize>
-
-The maximum size of a single batch before compression. The default value is
-500,000 bytes.
-
-=item I<batchtime>
-
-A comma separated list of hours during which batches should be generated for
-a given site. When B<send-uucp> runs, a site will only be processed if the
-current hour matches one of the hours in I<batchtime>. The default is no
-limitation on when to generate batches.
-
-=back
-
-Fields are seperated by spaces and only the site name needs to be specified,
-with defaults being used for unspecified values. If the first character on
-a line is a C<#> then the rest of the line is ignored.
-
-=head1 EXAMPLE
-
-Here is an example send-uucp.cf configuration file:
-
- zoetermeer gzip 1048576 5,18,22
- hoofddorp gzip 1048576 5,18,22
- pa3ebv gzip 1048576 5,18,22
- drinkel gzip 1048576 5,6,18,20,22,0,2
- manhole compress 1048576 5,18,22
- owl compress 1048576
- able
- pern::MYFUNNEL!
-
-This defines eight UUCP sites. The first four use gzip compression and the
-last three use compress. The first six use a batch size of 1MB, and the
-last site (able) uses the default of 500,000 bytes. The zoetermeer,
-hoofddorp, pa3ebv, and manhole sites will only have batches generated for
-them during the hours of 05:00, 18:00, and 22:00, and the drinkel site will
-only have batches generated during those hours and 20:00, 00:00, and 02:00.
-There are no restrictions on when batches will be generated for owl or able.
-
-The pern site is configured as a funnel into C<MYFUNNEL!>. B<send-uucp> will
-issue C<ctlinnd flush MYFUNNEL!> instead of C<ctlinnd flush pern>.
-
-=head1 FILES
-
-=over 4
-
-=item I<pathetc>/send-uucp.cf
-
-Configuration file specifying a list of sites to be processed.
-
-=back
-
-=head1 NOTES
-
-The usual flags used for a UUCP feed in the I<newsfeeds> file are C<Tf,Wfb>.
-
-=head1 SEE ALSO
-
-innd(8), newsfeeds(5), uucp(8)
-
-=head1 AUTHOR
-
-This program was originally written by Edvard Tuinder <ed@elm.net> and then
-maintained and extended by Miquel van Smoorenburg <miquels@cistron.nl>.
-Marco d'Itri <md@linux.it> cleaned up the code for inclusion in INN. This
-manual page was written by Mark Brown <broonie@sirena.org.uk>.
-
-=cut
+++ /dev/null
-#!/bin/sh
-# fixscript will replace this line with code to load innshellvars
-#
-# Submit path statistics based on ninpaths
-# $Id: sendinpaths.in 5854 2002-11-25 17:53:06Z rra $
-
-# Assuming the ninpaths dump files are in ${MOST_LOGS}/path/inpaths.%d
-
-cd ${MOST_LOGS}/path
-ME=`${NEWSBIN}/innconfval pathhost`
-report=30
-keep=14
-TMP=""
-defaddr="pathsurvey@top1000.org top1000@anthologeek.net"
-
-# Renice to give other processes priority, since this isn't too important.
-renice 20 -p $$ > /dev/null
-
-# Make report from (up to) $report days of dumps
-LOGS=`find . -name 'inpaths.*' ! -size 0 -mtime -$report -print`
-if [ -z "$LOGS" ] ; then
- echo "No data has been collected this month!"
- exit 1
-fi
-
-# for check dumps
-for i in $LOGS
-do
- ninpaths -u $i -r $ME > /dev/null 2>&1
- if test $? -eq 0; then :
- TMP="$TMP -u $i"
- fi
-done
-
-if [ "$1" = "-n" ] ; then
- ninpaths $TMP -r $ME
-else
- ninpaths $TMP -r $ME |\
- $MAILCMD -s "inpaths $ME" ${1:-$defaddr}
- # remove dumps older than $keep days
- find . -name 'inpaths.*' -mtime +$keep -exec rm '{}' \;
-fi
-
-exit 0
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-# $Id: sendxbatches.in 2674 1999-11-15 06:28:29Z rra $
-# By petri@ibr.cs.tu-bs.de with mods by libove@jerry.alf.dec.com
-#
-# Script to send xbatches for a site, wrapped around innxbatch
-# Invocation: sendxbatches <sitename> <hostname> <xbatch file name> ...
-#
-## TODO: - we should check the amount of queued batches for the site,
-## to prevent disk overflow due to unreachable sites.
-
-if [ $# -lt 3 ]
-then
- echo "usage: $0 <sitename> <hostname> <xbatch file name>"
- exit 1
-fi
-
-LOCK=${LOCKS}/LOCK.sendxbatches
-shlock -p $$ -f ${LOCK}
-if [ $? -ne 0 ]
-then
- echo Locked by `cat ${LOCK}`
- exit 1
-fi
-
-trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
-site="$1"
-host="$2"
-shift; shift
-
-ctlinnd -s flush "$site"
-if [ $? -ne 0 ]
-then
- echo "ctlinnd flush $site failed."
- exit 1
-fi
-sleep 5
-$NEWSBIN/innxbatch -D -v "$host" $*
+++ /dev/null
-/* $Id: shlock.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Produce reliable locks for shell scripts, by Peter Honeyman as told
-** to Rich $alz.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-
-
-static bool BinaryLock;
-
-
-/*
-** See if the process named in an existing lock still exists by
-** sending it a null signal.
-*/
-static bool
-ValidLock(char *name, bool JustChecking)
-{
- int fd;
- int i;
- pid_t pid;
- char buff[BUFSIZ];
-
- /* Open the file. */
- if ((fd = open(name, O_RDONLY)) < 0) {
- if (JustChecking)
- return false;
- syswarn("cannot open %s", name);
- return true;
- }
-
- /* Read the PID that is written there. */
- if (BinaryLock) {
- if (read(fd, (char *)&pid, sizeof pid) != sizeof pid) {
- close(fd);
- return false;
- }
- }
- else {
- if ((i = read(fd, buff, sizeof buff - 1)) <= 0) {
- close(fd);
- return false;
- }
- buff[i] = '\0';
- pid = (pid_t) atol(buff);
- }
- close(fd);
- if (pid <= 0)
- return false;
-
- /* Send the signal. */
- if (kill(pid, 0) < 0 && errno == ESRCH)
- return false;
-
- /* Either the kill worked, or we're optimistic about the error code. */
- return true;
-}
-
-
-/*
-** Unlink a file, print a message on error, and exit.
-*/
-static void
-UnlinkAndExit(char *name, int x)
-{
- if (unlink(name) < 0)
- syswarn("cannot unlink %s", name);
- exit(x);
-}
-
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: shlock [-u|-b] -f file -p pid\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- int i;
- char *p;
- int fd;
- char tmp[BUFSIZ];
- char buff[BUFSIZ];
- char *name;
- pid_t pid;
- bool ok;
- bool JustChecking;
-
- /* Establish our identity. */
- message_program_name = "shlock";
-
- /* Set defaults. */
- pid = 0;
- name = NULL;
- JustChecking = false;
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "bcup:f:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'b':
- case 'u':
- BinaryLock = true;
- break;
- case 'c':
- JustChecking = true;
- break;
- case 'p':
- pid = (pid_t) atol(optarg);
- break;
- case 'f':
- name = optarg;
- break;
- }
- ac -= optind;
- av += optind;
- if (ac || pid == 0 || name == NULL)
- Usage();
-
- /* Create the temp file in the same directory as the destination. */
- if ((p = strrchr(name, '/')) != NULL) {
- *p = '\0';
- snprintf(tmp, sizeof(tmp), "%s/shlock%ld", name, (long)getpid());
- *p = '/';
- }
- else
- snprintf(tmp, sizeof(tmp), "shlock%ld", (long)getpid());
-
- /* Loop until we can open the file. */
- while ((fd = open(tmp, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
- switch (errno) {
- default:
- /* Unknown error -- give up. */
- sysdie("cannot open %s", tmp);
- case EEXIST:
- /* If we can remove the old temporary, retry the open. */
- if (unlink(tmp) < 0)
- sysdie("cannot unlink %s", tmp);
- break;
- }
-
- /* Write the process ID. */
- if (BinaryLock)
- ok = write(fd, &pid, sizeof pid) == sizeof pid;
- else {
- snprintf(buff, sizeof(buff), "%ld\n", (long) pid);
- i = strlen(buff);
- ok = write(fd, buff, i) == i;
- }
- if (!ok) {
- syswarn("cannot write PID to %s", tmp);
- close(fd);
- UnlinkAndExit(tmp, 1);
- }
-
- close(fd);
-
- /* Handle the "-c" flag. */
- if (JustChecking) {
- if (ValidLock(name, true))
- UnlinkAndExit(tmp, 1);
- UnlinkAndExit(tmp, 0);
- }
-
- /* Try to link the temporary to the lockfile. */
- while (link(tmp, name) < 0)
- switch (errno) {
- default:
- /* Unknown error -- give up. */
- syswarn("cannot link %s to %s", tmp, name);
- UnlinkAndExit(tmp, 1);
- /* NOTREACHED */
- case EEXIST:
- /* File exists; if lock is valid, give up. */
- if (ValidLock(name, false))
- UnlinkAndExit(tmp, 1);
- if (unlink(name) < 0) {
- syswarn("cannot unlink %s", name);
- UnlinkAndExit(tmp, 1);
- }
- }
-
- UnlinkAndExit(tmp, 0);
- /* NOTREACHED */
- return 1;
-}
+++ /dev/null
-/* $Id: shrinkfile.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Shrink files on line boundaries.
-**
-** Written by Landon Curt Noll <chongo@toad.com>, and placed in the
-** public domain. Rewritten for INN by Rich Salz.
-**
-** Usage:
-** shrinkfile [-n] [-s size [-m maxsize]] [-v] file...
-** -n No writes, exit 0 if any file is too large, 1 otherwise
-** -s size Truncation size (0 default); suffix may be k, m,
-** or g to scale. Must not be larger than 2^31 - 1.
-** -m maxsize Maximum size allowed before truncation. If maxsize
-** <= size, then it is reset to size. Default == size.
-** -v Print status line.
-**
-** Files will be shrunk an end of line boundary. In no case will the
-** file be longer than size bytes if it was longer than maxsize bytes.
-** If the first line is longer than the absolute value of size, the file
-** will be truncated to zero length.
-**
-** The -n flag may be used to determine of any file is too large. No
-** files will be altered in this mode.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#define MAX_SIZE 0x7fffffffUL
-
-
-/*
-** Open a safe unique temporary file that will go away when closed.
-*/
-static FILE *
-OpenTemp(void)
-{
- FILE *F;
- char *filename;
- int fd;
-
- filename = concatpath(innconf->pathtmp, "shrinkXXXXXX");
- fd = mkstemp(filename);
- if (fd < 0)
- sysdie("cannot create temporary file");
- F = fdopen(fd, "w+");
- if (F == NULL)
- sysdie("cannot fdopen %s", filename);
- unlink(filename);
- free(filename);
- return F;
-}
-
-
-/*
-** Does file end with \n? Assume it does on I/O error, to avoid doing I/O.
-*/
-static int
-EndsWithNewline(FILE *F)
-{
- int c;
-
- if (fseeko(F, 1, SEEK_END) < 0) {
- syswarn("cannot seek to end of file");
- return true;
- }
-
- /* return the actual character or EOF */
- if ((c = fgetc(F)) == EOF) {
- if (ferror(F))
- syswarn("cannot read last byte");
- return true;
- }
- return c == '\n';
-}
-
-
-/*
-** Add a newline to location of a file.
-*/
-static bool
-AppendNewline(char *name)
-{
- FILE *F;
-
- if ((F = xfopena(name)) == NULL) {
- syswarn("cannot add newline");
- return false;
- }
-
- if (fputc('\n', F) == EOF
- || fflush(F) == EOF
- || ferror(F)
- || fclose(F) == EOF) {
- syswarn("cannot add newline");
- return false;
- }
-
- return true;
-}
-
-/*
-** Just check if it is too big
-*/
-static bool
-TooBig(FILE *F, off_t maxsize)
-{
- struct stat Sb;
-
- /* Get the file's size. */
- if (fstat((int)fileno(F), &Sb) < 0) {
- syswarn("cannot fstat");
- return false;
- }
-
- /* return true if too large */
- return (maxsize > Sb.st_size ? false : true);
-}
-
-/*
-** This routine does all the work.
-*/
-static bool
-Process(FILE *F, char *name, off_t size, off_t maxsize, bool *Changedp)
-{
- off_t len;
- FILE *tmp;
- struct stat Sb;
- char buff[BUFSIZ + 1];
- int c;
- size_t i;
- bool err;
-
- /* Get the file's size. */
- if (fstat((int)fileno(F), &Sb) < 0) {
- syswarn("cannot fstat");
- return false;
- }
- len = Sb.st_size;
-
- /* Process a zero size request. */
- if (size == 0 && len > maxsize) {
- if (len > 0) {
- fclose(F);
- if ((F = fopen(name, "w")) == NULL) {
- syswarn("cannot overwrite");
- return false;
- }
- fclose(F);
- *Changedp = true;
- }
- return true;
- }
-
- /* See if already small enough. */
- if (len <= maxsize) {
- /* Newline already present? */
- if (EndsWithNewline(F)) {
- fclose(F);
- return true;
- }
-
- /* No newline, add it if it fits. */
- if (len < size - 1) {
- fclose(F);
- *Changedp = true;
- return AppendNewline(name);
- }
- }
- else if (!EndsWithNewline(F)) {
- if (!AppendNewline(name)) {
- fclose(F);
- return false;
- }
- }
-
- /* We now have a file that ends with a newline that is bigger than
- * we want. Starting from {size} bytes from end, move forward
- * until we get a newline. */
- if (fseeko(F, -size, SEEK_END) < 0) {
- syswarn("cannot fseeko");
- fclose(F);
- return false;
- }
-
- while ((c = getc(F)) != '\n')
- if (c == EOF) {
- syswarn("cannot read");
- fclose(F);
- return false;
- }
-
- /* Copy rest of file to temp. */
- tmp = OpenTemp();
- err = false;
- while ((i = fread(buff, 1, sizeof buff, F)) > 0)
- if (fwrite(buff, 1, i, tmp) != i) {
- err = true;
- break;
- }
- if (err) {
- syswarn("cannot copy to temporary file");
- fclose(F);
- fclose(tmp);
- return false;
- }
-
- /* Now copy temp back to original file. */
- fclose(F);
- if ((F = fopen(name, "w")) == NULL) {
- syswarn("cannot overwrite file");
- fclose(tmp);
- return false;
- }
- fseeko(tmp, 0, SEEK_SET);
-
- while ((i = fread(buff, 1, sizeof buff, tmp)) > 0)
- if (fwrite(buff, 1, i, F) != i) {
- err = true;
- break;
- }
- if (err) {
- syswarn("cannot overwrite file");
- fclose(F);
- fclose(tmp);
- return false;
- }
-
- fclose(F);
- fclose(tmp);
- *Changedp = true;
- return true;
-}
-
-
-/*
-** Convert size argument to numeric value. Return -1 on error.
-*/
-static off_t
-ParseSize(char *p)
-{
- off_t scale;
- unsigned long str_num;
- char *q;
-
- /* Skip leading spaces */
- while (ISWHITE(*p))
- p++;
- if (*p == '\0')
- return -1;
-
- /* determine the scaling factor */
- q = &p[strlen(p) - 1];
- switch (*q) {
- default:
- return -1;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- scale = 1;
- break;
- case 'k': case 'K':
- scale = 1024;
- *q = '\0';
- break;
- case 'm': case 'M':
- scale = 1024 * 1024;
- *q = '\0';
- break;
- case 'g': case 'G':
- scale = 1024 * 1024 * 1024;
- *q = '\0';
- break;
- }
-
- /* Convert string to number. */
- if (sscanf(p, "%lud", &str_num) != 1)
- return -1;
- if (str_num > MAX_SIZE / scale)
- die("size is too big");
-
- return scale * str_num;
-}
-
-
-/*
-** Print usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr,
- "Usage: shrinkfile [-n] [ -m maxsize ] [-s size] [-v] file...");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- bool Changed;
- bool Verbose;
- bool no_op;
- FILE *F;
- char *p;
- int i;
- off_t size = 0;
- off_t maxsize = 0;
-
- /* First thing, set up our identity. */
- message_program_name = "shrinkfile";
-
- /* Set defaults. */
- Verbose = false;
- no_op = false;
- umask(NEWSUMASK);
-
- if (!innconf_read(NULL))
- exit(1);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "m:s:vn")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'n':
- no_op = true;
- break;
- case 'm':
- if ((maxsize = ParseSize(optarg)) < 0)
- Usage();
- break;
- case 's':
- if ((size = ParseSize(optarg)) < 0)
- Usage();
- break;
- case 'v':
- Verbose = true;
- break;
- }
- if (maxsize < size) {
- maxsize = size;
- }
- ac -= optind;
- av += optind;
- if (ac == 0)
- Usage();
-
- while ((p = *av++) != NULL) {
- if ((F = fopen(p, "r")) == NULL) {
- syswarn("cannot open %s", p);
- continue;
- }
-
- /* -n (no_op) or normal processing */
- if (no_op) {
-
- /* check if too big and exit zero if it is */
- if (TooBig(F, maxsize)) {
- if (Verbose)
- notice("%s is too large", p);
- exit(0);
- /* NOTREACHED */
- }
-
- /* no -n, do some real work */
- } else {
- Changed = false;
- if (!Process(F, p, size, maxsize, &Changed))
- syswarn("cannot shrink %s", p);
- else if (Verbose && Changed)
- notice("shrunk %s", p);
- }
- }
- if (no_op && Verbose) {
- notice("did not find a file that was too large");
- }
-
- /* if -n, then exit non-zero to indicate no file too big */
- exit(no_op ? 1 : 0);
- /* NOTREACHED */
-}
+++ /dev/null
-## $Id: Makefile 6299 2003-04-20 19:04:14Z vinocur $
-##
-## There are no installation rules or other top-level rules for this
-## directory as it's not properly part of INN. Installation should be
-## done by the user by hand for those files that they're interested in.
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS)
-
-ALL = archivegz backlogstat backupfeed cleannewsgroups delayer \
- findreadgroups makeexpctl makestorconf mlockfile newsresp \
- pullart reset-cnfs respool showtoken stathist thdexpire \
- tunefeed
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-clean clobber distclean:
- rm -f *.o $(ALL)
- rm -rf .libs
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Compilation rules.
-
-LINK = $(LIBLD) $(LDFLAGS) -o $@
-FIX = $(FIXSCRIPT)
-
-STORELIBS = $(LIBSTORAGE) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
-
-expirectl: expirectl.o ; $(LINK) expirectl.o
-mlockfile: mlockfile.o ; $(LINK) mlockfile.o
-newsresp: newsresp.o ; $(LINK) newsresp.o $(LIBS)
-pullart: pullart.o ; $(LINK) pullart.o $(LIBINN)
-reset-cnfs: reset-cnfs.o ; $(LINK) reset-cnfs.o
-respool: respool.o ; $(LINK) respool.o $(STORELIBS)
-
-archivegz: archivegz.in $(FIX) ; $(FIX) -i archivegz.in
-backlogstat: backlogstat.in $(FIX) ; $(FIX) backlogstat.in
-backupfeed: backupfeed.in $(FIX) ; $(FIX) -i backupfeed.in
-cleannewsgroups: cleannewsgroups.in $(FIX) ; $(FIX) cleannewsgroups.in
-delayer: delayer.in $(FIX) ; $(FIX) -i delayer.in
-findreadgroups: findreadgroups.in $(FIX) ; $(FIX) findreadgroups.in
-makeexpctl: makeexpctl.in $(FIX) ; $(FIX) makeexpctl.in
-makestorconf: makestorconf.in $(FIX) ; $(FIX) makestorconf.in
-showtoken: showtoken.in $(FIX) ; $(FIX) -i showtoken.in
-stathist: stathist.in $(FIX) ; $(FIX) -i stathist.in
-thdexpire: thdexpire.in $(FIX) ; $(FIX) thdexpire.in
-tunefeed: tunefeed.in $(FIX) ; $(FIX) -i tunefeed.in
+++ /dev/null
-This directory contains unsupported contributions to INN. Most of these
-programs are of interest to a limited set of sites, require some manual
-modifications to make work, and/or are separately maintained independent
-of INN. Programs in here may or may not have been tested on the latest
-version of INN, so keep that in mind when trying them out. The INN
-developers may not be able to answer bug reports for these utilities; it's
-best to send them to the original author.
-
-Volunteers who would like to take particularly useful applications in this
-directory and make them suitable for inclusion in INN proper are heartily
-encouraged, but discuss this on inn-workers@isc.org. Sometimes there's a
-reason why this hasn't already been done or something specific that's
-needed before they can be included.
-
-Type "make <program>" to build any of the following programs and then copy
-the binary to somewhere on your PATH to use it. For details on what each
-program does, see below, as well as the comments at the beginning of each
-file (if any).
-
-In addition to these files, also see the contrib section of the INN FTP
-site at <ftp://ftp.isc.org/isc/inn/contrib/> for more software designed
-to work with INN.
-
- -------------------------
-
-archivegz
-
- A compressing version of archive, writing out .gz files instead of
- plain text files. May not work with the storage API without some
- changes to use sm.
-
-backlogstat
-
- Prints informations about the current state of innfeed's backlog, if
- any.
-
-backupfeed
-
- Another version of suck or pullnews that downloads posts from a remote
- news server and offers them to the local news server.
-
-cleannewsgroups
-
- Performs various cleanups on the newsgroups file.
-
-count_overview.pl
-
- Counts the groups in a bunch of Xref records.
-
-delayer
-
- Sits in a data stream and delays it by some constant period of time.
- Mostly useful for delaying innfeed feeds to allow cancels a chance to
- remove articles before innfeed sends them to your peers. See the
- beginning of the file for an example of how to use it.
-
-expirectl
-
- Automatically builds expire.ctl based on current available disk space
- and a template, adjusting the expiration times of groups based on a
- weight and the available space. Uses a template expire.ctl.ctl file;
- see the end of expirectl.c for a sample.
-
-findreadgroups
-
- Scans the news log files and generates a file giving readership counts
- by newsgroup. Used by makeexpctl and makestorconf.
-
-fixhist
-
- Performs various cleanups and sanity checks on the history database.
-
-innconfcheck
-
- Merges your inn.conf settings with the inn.conf man page to make it
- easier to be sure that your settings match what you want. Edit this
- script to add the correct paths to the man page; see the comments at
- the beginning of this script.
-
-makeexpctl
-
- Generates an expire.ctl based on what newsgroups are actually read.
- Uses data generated by findreadgroups. This script will require
- editing before being usable for your server.
-
-makestorconf
-
- Generates a storage.conf file putting frequently read newsgroups into
- timecaf rather than CNFS. Uses data gefnerated by findreadgroups.
- This script will require editing before being usable for your server.
-
-mkbuf
-
- Creates a CNFS cycbuff; see the comments at the beginning of
- this script.
-
-mlockfile
-
- Locks files given on the command line into memory using mlock (only
- tested on Solaris). Useful primarily for locking the history files
- (history.hash and history.index) into memory on a system with
- sufficient memory to speed history lookups in innd. This seems to
- help some systems quite a lot and others not at all.
-
-newsresp
-
- Opens an NNTP channel to a server and takes a peek at various response
- times. Can check the round-trip time and the history lookup time.
- See the comments at the beginning of the source for more details.
-
-pullart
-
- Attempts to pull news articles out of CNFS cycbuffs. Useful for
- emergency recoveries.
-
-reset-cnfs
-
- Clears a CNFS cycbuff; see the comments at the beginning of
- this script.
-
-respool
-
- Takes a list of tokens on stdin and respools them, by retrieving the
- article, storing it again, and then calling SMcancel on the previous
- instance of the article. Note that after running this program, you'd
- need to rebuild the history and overview, since it doesn't update
- either.
-
-showtoken
-
- Decodes storage API tokens.
-
-stathist
-
- Parses and summarizes the log files created by the history profiling
- code.
-
-thdexpire
-
- A dynamic expire daemon for timehash and timecaf spools. It should
- be started along with innd and periodically looks if news spool space
- is getting tight, and then frees space by removing articles until
- enough is free. It is an adjunct to (not a replacement for) INN's
- expire program.
-
-tunefeed
-
- Given two active files, attempts to produce a good set of wildmat
- patterns for newsfeeds to minimize the number of rejects. For full
- documentation, run "perldoc tunefeed".
+++ /dev/null
-#!/usr/bin/perl
-# Copyright 1999 Stephen M. Benoit, Service Providers of America.
-# See notice at end of this file.
-#
-# Filename: archivegz.pl
-# Author: Stephen M. Benoit (benoits@servicepro.com)
-# Created: Wed Apr 14 13:56:01 1999
-# Version: $Id: archivegz.in 4329 2001-01-14 13:47:52Z rra $
-#
-$RCSID='$Id: archivegz.in 4329 2001-01-14 13:47:52Z rra $ ';
-
-# Specify command line options, and decode the command line.
-
-require 'newgetopt.pl';
-require 'newusage.pl';
-@opts =
- (
- "help|usage;;print this message",
- "version;;print version",
- "a=s;;directory to archive in instead of the default",
- "f;;directory names will be flattened out",
- "i=s;;append one line to the index file for each article (Destination name, Message ID, Subject)",
- "m;; Files are copied by making a link. Not applicable, ignored",
- "r;;Suppress stderr redirection to /var/log/news/errlog",
- "n=s;;the news spool (source) directory (default=/var/spool/news/)",
- "t=i;;timeout that separates batches (default 10 seconds)",
- ";;input",
- # Examples.
- #
- # "OPT;;Option without an argument",
- # "OPT!;;Negatable option without an argument",
- # "VAR=T;;Option with mandatory argumet T = s(tring),i(nteger), or f(loat).
- # "VAR:T;;Option with optional argument.
- # "OPT|AAA|BBB";;AAA and BBB are aliases for OPT",
- # "VAR=T@";;Push option argument onto array @opt_VAR"
- );
-$ignorecase = 0;
-$badopt = !&NGetOpt(&NMkOpts(@opts));
-# $badarg = (@ARGV != 0);
-if ($badarg || $badopt || $opt_help)
- {
- &NUsage($0,0,'',@opts);
- exit ($badopt||$badarg);
- }
-if ($opt_version) {print STDERR "$RCSID\n"; exit 0}
-
-# --------------------------------------------------------------------
-
-# --- constants and defaults ---
-$NEWS_ROOT = "/var/spool/news/";
-$NEWS_ERR = "/var/log/news/errlog";
-$NEWS_ARCHIVE = $NEWS_ROOT . "news.archive/";
-$timeout = 10;
-if ($opt_t)
- { $timeout = $opt_t;}
-if ($timeout<1) {$timeout=1;}
-
-# --------------------------------------------------------------------
-
-sub regexp_escape
- {
- local($data)=@_;
-
- $data =~ s+\\+\\\\+gi; # replace \ with \\
- $data =~ s+\/+\\\/+gi; # replace / with \/
-
- $data =~ s/([\+\*\?\[\]\(\)\{\}\.\|])/\\$1/gi; # replace +*?[](){}.|
-
- return $data;
- }
-
-sub fhbits {
- local(@fhlist) = split(' ',$_[0]);
- local($bits);
- for (@fhlist) {
- vec($bits,fileno($_),1) = 1;
- }
- $bits;
-}
-
-sub timed_getline
- {
- my ($fileh,$timeout)=@_;
- my $filehandle = (ref($fileh)
- ? (ref($fileh) eq 'GLOB'
- || UNIVERSAL::isa($fileh, 'GLOB')
- || UNIVERSAL::isa($fileh, 'IO::Handle'))
- : (ref(\$fileh) eq 'GLOB'));
- local(*FILEH) = *$fileh{FILEHANDLE};
-
- local($rin,$win,$ein);
- local($rout,$wout,$eout);
- $rin = $win = $ein = '';
- $rin = fhbits('FILEH');
- $ein = $rin | $win;
- local($nfound);
- local($offset)=0;
- local($accum)='';
- local($done)=0;
- local($result);
-
- $nfound = select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
-
- if ($nfound>0)
- {
-
- # use sysread() to get characters up to end-of-line (incl.)
- while (!$done)
- {
- $result = sysread(FILEH, $accum, 1, $offset);
- if ($result<=0)
- {
- $done=1;
- return undef;
- }
-
- if (substr($accum,$offset,1) eq "\n")
- {
- $done=1;
- }
- else
- {
- $offset+=$result;
- }
- }
- }
- return $accum;
- }
-
-# --------------------------------------------------------------------
-
-# --- source spool directory ---
-if ($opt_n)
- {
- if ($opt_n !~ /^\//) # absolute path?
- { $opt_n = $NEWS_ROOT . $opt_n; }
- if ($opt_n !~ /\/$/) # must end with /
- { $opt_n .= '/'; }
- $NEWS_ROOT = $opt_n;
- }
-
-# --- archive directory ---
-if ($opt_a)
- {
- if ($opt_a !~ /^\//) # absolute path?
- { $opt_a = $NEWS_ROOT . $opt_a; }
- if ($opt_a !~ /\/$/) # must end with /
- { $opt_a .= '/'; }
- $NEWS_ARCHIVE = $opt_a;
- }
-
-# --- redirect stderr ---
-if (!$opt_r)
- {
- open(SAVEERR, ">&STDERR");
- open(STDERR, ">>$NEWS_ERR") || die "Can't redirect stderr";
- }
-
-# --- get input file opened ---
-if ($infilename=shift(@ARGV))
- {
- if ($infilename !~ /^\//) # absolute filename?
- {
- $infilename = $NEWS_ROOT . $infilename;
- }
-
- }
-else
- {
- $infilename="-";
- }
-open(INFILE,"<$infilename");
-
-$done=0;
-while (!$done)
- {
- %sourcefile=();
- %destfile=();
- %destname=();
-
-
- # --- loop over each line in infile ---
- # comments start with '#', ignore blank lines, each line is a filename
- while ($srcfile = &timed_getline(INFILE,$timeout))
- {
- if ($srcfile =~ /\#/) {$srcfile = $`;}
- if ($srcfile =~ /^\s*/) {$srcfile = $';}
- if ($srcfile =~ /\s*$/) {$srcfile = $`;}
- if ($srcfile) # if a filename survived all that...
- {
- if ($srcfile !~ /^\//) # absolute filename?
- {
- $srcfile = $NEWS_ROOT . $srcfile;
- }
- # $srcfile is now a valid, absolute filename
- # split filename into news directory, newsgroup and article number
- $artnum=-1;
- $remaining=$srcfile;
- if ($remaining =~ /\/(\d*)$/) # remove / and article number
- { $artnum = $1; $remaining=$`;}
- $regex = ®exp_escape($NEWS_ROOT);
- if ($remaining =~ /^$regex/) # split off news dir
- { $newsdir = $&; $grpdir = $';}
- else
- { $newsdir = ''; $grpdir = $remaining; } # ... otherwise, grp = dir
- $newsgrp = $grpdir;
- $newsgrp =~ s/\//\./g; # replace slash (/) with dot (.)
- if ($opt_f)
- {
- $grpdir = "$newsgrp.gz";
- }
- else
- { $grpdir .= "/archive.gz"; }
- $destfile = $NEWS_ARCHIVE . $grpdir;
-
- # print STDERR "$srcfile --> $newsgrp --> $destfile\n";
- if ($sourcefile{$newsgrp}) {$sourcefile{$newsgrp} .= " ";}
- $sourcefile{$newsgrp} .= $srcfile;
- $destfile{$newsgrp} = $destfile;
- $destname{$newsgrp} = $grpdir;
- }
- }
-
- # --- is there anything to do at this time? ---
- if (%destfile)
- {
-
- # --- open INDEX ---
- if ($opt_i)
- {
- # make sure directory exists
- if ($opt_i =~ /\/[^\/]*$/)
- {
- $dirbase=$`;
- system("mkdir -p $dirbase");
- }
- open(INDEX,">>$opt_i");
- }
-
- # --- make sure that archive file can be written (make parent dirs) ---
- if ($destfile{$group} =~ /\/[^\/]*$/)
- {
- $dirbase=$`;
- system("mkdir -p $dirbase");
- }
-
- # --- process each article ---
- foreach $group (keys(%destfile))
- {
- # --- gzip the concatenated document, appending archive file ---
- open(GZIP, "|gzip -c >> $destfile{$group}") || die "Can't open gzip";
-
- # --- concatenate the articles, keeping header info if needed ---
- @accum_headers=();
- foreach $srcfile (split(/\s+/, $sourcefile{$group}))
- {
- # print STDERR "reading $srcfile...\n";
- $this_doc='';
- open(DOC, "<$srcfile");
- while ($line=<DOC>)
- {
- $this_doc .= $line;
- }
- close(DOC);
- print GZIP $this_doc;
- if ($opt_i)
- {
- # --- get header information and store it in index
- $subject=''; $mesageid=''; $destname='';
- if ($this_doc =~ /Subject:\s*(.*)/)
- { $subject = $1; }
- if ($subject =~ /^\s*/) {$subject = $';}
- if ($subject =~ /\s*$/) {$subject = $`;}
- if ($this_doc =~ /Message-ID:\s*(.*)/)
- {$messageid = $1; }
- if ($messageid =~ /^\s*/) {$messageid = $';}
- if ($messageid =~ /\s*$/) {$messageid = $`;}
-
- print INDEX "$destname{$group} $messageid $subject\n";
- }
- }
-
- close(GZIP);
- }
-
- # --- close index file ---
- if ($opt_i)
- {
- close(INDEX);
- }
- }
-
- if (!defined($srcfile)) # file was closed
- {
- $done=1;
- last; # "break"
- }
-
- }
-
-# --- restore stderr ---
-if (!$opt_r)
- {
- close(STDERR);
- open(STDERR,">>&SAVEERR");
- }
-
-# --- close input file ---
-close(INFILE);
-
-
-__END__
-# Local Variables:
-# mode: perl
-# End:
-
-# Copyright 1999 Stephen M. Benoit, Service Providers of America (SPA).
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose without fee 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 SPA not be used in advertising or
-# publicity pertaining to distribution of the software without specific,
-# written prior permission. SPA makes no representations about the
-# suitability of this software for any purpose. It is provided "as is"
-# without express or implied warranty.
-#
-# SPA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
-# SPA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
-# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+++ /dev/null
-This directory contains sample authorization programs for use with the
-'authinfo generic' command in nnrpd.
-
-The first program in here is from Doug Needham I have successfully
-tested this program when connecting to nnrpd by hand, but I've not
-taken the time to figure out how to get my newsreader to use
-'authinfo generic'. There is no Makefile here and no serious
-testing of it, so it's not integrated. If you have success using
-it and care to share what you've done. Please drop me a note
-(<inn@isc.org>). Thanks.
-
-
----------------------------------------------------------------------------
-
-Replied: Fri, 26 Jul 1996 19:29:17 +0200
-Replied: Douglas Wade Needham <dneedham@dneedham.inhouse.compuserve.com>
-Received: by gw.home.vix.com id UAA05867; Thu, 25 Jul 1996 20:45:27 -0700 (PDT)
-Received: (from dneedham@localhost) by dneedham.inhouse.compuserve.com (8.7.4/8.6.9) id XAA21103; Thu, 25 Jul 1996 23:45:25 -0400 (EDT)
-From: Douglas Wade Needham <dneedham@dneedham.inhouse.compuserve.com>
-Message-Id: <199607260345.XAA21103@dneedham.inhouse.compuserve.com>
-Subject: A sample program for authinfo generic (for inn 1.5)
-To: inn-workers@vix.com (INN Gurus/Workers)
-Date: Thu, 25 Jul 1996 23:45:25 -0400 (EDT)
-Cc: inn@isc.org, brister@vix.com (James A. Brister)
-X-Mailer: ELM [version 2.4 PL25]
-MIME-Version: 1.0
-Content-Type: multipart/mixed; boundary=%#%record%#%
-Status: U
-
---%#%record%#%
-Content-Type: text/plain; charset=US-ASCII
-Content-Transfer-Encoding: 7bit
-Content-Length: 1894
-
-Hi folks...
-
-Finally started to get some time to clear some things from my todo list...Here
-is a sample program which can be used by "authinfo generic" to validate a user
-against the password file on the news host. While not a great example, it does
-demonstrate how you can write an authentication program. All I ask is that
-credit be given.
-
-A couple of notes that I have found out about these programs for those of you
-who may be interested in writing your own...
-
-1) These programs have stdin and stdout connected all the way back to the
- reader, so they can carry on a dialog in whatever fashion they want to
- with the user's news reader. This can include passing Kerberos tickets,
- encrypted or hashed passwords, or doing a challenge-response type session
- for authenticating the user rather than passing the password in clear-text
- across the network.
-
-2) Regardless of the outcome, the authentication program must send NNRPD a
- record such as is found in nnrp.access by writing it to stderr.
-
-3) Successful authentication is indicated by a zero exit status, and
- unsuccessful authentication is indicated by a non-zero exit status.
-
-4) Need I say it (again)...these programs can be a security hole unless care is
- taken to avoid SUID programs and those that transmit/recieve passwords in
- the clear (especially those that use login passwords). We should give some
- thought to doing a similiar program for Kerberos authentication (what sort
- of instance should we use???) and other authentication methods such as
- Compuserve's Distributed Authentication (guess I should do this one once the
- standard is finialized with the IETF 8) ).
-
-Also, a question for the list as a whole... what readers easily support
-authinfo generic (including running a program at the reader's end to do things
-like challenge-response)???
-
-Well...here it is...enjoy 8)...
-
-- doug
-
-#### See auth_pass.c #####
+++ /dev/null
-/*
- * auth_pass.c ( $Revision: 6141 $ )
- *
- * Abstract:
- *
- * This module is the complete source for a sample "authinfo generic"
- * program. This program takes a user's login name and password
- * (supplied either as arguments or as responses to prompts) and
- * validates them against the contents of the password database.
- *
- * If the user properly authenticates themselves, a nnrp.auth style
- * record indicating the user's authenticated login and permitting
- * reading and posting to all groups is output on stderr (for reading by
- * nnrpd) and the program exits with a 0 status. If the user fails to
- * authenticate, then a record with the attempted login name and no
- * access is output on stderr and a non-zero exit status is returned.
- *
- * Exit statuses:
- * 0 Successfully authenticated.
- * 1 getpeername() failed, returned a bad address family, or
- * gethostbyaddr() failed.
- * 2 Entry not found in password file.
- * 3 No permission to read passwords, or password field is '*'.
- * 4 Bad password match.
- *
- * Environment:
- * Run by nnrpd with stdin/stdout connected to the reader and stderr
- * connected back to nnrpd. This program will need to be run as suid
- * root on systems where passwords are stored in a file readable only by
- * root.
- *
- * Written 1996 July 6 by Douglas Wade Needham (dneedham@oucsace.cs.ohiou.edu).
- *
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <netdb.h>
-#include <pwd.h>
-
-\f
-main(int argc, char** argv)
-/*+
- * Abstract:
- * Main routine of the program, implementing all prompting, validation,
- * and status returns.
- *
- * Arguments:
- * argc Argument count.
- * argv Null terminated argument vector.
- *
- * Returns:
- * Exits according to program status values.
- *
- * Variables:
- * hp Pointer to host entry.
- * length General integer variable
- * password Password given by user.
- * peername Hostname of the peer.
- * pwd Pointer to entry from passwd file.
- * sin Socket address structure.
- * username User's login name.
- */
-{
- struct hostent * hp;
- int length;
- char password[256];
- char peername[1024];
- struct passwd * pwd;
- struct sockaddr_in sin;
- char username[32];
-
- /*
- * Get the user name and password if needed.
- */
- if (argc<2) {
- fprintf(stdout, "Username: "); fflush(stdout);
- fgets(username, sizeof(username), stdin);
- } else {
- strlcpy(username, argv[1], sizeof(username));
- }
- if (argc<3) {
- fprintf(stdout, "Password: "); fflush(stdout);
- fgets(password, sizeof(password), stdin);
- } else {
- strlcpy(password, argv[2], sizeof(password));
- }
-
- /*
- * Strip CR's and NL's from the end.
- */
- length = strlen(username)-1;
- while (username[length] == '\r' || username[length] == '\n') {
- username[length--] = '\0';
- }
- length = strlen(password)-1;
- while (password[length] == '\r' || password[length] == '\n') {
- password[length--] = '\0';
- }
-
- /*
- * Get the hostname of the peer.
- */
- length = sizeof(sin);
- if (getpeername(0, (struct sockaddr *)&sin, &length) < 0) {
- if (!isatty(0)) {
- fprintf(stderr, "cant getpeername()::%s:+:!*\n", username);
- exit(1);
- }
- strlcpy(peername, "stdin", sizeof(peername));
- } else if (sin.sin_family != AF_INET) {
- fprintf(stderr, "Bad address family %ld::%s:+:!*\n",
- (long)sin.sin_family, username);
- exit(1);
- } else if ((hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET)) == NULL) {
- strlcpy(peername, inet_ntoa(sin.sin_addr), sizeof(peername));
- } else {
- strlcpy(peername, hp->h_name, sizeof(peername));
- }
-
- /*
- * Get the user name in the passwd file.
- */
- if ((pwd = getpwnam(username)) == NULL) {
-
- /*
- * No entry in the passwd file.
- */
- fprintf(stderr, "%s::%s:+:!*\n", peername, username);
- exit(2);
- }
-
- /*
- * Make sure we managed to read in the password.
- */
- if (strcmp(pwd->pw_passwd, "*")==0) {
-
- /*
- * No permission to read passwords.
- */
- fprintf(stderr, "%s::%s:+:!*\n", peername, username);
- exit(3);
- }
-
- /*
- * Verify the password.
- */
- if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd))!=0) {
-
- /*
- * Password was invalid.
- */
- fprintf(stderr, "%s::%s:+:!*\n", peername, username);
- exit(4);
- }
-
- /*
- * We managed to authenticate the user.
- */
- fprintf(stderr, "%s:RP:%s:+:*\n", peername, username);
- exit(0);
-}
+++ /dev/null
-#!/usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# backlogstat - display backlog to sites
-# based on bklog by bill davidsen <davidsen@tmr.com>
-
-# breaks if backlog-directory in innfeed.conf is not "innfeed"
-my $dir = "$inn::pathspool/innfeed";
-my $Revision = '1.8';
-
-use strict;
-use warnings;
-
-use Getopt::Std;
-use vars qw($opt_H $opt_h $opt_n $opt_t $opt_k $opt_S $opt_d);
-$| = 1;
-
-# option processing
-&getopts('HhntkS:d:') || &Usage;
-&Usage if $opt_h;
-
-# open the directory;
-$dir = $opt_d if $opt_d;
-print "$opt_d\n";
-chdir($dir) or die "Can't cd to $dir";
-opendir(DIR, ".") or die "Can't open dir";
-
-my %nodes;
-while (my $name = readdir(DIR)) {
- # must be a file, correct name, non-zero size
- my $size;
- next unless -f $name;
- next unless ($size = -s $name);
- next unless $name =~ m/.*\.(in|out)put/;
- my $io = $1;
- (my $nodename = $name) =~ s/\..*//;
-
- # check for only some sites wanted
- next if ($opt_S && $nodename !~ /^${opt_S}.*/);
- # here we do the counts if asked
- if ($opt_n) {
- # open the file and count lines
- if (open(IN, "<$name")) {
- if ($name =~ m/.*\.input/) {
- my $offset = <IN> + 0;
- seek(IN, $offset, 0);
- }
- $size = 0;
- for ($size = 0; <IN> ; ++$size) {};
- close IN;
- }
- } else {
- # get the offset on .input files
- if ($name =~ m/.*\.input/ && open(IN, "<$name")) {
- my $offset = <IN> + 0;
- $size -= $offset;
- close IN;
- }
- }
- $nodes{$nodename} = () unless defined $nodes{$nodename};
- $nodes{$nodename}->{$io} = ( $opt_k ? $size / 1024 : $size );
-}
-closedir DIR;
-
-# output the data for each node
-if (my $numnodes = keys %nodes) {
- if ($opt_H) {
- if ($opt_n) {
- print " <---------- posts ----------->\n";
- } else {
- print " <---------- bytes ----------->\n";
- }
- }
- my $ofmt;
- if ($opt_k) {
- print " input(k) output(k) total(k) Feed Name\n" if $opt_H;
- $ofmt = ( $opt_n ? "%10.2f" : "%10.1f" );
- } else {
- print " input output total Feed Name\n" if $opt_H;
- $ofmt = "%10d";
- }
- for my $node (sort keys %nodes) {
- my $hash = $nodes{$node};
- my $size_in = $hash->{in} || 0;
- my $size_out = $hash->{out} || 0;
- my $size_tot = $size_in + $size_out;
- printf "${ofmt} ${ofmt} ${ofmt} %s\n",
- $size_in, $size_out, $size_tot, $node;
- }
-} else {
- print "NO backlog!\n";
-}
-
-exit 0;
-
-sub Usage
-{
- print "\n"
- . "bklog - print innfeed backlog info - v$Revision\n"
- . "\n"
- . "Format:\n"
- . " bklog [ options ]\n"
- . "\n"
- . "Options:\n"
- . " -H output a header at the top of the output\n"
- . " -k scale all numbers in k (1024) units\n"
- . " -n count number of arts, not bytes of backlog filesize\n"
- . " Note: this may be SLOW for large files!\n"
- . " -Sxx Display only site names starting with xx\n"
- . " -d dir Use \"dir\" instead of \$pathspool/innfeed\n"
- . "\n"
- . " -h HELP - this is all, you got it!\n"
- . "\n";
-
- exit 1;
-}
-
-
+++ /dev/null
-#! /usr/bin/perl -w
-#
-# Date: 26 Jun 1999 17:59:00 +0200
-# From: kaih=7Jbfpa7mw-B@khms.westfalen.de (Kai Henningsen)
-# Newsgroups: news.software.nntp
-# Message-ID: <7Jbfpa7mw-B@khms.westfalen.de>
-# Subject: Re: Version of pullnews that support authentication?
-#
-# [...]
-# I'm appending a script I wrote (called backupfeed.pl for some reason). Hmm
-# ... oh, I hereby put that into the public domain. Use as you see fit. If
-# it breaks, you get to keep all the parts.
-#
-# Needs the newer Net::NNTP versions for the MODE READER fix.
-#
-# This thing is both faster and uses far less memory than suck. And it
-# inserts a predictable Path: entry (in case the host you pull from
-# doesn't).
-#
-# It's in production use as a backup to regular feeds, so it specifically
-# fetches only old articles unless you say -p 1 (default is -p 0.6666...).
-
-use strict;
-use Net::NNTP;
-use DB_File;
-use Data::Dumper;
-use Getopt::Std;
-use vars qw($Group $Host $Pos $Rc %Rc $Starttime
- $opt_S $opt_T $opt_d $opt_p $opt_s $opt_t);
-
-my ( @groups, $localhost, $remotehost, $accepted, $rejected, $lockf,
- $history, $acc, $rej, $his, @parms, $from, $to, $art, %err );
-
-$| = 1;
-
-$opt_S = 10; # sleep between groups
-$opt_T = 10000; # max running time
-$opt_d = 0; # debugging
-$opt_p = 2/3; # how many articles to fetch
-$opt_s = 0; # sleep between articles
-$opt_t = 0; # timeout for NNTP connections
-getopts("dt:p:s:S:T:");
-
-die <<USAGE if @ARGV < 2;
-Usage: $0 hostname /groups/wanted [ userid password ]
-Options:
- -d debugging
- -t s NNTP timeout
- -p nn how many articles (0.0 .. 1.0)
- -s s sleep between articles
- -S s sleep between groups
- -T s max running time
-USAGE
-
-my ($GroupsWanted, $userid, $password);
-($Host, $GroupsWanted, $userid, $password) = @ARGV;
-
-chdir("/var/local/lib/backupfeed") or die "chdir: $!";
-$lockf = "/var/lock/lock-backupfeed-$Host";
-system("/usr/lib/news/bin/shlock -p $$ -f $lockf")==0 or exit 0;
-
-open LOG, ">> /var/log/news/backupfeed.$Host" or die "normal log: $!";
-autoflush LOG;
-
-open ERR, ">> /var/log/news/backupfeed.$Host.errors" or die "error log: $!";
-autoflush ERR;
-
-print LOG scalar(localtime), " $0 starting for $Host\n";
-print ERR scalar(localtime), " $0 starting for $Host\n";
-
-open GUP, $GroupsWanted or die "Groups Wanted: $GroupsWanted: $!";
-@groups = <GUP>;
-close GUP;
-
-$Starttime = time;
-
-$localhost = Net::NNTP->new("localhost", "Debug", $opt_d, "Timeout", $opt_t, "Reader", 0) or die "localhost: $!";
-
-$remotehost = Net::NNTP->new($Host, "Debug", $opt_d, "Timeout", $opt_t) or die "remotehost: $!";
-$remotehost->reader;
-&lifecheck($remotehost, $Host);
-$remotehost->authinfo($userid, $password) if ($userid);
-&lifecheck($remotehost, $Host);
-
-tie %Rc, "DB_File", "$Host.bfrc" or die "$Host.bfrc: $!";
-
-$SIG{HUP} = 'IGNORE';
-$SIG{INT} = \&sig;
-$SIG{TERM} = \&sig;
-
-my $restart = $Rc{'=restart='};
-$restart='' unless ($restart);
-
-my @before = grep $_ lt $restart, @groups;
-my @after = grep $_ ge $restart, @groups;
-@groups = ( @after, @before );
-
-($acc, $rej, $his) = (0, 0, 0);
-foreach $Group (@groups) {
- chomp $Group;
- (@parms = $remotehost->group($Group)) or next;
- &lifecheck($remotehost, $Host);
- next if ($#parms < 3);
- $Rc{'=restart='} = $Group;
- print LOG scalar(localtime), " \t<$Group>\n";
- $Rc{$Group} = 0
- if (!defined $Rc{$Group});
- $Rc{$Group} = 0
- if (!$Rc{$Group});
- $from = $parms[1];
- $to = $parms[2];
- $to = $from + ($to - $from) * $opt_p;
- if ($to < $Rc{$Group}) {
- print LOG scalar(localtime), " \t watermark high, reset\n";
- $Rc{$Group} = $from-1;
- }
- $Rc{$Group} = $from-1
- if ($from > $Rc{$Group});
-# print LOG scalar(localtime), " \t\t",$Rc{$Group}+1,"-$to\n";
- $remotehost->nntpstat($Rc{$Group}+1);
-# print LOG scalar(localtime), " \t\t",$remotehost->message,"\n";
- &lifecheck($remotehost, $Host);
- $art = $remotehost->nntpstat;
- &lifecheck($remotehost, $Host);
- $remotehost->message =~ /^(\d+)/;
- $Pos = $1;
- $accepted=0;
- $rejected=0;
- $history=0;
- &offer($art)
- if ($art);
- while ($art = $remotehost->next) {
- &lifecheck($remotehost, $Host);
- $remotehost->message =~ /^(\d+)/;
- $Pos = $1;
- last
- if ($Pos > $to);
- &offer($art);
- }
- &lifecheck($remotehost, $Host);
- print LOG scalar(localtime), " \taccepted=$accepted rejected=$rejected history=$history\n";
- $acc+=$accepted;
- $rej+=$rejected;
- $his+=$history;
- $accepted=0;
- $rejected=0;
- $history=0;
- (tied %Rc)->sync;
- sleep $opt_S if $opt_S;
-}
-
-untie %Rc;
-
-$localhost->quit;
-
-$remotehost->quit;
-
-&end0;
-
-sub offer
-{
- system("echo $Host $Group $Pos > $Host.status");
- if ($localhost->ihave($_[0])) {
- &lifecheck($localhost, 'localhost');
- my $article = $remotehost->article;
- if (ref $article) {
- #open ART1, "> art1";
- #print ART1 @$article;
- #close ART1;
- my $i = 0;
- while ($i <= @$article && !($$article[$i] =~ /^Path:/i)) {
- $i++;
- }
- $$article[$i] =~ s/^(Path:\s*)/$1NNTP-from-$Host!/i;
- #open ART2, "> art2";
- #print ART2 @$article;
- #close ART2;
- #exit;
- $localhost->datasend($article);
- if ($localhost->dataend) {
- $accepted++;
- }
- else {
- $rejected++;
- $err{" local " . $localhost->code . " " . $localhost->message} ++;
- }
- $Rc{$Group} = $Pos;
- (tied %Rc)->sync;
- }
- else {
- $err{" remote " . $remotehost->code . " " . $remotehost->message} ++;
- }
- sleep $opt_s if $opt_s;
- }
- else {
- if ($localhost->status == 4) {
- if ($localhost->code == 435) {
- $err{" local " . $localhost->code . " " . $localhost->message} ++;
- }
- else {
- $err{" local " . $localhost->code . " " . $localhost->message} ++;
- print LOG scalar(localtime), " local ", $localhost->code, " ", $localhost->message, "\n";
- &end;
- }
- }
- &lifecheck($localhost, 'localhost');
- $history++;
- $Rc{$Group} = $Pos;
- }
-}
-
-sub lifecheck
-{
- unless (defined $_[0]->code and $_[0]->code > 0) {
- print LOG scalar(localtime), " Connection to $_[1] dropped\n";
- print ERR scalar(localtime), " Connection to $_[1] dropped\n";
- &end;
- }
- #print "time=",time," starttime=$Starttime\n";
- kill 'TERM', $$ if time-$Starttime > $opt_T;
-}
-
-sub sig
-{
- print LOG scalar(localtime), " Caught sig: ", Data::Dumper::Dumper(@_), "\n";
- print ERR scalar(localtime), " Caught sig: ", Data::Dumper::Dumper(@_), "\n";
- &end;
-}
-
-sub end
-{
- $acc+=$accepted;
- $rej+=$rejected;
- $his+=$history;
- &end0;
-}
-
-sub end0
-{
- print LOG scalar(localtime), " $0 $Host accepted=$acc rejected=$rej history=$his\n";
- foreach my $e (sort keys %err) {
- print ERR $err{$e}, $e, "\n";
- }
- print ERR scalar(localtime), " $0 $Host accepted=$acc rejected=$rej history=$his\n";
- close LOG;
- close ERR;
- unlink $lockf;
- exit 0;
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# This script cleans the newsgroups file:
-# * Groups no longer in the active file are removed.
-# * Duplicate entries are removed. The last of a set of duplicates
-# is the one retained. That way, you could simply append the
-# new/revised entries from a docheckgroups run and then this script
-# will remove the old ones.
-# * Groups with no description are removed.
-# * Groups matching the $remove regexp are removed.
-
-$remove='';
-# $remove='^alt\.';
-
-open ACT, $inn::active or die "Can't open $inn::active: $!\n";
-while(<ACT>) {
- ($group) = split;
- $act{$group} = 1 unless($remove ne "" && $group =~ /$remove/o);
-}
-close ACT;
-
-open NG, $inn::newsgroups or die "Can't open $inn::newsgroups: $!\n";
-while(<NG>) {
- chomp;
- ($group, $desc) = split /\s+/,$_,2;
- next unless(defined $act{$group});
-
- next if(!defined $desc);
- next if($desc =~ /^[?\s]*$/);
- next if($desc =~ /^no desc(ription)?(\.)?$/i);
-
- $hist{$group} = $desc;
-}
-close NG;
-
-open NG, ">$inn::newsgroups.new" or die "Can't open $inn::newsgroups.new for write: $!\n";
-foreach $group (sort keys %act) {
- if(defined $hist{$group}) {
- print NG "$group\t$hist{$group}\n" or die "Can't write: $!\n";
- }
-}
-close NG or die "Can't close: $!\n";
-
-rename "$inn::newsgroups.new", $inn::newsgroups or die "Can't rename $inn::newsgroups.new to $inn::newsgroups: $!\n";
+++ /dev/null
-#!/usr/local/bin/perl
-#
-# count_overview.pl: Count the groups in a bunch of xref records.
-
-while (<>) {
-
-chop;
-@xreflist = split(/\t/); # split apart record
-
-$_ = $xreflist[$#xreflist]; # xref is last.
-
-@xreflist = reverse(split(/ /)); #break part xref line.
-
-pop @xreflist; # get rid xref header
-pop @xreflist;
-
-while ($current = pop @xreflist) {
- ($current) = split(/:/,$current); #get newsgroup name
- $groups{$current}++; #tally
-}
-
-}
-
-# display accumulated groups and counts.
-foreach $current (sort keys %groups) {
- printf "%-50s\t%5d\n", $current, $groups{$current};
-}
+++ /dev/null
-#!/usr/bin/perl
-# -*- perl -*-
-#
-# delay lines for N seconds.
-#
-# primarily meant to be used with INN to generate a delayed feed with innfeed.
-#
-# put it into your newsfeeds file like
-#
-# innfeed-delayed!\
-# :!*\
-# :Tc,Wnm*,S16384:/usr/local/news/bin/delayer 60 \
-# /usr/local/news/bin/startinnfeed -c innfeed-delayed.conf
-#
-#
-#
-# done by christian mock <cm@tahina.priv.at> sometime in july 1998,
-# and put into the public domain.
-#
-$delay = shift || die "usage: $0 delay prog-n-args\n";
-
-$timeout = $delay;
-$eof = 0;
-
-open(OUT, "|" . join(" ", @ARGV)) || die "open |prog-n-args: $!\n";
-
-#select(OUT);
-#$| = 1;
-#select(STDOUT);
-
-$rin = '';
-vec($rin,fileno(STDIN),1) = 1;
-
-while(!$eof || $#queue >= 0) {
- if(!$eof) {
- ($nfound,$timeleft) =
- select($rout=$rin, undef, undef, $timeout);
- } else {
- sleep($timeout);
- }
- $now = time(); $exp = $now + $delay;
-
- if(!$eof && vec($rout,fileno(STDIN),1)) {
- $line = <STDIN>;
- if(!defined $line) { # exit NOW!
- foreach(@queue) {
- s/^[^:]+://g;
- print OUT;
- }
- close(OUT);
- sleep(1);
- exit;
- }
- push(@queue, "$exp:$line");
- }
-
- if($#queue < 0) {
- undef $timeout;
- next;
- }
-
- ($first, $line) = split(/:/, $queue[0], 2);
- while($#queue >= 0 && $first <= $now) {
- print OUT $line;
- shift(@queue);
- ($first, $line) = split(/:/, $queue[0], 2);
- }
- $timeout = $first - $now;
-
-}
-
+++ /dev/null
-/*
- * EXPIRECTL.C
- *
- * expirectl
- *
- * This program uses expire.ctl.ctl as input; please see the end of this
- * file for an example of such a file.
- */
-
-/*
- * Date: Mon, 21 Nov 1994 12:29:52 -0801
- * From: Matthew Dillon <dillon@apollo.west.oic.com>
- * Message-Id: <199411212030.MAA21835@apollo.west.oic.com>
- * To: rsalz@uunet.uu.net
- * Subject: Re: INN is great, bug fix for BSDI
- *
- * [...]
- * Oh, while I'm at it, I also wrote a cute program that builds the
- * expire.ctl file dynamically based on available space. Feel free
- * to include this in the dist (or not) as you please.
- *
- * Basically, the expirectl programs determines the amount of disk blocks
- * and inodes free in the spool and creates a new expire.ctl file based
- * on an expire.ctl.ctl template. The template specifies expiration times
- * as a fraction of nominal. expirectl adjusts the nominal expiration
- * up or down based on available disk space.
- *
- * The idea is to make expiration as hands off as possible. I tested
- * it on a smaller spool and it appeared to work fine. Currently it
- * only works for single-partition news spools tho. The above spool
- * will not really exercise the program for another 14 days or so :-).
- */
-
-
-#include <sys/types.h>
-#include <sys/mount.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define EXPIRE_CTL_DIR "/home/news"
-#define NEWS_SPOOL "/home/news/spool/news/."
-
-#define EXPIRE_DAYS EXPIRE_CTL_DIR "/expire.days"
-#define EXPIRE_CTL EXPIRE_CTL_DIR "/expire.ctl"
-#define EXPIRE_CTL_CTL EXPIRE_CTL_DIR "/expire.ctl.ctl"
-
-void
-main(int ac, char **av)
-{
- struct statfs sfs;
- long minFree = 100 * 1024 * 1024;
- long minIFree = 20 * 1024;
- long expireDays = 2;
- time_t expireIncTime = time(NULL) - 24 * 60 * 60;
- int modified = 0;
- int verbose = 0;
-
- /*
- * options
- */
-
- {
- int i;
-
- for (i = 1; i < ac; ++i) {
- char *ptr = av[i];
-
- if (*ptr == '-') {
- ptr += 2;
- switch(ptr[-1]) {
- case 'v':
- verbose = 1;
- break;
- case 'f':
- modified = 1;
- break;
- case 'n':
- modified = -1;
- break;
- case 'b':
- minFree = strtol(((*ptr) ? ptr : av[++i]), &ptr, 0);
- if (*ptr == 'k')
- minFree *= 1024;
- if (*ptr == 'm')
- minFree *= 1024 * 1024;
- break;
- case 'i':
- minIFree = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
- if (*ptr == 'k')
- minIFree *= 1024;
- if (*ptr == 'm')
- minIFree *= 1024 * 1024;
- break;
- default:
- fprintf(stderr, "bad option: %s\n", ptr - 2);
- exit(1);
- }
- } else {
- fprintf(stderr, "bad option: %s\n", ptr);
- exit(1);
- }
- }
- }
-
- if (statfs("/home/news/spool/news/.", &sfs) != 0) {
- fprintf(stderr, "expirectl: couldn't fsstat /home/news/spool/news/.\n");
- exit(1);
- }
-
- /*
- * Load /home/news/expire.days
- */
-
- {
- FILE *fi;
- char buf[256];
-
- if ((fi = fopen(EXPIRE_DAYS, "r")) != NULL) {
- while (fgets(buf, sizeof(buf), fi) != NULL) {
- if (strncmp(buf, "time", 4) == 0) {
- expireIncTime = strtol(buf + 4, NULL, 0);
- } else if (strncmp(buf, "days", 4) == 0) {
- expireDays = strtol(buf + 4, NULL, 0);
- }
- }
- fclose(fi);
- } else {
- if (modified >= 0)
- modified = 1;
- printf("creating %s\n", EXPIRE_DAYS);
- }
- }
-
- /*
- * print status
- */
-
- if (verbose) {
- printf("spool: %4.2lfM / %3.2lfKinode free\n",
- (double)sfs.f_fsize * (double)sfs.f_bavail / (1024.0 * 1024.0),
- (double)sfs.f_ffree / 1024.0
- );
- printf("decrs: %4.2lfM / %3.2lfKinode\n",
- (double)(minFree) / (double)(1024*1024),
- (double)(minIFree) / (double)(1024)
- );
- printf("incrs: %4.2lfM / %3.2lfKinode\n",
- (double)(minFree * 2) / (double)(1024*1024),
- (double)(minIFree * 2) / (double)(1024)
- );
- }
-
- /*
- * Check limits, update as appropriate
- */
-
- {
- double bytes;
- long inodes;
-
- bytes = (double)sfs.f_fsize * (double)sfs.f_bavail;
- inodes = sfs.f_ffree;
-
- if (bytes < (double)minFree || inodes < minIFree) {
- if (--expireDays <= 0) {
- expireDays = 1;
- expireIncTime = time(NULL) - 24 * 60 * 60;
- }
- if (modified >= 0)
- modified = 1;
- printf("decrement expiration to %d days\n", expireDays);
- } else if (bytes >= (double)minFree * 2.0 && inodes >= minIFree * 2) {
- long dt = (long)(time(NULL) - expireIncTime);
-
- if (dt >= 60 * 60 * 24 || dt < -60) {
- ++expireDays;
- expireIncTime = time(NULL);
- if (modified >= 0)
- modified = 1;
- printf("increment expiration to %d days\n", expireDays);
- } else {
- printf("will increment expiration later\n");
- }
- } else if (verbose) {
- printf("expiration unchanged: %d\n", expireDays);
- }
- }
-
- /*
- * Write EXPIRE_CTL file from EXPIRE_CTL_CTL template
- */
-
- if (modified > 0) {
- FILE *fi;
- FILE *fo;
-
- if ((fi = fopen(EXPIRE_CTL_CTL, "r")) != NULL) {
- if ((fo = fopen(EXPIRE_CTL ".tmp", "w")) != NULL) {
- char sbuf[2048];
- char dbuf[4096];
-
- while (fgets(sbuf, sizeof(sbuf), fi) != NULL) {
- char *base = sbuf;
- char *sptr;
- char *dptr = dbuf;
-
- while ((sptr = strchr(base, '[')) != NULL) {
- double d;
- int m = 0;
-
- bcopy(base, dptr, sptr - base);
- dptr += sptr - base;
- base = sptr;
-
- d = strtod(sptr + 1, &sptr);
- if (*sptr == '/')
- m = strtol(sptr + 1, &sptr, 0);
- if (*sptr == ']') {
- long v = (long)((double)expireDays * d + 0.5);
- if (v < 1)
- v = 1;
- if (v < m)
- v = m;
- sprintf(dptr, "%d", v);
- dptr += strlen(dptr);
- ++sptr;
- }
- base = sptr;
- }
- strcpy(dptr, base);
- fputs(dbuf, fo);
- }
- fclose(fo);
- if (rename(EXPIRE_CTL ".tmp", EXPIRE_CTL) != 0) {
- fprintf(stderr, "rename(%s,%s): %s\n",
- EXPIRE_CTL ".tmp",
- EXPIRE_CTL,
- strerror(errno)
- );
- }
- }
- fclose(fi);
- }
- }
-
- /*
- * Write EXPIRE_DAYS file
- */
-
- if (modified > 0) {
- FILE *fo;
-
- if ((fo = fopen(EXPIRE_DAYS, "w")) != NULL) {
- fprintf(fo, "time 0x%08lx\n", expireIncTime);
- fprintf(fo, "days %d\n", expireDays);
- fclose(fo);
- } else {
- fprintf(stderr, "unable to create %s\n", EXPIRE_DAYS);
- }
- }
- exit(0);
-}
-
-
-/*
-
-# Start of sample expire.ctl.ctl file.
-
-# EXPIRE.CTL.CTL (EXPIRE.CTL GENERATED FROM EXPIRE.CTL.CTL !!!)
-#
-# The expire.ctl file is generated by the expirectl program from the
-# expire.ctl.ctl file. The expirectl program calculates the proper
-# expiration based on the number of free inodes and free bytes available.
-#
-# This file is exactly expire.ctl but with the multiplier [N] replaced by
-# a calculated value, where a multiplier of '1' nominally fills the whole
-# disk.
-#
-# Any field [N] is substituted after being multiplied by the expiration
-# time (in days). A integer minimum can also be specified with a slash,
-# as in [N/minimum].
-#
-# expirectl is normally run just after expire is run. Note that expirectl
-# isn't very useful for the case where you are 'catching up' on news after
-# a long period of downtime UNLESS you use the -p option to expire.
-
-/remember/:[1.2/20]
-
-## Keep for 1-10 days, allow Expires headers to work.
-#
-*:A:1:[1.0]:[6.0]
-*.advocacy:A:1:[0.5]:[2.0]
-alt.binaries.pictures.erotica:A:1:[0.8]:[2.0]
-
-# permanent, semi-permanent
-#
-best.intro:A:never:never:never
-best.announce:A:5:60:120
-best.general:A:never:never:never
-best.bugs:A:never:never:never
-
-# End of sample expire.ctl.ctl file.
-
-*/
+++ /dev/null
-#!/usr/local/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Keep track of which groups are currently being read. Takes logfile input
-# on stdin.
-$readfile="$inn::newsetc/readgroups";
-
-$curtime = time;
-$oldtime = $curtime - 30 * 86400; # 30 days in the past
-
-if (open(RDF, $readfile)) {
- while (<RDF>) {
- chop;
- @foo=split(/ /); # foo[0] should be group, foo[1] lastreadtime
- if ($foo[1] < $oldtime) {
- next; # skip entries that are too old.
- }
- $groups{$foo[0]} = $foo[1];
- }
- close(RDF);
-}
-
-# read input logs.
-while (<>) {
- next unless /nnrpd/;
- next unless / group /;
- chop;
- @foo = split(/ +/);
- # group name is in the 8th field.
- $groups{$foo[7]} = $curtime;
-}
-
-open(WRF, ">$readfile") || die "cannot open $readfile for write.\n";
-foreach $i (keys %groups) {
- print WRF $i, " ", $groups{$i}, "\n";
-}
-
-exit(0);
+++ /dev/null
-#!/usr/local/bin/perl
-#
-# history database sanity checker
-# David Barr <barr@math.psu.edu>
-# version 1.4
-# w/mods from: hucka@eecs.umich.edu
-# Katsuhiro Kondou <kondou@nec.co.jp>
-# version 1.1
-# Throw away history entries with:
-# malformed lines (too long, contain nulls or special characters)
-#
-# INN Usage:
-# ctlinnd throttle 'fixing history'
-# ./fixhist <history >history.n
-# makedbz -s `wc -l <history.n` -f history.n
-# or use instructions from fixhist to avoid the `wc -l <history.n`
-# mv history.n history
-# mv history.n.dir history.dir
-### if TAGGED_HASH is DO or before inn2.0
-# mv history.n.pag history.pag
-### if TAGGED_HASH is DONT
-# mv history.n.hash history.hash
-# mv history.n.index history.index
-### endif
-# ctlinnd reload history x
-# ctlinnd go 'fixing history'
-# any malformed entries will be output to stderr.
-
-
-$MAXKEYLEN=254;
-$count=0;
-
-while (<>) {
- chop;
- ($msgid,$dates,$arts,$xtra) = split('\t');
- if ($xtra) {
- &tossit(); # too many fields
- next;
- }
- if (!($dates) && (($arts) || ($xtra))) {
- &tossit(); # if not date field, then the rest
- next; # should be empty
- }
- if (length($msgid) >= $MAXKEYLEN) {
- &tossit(); # message-id too long
- next;
- }
- if ($msgid !~ /^<[^<> ]*>$/) {
- if ($msgid =~ /^\[[0-9A-F]{32}\]$/) {
- if ($arts ne "") {
- if ($arts =~ /^\@[0-9A-F]{56}\@$/) {
- $arts =~ s/^\@([0-9A-F]{36})([0-9A-F]{20})\@$/\@${1}\@/;
- print "$msgid\t$dates\t$arts\n";
- next;
- }
- if ($arts !~ /^\@[0-9A-F]{36}\@$/) {
- &tossit();
- next;
- }
- }
- } else {
- &tossit(); # malformed msg-ids
- next;
- }
- } else {
- if ($arts ne "" && ($arts !~ /[^\/]*\/[0-9]*/)) {
- &tossit(); # malformed articles list
- next;
- }
- }
- if (/[\000-\010\012-\037\177-\237]/) { # non-control chars except tab
- &tossit(); # illegal chars
- next;
- }
- if ($dates) {
- if ($dates =~ /[^\d~\-]/) { # rudimentary check
- &tossit(); # full check would be too slow
- next;
- }
- }
- print "$_\n";
- $count++;
- $0 = "history line $./$count" if $. % 50000 == 0;
-}
-print STDERR "Done. Now run:\nmakedbz -s $count -f history.n\n";
-
-sub tossit {
- print STDERR "$_\n";
-}
+++ /dev/null
-#!/bin/ksh
-
-### INNCONFcheck v1.1
-
-### Revision history:
-# v1.0 B. Galliart (designed to work with 2.3 inn.conf man page)
-# v1.1 B. Galliart (optional support for using inn.conf POD src instead)
-
-### Description:
-# This script is written to inner-mix the inn.conf settings with the
-# documentation from the inn.conf man page. The concept was shamelessly
-# ripped off of a CGI application provided at Mib Software's Usenet Rapid
-# Knowledge Transfer (http://www.mibsoftware.com/userkt/inn2.0/).
-
-# The idea is that a news administrator usually must go through the
-# task of reading the inn.conf man page in parallel with the inn.conf
-# inn.conf to confirm that the settings are set as desired. Manually
-# matching up the two files can become troublesome. This script should
-# make the task easier and hopefully reduce the chance a misconfiguration
-# is missed.
-
-### Known bugs:
-# - Is very dependent on the format of the man page. It is know NOT to
-# work with the inn.conf man pages written before INN 2.3 and may
-# require minor rewriting to address future revisions of inn.conf
-# Note: this known bug is addressed via the "EDITPOD" option below
-# but is not enabled by default (details explained below).
-#
-# - SECURITY! While taken from the concept of a CGI script, it is not
-# intended to be a CGI script itself. It is *assumed* that the
-# inn.conf file is provided by a "trusted" source.
-
-### License: this script is provided under the same terms as the majority
-# of INN 2.3.0 as stated in the file "inn-2.3.0/LICENSE"
-
-### Warrenty/Disclaimer: There is no warrenty provided. For details, please
-# refer to the file "inn-2.3.0/LICENSE" from the INN 2.3 package
-
- ################
-
-### The User Modifiable Parameters/Settings:
-
-# INNCONF should be set to the actual location of the inn.conf file
-INNCONF=/usr/local/news/etc/inn.conf
-
-# INNCONFMAN should be set to the location of the inn.conf man page
-INNCONFMAN=/usr/local/news/man/man5/inn.conf.5
-
-# INNCONFPOD should be set to the location of the inn.conf POD source
-# INNCONFPOD=/usr/local/src/inn-2.3.0/doc/pod/inn.conf.pod
-INNCONFPOD=/usr/local/news/man/man5/inn.conf.pod
-
-# NROFF should be set to an approbate program for formating the man page
-# this could be the vendor provided nroff, the FSF's groff (which could be
-# used for producing PostScript output) or Earl Hood's man2html from
-# http://www.oac.uci.edu/indiv/ehood/man2html.html
-
-# NROFF=man2html
-NROFF="nroff -man"
-
-# Pager should be set to an approbate binary for making the output
-# readable in the user's desired method. Possible settings include
-# page, more, less, ghostview, lynx, mozilla, lpr, etc. If no pager
-# application is desire then by setting it to "cat" will cause the output
-# to continue on to stdout.
-PAGER=less
-
-# By default the script uses the inn.conf man page before being processed
-# by nroff to edit in the actual inn.conf settings. The problem with this
-# approach is that if the format of the inn.conf man page ever changes
-# assumptions about the format that this script makes will probably break.
-# Presently, the base/orginal format of the inn.conf man page is in perl
-# POD documentation. The formating of this file is less likely to change
-# in the future and is a cleaner format for automated editing. However,
-# their is some disadvantages to using this file. First disadvantage,
-# the POD file is not installed by INN 2.3.0 by default (see INNCONFPOD
-# enviromental variable for setting the script to find the file in the
-# correct location). Second disadvantage, pod2man does not appear to
-# support using stdin so the edited POD must be temporarily stored as a
-# file. Finally, the last disadvantage, the script is slower due to the
-# added processing time of pod2man. Weighing the advantages and
-# disadvantages to both approaches are left to the user. If you wish to
-# have innconfcheck edit the POD file then change the variable below to
-# a setting of "1", otherwise leave it with the setting of "0"
-EDITPOD=0
-
- ################
-
-### The Script: (non-developers should not need to go beyond this point)
-
-# All variable settings in inn.conf should not contain a comment
-# character of "#" and should have a ":" in the line. These variable names
-# should then be matched up with the man page "items" in the inn.conf file.
-# In the INN 2.3 man page, these items appear in the following format:
-# .Ip "\fIvariable name\fR" 4
-# Hence, if there exists an entry in the inn.conf of "verifycancels: false"
-# then the awk script will produce:
-# s#^.Ip "\fIvarifycancels\f$" 4#.Ip "\verifycancels: false\f$" 4#
-# once piped to sed, this expression will replace the man page item to
-# include the setting from the inn.conf file. The nroff and pager
-# applications then polish the script off to provide a documented formated
-# in a way that is easier to find incorrect setting withen.
-
-if [ $EDITPOD -eq 0 ] ; then
-
- grep -v "#" $INNCONF | grep ":" | \
- awk 'BEGIN { FS = ":" } { print "s#^.Ip \042\\\\fI"$1"\\\\fR\042 4#.Ip \042\\\\fI"$0"\\\\fR\042 4#" }' | \
- sed -f - $INNCONFMAN | $NROFF | $PAGER
-
-else
-
-# The next part is similar to above but provides working from the POD source
-# instead of from the resulting nroff/man page. This section is discussed
-# in more detail above with the "EDITPOD" setting.
-
- grep -v "#" $INNCONF | grep ":" | \
- awk 'BEGIN { FS = ":" } { print "s#=item I<"$1">#=item I<"$0">#" }' | \
- sed -f - $INNCONFPOD > /tmp/innconfcheck-$$
- pod2man /tmp/innconfcheck-$$ | $NROFF | $PAGER
- rm -f /tmp/innconfcheck-$$
-
-fi
-
-# That's all.
-# EOF
+++ /dev/null
-#!/usr/local/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Create expire.ctl script based on recently read articles. Argument gives
-# scale factor to use to adjust expires.
-
-$readfile="$inn::pathdb/readgroups";
-
-$expirectl=$inn::expirectl;
-if (open(RDF, $readfile)) {
- while (<RDF>) {
- chop;
- @foo=split(/ /); # foo[0] should be group, foo[1] lastreadtime
- if ($foo[1] < $oldtime) {
- next; # skip entries that are too old.
- }
- $groups{$foo[0]} = $foo[1];
- }
- close(RDF);
-}
-
-$scale = $ARGV[0];
-if ($scale <= 0) {
- die "invalid scale parameter\n";
-}
-
-rename($expirectl, "$expirectl.OLD") || die "rename $expirectl failed!\n";
-open(OUTFILE, ">$expirectl") || die "open $expirectl for write failed!\n";
-
-print OUTFILE <<'EOF' ;
-## expire.ctl - expire control file
-## Format:
-## /remember/:<keep>
-## <patterns>:<modflag>:<keep>:<default>:<purge>
-## First line gives history retention; other lines specify expiration
-## for newsgroups. Must have a "*:A:..." line which is the default.
-## <patterns> wildmat-style patterns for the newsgroups
-## <modflag> Pick one of M U A -- modifies pattern to be only
-## moderated, unmoderated, or all groups
-## <keep> Mininum number of days to keep article
-## <default> Default number of days to keep the article
-## <purge> Flush article after this many days
-## <keep>, <default>, and <purge> can be floating-point numbers or the
-## word "never." Times are based on when received unless -p is used;
-## see expire.8
-
-# How long to remember old history entries for.
-/remember/:2
-#
-EOF
-
-# defaults for most groups.
-printline("*", "A", 1);
-printline("alt*,misc*,news*,rec*,sci*,soc*,talk*,vmsnet*","U",3);
-printline("alt*,misc*,news*,rec*,sci*,soc*,talk*,vmsnet*","M",5);
-printline("comp*,gnu*,info*,ok*,ecn*,uok*", "U", 5);
-printline("comp*,gnu*,info*,ok*,ecn*,uok*", "M", 7);
-# and now handle each group that's regularly read,
-# assinging them 3* normal max expire
-foreach $i (keys %groups) {
- printline($i, "A", 21);
-}
-# and now put some overrides for groups which are too likely to fill spool if
-# we let them go to autoexpire.
-printline("*binaries*,*pictures*", "A", 0.5);
-printline("control*","A",1);
-printline("control.cancel","A",0.5);
-printline("news.lists.filters,alt.nocem.misc","A",1);
-
-close(OUTFILE);
-exit(1);
-
-sub printline {
- local($grpstr, $mflag, $len) = @_;
- print OUTFILE $grpstr,":",$mflag,":",$len*$scale,":",$len*$scale,":",$len*$scale,"\n";
-}
+++ /dev/null
-#!/usr/local/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Create storage.conf script based on recently read articles.
-
-$readfile="$inn::pathdb/readgroups";
-
-$outfile="$inn::pathdb/storage.conf";
-outloop:
-for ($level=9 ; $level >= 2; --$level) {
- # clear groups hash.
- foreach $i (keys %groups) {
- delete $groups{$i};
- }
- if (open(RDF, "sort $readfile|")) {
- while (<RDF>) {
- chop;
- next if (/^group/); # bogus
- @foo=split(/ /); # foo[0] should be group, foo[1] lastreadtime
- @bar=split(/\./,$foo[0]);
- if ( $level >= scalar @bar) {
- $grf = join(".", @bar);
- } else {
- $grf=join(".", @bar[0..($level-1)]) . ".*";
- }
- $groups{$grf} = 1;
- }
- close(RDF);
- }
- $grlist = join(",",keys(%groups));
- last outloop if (length($grlist) < 2048);
-}
-
-open(OUT, ">$outfile") || die "cant open $outfile";
-#open(OUT, ">/dev/tty");
-
-print OUT <<"EOF" ;
-method cnfs {
- newsgroups: control,control.*
- class: 1
- options: MINI
-}
-
-method timecaf {
- newsgroups: $grlist
- class: 1
-}
-
-method cnfs {
- newsgroups: *
- options: MONGO
- class: 0
-}
-EOF
-close(OUT);
-exit(0);
+++ /dev/null
-#!/usr/bin/perl
-
-sub usage {
- print STDERR "Usage: $0 <size in KB> <filename>\n";
- exit 1;
-}
-
-usage if(@ARGV != 2);
-
-$buf1k = "\0"x1024;
-$buf1m = "$buf1k"x1024;
-
-$kb = $ARGV[0] * 1;
-&usage if($kb == 0);
-
-if($ARGV[1] eq '-') {
- open(FILE, "|cat") or die;
-} else {
- open(FILE, ">$ARGV[1]") or die;
-}
-
-for($i = 0; $i+1024 <= $kb; $i+=1024) {
- print FILE $buf1m or die;
-}
-if($i < $kb) {
- print FILE "$buf1k"x($kb-$i) or die;
-}
-
-close FILE;
+++ /dev/null
-/* $Id: mlockfile.c 6014 2002-12-16 11:28:07Z alexk $ */
-
-/* Locks the files given on the command line into memory using mlock.
- This code has only been tested on Solaris and may not work on other
- platforms.
-
- Contributed by Alex Kiernan <alexk@demon.net>. */
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/stropts.h>
-
-struct mlock {
- const char *path;
- struct stat st;
- void *base;
- off_t offset;
- size_t length;
-};
-
-char *progname;
-
-int flush = 0;
-int interval = 60000;
-
-void
-inn_lock_files(struct mlock *ml)
-{
- for (; ml->path != NULL; ++ml) {
- int fd;
-
- fd = open(ml->path, O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "%s: can't open `%s' - %s\n",
- progname, ml->path, strerror(errno));
- } else {
- struct stat st;
-
- /* check if size, inode or device of the path have
- * changed, if so unlock the previous file & lock the new
- * one */
- if (fstat(fd, &st) != 0) {
- fprintf(stderr, "%s: can't stat `%s' - %s\n",
- progname, ml->path, strerror(errno));
- } else if (ml->st.st_ino != st.st_ino ||
- ml->st.st_dev != st.st_dev ||
- ml->st.st_size != st.st_size) {
- if (ml->base != MAP_FAILED)
- munmap(ml->base,
- ml->length ? ml->length : ml->st.st_size);
-
- /* free everything here, so in case of failure we try
- * again next time */
- ml->st.st_ino = 0;
- ml->st.st_dev = 0;
- ml->st.st_size = 0;
-
- ml->base = mmap(NULL,
- ml->length ? ml->length : st.st_size,
- PROT_READ,
- MAP_SHARED, fd, ml->offset);
-
- if (ml->base == MAP_FAILED) {
- fprintf(stderr, "%s: can't mmap `%s' - %s\n",
- progname, ml->path, strerror(errno));
- } else {
- if (mlock(ml->base,
- ml->length ? ml->length : st.st_size) != 0) {
- fprintf(stderr, "%s: can't mlock `%s' - %s\n",
- progname, ml->path, strerror(errno));
- } else {
- ml->st = st;
- }
- }
- } else if (flush) {
- msync(ml->base, ml->length ? ml->length : st.st_size, MS_SYNC);
- }
- }
- close (fd);
- }
-}
-
-static void
-usage(void)
-{
- fprintf(stderr,
- "usage: %s [-f] [-i interval] file[@offset[:length]] ...\n",
- progname);
- fprintf(stderr, " -f\tflush locked bitmaps at interval\n");
- fprintf(stderr, " -i interval\n\tset interval between checks/flushes\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- struct mlock *ml;
- int i;
-
- progname = *argv;
- while ((i = getopt(argc, argv, "fi:")) != EOF) {
- switch (i) {
- case 'i':
- interval = 1000 * atoi(optarg);
- break;
-
- case 'f':
- flush = 1;
- break;
-
- default:
- usage();
- return EX_USAGE;
- }
- }
- argc -= optind;
- argv += optind;
-
- /* construct list of pathnames which we're to operate on, zero out
- * the "cookies" so we lock it in core first time through */
- ml = malloc((1 + argc) * sizeof ml);
- for (i = 0; argc--; ++i, ++argv) {
- char *at;
- off_t offset = 0;
- size_t length = 0;
-
- ml[i].path = *argv;
- ml[i].st.st_ino = 0;
- ml[i].st.st_dev = 0;
- ml[i].st.st_size = 0;
- ml[i].base = MAP_FAILED;
-
- /* if we have a filename of the form ...@offset:length, only
- * map in that portion of the file */
- at = strchr(*argv, '@');
- if (at != NULL) {
- char *end;
-
- *at++ = '\0';
- errno = 0;
- offset = strtoull(at, &end, 0);
- if (errno != 0) {
- fprintf(stderr, "%s: can't parse offset `%s' - %s\n",
- progname, at, strerror(errno));
- return EX_USAGE;
- }
- if (*end == ':') {
- at = end + 1;
- errno = 0;
- length = strtoul(at, &end, 0);
- if (errno != 0) {
- fprintf(stderr, "%s: can't parse length `%s' - %s\n",
- progname, at, strerror(errno));
- return EX_USAGE;
- }
- }
- if (*end != '\0') {
- fprintf(stderr, "%s: unrecognised separator `%c'\n",
- progname, *end);
- return EX_USAGE;
- }
- }
- ml[i].offset = offset;
- ml[i].length = length;
- }
- ml[i].path = NULL;
-
- /* loop over the list of paths, sleeping 60s between iterations */
- for (;;) {
- inn_lock_files(ml);
- poll(NULL, 0, interval);
- }
- return EX_OSERR;
-}
+++ /dev/null
-/* newsresp.c - EUnet - bilse */
-
-/*
- * From: Koen De Vleeschauwer <koen@eu.net>
- * Subject: Re: innfeed-users: innfeed: measuring server response time
- * To: jeff.garzik@spinne.com (Jeff Garzik)
- * Date: Tue, 13 May 1997 16:33:27 +0200 (MET DST)
- * Cc: innfeed-users@vix.com
- *
- * > Is there an easy way to measure server response time, and print it out
- * > on the innfeed status page? Cyclone's nntpTime measures login banner
- * > response time and an article add and lookup operation.
- * >
- * > It seems to me that innfeed could do something very similar. It could
- * > very easily sample gettimeofday() or Time.Now to determine a remote
- * > server's average response time for lookups, lookup failures, article
- * > send throughput, whatever.
- * >
- * > These statistics might be invaluable to developers creating advanced
- * > connection and article delivery algorithms. If I knew, for example,
- * > that a site's article send/save throughput was really fast, but history
- * > lookups were really slow, my algorithm could reserve a channel or two
- * > for TAKETHIS-only use.
- *
- * We use a stand-alone program which opens up an additional nntp channel
- * from time to time and takes a peek at the various response times.
- * It's also interesting to tune one's own box.
- * I've included the source code; please consider this supplied 'as is';
- * bugs and features alike. SunOS, Solaris and Irix ought to be ok;
- * eg. gcc -traditional -o newsresp ./newsresp.c -lnsl -lsocket on S0laris.
- * If a host has an uncommonly long banner you may have to change a constant
- * somewhere; forget. Please note one has to interpret the output;
- * eg. whether one is measuring rtt or history lookup time.
- *
- * Basic usage is:
- * news 1 % newsresp -n 5 news.eu.net
- * ---------------------------------
- * news.eu.net is 134.222.90.2 port 119
- * elap diff
- * 0.0 0.0 Connecting ...
- * 0.0 0.0 OK, waiting for prompt
- * 0.0 0.0 <<< 200 EU.net InterNetNews server INN 1.5.1 17-Dec-1996 re [...]
- * 0.0 0.0 >>> ihave <244796399@a>
- * 0.0 0.0 <<< 335
- * 0.0 0.0 >>> .
- * 0.0 0.0 <<< 437 Empty article
- * 0.0 0.0 >>> ihave <244796398@a>
- * 0.0 0.0 <<< 335
- * 0.0 0.0 >>> .
- * 0.0 0.0 <<< 437 Empty article
- * 0.0 0.0 >>> ihave <244796397@a>
- * 0.0 0.0 <<< 335
- * 0.0 0.0 >>> .
- * 0.0 0.0 <<< 437 Empty article
- * 0.0 0.0 >>> ihave <244796396@a>
- * 0.1 0.0 <<< 335
- * 0.1 0.0 >>> .
- * 0.1 0.0 <<< 437 Empty article
- * 0.1 0.0 >>> ihave <244796395@a>
- * 0.1 0.0 <<< 335
- * 0.1 0.0 >>> .
- * 0.1 0.0 <<< 437 Empty article
- * 0.1 0.0 >>> quit
- * 0.1 0.0 <<< 205 .
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <errno.h>
-
-#define NNTPPORT 119
-struct sockaddr_in sock_in;
-int sock;
-char buf[1024];
-
-main(argc,argv)
-int argc;
-char *argv[];
-{
- int errflg = 0, c;
- extern char *optarg;
- extern int optind;
- struct hostent *host;
- unsigned long temp;
- unsigned numart = 1;
- struct protoent *tcp_proto;
- char **whoP;
-
- while ( (c = getopt(argc,argv,"n:")) != -1 )
- switch ( c ) {
- case 'n': sscanf(optarg,"%u",&numart); break;
- default : errflg++;
- }
- if ( numart == 0 || optind == argc )
- errflg++;
- if ( errflg ) {
- fprintf(stderr,"Usage: %s [-n articles] host ...\n",argv[0]);
- exit(1);
- }
-
- if ( (tcp_proto = getprotobyname("tcp")) == 0 )
- fatal("getprotobyname");
- for ( whoP = argv+optind; *whoP != 0; whoP++ ) {
- if ( (sock = socket(PF_INET,SOCK_STREAM,tcp_proto->p_proto)) < 0 )
- fatal("socket");
- temp = inet_addr(*whoP);
- if ( temp != (unsigned long) -1 ) {
- sock_in.sin_addr.s_addr = temp;
- sock_in.sin_family = AF_INET;
- }
- else {
- host = gethostbyname(*whoP);
- if ( host ) {
- sock_in.sin_family = host->h_addrtype;
- memcpy(&sock_in.sin_addr,host->h_addr,host->h_length);
- }
- else {
- fprintf(stderr,"gethostbyname can't find %s\n",*whoP);
- exit(1);
- }
- }
- sock_in.sin_port = htons(NNTPPORT);
- printf("---------------------------------\n%s is %s port %d\n",
- *whoP,inet_ntoa(sock_in.sin_addr),ntohs(sock_in.sin_port));
- punt(numart);
- close(sock);
- }
-}
-
-error(what)
-char *what;
-{
- ptime(); fflush(stdout);
- perror(what);
-}
-
-fatal(what)
-char *what;
-{
- error(what);
- exit(2);
-}
-
-ierror(how,what)
-char *how, *what;
-{
- printf("Expected %s, bailing out.\n",how);
-}
-
-ifatal(how,what)
-char *how, *what;
-{
- ierror(how,what);
- exit(1);
-}
-
-unsigned do_time(start)
-unsigned start;
-{
- struct timeval now;
-
- gettimeofday(&now,(struct timezone *)0);
- return ( now.tv_sec*1000 + now.tv_usec/1000 - start );
-}
-
-
-unsigned start, elapsed, diff;
-
-ptime()
-{
- diff = elapsed;
- elapsed = do_time(start);
- diff = elapsed - diff;
- printf("%5.1f %5.1f ",((float)elapsed)/1000.0,((float)diff)/1000.0);
-}
-
-massagebuff(bread,buf)
-int bread;
-char *buf;
-{
- char *p;
-
- if ( bread > 55 )
- strcpy(buf+55," [...]\n");
- else
- buf[bread] = '\0';
- for ( p = buf; *p != '\0'; )
- if ( *p != '\r' ) /* We like to do it RISC style. */
- p++;
- else {
- *p = ' ';
- p++;
- }
-}
-
-punt(numart)
-int numart;
-{
- static char ihave[32],
- dot[] = ".\r\n",
- quit[] = "quit\r\n";
- struct timeval start_tv;
- int bread;
-
- printf(" elap diff\n");
- diff = elapsed = 0;
- gettimeofday(&start_tv,(struct timezone *)0);
- start = start_tv.tv_sec*1000 + start_tv.tv_usec/1000;
-
- ptime();
- printf("Connecting ...\n");
- if ( connect(sock,(struct sockaddr*)&sock_in,sizeof(sock_in)) < 0 ) {
- error("connect");
- return(-1);
- }
- ptime();
- printf("OK, waiting for prompt\n");
-
- if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
- error("read socket");
- return(-1);
- }
- massagebuff(bread,buf);
- ptime();
- printf("<<< %s",buf);
- if ( strncmp(buf,"200",3) != 0 && strncmp(buf,"201",3) != 0 ) {
- ierror("200 or 201",buf);
- return(-1);
- }
-
- do {
- snprintf(ihave,sizeof(ihave),"ihave <%u@a>\r\n",start+numart);
- ptime();
- printf(">>> %s",ihave);
- if ( write(sock,ihave,strlen(ihave)) != strlen(ihave) ) {
- error("write socket");
- return(-1);
- }
-
- if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
- error("read socket");
- return(-1);
- }
- massagebuff(bread,buf);
- ptime();
- printf("<<< %s",buf);
- if ( strncmp(buf,"335",3) != 0 && strncmp(buf,"435",3) != 0 ) {
- ierror("335 or 435 ",buf);
- return(-1);
- }
-
- if ( strncmp(buf,"335",3) == 0 ) {
- ptime();
- printf(">>> %s",dot);
- if ( write(sock,dot,sizeof(dot)-1) != sizeof(dot)-1 ) {
- error("write socket");
- return(-1);
- }
-
- if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
- error("read socket");
- return(-1);
- }
- massagebuff(bread,buf);
- ptime();
- printf("<<< %s",buf);
- if ( strncmp(buf,"437",3) != 0 && strncmp(buf,"235",3) != 0 ) {
- ierror("437 or 235",buf);
- return(-1);
- }
- }
- } while ( --numart != 0 );
-
- ptime();
- printf(">>> %s",quit);
- if ( write(sock,quit,sizeof(quit)-1) != sizeof(quit)-1 ) {
- error("write socket");
- return(-1);
- }
-
- if ( (bread=read(sock,buf,sizeof(buf))) < 0 ) {
- error("read socket");
- return(-1);
- }
- massagebuff(bread,buf);
- ptime();
- printf("<<< %s",buf);
- if ( strncmp(buf,"205",3) != 0 ) {
- ierror("205",buf);
- return(-1);
- }
- return(0);
-}
+++ /dev/null
-/*
-June 14, 1999
-
-Recover text articles from cyclic buffers
-Articles start with "\0Path:"
-and end with "\r\n.\r\n"
-
-Tested with INND 2.2 under AIX 4.2
-
-rifkin@uconn.edu
-*/
-/*
-(1) Pull 16 bytes at a time
-(2) Last 7 bytes must be \000\000\000Path
-(3) When found, print "\nPath";
-(4) print subsequent bytes until \r\n.\r\n found
-*/
-
-#include "config.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define INFILE 1
-#define FILEPREFIX 2
-#define HEADER 3
-#define STRING 4
-
-/* String buffer size */
-#define NBUFF 512
-
-#define MAX_ART_SIZE 2200000
-
-
-#define WRITEMSG printf ("File %s line %i\n", __FILE__, __LINE__); \
- fflush(stdout);
-
-#define WRITEVAR(VAR_NAME,VAR_TYPE) \
- { \
- printf ("FILE %s LINE %i :", __FILE__, __LINE__); \
- printf ("%s = ", #VAR_NAME); \
- printf (#VAR_TYPE, (VAR_NAME) ); \
- printf ("\n"); \
- }
-
-#define WRITETXT(TEXT) \
- printf ("FILE %s LINE %i \"%s\"\n", __FILE__, __LINE__, TEXT); \
- fflush(stdout);
-
-#if 0
-#define WRITEMSG
-#define WRITEVAR(X,Y)
-#endif
-
-
-int WriteArticle (char *, int, char *, char *, char *, int);
-
-
-char ArtHead[7] = {0, 0, 0, 'P', 'a', 't', 'h'};
-char ArtTail[5] = {'\r', '\n', '.', '\r', '\n'};
-int LenTail = 5;
-
-int main (int argc, char *argv[])
- {
- FILE *Infile;
- int NumTailCharFound;
- bool ReadingArticle = false;
- char buffer[32];
- char *obuffer = NULL;
- char *header = NULL;
- char *string = NULL;
- int osize = MAX_ART_SIZE;
- int opos = 0;
- int i;
- int nchar;
- int fileno = 0;
- int artno = 0;
-
- /* Check number of args */
- if (argc<3)
- {
- printf ("Usage: pullart <cycbuff> <fileprefix> [<header> <string>]\n");
- printf (" Read cycbuffer <cycbuff> and print all articles whose\n");
- printf (" article header <header> contains <string>.\n");
- printf (" Articles are written to files name <fileprefix>.nnnnnn\n");
- printf (" where nnnnnn is numbered sequentially from 0.\n");
- printf (" If <header> and <string> not specified, all articles\n");
- printf (" are written.\n");
- printf (" Examples:\n");
- printf (" pullart /news3/cycbuff.3 alt.rec Newsgroup: alt.rec\n");
- printf (" pullart /news3/cycbuff.3 all\n");
- printf (" pullart firstbuff article Subject bluejay\n");
- return 0;
- }
-
- /* Allocate output buffer */
- obuffer = (char *) calloc (osize+1, sizeof(char));
- if (obuffer==NULL)
- {
- printf ("Cannot allocate obuffer[]\n");
- return 1;
- }
-
-
- /* Open input file */
- Infile = fopen (argv[INFILE], "rb");
- if (Infile==NULL)
- {
- printf ("Cannot open input file.\n");
- return 1;
- }
-
-
-if (argc>=4) header = argv[HEADER];
-if (argc>=5) string = argv[STRING];
-if (*header=='\0') header=NULL;
-if (*string=='\0') string=NULL;
-
-/*test*/
-printf ("filename <%s>\n", argv[INFILE]);
-printf ("fileprefix <%s>\n", argv[FILEPREFIX]);
-printf ("header <%s>\n", header);
-printf ("string <%s>\n", string);
-
-
- /* Skip first 0x38000 16byte buffers */
- i = fseek (Infile, 0x38000L, SEEK_SET);
-
- /* Read following 16 byte buffers */
- ReadingArticle = false;
- NumTailCharFound = 0;
- nchar=0;
- artno=0;
- while ( 0!=fread(buffer, 16, 1, Infile) )
- {
-
- nchar+=16;
-
- /* Found start of article, start writing to obuffer */
- if (0==memcmp(buffer+9, ArtHead, 7))
- {
- ReadingArticle = true;
- memcpy (obuffer, "Path", 4);
- opos = 4;
- continue;
- }
-
- /* Currnetly reading article */
- if (ReadingArticle)
- {
- for (i=0; i<16; i++)
- {
-
- /* Article too big, drop it and move on */
- if (opos>=osize)
- {
- printf
- ("article number %i bigger than buffer size %i.\n",
- artno+1, osize);
- artno++;
- ReadingArticle=false;
- break;
- }
-
- /* Add current character to output buffer, but remove \r */
- if ('\r' != buffer[i])
- obuffer[opos++] = buffer[i];
-
- /* Check for article ending sequence */
- if (buffer[i]==ArtTail[NumTailCharFound])
- {
- NumTailCharFound++;
- }
- else
- NumTailCharFound=0;
-
- /* End found, write article, reset for next */
- if (NumTailCharFound==LenTail)
- {
- ReadingArticle = false;
- NumTailCharFound = 0;
-
- /* Add trailing \0 to buffer */
- obuffer[opos+1] = '\0';
-
- fileno += WriteArticle
- (obuffer, opos, argv[FILEPREFIX],
- header, string, fileno);
- artno++;
- break;
- }
- }
-
- }
-
- }
-
- close (Infile);
-
- return 0;
- }
-
-
-
-/*
-Writes article stored in buff[] if it has a
-"Newsgroups:" header line which contains *newsgroup
-Write to a file named fileprefix.fileno
-*/
-int
-WriteArticle
-(char *buff, int n, char *fileprefix, char *headerin, char *string, int fileno)
- {
- char *begptr;
- char *endptr;
- char *newsptr;
- char savechar;
- char header[NBUFF];
- char filename[NBUFF];
- FILE *outfile;
-
-
- /* Prevent buffer overflow due to fileprefix too long */
- if (strlen(fileprefix)>384)
- {
- printf
- ("program error: cannot have file prefix greater then 384 characters\n");
- exit(1);
- }
-
- /*
- Is header here? Search if header string requested, leave if not found
- */
- if (headerin!=NULL)
- {
- /* Find \nHEADER */
- strlcpy(header, "\n", sizeof(header));
- strlcat(header, headerin, sizeof(header));
-
- begptr = strstr (buff, header);
-
- /* return if Header name not found */
- if (begptr==NULL)
- {
- return 0;
- }
-
- /*
- Header found. What about string?
- Search if string requested, leave if not found
- */
- if (string!=NULL)
- {
- /* Find end of header line */
- begptr++;
- endptr = strchr (begptr, '\n');
-
- /* Something is wrong, end of header not found, do not write
- * article
- */
- if (endptr==NULL)
- return 0;
-
- /* Temporarily make string end a null char */
- savechar = *endptr;
- *endptr = '\0';
- newsptr = strstr (begptr, string);
-
- /* Requested newsgroup not found */
- if (newsptr==NULL)
- return 0;
-
- /* Restore character at end of header string */
- *endptr = savechar;
- }
- /* No string specified */
-
- }
- /* No header specified */
-
- /* Open file, write buffer, close file */
- snprintf (filename, sizeof(filename), "%s.%06i", fileprefix, fileno);
-
- outfile = fopen (filename, "wt");
- if (outfile==NULL) {
- printf ("Cannot open file name %s\n", filename);
- exit(1);
- }
-
- while (n--)
- fprintf (outfile, "%c", *buff++);
-
- close (outfile);
-
- /* Return number of files written */
- return 1;
- }
+++ /dev/null
-/* Quick and Dirty Hack to reset a CNFS buffer without having to DD the
- * Entire Thing from /dev/zero again. */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <stdio.h>
-
-/* uncomment the below for LARGE_FILES support */
-/* #define LARGE_FILES */
-
-int main(int argc, char *argv[])
-{
- int fd;
- int i, j;
- char buf[512];
-#ifdef LARGE_FILES
- struct stat64 st;
-#else
- struct stat st;
-#endif
- int numwr;
-
- bzero(buf, sizeof(buf));
- for (i = 1; i < argc; i++) {
-#ifdef LARGE_FILES
- if ((fd = open(argv[i], O_LARGEFILE | O_RDWR, 0664)) < 0)
-#else
- if ((fd = open(argv[i], O_RDWR, 0664)) < 0)
-#endif
- fprintf(stderr, "Could not open file %s: %s\n", argv[i], strerror(errno));
- else {
-#ifdef LARGE_FILES
- if (fstat64(fd, &st) < 0) {
-#else
- if (fstat(fd, &st) < 0) {
-#endif
- fprintf(stderr, "Could not stat file %s: %s\n", argv[i], strerror(errno));
- } else {
- /* each bit in the bitfield is 512 bytes of data. Each byte
- * has 8 bits, so calculate as 512 * 8 bytes of data, plus
- * fuzz. buf has 512 bytes in it, therefore containing data for
- * (512 * 8) * 512 bytes of data. */
- numwr = (st.st_size / (512*8) / sizeof(buf)) + 50;
- printf("File %s: %u %u\n", argv[i], st.st_size, numwr);
- for (j = 0; j < numwr; j++) {
- if (!(j % 100))
- printf("\t%d/%d\n", j, numwr);
- write(fd, buf, sizeof(buf));
- }
- }
- close(fd);
- }
- }
-}
+++ /dev/null
-/*
-** Refile articles into the storage manager under the current storage.conf
-** rules, deleting articles from their old place in the spool.
-** Written 10-09-99 by rmtodd@servalan.servalan.com
-**
-** Note that history and overview will have to be rebuilt for the moved
-** articles to be visible after they're moved.
-*/
-
-/* include foo needed by libinn/storage manager */
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-char *ME;
-
-static void
-ProcessLine(char *line)
-{
- char *tokenptr;
- int len;
- ARTHANDLE *art;
- ARTHANDLE newart;
- TOKEN token, newtoken;
- char *arttmp;
- time_t arrived;
-
- tokenptr = line;
-
- /* zap newline at end of tokenptr, if present. */
- len = strlen(tokenptr);
- if (tokenptr[len-1] == '\n') {
- tokenptr[len-1] = '\0';
- }
-
- token = TextToToken(tokenptr);
- if ((art = SMretrieve(token, RETR_ALL)) == NULL) return;
-
- len = art->len;
- arrived = art->arrived;
- arttmp = xmalloc(len);
- memcpy(arttmp, art->data, len);
- SMfreearticle(art);
- if (!SMcancel(token)) {
- fprintf(stderr, "%s: cant cancel %s:%s\n", ME, tokenptr, SMerrorstr);
- return;
- }
-
- newart.data = arttmp;
- newart.len = len;
- newart.arrived = (time_t) 0; /* set current time */
- newart.token = (TOKEN *)NULL;
-
- newtoken = SMstore(newart);
- if (newtoken.type == TOKEN_EMPTY) {
- fprintf(stderr, "%s: cant store article:%s\n", ME, SMerrorstr);
- return;
- }
- free(arttmp);
- printf("refiled %s ",TokenToText(token));
- printf("to %s\n", TokenToText(newtoken));
- return;
-}
-
-int
-main(int argc UNUSED, char *argv[])
-{
- bool one = true;
- char buff[SMBUF];
-
- ME = argv[0];
-
- if (!innconf_read(NULL))
- exit(1);
-
- if (!SMsetup(SM_PREOPEN, &one) || !SMsetup(SM_RDWR, (void *)&one)) {
- fprintf(stderr, "can't init storage manager");
- exit(1);
- }
- if (!SMinit()) {
- fprintf(stderr, "Can't init storage manager: %s", SMerrorstr);
- }
- while (fgets(buff, SMBUF, stdin)) {
- ProcessLine(buff);
- }
- printf("\nYou will now need to rebuild history and overview for the moved"
- "\narticles to be visible again.\n");
- exit(0);
-}
+++ /dev/null
-#!/sbin/sh
-
-# This is a simple, bare-bones example of a SysV-style init.d script for INN.
-
-case $1 in
-
-start)
- su news -c /usr/local/news/bin/rc.news
- ;;
-
-stop)
- su news -c '/usr/local/news/bin/rc.news stop'
- ;;
-
-esac
-
-exit 0
-
+++ /dev/null
-#!/usr/bin/perl -w
-# showtoken - decode SM tokens
-# Olaf Titz, 1999. Marco d'Itri, 2000. Public domain.
-# Takes tokens on stdin and write them along with a decoded form on stdout.
-
-use strict;
-
-my ($pathspool, %NG);
-
-my @types = ('trash', '', 'timehash', 'cnfs', 'timecaf', 'tradspool');
-
-if ($ARGV[0]) {
- $pathspool = $ARGV[0];
- if (open(MAP, "$pathspool/tradspool.map")) {
- while (<MAP>) {
- my ($ng, $gnum) = split;
- $NG{$gnum} = $ng;
- }
- close MAP;
- }
-}
-
-$| = 1;
-while (<STDIN>) {
- chomp;
- next if not /^@.+@/;
- print "$_ ";
- splittoken($_);
-}
-
-sub splittoken {
- my $t = shift;
-
- $t =~ tr/@//d;
- $t = pack('H*', $t);
- my ($type, $class, $token, $index, $offset, $overlen, $cancelled) =
- unpack('C C a16 CLnc', $t);
-
- if (not $types[$type]) {
- print "type=$type unknown!\n";
- next;
- }
- print "type=$types[$type] class=$class ";
-
- if ($type == 0) { # trash
- } elsif ($type == 2) { # timehash
- my ($time, $seq) = unpack('Nn', $token);
- my ($a, $b, $c, $d) = unpack('CCCC', $token);
- printf 'time=%08lX seq=%04X file=time-%02x/%02x/%02x/%04x-%02x%02x',
- $time, $seq, $class, $b, $c, $seq, $a, $d;
- } elsif ($type == 3) { # cnfs
- my ($buffn, $offset, $cnum) = unpack('A8NN', $token);
- printf 'buffer=%s offset=%x cycnum=%x', $buffn, $offset * 512, $cnum;
- } elsif ($type == 4) { # timecaf
- my ($time, $seq) = unpack('Nn', $token);
- my (undef, $b, $c, $d) = unpack('CCCC', $token);
- printf 'time=%06lX seq=%04X caf=timecaf-%02x/%02x/%02x%02x.CF',
- $time, $seq, $class, $c, $b, $d;
- } elsif ($type == 5) { # tradspool
- my ($gnum, $art) = unpack('NN', $token);
- printf 'ng=%08X art=%d', $gnum, $art;
- print "file=articles/$NG{$gnum}/$art" if $NG{$gnum};
- } else {
- die "invalid type $type";
- }
- print " over=$index offset=$offset overlen=$overlen cancelled=$cancelled"
- if length $t > 36;
- print "\n";
-}
-__END__
-# Format of a token:
-# 1 type
-# 1 class
-# 16 token
-# 1 index
-# 4 offset
-# 2 overlen
-# 2 cancelled
-# The fields "index" and following are not available with OV3 (INN 2.3 up)
-#
-# the "token" field is:
-# for type=0 (trash) ignored
-# for type=2 (timehash)
-# 4 time
-# 2 seqnum
-# for type=3 (cnfs)
-# 8 cycbuffname
-# 4 offset/512
-# 4 cycnum
-# for type=4 (timecaf)
-# 4 time
-# 2 seqnum
-# for type=5 (tradspool)
-# 4 ngnum
-# 4 artnum
+++ /dev/null
-#!/usr/bin/perl -w
-
-# Parse log files created by innd history profiler
-# 2001/01/29 - Fabien Tassin
-
-use strict;
-use FileHandle;
-
-my $file = shift || "stathist.log";
-if ($file eq '-h' || $file eq '--help') {
- print "Usage: stathist [logfile]\n";
- exit 0;
-}
-
-sub parse {
- my $file = shift;
-
- my $f = new FileHandle $file;
- unless (defined $f) {
- print STDERR "Can't open file: $!\n";
- return {};
- }
- my $data = {};
- my $begin = 1;
- my @stack = ();
- while (defined (my $line = <$f>)) {
- next if $begin && $line !~ / HIS(havearticle|write|setup) begin/;
- $begin = 0;
- chomp $line;
- my @c = split /[\[\]\(\) ]+/, $line;
- ($c[4] eq 'begin') && do {
- push @stack, $c[3];
- my $d = $data;
- for my $l (@stack) {
- unless (defined $$d{$l}) {
- $$d{$l}{'min'} = 1E10;
- $$d{$l}{'total'} = $$d{$l}{'count'} = $$d{$l}{'max'} = 0;
- }
- $d = $$d{$l}
- }
- } ||
- ($c[4] eq 'end') && do {
- my $d = $data;
- for my $l (@stack) {
- $d = $$d{$l};
- }
- $$d{'count'}++;
- $$d{'total'} += $c[5];
- $$d{'min'} = $c[5] if $$d{'min'} > $c[5];
- $$d{'max'} = $c[5] if $$d{'max'} < $c[5];
- pop @stack;
- };
- }
- $f->close;
- $data;
-}
-
-sub report {
- my $data = shift;
- my $inc = shift;
-
- unless (defined $inc) {
- printf "%-16s %10s %14s %10s %10s %10s\n\n", "Function", "Invoked",
- "Total(s)", "Min(ms)", "Avg(ms)", "Max(ms)";
- $inc = 0;
- }
-
- for my $key (sort keys %$data) {
- next unless $key =~ m/^HIS/;
- printf "%-16s %10d %14.6f %10.3f %10.3f %10.3f\n", (' ' x $inc) . $key,
- $$data{$key}{'count'}, $$data{$key}{'total'}, $$data{$key}{'min'} * 1000,
- $$data{$key}{'total'} / $$data{$key}{'count'} * 1000,
- $$data{$key}{'max'} * 1000;
- &report($$data{$key}, $inc + 1)
- }
-}
-
-my $data = &parse($file);
-&report($data);
+++ /dev/null
-#!/usr/bin/perl -w
-# fixscript will replace this line with require innshellvars.pl
-$ID='$Id: thdexpire.in 4572 2001-02-24 22:31:05Z rra $$';
-
-use POSIX ":fcntl_h";
-use SDBM_File;
-use Getopt::Std;
-
-# With the -M switch this program installs its own man page.
-#-----------------------------------------------------------------------------
-
-=head1 NAME
-
-thdexpire - dynamic expire daemon for timehash and timecaf storage
-
-=head1 SYNOPSIS
-
-B<thdexpire>
-[ B<-t> I<minutes> ]
-[ B<-f> I<kilobytes> ]
-[ B<-i> I<inodes> ]
-[ B<-m> I<mindays> ]
-[ B<-x> I<minseconds> ]
-[ B<-N> ]
-[ B<-v> I<level> ]
-
-B<thdexpire -r>
-
-=head1 DESCRIPTION
-
-This is a daemon, to be started along with B<innd>, which periodically
-looks if news spool space is getting tight, and frees space by removing
-articles until enough is free. It is an adjunct (not a replacement) to
-INNs B<expire> program.
-
-=head2 Setting Up
-
-=over 4
-
-=item 1.
-
-Configure your storage classes carefully. Let the default go in class
-100 and choose the storage classes as relative (percent) retention
-times. E.g. if you want to give C<alt.binaries.*> a fifth of the
-default time, put them in class 20. Storage classes above 200 are
-ignored by this program. 0 expires immediately. An example is given
-in L<"EXAMPLES">.
-
-=item 2.
-
-Set up your F<expire.ctl> in a way that it puts only a maximum cap on
-retention times. Run B<expire> from B<news.daily> as usual. However,
-it should only expire articles which have an Expires line or are in
-classes above 200. See L<"EXAMPLES">.
-
-=item 3.
-
-Ensure to start this daemon along with B<innd>.
-
-=item 4.
-
-To get information and statistics, run B<thdexpire -r> (in parallel to
-a running daemon). This will show you the current actual retention
-times.
-
-=back
-
-=head2 How It Works
-
-B<thdexpire> works directly on the spool. It assumes the layout
-described in the timehash and timecaf sections of L<storage.conf(5)> as of
-INN-2.x-CURRENT (Dec. 5, 1998). For every storage class associated
-with timehash/timecaf, B<thdexpire> keeps a I<work time> which is the
-modification time of the oldest article/CAF file in this class. This
-time is chosen so that the difference of the work time of class N to
-now (i.e. the I<retention time> for class N) will be N/100 of the
-retention time of class 100. The work time of all classes is
-continuously adjusted as time goes by. Articles and CAF files which
-are older than the work time are deleted.
-
-=head1 OPTIONS
-
-=over 8
-
-=item B<-t> I<minutes>
-
-Check for free space every I<minutes> minutes (default 30).
-
-=item B<-f> I<kilobytes>
-
-Leave I<kilobytes> kilobytes of free disk space on each spool
-filesystem (default 50000).
-
-=item B<-i> I<inodes>
-
-Leave I<inodes> inodes free on each spool filesystem (default 5000).
-
-=item B<-m> I<mindays>
-
-Set the minimum normal holding time for class 100 to I<mindays> days
-(default 7).
-
-=item B<-x> I<minseconds>
-
-Set the absolute minimum holding time for any article to I<minseconds>
-seconds (default 86400, i.e. 1 day).
-
-=item B<-N>
-
-Do not delete any articles, just print what would be done.
-
-=item B<-v> I<level>
-
-Set the verbosity level. Values from 1 to 3 are meaningful, where
-higher levels are mostly for debugging.
-
-=item B<-r>
-
-Do not run as a daemon, instead print a report from the database (see
-L<FILES>) on the available storage classes, current expire times and
-other stuff.
-
-=back
-
-=head1 EXAMPLES
-
-Here is an example F<storage.conf> file:
-
- # Large postings in binary groups are expired fast:
- # 20% retention time
- method timehash {
- newsgroups: *.binaries.*,*.binaer.*,*.dateien.*,alt.mag.*
- size: 30000
- class: 20
- }
-
- # Local groups and *.answers groups don't expire at all with
- # thdexpire. These are handled by Expires lines and a cutoff
- # in expire.ctl.
- method timehash {
- newsgroups: *.answers,news.announce.*,local.*
- class: 201
- }
-
- # Expires lines are honored if they dont exceed 90 days.
- # Exempt those postings from thdexpire handling.
- method timehash {
- newsgroups: *
- expires: 1d,90d
- class: 202
- }
-
- # Default: should be class 100 because thdexpire bases its
- # calculations thereupon.
- method timecaf {
- newsgroups: *
- class: 100
- }
-
-And here is an F<expire.ctl> which fits:
-
- # Our local groups are held 6 months
- local.*:A:7:180:180
- # Everything else is handled by thdexpire, or Expires lines
- *:A:7:never:never
-
-Note that B<thdexpire> does not actually use these files, they just
-configure other parts of the news system in an appropriate way.
-
-=head1 FILES
-
-=over 4
-
-=item F<E<lt>inn::pathdbE<gt>/thdexpstat.{dir,pag}>
-
-Holds state information like classes, expire times, oldest articles.
-When this file is missing, it will be rebuilt the next time the daemon
-is started, which basically means scanning the spool directories to
-find the oldest articles. With the B<-r> option, the contents of this
-file are printed.
-
-=item F<E<lt>inn::innddirE<gt>/thdexpire.pid>
-
-Contains the PID of the running daemon.
-
-=back
-
-=head1 SIGNALS
-
-I<SIGINT> or I<SIGTERM> can be sent to the daemon at any time, causing
-it to gracefully exit immediately.
-
-=head1 SEE ALSO
-
-L<expire(8)>, L<news.daily(8)>, L<storage.conf(5)>
-
-=head1 NOTES
-
-This version needs the B<inndf> program supplied with newer releases of INN.
-
-The filenames for timecaf were wrong in older versions of the INN
-documentation. This program uses the true filenames, as found by
-reading the INN source.
-
-=head1 DIAGNOSTICS
-
-Any error messages are printed on standard error. Normal progress
-messages, as specified by the B<-v> option, are printed on standard
-output.
-
-=head1 BUGS
-
-Storage classes which are in I<storage.conf> but not on disk (i.e.
-which have never been filed into) when the daemon starts are ignored.
-
-The code is ugly and uses too many global variables.
-Should probably rewrite it in C.
-
-=head1 RESTRICTIONS
-
-Directories which are left empty are not removed.
-
-The overview database is not affected by B<thdexpire>, it has to be
-cleaned up by the daily regular B<news.daily> run. This may need a
-patch to B<expire>.
-
-=head1 AUTHOR
-
-Olaf Titz <olaf@bigred.inka.de>. Use and distribution of this work is
-permitted under the same terms as the B<INN> package.
-
-=head1 HISTORY
-
-Inspired by the old B<dexpire> program for the traditional spool.
-
-June 1998: wrote the first version for timehash.
-
-November 1998: added code for timecaf, works on multiple spool
-filesystems, PODed documentation.
-
-July 1999: bugfixes.
-
-=cut
-
-#-----------------------------------------------------------------------------
-
-chdir $inn::spool || die "chdir $inn::spool: $!";
-$opt_r=0; # make a report
-$opt_t=30; # check interval in minutes
-$opt_f=50000; # required space in kilobytes
-$opt_i=5000; # required space in inodes
-$opt_m=7; # minimum normal (class 100) time in days
-$opt_x=86400; # absolute minimum hold time in seconds
-$opt_N=0; # dont actually delete articles
-$opt_v=0; # verbosity level
-$opt_M=0; # install man page
-getopts("rt:f:i:m:x:Nv:M");
-
-$_=$inn::pathdb; $_=$inn::pathnews; # shut up warning
-$sfile="$inn::pathdb/thdexpstat";
-$ID=~/ ([^,]+,v [^ ]+)/; $ID=$1;
-
-if ($opt_M) {
- print "Installing thdexpire(8) man page\n";
- $0=~m:^(.*)/([^/]+)$:;
- chdir $1 || die "chdir $1";
- exec "pod2man --section=8 --center='Contributed News Software'" .
- " --release='$ID' $2 >$inn::pathnews/man/man8/thdexpire.8";
-}
-
-if ($opt_r) {
- tie(%S, SDBM_File, $sfile, O_RDONLY, 0664) || die "open $sfile: $!";
- &report;
- untie %S;
- exit 0;
-}
-
-(system "shlock", "-p", $$, "-f", "$inn::innddir/thdexpire.pid")>>8==0
- || die "Already running";
-tie(%S, SDBM_File, $sfile, O_RDWR|O_CREAT, 0664) || die "open $sfile: $!";
-$SIG{'TERM'}=$SIG{'INT'}='finish';
-$|=1;
-printf "%s starting at %s\n", $ID, &wtime(time) if ($opt_v>0);
-
-undef @c;
-$NOW=time; $ac=$cc=0;
-opendir(CD, ".") || &err("opendir $inn::spool: $!");
-while ($cd=readdir(CD), defined($cd)) {
- $cd=~/^time(caf)?-([0-9a-f][0-9a-f])$/i || next;
- $c{hex($2)}=1 unless hex($2)>200;
-}
-closedir CD;
-@classes=sort {$a<=>$b} keys %c;
-foreach $c (@classes) {
- &initclass($c);
- $S{"work$;$c"}=$S{"oldest$;$c"}&0xFFFFFF00;
-}
-
-$S{"classes"}=join(",", @classes);
-$S{"inittime"}=time;
-$S{"ID"}=$ID;
-printf "Checked %d articles, %d CAFs in %d seconds\n", $ac, $cc, time-$NOW
- if ($ac+$cc>0 && $opt_v>0);
-
-chdir $inn::spool || die "chdir $inn::spool: $!";
-while (1) {
- $S{"lastrun"}=$NOW=time;
- printf "%s\n", &wtime($NOW) if ($opt_v>0);
- $nt=0;
- foreach $c (@classes) {
- $t=($NOW-$S{"work$;$c"})*100/$c;
- $nt=$t if ($nt<$t);
- }
- printf "Normal time (class 100): %s\n", &xtime($NOW-$nt)
- if ($opt_v>0);
- if ($nt<$opt_m*24*60*60) {
- printf " capped at minimum %d days\n", $opt_m
- if ($opt_v>0);
- $nt=$opt_m*24*60*60;
- }
- if ($nt>180*24*60*60) {
- print " capped at maximum 180 days\n"
- if ($opt_v>0);
- $nt=180*24*60*60;
- }
- $S{"normaltime"}=$nt;
- $decrement=$opt_t*60;
- $pass=$need=0;
- $x="/";
- undef %needk; undef %needi;
- foreach $c (@classes) {
- $Dart{$c}=$Dcaf{$c}=$Dkb{$c}=$Dino{$c}=0;
- $y=sprintf("time-%02x", $c);
- if (-d $y) {
- @S=stat(_);
- if ($#S>=0) {
- $dev{$y}=$S[0];
- unless (defined($needk{$S[0]})) {
- $x.=" $y";
- $needk{$S[0]}=$needi{$S[0]}=-1;
- }
- }
- }
- $y=sprintf("timecaf-%02x", $c);
- if (-d $y) {
- @S=stat(_);
- if ($#S>=0) {
- $dev{$y}=$S[0];
- unless (defined($needk{$S[0]})) {
- $x.=" $y";
- $needk{$S[0]}=$needi{$S[0]}=-1;
- }
- }
- }
- }
- if (open(D, "inndf $x |")) {
- while (<D>) {
- @S=split(/\s+/, $_);
- $needk{$dev{$S[0]}}=$opt_f-$S[1] unless ($S[0] eq "/");
- }
- close D;
- }
- if (open(D, "inndf -i $x |")) {
- while (<D>) {
- @S=split(/\s+/, $_);
- $needi{$dev{$S[0]}}=$opt_i-$S[1] unless ($S[0] eq "/");
- }
- close D;
- }
- foreach $c (keys %needk) {
- printf "Device %d needs to free %d kilobytes, %d inodes\n",
- $c, $needk{$c}<0?0:$needk{$c}, $needi{$c}<0?0:$needi{$c}
- if ($opt_v>0 && ($needk{$c}>0 || $needi{$c}>0));
- if ($needk{$c}>0 || $needi{$c}>0) {
- ++$need;
- }
- }
- if ($opt_v>0 && $need<=0) {
- print " (nothing to do)\n";
- $tt=0;
- } else {
- $error=0;
- while (!$error && $need>0) {
- if ($S{"normaltime"}-$decrement<$opt_m*24*60*60) {
- print " Normal time hit minimum\n" if ($opt_v>0);
- last;
- }
- $S{"normaltime"}-=$decrement;
- printf " normal time (100) becomes %ld\n", $S{"normaltime"}
- if ($opt_v>2);
- ++$pass;
- $Dart=$Dcaf=$Dkb=$Dino=$need=0;
- foreach $c (keys %needk) {
- if ($needk{$c}>0 || $needi{$c}>0) {
- ++$need;
- }
- }
- if ($need) {
- foreach $c (@classes) {
- &worktime($c, $NOW-($S{"normaltime"}*$c/100));
- $Dart+=$dart; $Dcaf+=$dcaf; $Dkb+=$dbb>>10; $Dino+=$dino;
- $Dart{$c}+=$dart; $Dcaf{$c}+=$dcaf;
- $Dkb{$c}+=$dbb>>10; $Dino{$c}+=$dino;
- last if ($error);
- }
- }
- if ($Dart+$Dcaf) {
- printf " pass %d deleted %d arts, %d CAFs, %d kb\n",
- $pass, $Dart, $Dcaf, $Dkb if ($opt_v>1);
- $decrement-=$decrement>>2 if ($decrement>10*60);
- } else {
- $decrement+=$decrement>>1 if ($decrement<4*60*60);
- }
- }
- $Dkb=$Dart=$Dcaf=$Dino=0;
- foreach $c (@classes) {
- printf " class %3d: deleted %6d arts %6d CAFs %10d kb\n",
- $c, $Dart{$c}, $Dcaf{$c}, $Dkb{$c} if ($opt_v>1);
- $Dkb+=$Dkb{$c}; $Dart+=$Dart{$c}; $Dcaf+=$Dcaf{$c};
- }
- $tt=time-$NOW;
- printf " deleted %d articles, %d CAFs, %d kb in %d seconds\n",
- $Dart, $Dcaf, $Dkb, time-$NOW if ($opt_v>0);
- if ($tt>$opt_t*60) {
- printf STDERR "Round needed %d seconds, interval is %d\n",
- $tt, $opt_t*60;
- $tt=$opt_t*60;
- }
- }
- sleep $opt_t*60-$tt;
-}
-&finish(0);
-
-
-sub initclass
-{
- my $C=shift;
- if (!$S{"blocksize$;$C$;CAF"}) {
- # Determine filesystem blocksize
- # unfortunately no way in perl to statfs
- my $x=sprintf("%s/timecaf-%02x/test%d", $inn::spool, $C, $$);
- if (open(A, ">$x")) {
- print A "X" x 4096;
- close A;
- @S=stat $x;
- $#S>=12 || die "stat: $!";
- if ($S[12]) {
- $S{"blocksize$;$C$;CAF"}=$S[7]/$S[12];
- } else {
- $S{"blocksize$;$C$;CAF"}=512;
- warn "hack around broken stat blocksize";
- }
- unlink $x;
- }
- }
- return if ($S{"oldest$;$C"});
- my $oldest=time;
- $S{"oldest$;$C"}=$oldest;
- my $base=sprintf("%s/time-%02x", $inn::spool, $C);
- my $count=0;
- if (chdir $base) {
- printf "Finding oldest in class %d (%s)\n", $C, $base if ($opt_v>0);
- opendir(D0, ".");
- while ($d1=readdir(D0), defined($d1)) {
- $d1=~/^[0-9a-f][0-9a-f]$/ || next;
- chdir $d1;
- opendir(D1, ".") || next;
- while ($d2=readdir(D1), defined($d2)) {
- $d2=~/^[0-9a-f][0-9a-f]$/ || next;
- chdir $d2;
- opendir(D2, ".") || next;
- while ($a=readdir(D2), defined($a)) {
- $a=~/^\./ && next;
- @S=stat($a);
- $oldest=$S[9] if ($S[9]<$oldest);
- ++$count;
- }
- closedir D2;
- chdir "..";
- }
- closedir D1;
- chdir "..";
- }
- closedir D0;
- $ac+=$count;
- }
- $base=sprintf("%s/timecaf-%02x", $inn::spool, $C);
- if (chdir $base) {
- printf "Finding oldest in class %d (%s)\n", $C, $base if ($opt_v>0);
- opendir(D0, ".");
- while ($d1=readdir(D0), defined($d1)) {
- $d1=~/^[0-9a-f][0-9a-f]$/ || next;
- chdir $d1;
- opendir(D1, ".") || next;
- while ($a=readdir(D1), defined($a)) {
- $a=~/^\./ && next;
- @S=stat($a);
- $oldest=$S[9] if ($S[9]<$oldest);
- ++$count;
- }
- closedir D1;
- chdir "..";
- }
- closedir D0;
- $cc+=$count;
- }
- $S{"count$;$C"}=$count;
- $S{"oldest$;$C"}=$oldest;
-}
-
-sub worktime
-{
- my $C=shift;
- my $goal=shift;
- $goal&=0xFFFFFF00;
- printf " goal for class %d becomes %s\n", $C, &xtime($goal)
- if ($opt_v>2);
- if ($goal>$NOW-$opt_x) {
- printf " goal for class %d cut off\n", $C
- if ($opt_v>1);
- $error=1;
- return;
- }
- $dart=$dcaf=$dbb=$dino=0;
- $hdir=sprintf("time-%02x", $C);
- $cdir=sprintf("timecaf-%02x", $C);
- while (($_=$S{"work$;$C"})<$goal) {
- printf " running: %08x\n", $_ if ($opt_v>2);
- ($aa,$bb,$cc) = (($_>>24)&0xFF, ($_>>16)&0xFF, ($_>>8)&0xFF);
- $dir=sprintf("%s/%02x/%02x", $hdir, $bb, $cc);
- $pat=sprintf("[0-9a-f]{4}-%02x[0-9a-f]{2}", $aa);
- if (opendir(D, $dir)) {
- while ($_=readdir(D), defined($_)) {
- /^$pat$/ || next;
- $art="$dir/$_";
- @S=stat($art);
- if ($#S>=7) {
- if ($opt_N) {
- print " would delete $art" if ($opt_v>2);
- } else {
- print " deleting $art" if ($opt_v>2);
- unlink $art;
- }
- ++$dart; ++$dino;
- printf " %d kb\n", $S[7]>>10 if ($opt_v>2);
- $dbb+=$S[7];
- $needk{$dev{$hdir}}-=$S[7]>>10;
- $needi{$dev{$hdir}}--;
- }
- }
- } else {
- printf " (no dir %s)\n", $dir if ($opt_v>2);
- }
- $caf=sprintf("%s/%02x/%02x%02x.CF", $cdir, $bb, $aa, $cc);
- @S=stat($caf);
- if ($#S>=12) {
- if ($opt_N) {
- print " would delete $caf" if ($opt_v>2);
- } else {
- print " deleting $caf" if ($opt_v>2);
- unlink $caf;
- }
- $y=0;
- if (open(C, $caf)) {
- # try to find how much there is in the CAF
- sysread(C, $_, 16);
- @C=unpack("a4LLL", $_);
- if ($C[0] eq "CRMT") {
- $y=$C[3]-$C[1];
- $dart+=$y;
- }
- close C;
- }
- ++$dcaf; ++$dino;
- if ($S[12]) {
- $x=$S[12]*$S{"blocksize$;$C$;CAF"};
- } else {
- $x=$S[7];
- warn "hack around broken stat blocksize";
- }
- printf " %d arts %d kb\n", $y, $x>>10 if ($opt_v>2);
- $dbb+=$x;
- $needk{$dev{$cdir}}-=$x>>10;
- $needi{$dev{$cdir}}--;
- }
- $S{"work$;$C"}+=0x100;
- $S{"oldest$;$C"}=$S{"work$;$C"} unless ($opt_N);
- }
-}
-
-sub report
-{
- $NOW=time;
- my $cc=$S{"classes"};
- my $nt=$S{"normaltime"};
- unless ($cc && $nt) {
- print "Not initialized.\n";
- return;
- }
- printf "Version: %s (this: %s)\n", $S{"ID"}, $ID;
- printf "Started at: %s\n", &xtime($S{"inittime"}) if ($S{"inittime"});
- printf "Last run: %s\n", &xtime($S{"lastrun"}) if ($S{"lastrun"});
- printf "Classes: %s\n", $cc;
- foreach $c (split(/,/, $cc)) {
- printf "Class %d:\n", $c;
- #printf " Initial count %d articles\n", $S{"count$;$c"};
- printf " Oldest article: %s\n", &xtime($S{"oldest$;$c"});
- printf " Expiring at: %s\n", &xtime($S{"work$;$c"});
- printf " Normal time: %s\n", &xtime($NOW-$nt*$c/100);
- printf " Filesystem block size (CAF): %d\n", $S{"blocksize$;$c$;CAF"};
- }
-}
-
-sub wtime
-{
- my $t=shift;
- my @T=localtime($t);
- sprintf("%04d-%02d-%02d %02d:%02d",
- $T[5]+1900, $T[4]+1, $T[3], $T[2], $T[1]);
-}
-
-sub xtime
-{
- my $t=shift;
- if ($NOW-$t<0 || $NOW-$t>350*24*60*60) {
- return &wtime($t);
- }
- my @T=localtime($t);
- my @D=gmtime($NOW-$t);
- sprintf("%04d-%02d-%02d %02d:%02d (%dd %dh %dm)",
- $T[5]+1900, $T[4]+1, $T[3], $T[2], $T[1],
- $D[7], $D[2], $D[1]);
-}
-
-sub err
-{
- printf STDERR "%s\n", shift;
- &finish(0);
-}
-
-sub finish
-{
- untie(%S);
- unlink "$inn::innddir/thdexpire.pid";
- exit 0;
-}
-#-----------------------------------------------------------------------------
+++ /dev/null
-#!/usr/bin/perl
-$version = q$Id: tunefeed.in 4329 2001-01-14 13:47:52Z rra $;
-#
-# tunefeed -- Compare active files with a remote site to tune a feed.
-# Copyright 1998 by Russ Allbery <rra@stanford.edu>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the same terms as Perl itself.
-
-############################################################################
-# Site configuration
-############################################################################
-
-# A list of hierarchies in the Big Eight.
-%big8 = map { $_ => 1 } qw(comp humanities misc news rec sci soc talk);
-
-# A list of hierarchies that are considered global and not language
-# hierarchies.
-%global = map { $_ => 1 } qw(bionet bit biz borland ddn gnu gov ieee info
- linux k12 microsoft netscape tnn vmsnet);
-
-# The pattern matching local-only hierarchies (that we should disregard when
-# doing feed matching).
-%ignore = map { $_ => 1 } qw(clari control junk);
-
-
-############################################################################
-# Modules and declarations
-############################################################################
-
-require 5.003;
-
-use Getopt::Long qw(GetOptions);
-
-use strict;
-use vars qw(%big8 $days %global %ignore $threshold %traffic $version);
-
-
-############################################################################
-# Active file hashing and analysis
-############################################################################
-
-# Read in an active file, putting those groups into a hash where the key is
-# the name of the group and the value is always 1. If the optional third
-# argument is true, exclude any groups in the hierarchies listed in %local
-# and use this active file to store traffic information (in a rather
-# simple-minded fashion).
-sub hash {
- my ($file, $hash, $local) = @_;
- open (ACTIVE, $file) or die "$0: cannot open $file: $!\n";
- local $_;
- while (<ACTIVE>) {
- my ($group, $high, $low, $flags) = split;
- next if ($flags =~ /^=|^x/);
- my $hierarchy = (split (/\./, $group, 2))[0];
- next if ($local && $ignore{$hierarchy});
- $$hash{$group} = 1;
- $traffic{$group} = ($high - $low) / $days if $local;
- }
- close ACTIVE;
-}
-
-# Read in a file that gives traffic statistics. We assume it's in the form
-# group, whitespace, number of articles per day, and we just read it
-# directly into the %traffic hash.
-sub traffic {
- my ($file) = @_;
- open (TRAFFIC, $file) or die "$0: cannot open $file: $!\n";
- local $_;
- while (<TRAFFIC>) {
- my ($group, $traffic) = split;
- $traffic{$group} = $traffic;
- }
- close TRAFFIC;
-}
-
-# Pull off the first X nodes of a group name.
-sub prefix {
- my ($group, $count) = @_;
- my @group = split (/\./, $group);
- splice (@group, $count);
- join ('.', @group);
-}
-
-# Find the common hierarchical prefix of a list.
-sub common {
- my (@list) = @_;
- my @prefix = split (/\./, shift @list);
- local $_;
- while (defined ($_ = shift @list)) {
- my @group = split /\./;
- my $i;
- $i++ while ($prefix[$i] && $prefix[$i] eq $group[$i]);
- if ($i <= $#prefix) { splice (@prefix, $i) }
- }
- join ('.', @prefix);
-}
-
-# Given two lists, a list of groups that the remote site does have and a
-# list of groups that the remote site doesn't have, in a single hierarchy,
-# perform a smash. The object is to find the minimal pattern that expresses
-# just the groups they want. We're also given the common prefix of all the
-# groups in the have and exclude lists, and a flag indicating whether we're
-# coming in with a positive assumption (all groups sent unless excluded) or
-# a negative assumption (no groups sent unless added).
-sub smash {
- my ($have, $exclude, $top, $positive) = @_;
- my (@positive, @negative);
- my $level = ($top =~ tr/././) + 1;
-
- # Start with the positive assumption. We make copies of our @have and
- # @exclude arrays since we're going to be needing the virgin ones again
- # later for the negative assumption. If we're coming in with the
- # negative assumption, we have to add a wildcarded entry to switch
- # assumptions, and we also have to deal with the cases where there is a
- # real group at the head of the hierarchy.
- my @have = @$have;
- my @exclude = @$exclude;
- if ($top eq $have[0]) {
- shift @have;
- push (@positive, "$top*") unless $positive;
- } else {
- if ($top eq $exclude[0]) {
- if ($positive && $traffic{$top} > $threshold) {
- push (@positive, "!$top");
- }
- shift @exclude;
- }
- push (@positive, "$top.*") unless $positive;
- }
-
- # Now that we've got things started, keep in mind that we're set up so
- # that every group will be sent *unless* it's excluded. So we step
- # through the list of exclusions. The idea here is to pull together all
- # of the exclusions with the same prefix (going one level deeper into
- # the newsgroup names than we're currently at), and then find all the
- # groups with the same prefix that the remote site *does* want. If
- # there aren't any, then we can just exclude that whole prefix provided
- # that we're saving enough traffic to make it worthwhile (checked
- # against the threshold). If there are, and if the threshold still
- # makes it worthwhile to worry about this, we call this sub recursively
- # to compute the best pattern for that prefix.
- while (defined ($_ = shift @exclude)) {
- my ($prefix) = prefix ($_, $level + 1);
- my @drop = ($_);
- my @keep;
- my $traffic = $traffic{$_};
- while ($exclude[0] =~ /^\Q$prefix./) {
- $traffic += $traffic{$exclude[0]};
- push (@drop, shift @exclude);
- }
- $prefix = common (@drop);
- my $saved = $traffic;
- while (@have && $have[0] le $prefix) { shift @have }
- while ($have[0] =~ /^\Q$prefix./) {
- $traffic += $traffic{$have[0]};
- push (@keep, shift @have);
- }
- next unless $saved > $threshold;
- if (@keep) {
- $traffic{"$prefix*"} = $traffic;
- push (@positive, smash (\@keep, \@drop, $prefix, 1));
- } elsif (@drop == 1) {
- push (@positive, "!$_");
- } elsif ($prefix eq $_) {
- push (@positive, "!$prefix*");
- } else {
- push (@positive, "!$prefix.*");
- }
- }
-
- # Now we do essentially the same thing, but from the negative
- # perspective (adding a wildcard pattern as necessary to make sure that
- # we're not sending all groups and then finding the groups we are
- # sending and trying to smash them into minimal wildcard patterns).
- @have = @$have;
- @exclude = @$exclude;
- if ($top eq $exclude[0]) {
- shift @exclude;
- push (@negative, "!$top*") if $positive;
- } else {
- if ($top eq $have[0]) {
- push (@negative, $top) unless $positive;
- shift @have;
- }
- push (@negative, "!$top.*") if $positive;
- }
-
- # This again looks pretty much the same as what we do for the positive
- # case; the primary difference is that we have to make sure that we send
- # them every group that they want, so we still err on the side of
- # sending too much, rather than too little.
- while (defined ($_ = shift @have)) {
- my ($prefix) = prefix ($_, $level + 1);
- my @keep = ($_);
- my @drop;
- my $traffic = $traffic{$_};
- while ($have[0] =~ /^\Q$prefix./) {
- $traffic += $traffic{$have[0]};
- push (@keep, shift @have);
- }
- $prefix = common (@keep);
- while (@exclude && $exclude[0] le $prefix) { shift @exclude }
- my $saved = 0;
- while ($exclude[0] =~ /^\Q$prefix./) {
- $saved += $traffic{$exclude[0]};
- push (@drop, shift @exclude);
- }
- if (@drop && $saved > $threshold) {
- $traffic{"$prefix*"} = $traffic + $saved;
- push (@negative, smash (\@keep, \@drop, $prefix, 0));
- } elsif (@keep == 1) {
- push (@negative, $_);
- } elsif ($prefix eq $_) {
- push (@negative, "$prefix*");
- } else {
- push (@negative, "$prefix.*");
- }
- }
-
- # Now that we've built both the positive and negative case, we decide
- # which to return. We want the one that's the most succinct, and if
- # both descriptions are equally succinct, we return the negative case on
- # the grounds that it's likely to send less of what they don't want.
- (@positive < @negative) ? @positive : @negative;
-}
-
-
-############################################################################
-# Output
-############################################################################
-
-# We want to sort Big Eight ahead of alt.* ahead of global non-language
-# hierarchies ahead of regionals and language hierarchies.
-sub score {
- my ($hierarchy) = @_;
- if ($big8{$hierarchy}) { return 1 }
- elsif ($hierarchy eq 'alt') { return 2 }
- elsif ($global{$hierarchy}) { return 3 }
- else { return 4 }
-}
-
-# Our special sort routine for hierarchies. It calls score to get a
-# hierarchy score and sorts on that first.
-sub by_hierarchy {
- (score $a) <=> (score $b) || $a cmp $b;
-}
-
-# Given a reference to a list of patterns, output it in some reasonable
-# form. Currently, this is lines prefixed by a tab, with continuation lines
-# like INN likes to have in newsfeeds, 76 column margin, and with a line
-# break each time the hierarchy score changes.
-sub output {
- my ($patterns) = @_;
- my ($last, $line);
- for (@$patterns) {
- my ($hierarchy) = /^!?([^.]+)/;
- my $score = score $hierarchy;
- $line += 1 + length $_;
- if (($last && $score > $last) || $line > 76) {
- print ",\\\n\t";
- $line = 8 + length $_;
- } elsif ($last) {
- print ',';
- } else {
- print "\t";
- $line += 8;
- }
- print;
- $last = $score;
- }
- print "\n";
-}
-
-
-############################################################################
-# Main routine
-############################################################################
-
-# Clean up the name of this program for error messages.
-my $fullpath = $0;
-$0 =~ s%.*/%%;
-
-# Parse the command line. Our argument is the path to an active file (we
-# tell the difference by seeing if it contains a /).
-my ($help, $print_version);
-Getopt::Long::config ('bundling');
-GetOptions ('help|h' => \$help,
- 'days|d=i' => \$days,
- 'threshold|t=i' => \$threshold,
- 'version|v' => \$print_version) or exit 1;
-
-# Set a default for the minimum threshold traffic required to retain an
-# exclusion, and assume that active file differences represent one day of
-# traffic unless told otherwise.
-$threshold = (defined $threshold) ? $threshold : 250;
-$days ||= 1;
-
-# If they asked for our version number, abort and just print that.
-if ($print_version) {
- my ($program, $ver) = (split (' ', $version))[1,2];
- $program =~ s/,v$//;
- die "$program $ver\n";
-}
-
-# If they asked for help, give them the documentation.
-if ($help) {
- print "Feeding myself to perldoc, please wait....\n";
- exec ('perldoc', '-t', $fullpath) or die "$0: can't fork: $!\n";
-}
-
-# Hash the active files, skipping groups we ignore in the local one. Make
-# sure we have our two files listed first.
-unless (@ARGV == 2 || @ARGV == 3) {
- die "Usage: $0 [-hv] [-t <threshold>] <local> <remote> [<traffic>]\n";
-}
-my (%local, %remote);
-hash (shift, \%local, 1);
-hash (shift, \%remote);
-traffic (shift) if @ARGV;
-
-# Now, we analyze the differences between the two feeds. We're trying to
-# build a pattern of what *we* should send *them*, so stuff that's in
-# %remote and not in %local doesn't concern us. Rather, we're looking for
-# stuff that we carry that they don't, since that's what we'll want to
-# exclude from a full feed.
-my (%have, %exclude, %count, $have, $exclude, $positive);
-for (sort keys %local) {
- my ($hierarchy) = (split /\./);
- $count{$hierarchy}++;
- $traffic{"$hierarchy*"} += $traffic{$_};
- if ($remote{$_}) { push (@{$have{$hierarchy}}, $_); $have++ }
- else { push (@{$exclude{$hierarchy}}, $_); $exclude++ }
-}
-my @patterns;
-if ($have > $exclude * 4) {
- push (@patterns, "*");
- $positive = 1;
-}
-for (sort by_hierarchy keys %count) {
- if ($have{$_} && !$exclude{$_}) {
- push (@patterns, "$_.*") unless $positive;
- } elsif ($exclude{$_} && !$have{$_}) {
- push (@patterns, "!$_.*") if $positive;
- } else {
- push (@patterns, smash ($have{$_}, $exclude{$_}, $_, $positive));
- }
-}
-output (\@patterns);
-__END__
-
-
-############################################################################
-# Documentation
-############################################################################
-
-=head1 NAME
-
-tunefeed - Build a newsgroups pattern for a remote feed
-
-=head1 SYNOPSIS
-
-B<tunefeed> [B<-hv>] [B<-t> I<threshold>] [B<-d> I<days>] I<local>
-I<remote> [I<traffic>]
-
-=head1 DESCRIPTION
-
-Given two active files, B<tunefeed> generates an INN newsfeeds pattern for
-a feed from the first site to the second, that sends the second site
-everything in its active file carried by the first site but tries to
-minimize the number of rejected articles. It does this by noting
-differences between the two active files and then trying to generate
-wildcard patterns that cover the similarities without including much (or
-any) unwanted traffic.
-
-I<local> and I<remote> should be standard active files. You can probably
-get the active file of a site that you feed (provided they're running INN)
-by connecting to their NNTP port and typing C<LIST ACTIVE>.
-
-B<tunefeed> makes an effort to avoid complex patterns when they're of
-minimal gain. I<threshold> is the number of messages per day at which to
-worry about excluding a group; if a group the remote site doesn't want to
-receive gets below that number of messages per day, then that group is
-either sent or not sent depending on which choice results in the simplest
-(shortest) wildcard pattern. If you want a pattern that exactly matches
-what the remote site wants, use C<-t 0>.
-
-Ideally, B<tunefeed> likes to be given the optional third argument,
-I<traffic>, which points at a file listing traffic numbers for each group.
-The format of this file is a group name, whitespace, and then the number
-of messages per day it receives. Without such a file, B<tunefeed> will
-attempt to guess traffic by taking the difference between the high and low
-numbers in the active file as the amount of traffic in that group per day.
-This will almost always not be accurate, but it should at least be a
-ballpark figure. If you know approximately how many days of traffic the
-active file numbers represent, you can tell B<tunefeed> this information
-using the B<-d> flag.
-
-B<tunefeed>'s output will look something like:
-
- comp.*,humanities.classics,misc.*,news.*,rec.*,sci.*,soc.*,talk.*,\
- alt.*,!alt.atheism,!alt.binaries.*,!alt.nocem.misc,!alt.punk*,\
- !alt.sex*,!alt.video.dvd,\
- bionet.*,biz.*,gnu.*,vmsnet.*,\
- ba.*,!ba.jobs.agency,ca.*,sbay.*
-
-(with each line prefixed by a tab, and with standard INN newsfeeds
-continuation syntax). Due to the preferences of the author, it will also
-be sorted as Big Eight, then alt.*, then global non-language hierarchies,
-then regional and language hierarchies.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-h>, B<--help>
-
-Print out this documentation (which is done simply by feeding the script
-to C<perldoc -t>.
-
-=item B<-v>, B<--version>
-
-Print out the version of B<tunefeed> and exit.
-
-=item B<-d> I<days>, B<--days>=I<days>
-
-Assume that the difference between the high and low numbers in the active
-file represent I<days> days of traffic.
-
-=item B<-t> I<threshold>, B<--threshold>=I<threshold>
-
-Allow any group with less than I<threshold> articles per day in traffic to
-be either sent or not sent depending on which choice makes the wildcard
-patterns simpler. If a threshold isn't specified, the default value is
-250.
-
-=back
-
-=head1 BUGS
-
-This program takes a long time to run, not to mention being a nasty memory
-hog. The algorithm is thorough, but definitely not very optimized, and
-isn't all that friendly.
-
-Guessing traffic from active file numbers is going to produce very skewed
-results on sites with expiration policies that vary widely by group.
-
-There is no way to optimize for size in avoiding rejections, only quantity
-of articles.
-
-There should be a way to turn off the author's idiosyncratic ordering of
-hierarchies, or to specify a different ordering, without editing this
-script.
-
-This script should attempt to retrieve the active file from the remote
-site automatically if so desired.
-
-This script should be able to be given some existing wildcard patterns and
-take them into account when generating new ones.
-
-=head1 CAVEATS
-
-Please be aware that your neighbor's active file may not accurately
-represent the groups they wish to receive from you. As with everything,
-choices made by automated programs like this one should be reviewed by a
-human and the remote site should be notified, and if they have sent
-explicit patterns, those should be honored instead. I definitely do *not*
-recommend running this program on any sort of automated basis.
-
-=head1 AUTHOR
-
-Russ Allbery E<lt>rra@stanford.eduE<gt>
-
-=cut
+++ /dev/null
-## $Id: Makefile 6806 2004-05-18 01:18:57Z rra $
-
-include ../Makefile.global
-
-top = ..
-
-ALL = controlbatch controlchan docheckgroups gpgverify perl-nocem \
- pgpverify signcontrol
-
-MAN = ../doc/man/perl-nocem.8 ../doc/man/pgpverify.1
-
-all: $(ALL)
-
-install: all
- for F in $(ALL) ; do \
- $(CP_XPUB) $$F $D$(PATHBIN)/$$F ; \
- done
- for M in modules/*.pl ; do \
- $(CP_RPUB) $$M $D$(PATHCONTROL)/`basename $$M` ; \
- done
-
-man: $(MAN)
-
-clean clobber distclean:
- rm -f $(ALL)
-
-profiled: all
-depend:
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Build rules.
-
-FIX = $(FIXSCRIPT)
-
-controlbatch: controlbatch.in $(FIX) ; $(FIX) controlbatch.in
-controlchan: controlchan.in $(FIX) ; $(FIX) controlchan.in
-docheckgroups: docheckgroups.in $(FIX) ; $(FIX) docheckgroups.in
-gpgverify: gpgverify.in $(FIX) ; $(FIX) gpgverify.in
-perl-nocem: perl-nocem.in $(FIX) ; $(FIX) perl-nocem.in
-pgpverify: pgpverify.in $(FIX) ; $(FIX) pgpverify.in
-signcontrol: signcontrol.in $(FIX) ; $(FIX) -i signcontrol.in
-
-../doc/man/perl-nocem.8: perl-nocem
- $(POD2MAN) -s 8 $? > $@
-
-../doc/man/pgpverify.1: pgpverify
- $(POD2MAN) -s 1 $? > $@
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-########################################################################
-# controlbatch - Run controlchan against a batch file.
-#
-# Command usage: controlbatch [feedsite batchfile]
-# Defaults are feedsite: controlchan!, batchfile: ${BATCH}/controlchan!
-########################################################################
-#
-# This script will run controlchan against a batch file. You can use
-# it to clear occasional backlogs while running controls from a
-# channel, or even skip the channel and run control messages as a file
-# feed.
-#
-########################################################################
-#
-# If you're doing the channel thing, you might want to put something
-# like this in your crontab to do a cleanup in the wee hours:
-#
-# 00 04 * * * @prefix@/bin/controlbatch
-#
-########################################################################
-#
-# If you would rather skip the channel and just process controls each
-# hour in a batch, use this newsfeeds entry instead of the "stock"
-# version:
-#
-# controlchan!\
-# :!*,control,control.*,!control.cancel\
-# :Tf,Wnsm:
-#
-# And, a crontab entry something like this:
-#
-# 30 * * * * @prefix@/bin/controlbatch
-#
-########################################################################
-
-batchlock="${LOCKS}/LOCK.controlbatch"
-mypid=$$
-
-# A concession to INN 1.x
-if [ me${PATHBIN}ow = meow ] ; then
- PATHBIN=${NEWSBIN}
- export PATHBIN
-fi
-
-# See if we have no arguments and should use the defaults. If there are
-# arguments, make sure we have enough to attempt something useful.
-if [ me${1}ow != meow ] ; then
- if [ me${2}ow = meow ] ; then
- echo "Usage: ${0} [feedsite batchfile]" >&2
- exit 0
- else
- feedsite=${1}
- batchfile=${2}
- fi
-else
- feedsite=controlchan\!
- batchfile=controlchan\!
-fi
-
-# Check if any other copies of controlbatch are running. If we are not
-# alone, give up here and now.
-${PATHBIN}/shlock -p $mypid -f ${batchlock} || exit 0
-
-cd ${BATCH}
-
-if [ -s ${batchfile}.work ] ; then
- cat ${batchfile}.work >>${batchfile}.doit
- rm -f ${batchfile}.work
-fi
-
-if [ -s ${batchfile} ] ; then
- mv ${batchfile} ${batchfile}.work
- if ${PATHBIN}/ctlinnd -s -t30 flush ${feedsite} ; then
- cat ${batchfile}.work >>${batchfile}.doit
- rm -f ${batchfile}.work
- fi
-fi
-
-if [ -s ${batchfile}.doit ] ; then
- ${PATHBIN}/controlchan \
- < ${batchfile}.doit >> ${MOST_LOGS}/controlbatch.log 2>&1
- # if you want extra assurance that nothing gets lost...
- # cat ${batchfile}.doit >> ${batchfile}.done
- rm -f ${batchfile}.doit
-fi
-
-rm -f ${batchlock}
+++ /dev/null
-#! /usr/bin/perl -w
-require "/usr/local/news/lib/innshellvars.pl";
-
-## $Id: controlchan.in 7591 2006-11-22 07:20:46Z eagle $
-##
-## Channel feed program to route control messages to an appropriate handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-##
-## Give this program its own newsfeed. Make sure that you've created
-## the newsgroup control.cancel so that you don't have to scan through
-## cancels, which this program won't process anyway.
-##
-## Make a newsfeeds entry like this:
-##
-## controlchan!\
-## :!*,control,control.*,!control.cancel\
-## :Tc,Wnsm\
-## :@prefix@/bin/controlchan
-
-require 5.004_03;
-use strict;
-
-delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
-
-# globals
-my ($cachedctl, $curmsgid);
-my $lastctl = 0;
-my $use_syslog = 0;
-my $debug = 0;
-
-# setup logging ###########################################################
-# do not log to syslog if stderr is connected to a console
-if (not -t 2) {
- eval { require INN::Syslog; import INN::Syslog; $use_syslog = 1; };
- eval { require Sys::Syslog; import Sys::Syslog; $use_syslog = 1; }
- unless $use_syslog;
-}
-
-if ($use_syslog) {
- eval "sub Sys::Syslog::_PATH_LOG { '/dev/log' }" if $^O eq 'dec_osf';
- Sys::Syslog::setlogsock('unix') if $^O =~ /linux|dec_osf|freebsd|darwin/;
- openlog('controlchan', 'pid', $inn::syslog_facility);
-}
-logmsg('starting');
-
-# load modules from the control directory #################################
-opendir(CTL, $inn::controlprogs)
- or logdie("Cannot open $inn::controlprogs: $!", 'crit');
-foreach (readdir CTL) {
- next if not /^([a-z\.]+\.pl)$/ or not -f "$inn::controlprogs/$_";
- eval { require "$inn::controlprogs/$1" };
- if ($@) {
- $@ =~ s/\n/ /g;
- logdie($@, 'crit');
- }
- logmsg("loaded $inn::controlprogs/$1", 'debug');
-}
-closedir CTL;
-
-# main loop ###############################################################
-while (<STDIN>) {
- chop;
- my ($token, $sitepath, $msgid) = split(/\s+/, $_);
- next if not defined $token;
- $sitepath ||= '';
- $curmsgid = $msgid || '';
-
- my $artfh = open_article($token);
- next if not defined $artfh;
-
- # suck in headers and body, normalize the strange ones
- my (@headers, @body, %hdr);
- if (not parse_article($artfh, \@headers, \@body, \%hdr)) {
- close $artfh;
- next;
- }
- close $artfh or logdie('sm died with status ' . ($? >> 8));
-
- next if not exists $hdr{control};
-
- $curmsgid = $hdr{'message-id'};
- my $sender = cleanaddr($hdr{sender} || $hdr{from});
- my $replyto = cleanaddr($hdr{'reply-to'} || $hdr{from});
-
- my (@progparams, $progname);
- if ($hdr{control} =~ /\s/) {
- $hdr{control} =~ /^(\S+)\s+(.+)?/;
- $progname = lc $1;
- @progparams = split(/\s+/, lc $2) if $2;
- } else {
- $progname = lc $hdr{control};
- }
-
- next if $progname eq 'cancel';
-
- if ($progname !~ /^([a-z]+)$/) {
- logmsg("Naughty control in article $curmsgid ($progname)");
- next;
- }
- $progname = $1;
-
- # Do we want to process the message? Let's check the permissions.
- my ($action, $logname, $newsgrouppats) =
- ctlperm($progname, $sender, $progparams[0],
- $token, \@headers, \@body);
-
- next if $action eq 'drop';
-
- if ($action eq '_pgpfail') {
- my $type = '';
- if ($progname and $progname eq 'newgroup') {
- if ($progparams[1] and $progparams[1] eq 'moderated') {
- $type = 'm ';
- } else {
- $type = 'y ';
- }
- }
- logmsg("skipping $progname $type$sender"
- . "(pgpverify failed) in $curmsgid");
- next;
- }
-
- # used by checkgroups. Convert from perl regexp to grep regexp.
- if (local $_ = $newsgrouppats) {
- s/\$\|/|/g;
- s/[^\\]\.[^*]/?/g;
- s/\$//;
- s/\.\*/*/g;
- s/\\([\$\+\.])/$1/g;
- $progparams[0] = $_;
- }
-
- # find the appropriate module and call it
- my $subname = "control_$progname";
- my $subfind = \&$subname;
- if (not defined &$subfind) {
- if ($logname) {
- logger($logname, "Unknown control message by $sender",
- \@headers, \@body);
- } else {
- logmsg("Unknown \"$progname\" control by $sender");
- }
- next;
- }
-
- my $approved = $hdr{approved} ? 1 : 0;
- logmsg("$subname, " . join(' ', @progparams)
- . " $sender $replyto $token, $sitepath, $action"
- . ($logname ? "=$logname" : '') .", $approved");
-
- &$subfind(\@progparams, $sender, $replyto, $sitepath,
- $action, $logname, $approved, \@headers, \@body);
-}
-
-closelog() if $use_syslog;
-exit 0;
-
-print $inn::most_logs.$inn::syslog_facility.$inn::mta.
- $inn::newsmaster.$inn::locks; # lint food
-
-# misc functions ##########################################################
-sub parse_article {
- my ($artfh, $headers, $body, $hdr) = @_;
- my $h;
- my %uniquehdr = map { $_ => 1 } qw(date followup-to from message-id
- newsgroups path reply-to subject sender);
-
- while (<$artfh>) {
- s/\r?\n$//;
- last if /^$/;
- push @$headers, $_;
- if (/^(\S+):\s+(.+)/) {
- $h = lc $1;
- if (exists $hdr->{$h}) {
- if (exists $uniquehdr{$h}) {
- logmsg("Multiple $1 headers in article $curmsgid");
- return 0;
- }
- $hdr->{$h} .= ' ' . $2;
- } else {
- $hdr->{$h} = $2;
- }
- next;
- } elsif (/^\s+(.+)/) {
- if (defined $h) {
- $hdr->{$h} .= ' ' . $1;
- next;
- }
- }
- logmsg("Broken headers in article $curmsgid");
- return 0;
- }
-
- # article is empty or does not exist
- return 0 if not @$headers;
-
- chop (@$body = <$artfh>);
- return 1;
-}
-
-# Strip a mail address, innd-style.
-sub cleanaddr {
- local $_ = shift;
- s/(\s+)?\(.*\)(\s+)?//g;
- s/.*<(.*)>.*/$1/;
- s/[^-a-zA-Z0-9+_.@%]/_/g; # protect MTA
- s/^-/_/; # protect MTA
- return $_;
-}
-
-# Read and cache control.ctl.
-sub readctlfile {
- my $mtime = (stat($inn::ctlfile))[9];
- return $cachedctl if $lastctl == $mtime; # mtime has not changed.
- $lastctl = $mtime;
-
- my @ctllist;
- open(CTLFILE, $inn::ctlfile)
- or logdie("Cannot open $inn::ctlfile: $!", 'crit');
- while (<CTLFILE>) {
- chop;
- # Not a comment or blank? Convert wildmat to regex
- next if not /^(\s+)?[^\#]/ or /^$/;
- if (not /:(?:doit|doifarg|drop|log|mail|verify-.*)(?:=.*)?$/) {
- s/.*://;
- logmsg("$_ is not a valid action for control.ctl", 'err');
- next;
- }
- # Convert to a : separated list of regexps
- s/^all:/*:/i;
- s/([\$\+\.])/\\$1/g;
- s/\*/.*/g;
- s/\?/./g;
- s/(.*)/^$1\$/;
- s/:/\$:^/g;
- s/\|/\$|^/g;
- push @ctllist, $_;
- }
- close CTLFILE;
-
- logmsg('warning: control.ctl is empty!', 'err') if not @ctllist;
- return $cachedctl = [ reverse @ctllist ];
-}
-
-# Parse a control message's permissions.
-sub ctlperm {
- my ($type, $sender, $newsgroup, $token, $headers, $body) = @_;
-
- my $action = 'drop'; # default
- my ($logname, $hier);
-
- # newgroup and rmgroup require newsgroup names; check explicitly for that
- # here and return drop if the newsgroup is missing (to avoid a bunch of
- # warnings from undefined values later on in permission checking).
- if ($type eq 'newgroup' or $type eq 'rmgroup') {
- unless ($newsgroup) {
- return ('drop', undef, undef);
- }
- }
-
- my $ctllist = readctlfile();
- foreach (@$ctllist) {
- my @ctlline = split /:/;
- # 0: type 1: from@addr 2: group.* 3: action
- if ($type =~ /$ctlline[0]/ and $sender =~ /$ctlline[1]/i and
- ($type !~ /(?:new|rm)group/ or $newsgroup =~ /$ctlline[2]/)) {
- $action = $ctlline[3];
- $action =~ s/\^(.+)\$/$1/;
- $action =~ s/\\//g;
- $hier = $ctlline[2] if $type eq 'checkgroups';
- last;
- }
- }
-
- ($action, $logname) = split(/=/, $action);
-
- if ($action =~ /^verify-(.+)/) {
- my $keyowner = $1;
- if ($inn::pgpverify and $inn::pgpverify =~ /^(?:true|on|yes)$/i) {
- my $pgpresult = defined &local_pgpverify ?
- local_pgpverify($token, $headers, $body) : pgpverify($token);
- if ($keyowner eq $pgpresult) {
- $action = 'doit';
- } else {
- $action = '_pgpfail';
- }
- } else {
- $action = 'mail';
- }
- }
-
- return ($action, $logname, $hier);
-}
-
-# Write stuff to a log or send mail to the news admin.
-sub logger {
- my ($logfile, $message, $headers, $body) = @_;
-
- if ($logfile eq 'mail') {
- my $mail = sendmail($message);
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n" . join ('', map { s/^~/~~/; "$_\n" } @$body)
- if $body;
- close $mail or logdie("Cannot send mail: $!");
- return;
- }
-
- if ($logfile =~ /^([^.\/].*)/) {
- $logfile = $1;
- } else {
- logmsg("Invalid log file: $logfile", 'err');
- $logfile = 'control';
- }
-
- $logfile = "$inn::most_logs/$logfile.log" unless $logfile =~ /^\//;
- my $lockfile = $logfile;
- $lockfile =~ s#.*/##;
- $lockfile = "$inn::locks/LOCK.$lockfile";
- shlock($lockfile);
-
- open(LOGFILE, ">>$logfile") or logdie("Cannot open $logfile: $!");
- print LOGFILE "$message\n";
- foreach (@$headers, '', @$body, '') {
- print LOGFILE " $_\n";
- }
- close LOGFILE;
- unlink $lockfile;
-}
-
-# write to syslog or errlog
-sub logmsg {
- my ($msg, $lvl) = @_;
-
- return if $lvl and $lvl eq 'debug' and not $debug;
- if ($use_syslog) {
- syslog($lvl || 'notice', '%s', $msg);
- } else {
- print STDERR (scalar localtime) . ": $msg\n";
- }
-}
-
-# log a message and then die
-sub logdie {
- my ($msg, $lvl) = @_;
-
- $msg .= " ($curmsgid)" if $curmsgid;
- logmsg($msg, $lvl || 'err');
- exit 1;
-}
-
-# wrappers executing external programs ####################################
-
-# Open an article appropriately to our storage method (or lack thereof).
-sub open_article {
- my $token = shift;
-
- if ($token =~ /^\@.+\@$/) {
- my $pid = open(ART, '-|');
- logdie('Cannot fork: ' . $!) if $pid < 0;
- if ($pid == 0) {
- exec("$inn::newsbin/sm", '-q', $token) or
- logdie("Cannot exec sm: $!");
- }
- return *ART;
- } else {
- return *ART if open(ART, $token);
- logmsg("Cannot open article $token: $!");
- }
- return undef;
-}
-
-sub pgpverify {
- my $token = shift;
-
- if ($token =~ /^\@.+\@$/) {
- open(PGPCHECK, "$inn::newsbin/sm -q $token "
- . "| $inn::newsbin/pgpverify |") or goto ERROR;
- } else {
- open(PGPCHECK, "$inn::newsbin/pgpverify < $token |") or goto ERROR;
- }
- my $pgpresult = <PGPCHECK>;
- close PGPCHECK or goto ERROR;
- $pgpresult ||= '';
- chop $pgpresult;
- return $pgpresult;
-ERROR:
- logmsg("pgpverify failed: $!", 'debug');
- return '';
-}
-
-sub ctlinnd {
- my ($cmd, @args) = @_;
-
- my $st = system("$inn::newsbin/ctlinnd", '-s', $cmd, @args);
- logdie('Cannot run ctlinnd: ' . $!) if $st == -1;
- logdie('ctlinnd returned status ' . ($st & 255)) if $st > 0;
-}
-
-sub shlock {
- my $lockfile = shift;
-
- my $locktry = 0;
- while ($locktry < 60) {
- if (system("$inn::newsbin/shlock", '-p', $$, '-f', $lockfile) == 0) {
- return 1;
- }
- $locktry++;
- sleep 2;
- }
-
- my $lockreason;
- if (open(LOCKFILE, $lockfile)) {
- $lockreason = 'held by ' . (<LOCKFILE> || '?');
- close LOCKFILE;
- } else {
- $lockreason = $!;
- }
- logdie("Cannot get lock $lockfile: $lockreason");
- return undef;
-}
-
-# If $body is not defined, returns a file handle which must be closed.
-# Don't forget checking the return value of close().
-# $addresses may be a scalar or a reference to a list of addresses.
-# If not defined, $inn::newsmaster is the default.
-# parts of this code stolen from innmail.pl
-sub sendmail {
- my ($subject, $addresses, $body) = @_;
- $addresses = [ $addresses || $inn::newsmaster ] if not ref $addresses;
- $subject ||= '(no subject)';
-
- # fix up all addresses
- my @addrs = map { s#[^-a-zA-Z0-9+_.@%]##g; $_ } @$addresses;
-
- my $sm = $inn::mta;
- if ($sm =~ /%s/) {
- $sm = sprintf($sm, join(' ', @addrs));
- } else {
- $sm .= ' ' . join(' ', @addrs);
- }
-
- # fork and spawn the MTA whitout using the shell
- my $pid = open(MTA, '|-');
- logdie('Cannot fork: ' . $!) if $pid < 0;
- if ($pid == 0) {
- exec(split(/\s+/, $sm)) or logdie("Cannot exec $sm: $!");
- }
-
- print MTA 'To: ' . join(",\n\t", @addrs) . "\nSubject: $subject\n\n";
- return *MTA if not defined $body;
- $body = join("\n", @$body) if ref $body eq 'ARRAY';
- print MTA $body . "\n";
- close MTA or logdie("Execution of $sm failed: $!");
- return 1;
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 7743 $
-## Script to execute checkgroups text; results to stdout.
-
-T=${TMPDIR}
-
-cat /dev/null >${T}/$$out
-
-## Copy the article without headers, append local newsgroups.
-cat >${T}/$$msg
-test -f ${LOCALGROUPS} && cat ${LOCALGROUPS} >>${T}/$$msg
-
-## Get the top-level newsgroup names from the message and turn it into
-## an egrep pattern.
-PATS=`${SED} <${T}/$$msg \
- -e 's/[ ].*//' -e 's/\..*//' \
- -e 's/^!//' -e '/^$/d' \
- -e 's/^/^/' -e 's/$/[. ]/' \
- | sort -u \
- | (tr '\012' '|' ; echo '' )\
- | ${SED} -e 's/|$//'`
-
-${EGREP} "${PATS}" ${ACTIVE} | ${EGREP} "${1:-.}" | ${SED} 's/ .*//' | sort >${T}/$$active
-${EGREP} "${PATS}" ${T}/$$msg | ${EGREP} "${1:-.}" | ${SED} 's/[ ].*//' | sort >${T}/$$newsgrps
-
-comm -13 ${T}/$$active ${T}/$$newsgrps >${T}/$$missing
-comm -23 ${T}/$$active ${T}/$$newsgrps >${T}/$$remove
-
-${EGREP} "${PATS}" ${ACTIVE} | ${EGREP} "${1:-.}" | ${SED} -n '/ m$/s/ .*//p' | sort >${T}/$$amod.all
-${EGREP} "${PATS}" ${T}/$$msg | ${EGREP} "${1:-.}" | ${SED} 's/\r\?$//' |
-${SED} -n '/(Moderated)$/s/[ ].*//p' | sort >${T}/$$ng.mod
-
-comm -12 ${T}/$$missing ${T}/$$ng.mod >${T}/$$add.mod
-comm -23 ${T}/$$missing ${T}/$$ng.mod >${T}/$$add.unmod
-cat ${T}/$$add.mod ${T}/$$add.unmod >>${T}/$$add
-
-comm -23 ${T}/$$amod.all ${T}/$$remove >${T}/$$amod
-comm -13 ${T}/$$ng.mod ${T}/$$amod >${T}/$$ismod
-comm -23 ${T}/$$ng.mod ${T}/$$amod >${T}/$$nm.all
-comm -23 ${T}/$$nm.all ${T}/$$add >${T}/$$notmod
-
-${EGREP} "${PATS}" ${NEWSGROUPS} | ${EGREP} "${1:-.}" | ${SED} 's/[ ]\+/ /' | sort >${T}/$$localdesc
-${EGREP} "${PATS}" ${T}/$$msg | ${EGREP} "${1:-.}" | ${SED} 's/\r\?$//' |
-${SED} 's/[ ]\+/ /' | sort >${T}/$$newdesc
-
-if ! (head -1 ${T}/$$newdesc | egrep " [[:digit:]]+ [[:digit:]]+ " > /dev/null) ; then
- comm -13 ${T}/$$localdesc ${T}/$$newdesc >${T}/$$missingdesc
- comm -23 ${T}/$$localdesc ${T}/$$newdesc >${T}/$$removedesc
-fi
-
-if [ -s ${T}/$$remove ] ; then
- (
- echo "# The following newsgroups are non-standard."
- ${SED} "s/^/# /" ${T}/$$remove
- echo "# You can remove them by executing the commands:"
- for i in `cat ${T}/$$remove` ; do
- echo " ${PATHBIN}/ctlinnd rmgroup $i"
- ${EGREP} "^$i " ${NEWSGROUPS} >>${T}/$$ngdel
- done
- echo ''
- ) >>${T}/$$out
-fi
-
-if [ -s ${T}/$$add ] ; then
- (
- echo "# The following newsgroups were missing and should be added."
- ${SED} "s/^/# /" ${T}/$$add
- echo "# You can do this by executing the command(s):"
- for i in `cat ${T}/$$add.unmod` ; do
- echo " ${PATHBIN}/ctlinnd newgroup $i y ${FROM}"
- ${EGREP} "^$i " ${T}/$$msg >>${T}/$$ngadd
- done
- for i in `cat ${T}/$$add.mod` ; do
- echo " ${PATHBIN}/ctlinnd newgroup $i m ${FROM}"
- ${EGREP} "^$i " ${T}/$$msg >>${T}/$$ngadd
- done
- echo ''
- ) >>${T}/$$out
-fi
-
-if [ -s ${T}/$$ismod ] ; then
- (
- echo "# The following groups are incorrectly marked as moderated:"
- ${SED} "s/^/# /" ${T}/$$ismod
- echo "# You can correct this by executing the following:"
- for i in `cat ${T}/$$ismod` ; do
- echo " ${PATHBIN}/ctlinnd changegroup $i y"
- ${EGREP} "^$i " ${T}/$$msg >>${T}/$$ngchng
- done
- echo ''
- ) >>${T}/$$out
-fi
-
-if [ -s ${T}/$$notmod ] ; then
- (
- echo "# The following groups are incorrectly marked as unmoderated:"
- ${SED} "s/^/# /" ${T}/$$notmod
- echo "# You can correct this by executing the following:"
- for i in `cat ${T}/$$notmod` ;do
- echo " ${PATHBIN}/ctlinnd changegroup $i m"
- ${EGREP} "^$i " ${T}/$$msg >>${T}/$$ngchng
- done
- echo ''
- ) >>${T}/$$out
-fi
-
-if [ -s ${T}/$$removedesc ] ; then
- (
- echo "# The following newsgroups descriptions are obsolete."
- ${SED} "s/^/# /" ${T}/$$removedesc
- echo "# You can remove them by editing ${NEWSGROUPS}."
- echo ''
- ) >>${T}/$$out
-fi
-
-if [ -s ${T}/$$missingdesc ] ; then
- (
- echo "# The following newsgroups descriptions were missing and should be added."
- ${SED} "s/^/# /" ${T}/$$missingdesc
- echo "# You can add them by editing ${NEWSGROUPS}."
- echo ''
- ) >>${T}/$$out
-fi
-
-
-test -s ${T}/$$out && {
- cat ${T}/$$out
- echo 'exit # so you can feed this message into the shell'
- echo "# And remember to update ${NEWSGROUPS}."
- test -s ${T}/$$ngdel && {
- echo "# Remove these lines:"
- ${SED} "s/^/# /" ${T}/$$ngdel
- echo ''
- }
- test -s ${T}/$$ngadd && {
- echo "# Add these lines:"
- ${SED} "s/^/# /" ${T}/$$ngadd
- echo ''
- }
- test -s ${T}/$$ngchng && {
- echo "# Change these lines:"
- ${SED} "s/^/# /" ${T}/$$ngchng
- echo ''
- }
-}
-
-rm -f ${T}/$$*
+++ /dev/null
-#!/usr/bin/perl -w
-require '/etc/news/innshellvars.pl';
-
-# written April 1996, tale@isc.org (David C Lawrence)
-# mostly rewritten 2001-03-21 by Marco d'Itri <md@linux.it>
-#
-# requirements:
-# - GnuPG
-# - perl 5.004_03 and working Sys::Syslog
-# - syslog daemon
-#
-# There is no locking because gpg is supposed to not need it and controlchan
-# will serialize control messages processing anyway.
-
-require 5.004_03;
-use strict;
-
-# if you keep your keyring somewhere that is not the default used by gpg,
-# change the location below.
-my $keyring;
-if ($inn::newsetc && -d "$inn::newsetc/pgp") {
- $keyring = $inn::newsetc . '/pgp/pubring.gpg';
-}
-
-# If you have INN and the script is able to successfully include your
-# innshellvars.pl file, the value of the next two variables will be
-# overridden.
-my $tmpdir = '/var/log/news/';
-my $syslog_facility = 'news';
-
-# 1: print PGP output
-my $debug = 0;
-#$debug = 1 if -t 1;
-
-### Exit value:
-### 0 good signature
-### 1 no signature
-### 2 unknown signature
-### 3 bad signature
-### 255 problem not directly related to gpg analysis of signature
-
-##############################################################################
-################ NO USER SERVICEABLE PARTS BELOW THIS COMMENT ################
-##############################################################################
-my $tmp = ($inn::pathtmp ? $inn::pathtmp : $tmpdir) . "/pgp$$";
-$syslog_facility = $inn::syslog_facility if $inn::syslog_facility;
-
-my $nntp_format = 0;
-$0 =~ s#^.*/##; # trim /path/to/prog to prog
-
-die "Usage: $0 < message\n" if $#ARGV != -1;
-
-# Path to gpg binary
-my $gpg;
-if ($inn::gpgv) {
- $gpg = $inn::gpgv;
-} else {
- foreach (split(/:/, $ENV{PATH}), qw(/usr/local/bin /opt/gnu/bin)) {
- if (-x "$_/gpgv") {
- $gpg = "$_/gpgv"; last;
- }
- }
-}
-fail('cannot find the gpgv binary') if not $gpg;
-
-# this is, by design, case-sensitive with regards to the headers it checks.
-# it's also insistent about the colon-space rule.
-my ($label, $value, %dup, %header);
-while (<STDIN>) {
- # if a header line ends with \r\n, this article is in the encoding
- # it would be in during an NNTP session. some article storage
- # managers keep them this way for efficiency.
- $nntp_format = /\r\n$/ if $. == 1;
- s/\r?\n$//;
-
- last if /^$/;
- if (/^(\S+):[ \t](.+)/) {
- ($label, $value) = ($1, $2);
- $dup{$label} = 1 if $header{$label};
- $header{$label} = $value;
- } elsif (/^\s/) {
- fail("non-header at line $.: $_") unless $label;
- $header{$label} .= "\n$_";
- } else {
- fail("non-header at line $.: $_");
- }
-}
-
-my $pgpheader = 'X-PGP-Sig';
-$_ = $header{$pgpheader};
-exit 1 if not $_; # no signature
-
-# the $sep value means the separator between the radix64 signature lines
-# can have any amount of spaces or tabs, but must have at least one space
-# or tab, if there is a newline then the space or tab has to follow the
-# newline. any number of newlines can appear as long as each is followed
-# by at least one space or tab. *phew*
-my $sep = "[ \t]*(\n?[ \t]+)+";
-# match all of the characters in a radix64 string
-my $r64 = '[a-zA-Z0-9+/]';
-fail("$pgpheader not in expected format")
- unless /^(\S+)$sep(\S+)(($sep$r64{64})+$sep$r64+=?=?$sep=$r64{4})$/;
-
-my ($version, $signed_headers, $signature) = ($1, $3, $4);
-$signature =~ s/$sep/\n/g;
-
-my $message = "-----BEGIN PGP SIGNED MESSAGE-----\n\n"
- . "X-Signed-Headers: $signed_headers\n";
-
-foreach $label (split(',', $signed_headers)) {
- fail("duplicate signed $label header, can't verify") if $dup{$label};
- $message .= "$label: ";
- $message .= $header{$label} if $header{$label};
- $message .= "\n";
-}
-$message .= "\n"; # end of headers
-
-while (<STDIN>) { # read body lines
- if ($nntp_format) {
- # check for end of article; some news servers (eg, Highwind's
- # "Breeze") include the dot-CRLF of the NNTP protocol in the
- # article data passed to this script
- last if $_ eq ".\r\n";
-
- # remove NNTP encoding
- s/^\.\./\./;
- s/\r\n$/\n/;
- }
-
- s/^-/- -/; # pgp quote ("ASCII armor") dashes
- $message .= $_;
-}
-
-$message .=
- "\n-----BEGIN PGP SIGNATURE-----\n" .
- "Version: $version\n" .
- $signature .
- "\n-----END PGP SIGNATURE-----\n";
-
-open(TMP, ">$tmp") or fail("open $tmp: $!");
-print TMP $message;
-close TMP or errmsg("close $tmp: $!");
-
-my $opts = '--quiet --status-fd=1 --logger-fd=1';
-$opts .= " --keyring=$keyring" if $keyring;
-
-open(PGP, "$gpg $opts $tmp |") or fail("failed to execute $gpg: $!");
-
-undef $/;
-$_ = <PGP>;
-
-unlink $tmp or errmsg("unlink $tmp: $!");
-
-if (not close PGP) {
- if ($? >> 8) {
- my $status = $? >> 8;
- errmsg("gpg exited status $status") if $status > 1;
- } else {
- errmsg('gpg died on signal ' . ($? & 255));
- }
-}
-
-print STDERR $_ if $debug;
-
-my $ok = 255; # default exit status
-my $signer;
-if (/^\[GNUPG:\]\s+GOODSIG\s+\S+\s+(\S+)/m) {
- $ok = 0;
- $signer = $1;
-} elsif (/^\[GNUPG:\]\s+NODATA/m or /^\[GNUPG:\]\s+UNEXPECTED/m) {
- $ok = 1;
-} elsif (/^\[GNUPG:\]\s+NO_PUBKEY/m) {
- $ok = 2;
-} elsif (/^\[GNUPG:\]\s+BADSIG\s+/m) {
- $ok = 3;
-}
-
-print "$signer\n" if $signer;
-exit $ok;
-
-sub errmsg {
- my $msg = $_[0];
-
- eval 'use Sys::Syslog qw(:DEFAULT setlogsock)';
- die "$0: cannot use Sys::Syslog: $@ [$msg]\n" if $@;
-
- die "$0: cannot set syslog method [$msg]\n"
- if not (setlogsock('unix') or setlogsock('inet'));
-
- $msg .= " processing $header{'Message-ID'}" if $header{'Message-ID'};
-
- openlog($0, 'pid', $syslog_facility);
- syslog('err', '%s', $msg);
- closelog();
-}
-
-sub fail {
- errmsg($_[0]);
- unlink $tmp;
- exit 255;
-}
-
-__END__
-
-# Copyright 2000 by Marco d'Itri
-
-# License of the original version distributed by David C. Lawrence:
-
-# Copyright (c) 1996 UUNET Technologies, Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-# must display the following acknowledgement:
-# This product includes software developed by UUNET Technologies, Inc.
-# 4. The name of UUNET Technologies ("UUNET") may not be used to endorse or
-# promote products derived from this software without specific prior
-# written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY UUNET ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL UUNET BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
+++ /dev/null
-## $Id: checkgroups.pl 7743 2008-04-06 10:04:43Z iulius $
-##
-## checkgroups control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_checkgroups {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($newsgrouppats) = @$par;
-
- if ($action eq 'mail') {
- my $mail = sendmail("checkgroups by $sender");
- print $mail "$sender posted the following checkgroups message:\n";
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail <<END;
-
-If you want to process it, feed the body
-of the message to docheckgroups while logged
-in as user ID "$inn::newsuser":
-
-$inn::pathbin/docheckgroups '$newsgrouppats' <<zRbJ
-END
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- print $mail "zRbJ\n";
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "checkgroups by $sender", $headers, $body);
- } else {
- logmsg("checkgroups by $sender");
- }
- } elsif ($action eq 'doit') {
- if (defined &local_docheckgroups) {
- local_docheckgroups($body, $newsgrouppats, $log, $sender);
- } else {
- docheckgroups($body, $newsgrouppats, $log, $sender);
- }
- }
-}
-
-sub docheckgroups {
- my ($body, $newsgrouppats, $log, $sender) = @_;
-
- my $tempfile = "$inn::tmpdir/checkgroups.$$";
- open(TEMPART, ">$tempfile.art")
- or logdie("Cannot open $tempfile.art: $!");
- print TEMPART map { s/^~/~~/; "$_\n" } @$body;
- close TEMPART;
-
- open(OLDIN, '<&STDIN') or die $!;
- open(OLDOUT, '>&STDOUT') or die $!;
- open(STDIN, "$tempfile.art") or die $!;
- open(STDOUT, ">$tempfile") or die $!;
- my $st = system("$inn::pathbin/docheckgroups", $newsgrouppats);
- logdie('Cannot run docheckgroups: ' . $!) if $st == -1;
- logdie('docheckgroups returned status ' . ($st & 255)) if $st > 0;
- close(STDIN);
- close(STDOUT);
- open(STDIN, '<&OLDIN') or die $!;
- open(STDOUT, '>&OLDOUT') or die $!;
-
- open(TEMPFILE, $tempfile) or logdie("Cannot open $tempfile: $!");
- my @output = <TEMPFILE>;
- chop @output;
- # There is no need to send an empty mail.
- if ($#output > 0) {
- logger($log || 'mail', "checkgroups by $sender", \@output);
- } else {
- logmsg("checkgroups by $sender processed (no change)");
- }
- close TEMPFILE;
- unlink($tempfile, "$tempfile.art");
-}
-
-1;
+++ /dev/null
-## $Id: ihave.pl 4932 2001-07-19 00:32:56Z rra $
-##
-## ihave control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_ihave {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
-
- if ($action eq 'mail') {
- my $mail = sendmail("ihave by $sender");
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie('Cannot send mail: ' . $!);
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "ihave $sender", $headers, $body);
- } else {
- logmsg("ihave $sender");
- }
- } elsif ($action eq 'doit') {
- my $tempfile = "$inn::tmpdir/ihave.$$";
- open(GREPHIST, "|grephistory -i > $tempfile")
- or logdie('Cannot run grephistory: ' . $!);
- foreach (@$body) {
- print GREPHIST "$_\n";
- }
- close GREPHIST;
-
- if (-s $tempfile) {
- my $inews = open("$inn::inews -h")
- or logdie('Cannot run inews: ' . $!);
- print $inews "Newsgroups: to.$site\n"
- . "Subject: cmsg sendme $inn::pathhost\n"
- . "Control: sendme $inn::pathhost\n\n";
- open(TEMPFILE, $tempfile) or logdie("Cannot open $tempfile: $!");
- print $inews $_ while <TEMPFILE>;
- close $inews or die $!;
- close TEMPFILE;
- }
- unlink $tempfile;
- }
-}
-
-1;
+++ /dev/null
-## $Id: newgroup.pl 7849 2008-05-25 17:11:32Z iulius $
-##
-## newgroup control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_newgroup {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($groupname, $modflag) = @$par;
-
- $modflag ||= '';
- my $modcmd = $modflag eq 'moderated' ? 'm' : 'y';
-
- my $errmsg;
- $errmsg= local_checkgroupname($groupname) if defined &local_checkgroupname;
- if ($errmsg) {
- $errmsg = checkgroupname($groupname) if $errmsg eq 'DONE';
-
- if ($log) {
- logger($log, "skipping newgroup ($errmsg)", $headers, $body);
- } else {
- logmsg("skipping newgroup ($errmsg)");
- }
- return;
- }
-
- # Scan active to see what sort of change we are making.
- open(ACTIVE, $inn::active) or logdie("Cannot open $inn::active: $!");
- my @oldgroup;
- while (<ACTIVE>) {
- next unless /^(\Q$groupname\E)\s\d+\s\d+\s(\w)/;
- @oldgroup = split /\s+/;
- last;
- }
- close ACTIVE;
-
- my $status;
- my $ngdesc = 'No description.';
- my $olddesc = '';
- my $ngname = $groupname;
-
- # If there is a tag line, search whether the description has changed.
- my $found = 0;
- my $ngline = '';
- foreach (@$body) {
- if ($found) {
- # It is the line which contains the description.
- $ngline = $_;
- last;
- }
- $found = 1 if $_ =~ /^For your newsgroups file:\s*$/;
- }
-
- if ($found) {
- ($ngname, $ngdesc) = split(/\s+/, $ngline, 2);
- if ($ngdesc) {
- $ngdesc =~ s/\s+$//;
- $ngdesc =~ s/\s+\(moderated\)\s*$//i;
- $ngdesc .= ' (Moderated)' if $modflag eq 'moderated';
- }
- # Scan newsgroups to see the previous description, if any.
- open(NEWSGROUPS, $inn::newsgroups)
- or logdie("Cannot open $inn::newsgroups: $!");
- while (<NEWSGROUPS>) {
- if (/^\Q$groupname\E\s+(.*)/) {
- $olddesc = $1;
- last;
- }
- }
- close NEWSGROUPS;
- }
-
- if (@oldgroup) {
- if ($oldgroup[3] eq 'm' and $modflag ne 'moderated') {
- $status = 'be made unmoderated';
- } elsif ($oldgroup[3] ne 'm' and $modflag eq 'moderated') {
- $status = 'be made moderated';
- } else {
- if ($ngdesc eq $olddesc) {
- $status = 'no change';
- } else {
- $status = 'have a new description';
- }
- }
- } elsif (not $approved) {
- $status = 'unapproved';
- } else {
- $status = 'be created';
- }
-
- if ($action eq 'mail' and $status !~ /(no change|unapproved)/) {
- my $mail = sendmail("newgroup $groupname $modcmd $sender");
- print $mail <<END;
-$sender asks for $groupname
-to $status.
-
-If this is acceptable, type:
- $inn::newsbin/ctlinnd newgroup $groupname $modcmd $sender
-
-And do not forget to update the corresponding description in your
-newsgroups file.
-
-The control message follows:
-
-END
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n";
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "skipping newgroup $groupname $modcmd"
- . " $sender (would $status)", $headers, $body);
- } else {
- logmsg("skipping newgroup $groupname $modcmd $sender"
- . " (would $status)");
- }
- } elsif ($action eq 'doit' and $status ne 'unapproved') {
- if ($status ne 'no change') {
- # The status 'be made (un)moderated' prevails over
- # 'have a new description' so it is executed.
- ctlinnd('newgroup', $groupname, $modcmd, $sender)
- if $status ne 'have a new description';
- # We know the description has changed.
- update_desc($ngname, $ngdesc) if $ngdesc and $ngname eq $groupname;
- }
-
- if ($log) {
- logger($log, "newgroup $groupname $modcmd $status $sender",
- $headers, $body) if ($log ne 'mail' or $status ne 'no change');
- }
- }
- return;
-}
-
-sub update_desc {
- my ($name, $desc) = @_;
- shlock("$inn::locks/LOCK.newsgroups");
- my $tempfile = "$inn::newsgroups.$$";
- open(NEWSGROUPS, $inn::newsgroups)
- or logdie("Cannot open $inn::newsgroups: $!");
- open(TEMPFILE, ">$tempfile") or logdie("Cannot open $tempfile: $!");
- while (<NEWSGROUPS>) {
- next if (/^\Q$name\E\s+(.*)/);
- print TEMPFILE $_;
- }
- # We now write a pretty line for the description.
- if (length $name < 8) {
- print TEMPFILE "$name\t\t\t$desc\n";
- } elsif (length $name < 16) {
- print TEMPFILE "$name\t\t$desc\n";
- } else {
- print TEMPFILE "$name\t$desc\n";
- }
- close TEMPFILE;
- close NEWSGROUPS;
- rename($tempfile, $inn::newsgroups)
- or logdie("Cannot rename $tempfile: $!");
- unlink("$inn::locks/LOCK.newsgroups", $tempfile);
-}
-
-# Check the group name. This is partially derived from C News.
-# Some checks are commented out if I think they're too strict or
-# language-dependent. Your mileage may vary.
-sub checkgroupname {
- local $_ = shift;
-
- # whole-name checking
- return 'Empty group name' if /^$/;
- return 'Whitespace in group name' if /\s/;
- return 'Unsafe group name' if /[\`\/:;]/;
- return 'Bad dots in group name' if /^\./ or /\.$/ or /\.\./;
-# return 'Group name does not begin/end with alphanumeric'
-# if (/^[a-zA-Z0-9].+[a-zA-Z0-9]$/;
- return 'Group name begins in control., junk. or to.' if /^(?:control|junk|to)\./;
-# return 'Group name too long' if length $_ > 128;
-
- my @components = split(/\./);
- # prevent alt.a.b.c.d.e.f.g.w.x.y.z...
- return 'Too many components' if $#components > 9;
-
- # per-component checking
- for (my $i = 0; $i <= $#components; $i++) {
- local $_ = $components[$i];
- return 'all-numeric name component' if /^[0-9]+$/;
-# return 'name component starts with non-alphanumeric' if /^[a-zA-Z0-9]/;
-# return 'name component does not contain letter' if not /[a-zA-Z]/;
- return "`all' or `ctl' used as name component" if /^(?:all|ctl)$/;
-# return 'name component longer than 30 characters' if length $_ > 30;
-# return 'uppercase letter(s) in name' if /[A-Z]/;
- return 'illegal character(s) in name' if /[^a-z0-9+_\-.]/;
- # sigh, c++ etc must be allowed
- return 'repeated punctuation in name' if /--|__|\+\+./;
-# return 'repeated component(s) in name' if ($i + 2 <= $#components
-# and $_ eq $components[$i + 1] and $_ eq $components[$i + 2]);
- }
- return '';
-}
-
-1;
+++ /dev/null
-## $Id: rmgroup.pl 7743 2008-04-06 10:04:43Z iulius $
-##
-## rmgroup control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_rmgroup {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($groupname) = @$par;
-
- # Scan active to see what sort of change we are making.
- open(ACTIVE, $inn::active) or logdie("Cannot open $inn::active: $!");
- my @oldgroup;
- while (<ACTIVE>) {
- next unless /^(\Q$groupname\E)\s\d+\s\d+\s(\w)/;
- @oldgroup = split /\s+/;
- last;
- }
- close ACTIVE;
- my $status;
- if (not @oldgroup) {
- $status = 'no change';
- } elsif (not $approved) {
- $status = 'unapproved';
- } else {
- $status = 'removed';
- }
-
- if ($action eq 'mail' and $status !~ /(no change|unapproved)/) {
- my $mail = sendmail("rmgroup $groupname $sender");
- print $mail <<END;
-$sender asks for $groupname
-to be $status.
-
-If this is acceptable, type:
- $inn::newsbin/ctlinnd rmgroup $groupname
-
-And do not forget to remove the corresponding description, if any,
-from your newsgroups file.
-
-The control message follows:
-
-END
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n";
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "skipping rmgroup $groupname"
- . " $sender (would be $status)", $headers, $body);
- } else {
- logmsg("skipping rmgroup $groupname $sender (would be $status)");
- }
- } elsif ($action eq 'doit' and $status !~ /(no change|unapproved)/) {
- ctlinnd('rmgroup', $groupname);
- # Update newsgroups too.
- shlock("$inn::locks/LOCK.newsgroups");
- open(NEWSGROUPS, $inn::newsgroups)
- or logdie("Cannot open $inn::newsgroups: $!");
- my $tempfile = "$inn::newsgroups.$$";
- open(TEMPFILE, ">$tempfile") or logdie("Cannot open $tempfile: $!");
- while (<NEWSGROUPS>) {
- print TEMPFILE $_ if not /^\Q$groupname\E\s/;
- }
- close TEMPFILE;
- close NEWSGROUPS;
- rename($tempfile, $inn::newsgroups)
- or logdie("Cannot rename $tempfile: $!");
- unlink "$inn::locks/LOCK.newsgroups";
- unlink $tempfile;
-
- logger($log, "rmgroup $groupname $status $sender", $headers, $body)
- if $log;
- }
-}
-
-1;
+++ /dev/null
-## $Id: sendme.pl 4932 2001-07-19 00:32:56Z rra $
-##
-## sendme control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_sendme {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
-
- if ($action eq 'mail') {
- my $mail = sendmail("sendme by $sender");
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie('Cannot send mail: ' . $!);
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "sendme $sender", $headers, $body);
- } else {
- logmsg("sendme from $sender");
- }
- } elsif ($action eq 'doit') {
- my $tempfile = "$inn::tmpdir/sendme.$$";
- open(GREPHIST, "|grephistory -s > $tempfile")
- or logdie("Cannot run grephistory: $!");
- foreach (@$body) {
- print GREPHIST "$_\n";
- }
- close GREPHIST or logdie("Cannot run grephistory: $!");
-
- if (-s $tempfile and $site =~ /^[a-zA-Z0-9.-_]+$/) {
- open(TEMPFILE, $tempfile) or logdie("Cannot open $tempfile: $!");
- open(BATCH, ">>$inn::batch/$site.work")
- or logdie("Cannot open $inn::batch/$site.work: $!");
- print BATCH $_ while <TEMPFILE>;
- close BATCH;
- close TEMPFILE;
- }
- unlink $tempfile;
- }
-}
-
-1;
+++ /dev/null
-## $Id: sendsys.pl 4932 2001-07-19 00:32:56Z rra $
-##
-## sendsys control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_sendsys {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($where) = @$par;
-
- if ($action eq 'mail') {
- my $mail = sendmail("sendsys $sender");
- print $mail <<END;
-$sender has requested that you send a copy
-of your newsgroups file.
-
-If this is acceptable, type:
- $inn::mailcmd -s "sendsys reply from $inn::pathhost" $replyto < $inn::newsfeeds
-
-The control message follows:
-
-END
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n";
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "sendsys $sender", $headers, $body);
- } else {
- logmsg("sendsys $sender");
- }
- } elsif ($action =~ /^(doit|doifarg)$/) {
- if ($action eq 'doifarg' and $where ne $inn::pathhost) {
- logmsg("skipped sendsys $sender");
- return;
- }
- my $mail = sendmail("sendsys reply from $inn::pathhost", $replyto);
- open(NEWSFEEDS, $inn::newsfeeds)
- or logdie("Cannot open $inn::newsfeeds: $!");
- print $mail $_ while <NEWSFEEDS>;
- print $mail "\n";
- close NEWSFEEDS;
- close $mail or logdie("Cannot send mail: $!");
-
- logger($log, "sendsys $sender to $replyto", $headers, $body) if $log;
- }
-}
-
-1;
+++ /dev/null
-## $Id: senduuname.pl 4932 2001-07-19 00:32:56Z rra $
-##
-## senduuname control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_senduuname {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($where) = @$par;
-
- if ($action eq 'mail') {
- my $mail = sendmail("senduuname $sender");
- print $mail <<END;
-$sender has requested information about your UUCP name.
-
-If this is acceptable, type:
- uuname | $inn::mailcmd -s "senduuname reply from $inn::pathhost" $replyto
-
-The control message follows:
-
-END
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n";
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "senduuname $sender", $headers, $body);
- } else {
- logmsg("senduuname $sender");
- }
- } elsif ($action =~ /^(doit|doifarg)$/) {
- if ($action eq 'doifarg' and $where ne $inn::pathhost) {
- logmsg("skipped senduuname $sender");
- return;
- }
- my $mail = sendmail("senduuname reply from $inn::pathhost", $replyto);
- open(UUNAME, 'uuname|') or logdie("Cannot run uuname: $!");
- print $mail $_ while <UUNAME>;
- close UUNAME or logdie("Cannot run uuname: $!");
- close $mail or logdie("Cannot send mail: $!");
-
- logger($log, "senduuname $sender to $replyto", $headers, $body) if $log;
- }
-}
-
-1;
+++ /dev/null
-## $Id: version.pl 4932 2001-07-19 00:32:56Z rra $
-##
-## version control message handler.
-##
-## Copyright 2001 by Marco d'Itri <md@linux.it>
-##
-## Redistribution and use in source and binary forms, with or without
-## modification, are permitted provided that the following conditions
-## are met:
-##
-## 1. Redistributions of source code must retain the above copyright
-## notice, this list of conditions and the following disclaimer.
-##
-## 2. Redistributions in binary form must reproduce the above copyright
-## notice, this list of conditions and the following disclaimer in the
-## documentation and/or other materials provided with the distribution.
-
-use strict;
-
-sub control_version {
- my ($par, $sender, $replyto, $site, $action, $log, $approved,
- $headers, $body) = @_;
- my ($where) = @$par;
-
- my $version = $inn::version || '(unknown version)';
-
- if ($action eq 'mail') {
- my $mail = sendmail("version $sender");
- print $mail <<END;
-$sender has requested information about your
-news software version.
-
-If this is acceptable, type:
- echo "InterNetNews $version" | $inn::mailcmd -s "version reply from $inn::pathhost" $replyto
-
-The control message follows:
-
-END
- print $mail map { s/^~/~~/; "$_\n" } @$headers;
- print $mail "\n";
- print $mail map { s/^~/~~/; "$_\n" } @$body;
- close $mail or logdie("Cannot send mail: $!");
- } elsif ($action eq 'log') {
- if ($log) {
- logger($log, "version $sender", $headers, $body);
- } else {
- logmsg("version $sender");
- }
- } elsif ($action =~ /^(doit|doifarg)$/) {
- if ($action eq 'doifarg' and $where ne $inn::pathhost) {
- logmsg("skipped version $sender");
- return;
- }
- sendmail("version reply from $inn::pathhost", $replyto,
- [ "InterNetNews $version\n" ]);
-
- logger($log, "version $sender to $replyto", $headers, $body) if $log;
- }
-}
-
-1;
+++ /dev/null
-#!/usr/bin/perl -w
-# fixscript will replace this line with require innshellvars.pl
-
-##############################################################################
-# perl-nocem - a NoCeM-on-spool implementation for INN 2.x.
-# Copyright 2000 by Miquel van Smoorenburg <miquels@cistron.nl>
-# Copyright 2001 by Marco d'Itri <md@linux.it>
-# This program is licensed under the terms of the GNU General Public License.
-#
-# List of changes:
-#
-# 2002: Patch by Steven M. Christey for untrusted printf input.
-# 2007: Patch by Christoph Biedl for checking a timeout.
-# Documentation improved by Jeffrey M. Vinocur (2002), Russ Allbery (2006)
-# and Julien Elie (2007).
-#
-##############################################################################
-
-require 5.00403;
-use strict;
-
-# XXX FIXME I haven't been able to load it only when installed.
-# If nobody can't fix it just ship the program with this line commented.
-#use Time::HiRes qw(time);
-
-my $keyring = $inn::pathetc . '/pgp/ncmring.gpg';
-
-# XXX To be moved to a config file.
-#sub local_want_cancel_id {
-# my ($group, $hdrs) = @_;
-#
-## Hippo has too many false positives to be useful outside of pr0n groups
-# if ($hdrs->{issuer} =~ /(?:Ultra|Spam)Hippo/) {
-# foreach (split(/,/, $group)) {
-# return 1 if /^alt\.(?:binar|sex)/;
-# }
-# return 0;
-# }
-# return 1;
-#}
-
-# no user serviceable parts below this line ###################################
-
-# global variables
-my ($working, $got_sighup, $got_sigterm, @ncmperm, $cancel);
-my $use_syslog = 0;
-my $log_open = 0;
-my $nntp_open = 0;
-my $last_cancel = 0;
-my $socket_timeout = $inn::peertimeout - 100;
-
-my $logfile = $inn::pathlog . '/perl-nocem.log';
-
-# initialization and main loop ###############################################
-
-eval { require Sys::Syslog; import Sys::Syslog; $use_syslog = 1; };
-
-if ($use_syslog) {
- eval "sub Sys::Syslog::_PATH_LOG { '/dev/log' }" if $^O eq 'dec_osf';
- Sys::Syslog::setlogsock('unix') if $^O =~ /linux|dec_osf/;
- openlog('nocem', '', $inn::syslog_facility);
-}
-
-if (not $inn::gpgv) {
- logmsg('cannot find the gpgv binary', 'err');
- sleep 5;
- exit 1;
-}
-
-if ($inn::version and not $inn::version =~ /^INN 2\.[0123]\./) {
- $cancel = \&cancel_nntp;
-} else {
- $cancel = \&cancel_ctlinnd;
-}
-
-$SIG{HUP} = \&hup_handler;
-$SIG{INT} = \&term_handler;
-$SIG{TERM} = \&term_handler;
-$SIG{PIPE} = \&term_handler;
-
-logmsg('starting up');
-
-unless (read_ctlfile()) {
- sleep 5;
- exit 1;
-}
-
-while (<STDIN>) {
- chop;
- $working = 1;
- do_nocem($_);
- $working = 0;
- term_handler() if $got_sigterm;
- hup_handler() if $got_sighup;
-}
-
-logmsg('exiting because of EOF', 'debug');
-exit 0;
-
-##############################################################################
-
-# Process one NoCeM notice.
-sub do_nocem {
- my $token = shift;
- my $start = time;
-
- # open the article and verify the notice
- my $artfh = open_article($token);
- return if not defined $artfh;
- my ($msgid, $nid, $issuer, $nocems) = read_nocem($artfh);
- close $artfh;
- return unless $nocems;
-
- &$cancel($nocems);
- logmsg("Articles cancelled: " . join(' ', @$nocems), 'debug');
- my $diff = (time - $start) || 0.01;
- my $nr = scalar @$nocems;
- logmsg(sprintf("processed notice %s by %s (%d ids, %.5f s, %.1f/s)",
- $nid, $issuer, $nr, $diff, $nr / $diff));
-}
-
-# - Check if it is a PGP signed NoCeM notice
-# - See if we want it
-# - Then check PGP signature
-sub read_nocem {
- my $artfh = shift;
-
- # Examine the first 200 lines to see if it is a PGP signed NoCeM.
- my $ispgp = 0;
- my $isncm = 0;
- my $inhdr = 1;
- my $i = 0;
- my $body = '';
- my ($from, $msgid);
- while (<$artfh>) {
- last if $i++ > 200;
- s/\r\n$/\n/;
- if ($inhdr) {
- if (/^$/) {
- $inhdr = 0;
- } elsif (/^From:\s+(.*)\s*$/i) {
- $from = $1;
- } elsif (/^Message-ID:\s+(<.*>)/i) {
- $msgid = $1;
- }
- } else {
- $body .= $_;
- $ispgp = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----/;
- if (/^\@\@BEGIN NCM HEADERS/) {
- $isncm = 1;
- last;
- }
- }
- }
-
- # must be a PGP signed NoCeM.
- if (not $ispgp) {
- logmsg("Article $msgid: not PGP signed", 'debug');
- return;
- }
- if (not $isncm) {
- logmsg("Article $msgid: not a NoCeM", 'debug');
- return;
- }
-
- # read the headers of this NoCeM, and check if it's supported.
- my %hdrs;
- while (<$artfh>) {
- s/\r\n/\n/;
- $body .= $_;
- last if /^\@\@BEGIN NCM BODY/;
- my ($key, $val) = /^([^:]+)\s*:\s*(.*)$/;
- $hdrs{lc $key} = $val;
- }
- foreach (qw(action issuer notice-id type version)) {
- next if $hdrs{$_};
- logmsg("Article $msgid: missing $_ pseudo header", 'debug');
- return;
- }
- return if not supported_nocem($msgid, \%hdrs);
-
- # decide if we want it.
- if (not want_nocem(\%hdrs)) {
- logmsg("Article $msgid: unwanted ($hdrs{issuer}/$hdrs{type})", 'debug');
- return;
- }
-# XXX want_hier() not implemented
-# if ($hdrs{hierarchies} and not want_hier($hdrs{hierarchies})) {
-# logmsg("Article $msgid: unwanted hierarchy ($hdrs{hierarchies})",
-# 'debug');
-# return;
-# }
-
- # We do want it, so read the entire article. Also copy it to
- # a temp file so that we can check the PGP signature when done.
- my $tmpfile = "$inn::pathtmp/nocem.$$";
- if (not open(OFD, ">$tmpfile")) {
- logmsg("cannot open temp file $tmpfile: $!", 'err');
- return;
- }
- print OFD $body;
- undef $body;
-
- # process NoCeM body.
- my $inbody = 1;
- my @nocems;
- my ($lastid, $lastgrp);
- while (<$artfh>) {
- s/\r\n$/\n/;
- print OFD;
- $inbody = 0 if /^\@\@END NCM BODY/;
- next if not $inbody or /^#/;
-
- my ($id, $grp) = /^(\S*)\s+(\S+)/;
- next if not $grp;
- if ($id) {
- push @nocems, $lastid
- if $lastid and want_cancel_id($lastgrp, \%hdrs);
- $lastid = $id;
- $lastgrp = $grp;
- } else {
- $lastgrp .= ',' . $grp;
- }
- }
- push @nocems, $lastid if $lastid and want_cancel_id($lastgrp, \%hdrs);
- close OFD;
-
- # at this point we need to verify the PGP signature.
- return if not @nocems;
- my $e = pgp_check($hdrs{issuer}, $msgid, $tmpfile);
- unlink $tmpfile;
- return if not $e;
-
- return ($msgid, $hdrs{'notice-id'}, $hdrs{issuer}, \@nocems);
-}
-
-# XXX not implemented: code to discard notices for groups we don't carry
-sub want_cancel_id {
- my ($group, $hdrs) = @_;
-
- return local_want_cancel_id(@_) if defined &local_want_cancel_id;
- 1;
-}
-
-# Do we actually want this NoCeM?
-sub want_nocem {
- my $hdrs = shift;
-
- foreach (@ncmperm) {
- my ($issuer, $type) = split(/\001/);
- if ($hdrs->{issuer} =~ /$issuer/i) {
- return 1 if '*' eq $type or lc $hdrs->{type} eq $type;
- }
- }
- return 0;
-}
-
-sub supported_nocem {
- my ($msgid, $hdrs) = @_;
-
- if ($hdrs->{version} !~ /^0\.9[0-9]?$/) {
- logmsg("Article $msgid: version $hdrs->{version} not supported",
- 'debug');
- return 0;
- }
- if ($hdrs->{action} ne 'hide') {
- logmsg("Article $msgid: action $hdrs->{action} not supported",
- 'debug');
- return 0;
- }
- return 1;
-}
-
-# Check the PGP signature on an article.
-sub pgp_check {
- my ($issuer, $msgid, $art) = @_;
-
- # fork and spawn a child
- my $pid = open(PFD, '-|');
- if (not defined $pid) {
- logmsg("pgp_check: cannot fork: $!", 'err');
- return 0;
- }
- if ($pid == 0) {
- open(STDERR, '>&STDOUT');
- exec($inn::gpgv, '--status-fd=1',
- $keyring ? '--keyring=' . $keyring : '', $art);
- exit 126;
- }
-
- # Read the result and check status code.
- local $_ = join('', <PFD>);
- my $status = 0;
- if (not close PFD) {
- if ($? >> 8) {
- $status = $? >> 8;
- } else {
- logmsg("Article $msgid: $inn::gpgv killed by signal " . ($? & 255));
- return 0;
- }
- }
-# logmsg("Command line was: $inn::gpgv --status-fd=1"
-# . ($keyring ? ' --keyring=' . $keyring : '') . " $art", 'debug');
-# logmsg("Full PGP output: >>>$_<<<", 'debug');
-
- if (/^\[GNUPG:\]\s+GOODSIG\s+\S+\s+(.*)/m) {
- return 1 if $1 =~ /\Q$issuer\E/;
- logmsg("Article $msgid: signed by $1 instead of $issuer");
- } elsif (/^\[GNUPG:\]\s+NO_PUBKEY\s+(\S+)/m) {
- logmsg("Article $msgid: $issuer (ID $1) not in keyring");
- } elsif (/^\[GNUPG:\]\s+BADSIG\s+\S+\s+(.*)/m) {
- logmsg("Article $msgid: bad signature from $1");
- } elsif (/^\[GNUPG:\]\s+BADARMOR/m or /^\[GNUPG:\]\s+UNEXPECTED/m) {
- logmsg("Article $msgid: malformed signature");
- } elsif (/^\[GNUPG:\]\s+ERRSIG\s+(\S+)/m) {
- # safety net: we get there if we don't know about some token
- logmsg("Article $msgid: unknown error (ID $1)");
- } else {
- # some other error we don't know about happened.
- # 126 is returned by the child if exec fails.
- s/ at \S+ line \d+\.\n$//; s/\n/_/;
- logmsg("Article $msgid: $inn::gpgv exited "
- . (($status == 126) ? "($_)" : "with status $status"), 'err');
- }
- return 0;
-}
-
-# Read article.
-sub open_article {
- my $token = shift;
-
- if ($token =~ /^\@.+\@$/) {
- my $pid = open(ART, '-|');
- if ($pid < 0) {
- logmsg('Cannot fork: ' . $!, 'err');
- return undef;
- }
- if ($pid == 0) {
- exec("$inn::newsbin/sm", '-q', $token) or
- logmsg("Cannot exec sm: $!", 'err');
- return undef;
- }
- return *ART;
- } else {
- return *ART if open(ART, $token);
- logmsg("Cannot open article $token: $!", 'err');
- }
- return undef;
-}
-
-# Cancel a number of Message-IDs. We use ctlinnd to do this,
-# and we run up to 15 of them at the same time (10 usually).
-sub cancel_ctlinnd {
- my @ids = @{$_[0]};
-
- while (@ids > 0) {
- my $max = @ids <= 15 ? @ids : 10;
- for (my $i = 1; $i <= $max; $i++) {
- my $msgid = shift @ids;
- my $pid;
- sleep 5 until (defined ($pid = fork));
- if ($pid == 0) {
- exec "$inn::pathbin/ctlinnd", '-s', '-t', '180',
- 'cancel', $msgid;
- exit 126;
- }
-# logmsg("cancelled: $msgid [$i/$max]", 'debug');
- }
- # Now wait for all children.
- while ((my $pid = wait) > 0) {
- next unless $?;
- if ($? >> 8) {
- logmsg("Child $pid died with status " . ($? >> 8), 'err');
- } else {
- logmsg("Child $pid killed by signal " . ($? & 255), 'err');
- }
- }
- }
-}
-
-sub cancel_nntp {
- my $ids = shift;
- my $r;
-
- if ($nntp_open and time - $socket_timeout > $last_cancel) {
- logmsg('Close socket for timeout');
- close (NNTP);
- $nntp_open = 0;
- }
- if (not $nntp_open) {
- use Socket;
- if (not socket(NNTP, PF_UNIX, SOCK_STREAM, 0)) {
- logmsg("socket: $!", 'err');
- goto ERR;
- }
- if (not connect(NNTP, sockaddr_un($inn::pathrun . '/nntpin'))) {
- logmsg("connect: $!", 'err');
- goto ERR;
- }
- if (($r = <NNTP>) !~ /^200 /) {
- $r =~ s/\r\n$//;
- logmsg("bad reply from server: $r", 'err');
- goto ERR;
- }
- select NNTP; $| = 1; select STDOUT;
- print NNTP "MODE CANCEL\r\n";
- if (($r = <NNTP>) !~ /^284 /) {
- $r =~ s/\r\n$//;
- logmsg("MODE CANCEL not supported: $r", 'err');
- goto ERR;
- }
- $nntp_open = 1;
- }
- foreach (@$ids) {
- print NNTP "$_\r\n";
- if (($r = <NNTP>) !~ /^289/) {
- $r =~ s/\r\n$//;
- logmsg("cannot cancel $_: $r", 'err');
- goto ERR;
- }
- }
- $last_cancel = time;
- return;
-
-ERR:
- # discard unusable socket
- close (NNTP);
- logmsg('Switching to ctlinnd...', 'err');
- cancel_ctlinnd($ids);
- $cancel = \&cancel_ctlinnd;
-}
-
-sub read_ctlfile {
- my $permfile = $inn::pathetc . '/nocem.ctl';
-
- unless (open(CTLFILE, $permfile)) {
- logmsg("Cannot open $permfile: $!", 'err');
- return 0;
- }
- while (<CTLFILE>) {
- chop;
- s/^\s+//; s/\s+$//;
- next if /^#/ or /^$/;
- my ($issuer, $type) = split(/:/, lc $_);
- logmsg("Cannot parse nocem.ctl line <<$_>>", 'err')
- if not $issuer and $type;
- $type =~ s/\s//g;
- push @ncmperm, "$issuer\001$_" foreach split(/,/, $type);
- }
- close CTLFILE;
- return 1;
-}
-
-sub logmsg {
- my ($msg, $lvl) = @_;
-
- if (not $use_syslog) {
- if ($log_open == 0) {
- open(LOG, ">>$logfile") or die "Cannot open log: $!";
- $log_open = 1;
- select LOG; $| = 1; select STDOUT;
- }
- $lvl ||= 'notice';
- print LOG "$lvl: $msg\n";
- return;
- }
- syslog($lvl || 'notice', '%s', $msg);
-}
-
-sub hup_handler {
- $got_sighup = 1;
- return if $working;
- close LOG;
- $log_open = 0;
-}
-
-sub term_handler {
- $got_sigterm = 1;
- return if $working;
- logmsg('exiting because of signal');
- exit 1;
-}
-
-# lint food
-print $inn::pathrun.$inn::pathlog.$inn::pathetc.$inn::newsbin.$inn::pathbin
- .$inn::pathtmp.$inn::peertimeout.$inn::syslog_facility;
-
-__END__
-
-=head1 NAME
-
-perl-nocem - A NoCeM-on-spool implementation for S<INN 2.x>
-
-=head1 SYNOPSIS
-
-perl-nocem
-
-=head1 DESCRIPTION
-
-NoCeM, which is pronounced I<No See 'Em>, is a protocol enabling
-authenticated third-parties to issue notices which can be used
-to cancel unwanted articles (like spam and articles in moderated
-newsgroups which were not approved by their moderators). It can
-also be used by readers as a I<third-party killfile>. It is
-intended to eventually replace the protocol for third-party cancel
-messages.
-
-B<perl-nocem> processes third-party, PGP-signed article cancellation
-notices. It is possible not to honour all NoCeM notices but only those
-which are sent by people whom you trust (that is to say if you trust
-the PGP key they use to sign their NoCeM notices). Indeed, it is up
-to you to decide whether you wish to honour their notices, depending
-on the criteria they use.
-
-Processing NoCeM notices is easy to set up:
-
-=over 4
-
-=item 1.
-
-Import the keys of the NoCeM issuers you trust in order to check
-the authenticity of their notices. You can do:
-
- gpg --no-default-keyring --primary-keyring <pathetc>/pgp/ncmring.gpg \
- --no-options --allow-non-selfsigned-uid --no-permission-warning \
- --batch --import <key-file>
-
-where <pathetc> is the value of the I<pathetc> parameter set in F<inn.conf>
-and <key-file> the file containing the key(s) to import. The keyring
-must be located in I<pathetc>/pgp/ncmring.gpg (create the directory
-before using B<gpg>). For old PGP-generated keys, you may have to use
-B<--allow-non-selfsigned-uid> if they are not properly self-signed,
-but anyone creating a key really should self-sign the key. Current
-PGP implementations do this automatically.
-
-The keys of NoCeM issuers can be found in the web site of I<The NoCeM Registry>:
-L<http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html>. You can even
-download there a unique file which contains all the keys.
-
-=item 2.
-
-Create a F<nocem.ctl> config file in I<pathetc> indicating the NoCeM issuers
-and notices you want to follow. This permission file contains lines like:
-
- annihilator-1:*
- clewis@ferret.ocunix:mmf
- stephane@asynchrone:mmf,openproxy,spam
-
-This will remove all articles for which the issuer (first part of the line,
-before the colon C<:>) has issued NoCeM notices corresponding to the
-criteria specified after the colon.
-
-You will also find information about that on the web site of
-I<The NoCeM Registry>.
-
-=item 3.
-
-Add to the F<newsfeeds> file an entry like this one in order to feed
-B<perl-nocem> the NoCeM notices posted to alt.nocem.misc and
-news.lists.filters:
-
- nocem!\
- :!*,alt.nocem.misc,news.lists.filters\
- :Tc,Wf,Ap:<pathbin>/perl-nocem
-
-with the correct path to B<perl-nocem>, located in <pathbin>. Then, reload
-the F<newsfeeds> file (C<ctlinnd reload newsfeeds 'NoCeM channel feed'>).
-
-Note that you should at least carry news.lists.filters on your news
-server (or other newsgroups where NoCeM notices are sent) if you wish
-to process them.
-
-=item 4.
-
-Everything should now work. However, do not hesitate to manually test
-B<perl-nocem> with a NoCeM notice, using:
-
- grephistory '<Message-ID>' | perl-nocem
-
-Indeed, B<perl-nocem> expects tokens on its standard input, and
-B<grephistory> can easily give it the token of a known article,
-thanks to its Message-ID.
-
-=back
-
-When you have verified that everything works, you can eventually turn
-off regular spam cancels, if you want, not processing any longer
-cancels containing C<cyberspam> in the Path: header (see the
-I<refusecybercancels> parameter in F<inn.conf>).
-
-=head1 FILES
-
-=over 4
-
-=item I<pathbin>/perl-nocem
-
-The Perl script itself used to process NoCeM notices.
-
-=item I<pathetc>/nocem.ctl
-
-The configuration file which specifies the NoCeM notices to be processed.
-
-=item I<pathetc>/pgp/ncmring.gpg
-
-The keyring which contains the public keys of trusted NoCeM issuers.
-
-=back
-
-=head1 BUGS
-
-The Subject: header is not checked for the @@NCM string and there is no
-check for the presence of the References: header.
-
-The Newsgroups: pseudo header is not checked, but this can be done in
-local_want_cancel_id().
-
-The Hierarchies: header is ignored.
-
-=head1 HISTORY
-
-Copyright 2000 by Miquel van Smoorenburg <miquels@cistron.nl>.
-
-Copyright 2001 by Marco d'Itri <md@linux.it>.
-
-$Id: perl-nocem.in 7733 2008-04-06 09:16:20Z iulius $
-
-=head1 SEE ALSO
-
-gpgv(1), grephistory(1), inn.conf(5), newsfeeds(5), pgp(1).
-
-=cut
+++ /dev/null
-#! /usr/bin/perl -w
-# do '@LIBDIR@/innshellvars.pl';
-# If running inside INN, uncomment the above and point to innshellvars.pl.
-#
-# Written April 1996, <tale@isc.org> (David C Lawrence)
-# Currently maintained by Russ Allbery <rra@stanford.edu>
-# Version 1.27, 2005-07-02
-#
-# NOTICE TO INN MAINTAINERS: The version that is shipped with INN is the
-# same as the version that I make available to the rest of the world
-# (including non-INN sites), so please make all changes through me.
-#
-# This program requires Perl 5, probably at least about Perl 5.003 since
-# that's when FileHandle was introduced. If you want to use this program
-# and your Perl is too old, please contact me (rra@stanford.edu) and tell
-# me about it; I want to know what old versions of Perl are still used in
-# practice.
-#
-# Changes from 1.26 -> 1.27
-# -- Default to pubring.gpg when trustedkeys.gpg is not found in the
-# default key location, for backward compatibility.
-#
-# Changes from 1.25 -> 1.26
-# -- Return the correct status code when the message isn't verified
-# instead of always returning 255.
-#
-# Changes from 1.24 -> 1.25
-# -- Fix the -test switch to actually do something.
-# -- Improve date generation when logging to standard output.
-#
-# Changes from 1.23 -> 1.24
-# -- Fix bug in the recognition of wire-format articles.
-#
-# Changes from 1.15 -> 1.23
-# -- Bump version number to match CVS revision number.
-# -- Replaced all signature verification code with code that uses detached
-# signatures. Signatures generated by GnuPG couldn't be verified using
-# attached signatures without adding a Hash: header, and this was the
-# path of least resistance plus avoids munging problems in the future.
-# Code taken from PGP::Sign.
-#
-# Changes from 1.14 -> 1.15
-# -- Added POD documentation.
-# -- Fixed the -test switch so that it works again.
-# -- Dropped Perl 4 compatibility and reformatted. Now passes use strict.
-#
-# Changes from 1.13.1 -> 1.14
-# -- Native support for GnuPG without the pgpgpg wrapper, using GnuPG's
-# program interface by Marco d'Itri.
-# -- Always use Sys::Syslog without any setlogsock call for Perl 5.6.0 or
-# later, since Sys::Syslog in those versions of Perl uses the C library
-# interface and is now portable.
-# -- Default to expecting the key ring in $inn'newsetc/pgp if it exists.
-# -- Fix a portability problem for Perl 4 introduced in 1.12.
-#
-# Changes from 1.13 -> 1.13.1
-# -- Nothing functional, just moved the innshellvars.pl line to the head of
-# the script, to accomodate the build process of INN.
-#
-# Changes from 1.12 -> 1.13
-# -- Use INN's syslog_facility if available.
-#
-# Changes from 1.11 -> 1.12
-# -- Support for GnuPG.
-# -- Use /usr/ucb/logger, if present, instead of /usr/bin/logger (the latter
-# of which, on Solaris at least, is some sort of brain damaged POSIX.2
-# command which doesn't use syslog).
-# -- Made syslog work for dec_osf (version 4, at least).
-# -- Fixed up priority of '.' operator vs bitwise operators.
-#
-# Changes from 1.10 -> 1.11
-# -- Code to log error messages to syslog.
-# See $syslog and $syslog_method configurable variables.
-# -- Configurably allow date stamp on stderr error messages.
-# -- Added locking for multiple concurrent pgp instances.
-# -- More clear error message if pgp exits abnormally.
-# -- Identify PGP 5 "BAD signature" string.
-# -- Minor diddling for INN (path to innshellvars.pl changed).
-#
-# Changes from 1.9 -> 1.10
-# -- Minor diddling for INN 2.0: use $inn'pathtmp if it exists, and
-# work with the new subst method to find innshellvars.pl.
-# -- Do not truncate the tmp file when opening, in case it is really
-# linked to another file.
-#
-# Changes from 1.8 -> 1.9
-# -- Match 'Bad signature' pgp output to return exit status 3 by removing
-# '^' in regexp matched on multiline string.
-#
-# Changes from 1.7 -> 1.8
-# -- Ignore final dot-CRLF if article is in NNTP format.
-#
-# Changes from 1.6 -> 1.7
-# -- Parse PGP 5.0 'good signature' lines.
-# -- Allow -test switch; prints pgp input and output.
-# -- Look for pgp in INN's innshellvars.pl.
-# -- Changed regexp delimiters for stripping $0 to be compatible with old
-# Perl.
-#
-# Changes from 1.5 -> 1.6
-# -- Handle articles encoded in NNTP format ('.' starting line is doubled,
-# \r\n at line end) by stripping NNTP encoding.
-# -- Exit 255 with pointer to $HOME or $PGPPATH if pgp can't find key
-# ring. (It probably doesn't match the necessary error message with
-# ViaCrypt PGP.)
-# -- Failures also report Message-ID so the article can be looked up to
-# retry.
-#
-# Changes from 1.4 -> 1.5
-# -- Force English language for 'Good signature from user' by passing
-# +language=en on pgp command line, rather than setting the
-# environment variable LANGUAGE to 'en'.
-#
-# Changes from 1.3 -> 1.4
-# -- Now handles wrapped headers that have been unfolded.
-# (Though I do believe news software oughtn't be unfolding them.)
-# -- Checks to ensure that the temporary file is really a file, and
-# not a link or some other weirdness.
-
-# Path to the GnuPG gpgv binary, if you have GnuPG. If you do, this will
-# be used in preference to PGP. For most current control messages, you
-# need a version of GnuPG that can handle RSA signatures. If you have INN
-# and the script is able to successfully include your innshellvars.pl
-# file, the value of $inn::gpgv will override this.
-# $gpgv = '/usr/local/bin/gpgv';
-
-# Path to pgp binary; for PGP 5.0, set the path to the pgpv binary. If
-# you have INN and the script is able to successfully include your
-# innshellvars.pl file, the value of $inn::pgp will override this.
-$pgp = '/usr/local/bin/pgp';
-
-# If you keep your keyring somewhere that is not the default used by pgp,
-# uncomment the next line and set appropriately. If you have INN and the
-# script is able to successfully include your innshellvars.pl file, this
-# will be set to $inn::newsetc/pgp if that directory exists unless you set
-# it explicitly. GnuPG will use a file named pubring.gpg in this
-# directory.
-# $keyring = '/path/to/your/pgp/config';
-
-# If you have INN and the script is able to successfully include your
-# innshellvars.pl file, the value of $inn::pathtmp and $inn::locks will
-# override these.
-$tmpdir = "/tmp";
-$lockdir = $tmpdir;
-
-# How should syslog be accessed?
-#
-# As it turns out, syslogging is very hard to do portably in versions of
-# Perl prior to 5.6.0. Sys::Syslog should work without difficulty in
-# 5.6.0 or later and will be used automatically for those versions of Perl
-# (unless $syslog_method is ''). For earlier versions of Perl, 'inet' is
-# all that's available up to version 5.004_03. If your syslog does not
-# accept UDP log packets, such as when syslogd runs with the -l flag,
-# 'inet' will not work. A value of 'unix' will try to contact syslogd
-# directly over a Unix domain socket built entirely in Perl code (no
-# subprocesses). If that is not working for you, and you have the
-# 'logger' program on your system, set this variable to its full path name
-# to have a subprocess contact syslogd. If the method is just "logger",
-# the script will search some known directories for that program. If it
-# can't be found & used, everything falls back on stderr logging.
-#
-# You can test the script's syslogging by running "pgpverify <
-# /some/text/file" on a file that is not a valid news article. The
-# "non-header at line #" error should be syslogged.
-#
-# $syslog_method = 'unix'; # Unix doman socket, Perl 5.004_03 or higher.
-# $syslog_method = 'inet'; # UDP to port 514 of localhost.
-# $syslog_method = ''; # Don't ever try to do syslogging.
-$syslog_method = 'logger'; # Search for the logger program.
-
-# The next two variables are the values to be used for syslog's facility
-# and level to use, as would be found in syslog.conf. For various
-# reasons, it is impossible to economically have the script figure out how
-# to do syslogging correctly on the machine. If you have INN and the
-# script is able to successfully include you innshellvars.pl file, then
-# the value of $inn::syslog_facility will override this value of
-# $syslog_facility; $syslog_level is unaffected.
-$syslog_facility = 'news';
-$syslog_level = 'err';
-
-# Prepend the error message with a timestamp? This is only relevant if
-# not syslogging, when errors go to stderr.
-#
-# $log_date = 0; # Zero means don't do it.
-# $log_date = 1; # Non-zero means do it.
-$log_date = -t STDOUT; # Do it if STDOUT is to a terminal.
-
-# End of configuration section.
-
-
-require 5;
-
-use strict;
-use vars qw($gpgv $pgp $keyring $tmp $tmpdir $lockdir $syslog_method
- $syslog_facility $syslog_level $log_date $test $messageid);
-
-use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
-use FileHandle;
-use IPC::Open3 qw(open3);
-use POSIX qw(strftime);
-
-# Turn on test mode if the first argument is '-test'.
-if (@ARGV && $ARGV[0] eq '-test') {
- shift @ARGV;
- $test = 1;
-}
-
-# Not syslogged, such an error is almost certainly from someone running
-# the script manually.
-die "Usage: $0 < message\n" if @ARGV != 0;
-
-# Grab various defaults from innshellvars.pl if running inside INN.
-$pgp = $inn::pgp
- if $inn::pgp && $inn::pgp ne "no-pgp-found-during-configure";
-$gpgv = $inn::gpgv if $inn::gpgv;
-$tmp = ($inn::pathtmp ? $inn::pathtmp : $tmpdir) . "/pgp$$";
-$lockdir = $inn::locks if $inn::locks;
-$syslog_facility = $inn::syslog_facility if $inn::syslog_facility;
-if (! $keyring && $inn::newsetc) {
- $keyring = $inn::newsetc . '/pgp' if -d $inn::newsetc . '/pgp';
-}
-
-# Trim /path/to/prog to prog for error messages.
-$0 =~ s%^.*/%%;
-
-# Make sure that the signature verification program can be executed.
-if ($gpgv) {
- if (! -x $gpgv) {
- &fail("$0: $gpgv: " . (-e _ ? "cannot execute" : "no such file") . "\n");
- }
-} elsif (! -x $pgp) {
- &fail("$0: $pgp: " . (-e _ ? "cannot execute" : "no such file") . "\n");
-}
-
-# Parse the article headers and generate the PGP message.
-my ($nntp_format, $header, $dup) = &parse_header();
-exit 1 unless $$header{'X-PGP-Sig'};
-my ($message, $signature, $version)
- = &generate_message($nntp_format, $header, $dup);
-if ($test) {
- print "-----MESSAGE-----\n$message\n-----END MESSAGE-----\n\n";
- print "-----SIGNATURE-----\n$signature\n-----SIGNATURE-----\n\n";
-}
-
-# The call to pgp needs to be locked because it tries to both read and
-# write a file named randseed.bin but doesn't do its own locking as it
-# should, and the consequences of a multiprocess conflict is failure to
-# verify.
-my $lock;
-unless ($gpgv) {
- $lock = "$lockdir/LOCK.$0";
- until (&shlock($lock) > 0) {
- sleep(2);
- }
-}
-
-# Verify the message.
-my ($ok, $signer) = pgp_verify($signature, $version, $message);
-unless ($gpgv) {
- unlink ($lock) or &errmsg("$0: unlink $lock: $!\n");
-}
-print "$signer\n" if $signer;
-unless ($ok == 0) {
- &errmsg("$0: verification failed\n");
-}
-exit $ok;
-
-
-# Parse the article headers and return a flag saying whether the message
-# is in NNTP format and then two references to hashes. The first hash
-# contains all the header/value pairs, and the second contains entries for
-# every header that's duplicated. This is, by design, case-sensitive with
-# regards to the headers it checks. It's also insistent about the
-# colon-space rule.
-sub parse_header {
- my (%header, %dup, $label, $value, $nntp_format);
- while (<>) {
- # If the first header line ends with \r\n, this article is in the
- # encoding it would be in during an NNTP session. Some article
- # storage managers keep them this way for efficiency.
- $nntp_format = /\r\n$/ if $. == 1;
- s/\r?\n$//;
-
- last if /^$/;
- if (/^(\S+):[ \t](.+)/) {
- ($label, $value) = ($1, $2);
- $dup{$label} = 1 if $header{$label};
- $header{$label} = $value;
- } elsif (/^\s/) {
- &fail("$0: non-header at line $.: $_\n") unless $label;
- $header{$label} .= "\n$_";
- } else {
- &fail("$0: non-header at line $.: $_\n");
- }
- }
- $messageid = $header{'Message-ID'};
- return ($nntp_format, \%header, \%dup);
-}
-
-# Generate the PGP message to verify. Takes a flag indicating wire
-# format, the hash of headers and header duplicates returned by
-# parse_header and returns a list of three elements. The first is the
-# message to verify, the second is the signature, and the third is the
-# version number.
-sub generate_message {
- my ($nntp_format, $header, $dup) = @_;
-
- # The regexp below might be too strict about the structure of PGP
- # signature lines.
-
- # The $sep value means the separator between the radix64 signature lines
- # can have any amount of spaces or tabs, but must have at least one
- # space or tab; if there is a newline then the space or tab has to
- # follow the newline. Any number of newlines can appear as long as each
- # is followed by at least one space or tab. *phew*
- my $sep = "[ \t]*(\n?[ \t]+)+";
-
- # Match all of the characters in a radix64 string.
- my $r64 = '[a-zA-Z0-9+/]';
-
- local $_ = $$header{'X-PGP-Sig'};
- &fail("$0: X-PGP-Sig not in expected format\n")
- unless /^(\S+)$sep(\S+)(($sep$r64{64})+$sep$r64+=?=?$sep=$r64{4})$/;
-
- my ($version, $signed_headers, $signature) = ($1, $3, $4);
- $signature =~ s/$sep/\n/g;
- $signature =~ s/^\s+//;
-
- my $message = "X-Signed-Headers: $signed_headers\n";
- my $label;
- foreach $label (split(",", $signed_headers)) {
- &fail("$0: duplicate signed $label header, can't verify\n")
- if $$dup{$label};
- $message .= "$label: ";
- $message .= "$$header{$label}" if $$header{$label};
- $message .= "\n";
- }
- $message .= "\n"; # end of headers
-
- while (<>) { # read body lines
- if ($nntp_format) {
- # Check for end of article; some news servers (eg, Highwind's
- # "Breeze") include the dot-CRLF of the NNTP protocol in the article
- # data passed to this script.
- last if $_ eq ".\r\n";
-
- # Remove NNTP encoding.
- s/^\.\./\./;
- s/\r\n$/\n/;
- }
- $message .= $_;
- }
-
- # Strip off all trailing whitespaces for compatibility with the way that
- # pgpverify used to work, using attached signatures.
- $message =~ s/[ \t]+\n/\n/g;
-
- return ($message, $signature, $version);
-}
-
-# Check a detached signature for given data. Takes a signature block (in
-# the form of an ASCII-armored string with embedded newlines), a version
-# number (which may be undef), and the message. We return an exit status
-# and the key id if the signature is verified. 0 means good signature, 1
-# means bad data, 2 means an unknown signer, and 3 means a bad signature.
-# In the event of an error, we report with errmsg.
-#
-# This code is taken almost verbatim from PGP::Sign except for the code to
-# figure out the PGP style.
-sub pgp_verify {
- my ($signature, $version, $message) = @_;
- chomp $signature;
-
- # Ignore SIGPIPE, since we're going to be talking to PGP.
- local $SIG{PIPE} = 'IGNORE';
-
- # Set the PGP style based on whether $gpgv is set.
- my $pgpstyle = ($gpgv ? 'GPG' : 'PGP2');
-
- # Because this is a detached signature, we actually need to save both
- # the signature and the data to files and then run PGP on the signature
- # file to make it verify the signature. Because this is a detached
- # signature, though, we don't have to do any data mangling, which makes
- # our lives much easier. It would be nice to do this without having to
- # use temporary files, but I don't see any way to do so without running
- # into mangling problems.
- #
- # PGP v5 *requires* there be some subheader or another. *sigh*. So we
- # supply one if Version isn't given. :)
- my $umask = umask 077;
- my $filename = $tmpdir . '/pgp' . time . '.' . $$;
- my $sigfile = new FileHandle "$filename.asc", O_WRONLY|O_EXCL|O_CREAT;
- unless ($sigfile) {
- &errmsg ("Unable to open temp file $filename.asc: $!\n");
- return (255, undef);
- }
- if ($pgpstyle eq 'PGP2') {
- print $sigfile "-----BEGIN PGP MESSAGE-----\n";
- } else {
- print $sigfile "-----BEGIN PGP SIGNATURE-----\n";
- }
- if (defined $version) {
- print $sigfile "Version: $version\n";
- } elsif ($pgpstyle ne 'GPG') {
- print $sigfile "Comment: Use GnuPG; it's better :)\n";
- }
- print $sigfile "\n", $signature;
- if ($pgpstyle eq 'PGP2') {
- print $sigfile "\n-----END PGP MESSAGE-----\n";
- } else {
- print $sigfile "\n-----END PGP SIGNATURE-----\n";
- }
- close $sigfile;
-
- # Signature saved. Now save the actual message.
- my $datafile = new FileHandle "$filename", O_WRONLY|O_EXCL|O_CREAT;
- unless ($datafile) {
- &errmsg ("Unable to open temp file $filename: $!\n");
- unlink "$filename.asc";
- return (255, undef);
- }
- print $datafile $message;
- close $datafile;
-
- # Figure out what command line we'll be using.
- my @command;
- if ($pgpstyle eq 'GPG') {
- @command = ($gpgv, qw/--quiet --status-fd=1 --logger-fd=1/);
- } else {
- @command = ($pgp, '+batchmode', '+language=en');
- }
-
- # Now, call PGP to check the signature. Because we've written
- # everything out to a file, this is actually fairly simple; all we need
- # to do is grab stdout. PGP prints its banner information to stderr, so
- # just ignore stderr. Set PGPPATH if desired.
- #
- # For GnuPG, use pubring.gpg if an explicit keyring was configured or
- # found. Otherwise, use trustedkeys.gpg in the default keyring location
- # if found and non-zero, or fall back on pubring.gpg. This is
- # definitely not the logic that I would use if writing this from
- # scratch, but it has the most backward compatibility.
- local $ENV{PGPPATH} = $keyring if ($keyring && $pgpstyle ne 'GPG');
- if ($pgpstyle eq 'GPG') {
- if ($keyring) {
- push (@command, "--keyring=$keyring/pubring.gpg");
- } else {
- my $home = $ENV{GNUPGHOME} || $ENV{HOME};
- $home .= '/.gnupg' if $home;
- if ($home && ! -s "$home/trustedkeys.gpg" && -f "$home/pubring.gpg") {
- push (@command, "--keyring=pubring.gpg");
- }
- }
- }
- push (@command, "$filename.asc");
- push (@command, $filename);
- my $input = new FileHandle;
- my $output = new FileHandle;
- my $pid = eval { open3 ($input, $output, $output, @command) };
- if ($@) {
- &errmsg ($@);
- &errmsg ("Execution of $command[0] failed.\n");
- unlink ($filename, "$filename.asc");
- return (255, undef);
- }
- close $input;
-
- # Check for the message that gives us the key status and return the
- # appropriate thing to our caller. This part is a zoo due to all of the
- # different formats used. GPG has finally done the right thing and
- # implemented a separate status stream with parseable data.
- #
- # MIT PGP 2.6.2 and PGP 6.5.2:
- # Good signature from user "Russ Allbery <rra@stanford.edu>".
- # ViaCrypt PGP 4.0:
- # Good signature from user: Russ Allbery <rra@stanford.edu>
- # PGP 5.0:
- # Good signature made 1999-02-10 03:29 GMT by key:
- # 1024 bits, Key ID 0AFC7476, Created 1999-02-10
- # "Russ Allbery <rra@stanford.edu>"
- #
- # Also, PGP v2 prints out "Bad signature" while PGP v5 uses "BAD
- # signature", and PGP v6 reverts back to "Bad signature".
- local $_;
- local $/ = '';
- my $signer;
- my $ok = 255;
- while (<$output>) {
- print if $test;
- if ($pgpstyle eq 'GPG') {
- if (/\[GNUPG:\]\s+GOODSIG\s+\S+\s+(\S+)/) {
- $ok = 0;
- $signer = $1;
- } elsif (/\[GNUPG:\]\s+NODATA/ || /\[GNUPG:\]\s+UNEXPECTED/) {
- $ok = 1;
- } elsif (/\[GNUPG:\]\s+NO_PUBKEY/) {
- $ok = 2;
- } elsif (/\[GNUPG:\]\s+BADSIG\s+/) {
- $ok = 3;
- }
- } else {
- if (/^Good signature from user(?::\s+(.*)|\s+\"(.*)\"\.)$/m) {
- $signer = $+;
- $ok = 0;
- last;
- } elsif (/^Good signature made .* by key:\n.+\n\s+\"(.*)\"/m) {
- $signer = $1;
- $ok = 0;
- last;
- } elsif (/^\S+: Good signature from \"(.*)\"/m) {
- $signer = $1;
- $ok = 0;
- last;
- } elsif (/^(?:\S+: )?Bad signature /im) {
- $ok = 3;
- last;
- }
- }
- }
- close $input;
- waitpid ($pid, 0);
- unlink ($filename, "$filename.asc");
- umask $umask;
- return ($ok, $signer || '');
-}
-
-# Log an error message, attempting syslog first based on $syslog_method
-# and falling back on stderr.
-sub errmsg {
- my ($message) = @_;
- $message =~ s/\n$//;
-
- my $date = '';
- if ($log_date) {
- $date = strftime ('%Y-%m-%d %T ', localtime);
- }
-
- if ($syslog_method && $] >= 5.006) {
- eval "use Sys::Syslog";
- $syslog_method = 'internal';
- }
-
- if ($syslog_method eq "logger") {
- my @loggers = ('/usr/ucb/logger', '/usr/bin/logger',
- '/usr/local/bin/logger');
- my $try;
- foreach $try (@loggers) {
- if (-x $try) {
- $syslog_method = $try;
- last;
- }
- }
- $syslog_method = '' if $syslog_method eq 'logger';
- }
-
- if ($syslog_method ne '' && $syslog_method !~ m%/logger$%) {
- eval "use Sys::Syslog";
- }
-
- if ($@ || $syslog_method eq '') {
- warn $date, "$0: trying to use Perl's syslog: $@\n" if $@;
- warn $date, $message, "\n";
- warn $date, "... while processing $messageid\n"
- if $messageid;
-
- } else {
- $message .= " processing $messageid"
- if $messageid;
-
- if ($syslog_method =~ m%/logger$%) {
- unless (system($syslog_method, "-i", "-p",
- "$syslog_facility.$syslog_level", $message) == 0) {
- if ($? >> 8) {
- warn $date, "$0: $syslog_method exited status ", $? >> 8, "\n";
- } else {
- warn $date, "$0: $syslog_method died on signal ", $? & 255, "\n";
- }
- $syslog_method = '';
- &errmsg($message);
- }
-
- } else {
- # setlogsock arrived in Perl 5.004_03 to enable Sys::Syslog to use a
- # Unix domain socket to talk to syslogd, which is the only way to do
- # it when syslog runs with the -l switch.
- if ($syslog_method eq "unix") {
- if ($^O eq "dec_osf" && $] >= 5) {
- eval 'sub Sys::Syslog::_PATH_LOG { "/dev/log" }';
- }
- if ($] <= 5.00403 || ! eval "setlogsock('unix')") {
- warn $date, "$0: cannot use syslog_method 'unix' on this system\n";
- $syslog_method = '';
- &errmsg($message);
- return;
- }
- }
-
- # Unfortunately, there is no way to definitively know in this
- # program if the message was logged. I wish there were a way to
- # send a message to stderr if and only if the syslog attempt failed.
- &openlog($0, 'pid', $syslog_facility);
- &syslog($syslog_level, $_[0]);
- &closelog();
- }
- }
-}
-
-sub fail {
- &errmsg($_[0]);
- exit 255;
-}
-
-# Get a lock in essentially the same fashion as INN's shlock. return 1 on
-# success, 0 for normal failure, -1 for abnormal failure. "normal
-# failure" is that a lock is apparently in use by someone else.
-sub shlock {
- my ($file) = @_;
- my ($ltmp, $pid);
-
- unless (defined(&ENOENT)) {
- eval "require POSIX qw(:errno_h)";
- if ($@) {
- # values taken from BSD/OS 3.1
- sub ENOENT { 2 }
- sub ESRCH { 3 }
- sub EEXIST { 17 }
- }
- }
-
- $ltmp = ($file =~ m%(.*/)%)[0] . "shlock$$";
-
- # This should really attempt to use another temp name.
- -e $ltmp && (unlink($ltmp) || return -1);
-
- open(LTMP, ">$ltmp") || return -1;
- print LTMP "$$\n" || (unlink($ltmp), return -1);
- close(LTMP) || (unlink($ltmp), return -1);
-
- if (!link($ltmp, $file)) {
- if ($! == &EEXIST) {
- if (open(LOCK, "<$file")) {
- $pid = <LOCK>;
- if ($pid =~ /^\d+$/ && (kill(0, $pid) == 1 || $! != &ESRCH)) {
- unlink($ltmp);
- return 0;
- }
-
- # OK, the pid in the lockfile is not a number or no longer exists.
- close(LOCK); # silent failure is ok here
-
- # Unlink failed.
- if (unlink($file) != 1 && $! != &ENOENT) {
- unlink($ltmp);
- return 0;
- }
-
- # Check if open failed for reason other than file no longer present.
- } elsif ($! != &ENOENT) {
- unlink($ltmp);
- return -1;
- }
-
- # Either this process unlinked the lockfile because it was bogus, or
- # between this process's link() and open() the other process holding
- # the lock unlinked it. This process can now try to acquire.
- if (! link($ltmp, $file)) {
- unlink($ltmp);
- return $! == &EEXIST ? 0 : -1; # Maybe another proc grabbed the lock.
- }
-
- } else { # First attempt to link failed.
- unlink($ltmp);
- return 0;
- }
- }
- unlink($ltmp);
- return 1;
-}
-
-=head1 NAME
-
-pgpverify - Cryptographically verify Usenet control messages
-
-=head1 SYNOPSIS
-
-B<pgpverify> [B<-test>] < I<message>
-
-=head1 DESCRIPTION
-
-The B<pgpverify> program reads (on standard input) a Usenet control
-message that has been cryptographically signed using the B<signcontrol>
-program (or some other program that produces a compatible format).
-B<pgpverify> then uses a PGP implementation to determine who signed the
-control message. If the control message has a valid signature,
-B<pgpverify> prints (to stdout) the user ID of the key that signed the
-message. Otherwise, it exits with a non-zero exit status.
-
-If B<pgpverify> is installed as part of INN, it uses INN's configuration
-to determine what signature verification program to use, how to log
-errors, what temporary directory to use, and what keyring to use.
-Otherwise, all of those parameters can be set by editing the beginning of
-this script.
-
-By default, when running as part of INN, B<pgpverify> expects the PGP key
-ring to be found in I<pathetc>/pgp (as either F<pubring.pgp> or
-F<pubring.gpg> depending on whether PGP or GnuPG is used to verify
-signatures). If that directory doesn't exist, it will fall back on using
-the default key ring, which is in a F<.pgp> or F<.gnupg> subdirectory of
-the running user's home directory.
-
-INN, when using GnuPG, configures B<pgpverify> to use B<gpgv>, which by
-default expects keys to be in a keyring named F<trustedkeys.gpg>, since it
-doesn't implement trust checking directly. B<pgpverify> uses that file if
-present but falls back to F<pubring.gpg> if it's not found. This bypasses
-the trust model for checking keys, but is compatible with the way that
-B<pgpverify> used to behave. Of course, if a keyring is found in
-I<pathetc>/pgp or configured at the top of the script, that overrides all of
-this behavior.
-
-=head1 OPTIONS
-
-The B<-test> flag causes B<pgpverify> to print out the input that it is
-passing to PGP (which is a reconstructed version of the input that
-supposedly created the control message) as well as the output from PGP's
-analysis of the message.
-
-=head1 EXIT STATUS
-
-B<pgpverify> may exit with the following statuses:
-
-=over 4
-
-=item 0Z<>
-
-The control message had a good PGP signature.
-
-=item 1
-
-The control message had no PGP signature.
-
-=item 2
-
-The control message had an unknown PGP signature.
-
-=item 3
-
-The control message had a bad PGP signature.
-
-=item 255
-
-A problem occurred not directly related to PGP analysis of signature.
-
-=back
-
-=head1 ENVIRONMENT
-
-B<pgpverify> does not modify or otherwise alter the environment before
-invoking the B<pgp> or B<gpgv> program. It is the responsibility of the
-person who installs B<pgpverify> to ensure that when B<pgp> or B<gpgv>
-runs, it has the ability to locate and read a PGP key file that contains
-the PGP public keys for the appropriate Usenet hierarchy administrators.
-B<pgpverify> can be pointed to an appropriate key ring by editing
-variables at the beginning of this script.
-
-=head1 NOTES
-
-Historically, Usenet news server administrators have configured their news
-servers to automatically honor Usenet control messages based on the
-originator of the control messages and the hierarchies for which the
-control messages applied. For example, in the past, David Lawrence always
-issued control messages for the S<"Big 8"> hierarchies (comp, humanities,
-misc, news, rec, sci, soc, talk). Usenet news administrators would
-configure their news server software to automatically honor newgroup and
-rmgroup control messages that originated from David Lawrence and applied
-to any of the S<Big 8> hierarchies.
-
-Unfortunately, Usenet news articles (including control messages) are
-notoriously easy to forge. Soon, malicious users realized they could
-create or remove (at least temporarily) any S<Big 8> newsgroup they wanted by
-simply forging an appropriate control message in David Lawrence's name.
-As Usenet became more widely used, forgeries became more common.
-
-The B<pgpverify> program was designed to allow Usenet news administrators
-to configure their servers to cryptographically verify control messages
-before automatically acting on them. Under the B<pgpverify> system, a Usenet
-hierarchy maintainer creates a PGP public/private key pair and
-disseminates the public key. Whenever the hierarchy maintainer issues a
-control message, he uses the B<signcontrol> program to sign the control
-message with the PGP private key. Usenet news administrators configure
-their news servers to run the B<pgpverify> program on the appropriate
-control messages, and take action based on the PGP key User ID that signed
-the control message, not the name and address that appear in the control
-message's From: or Sender: headers.
-
-Thus, appropriate use of the B<signcontrol> and B<pgpverify> programs
-essentially eliminates the possibility of malicious users forging Usenet
-control messages that sites will act upon, as such users would have to
-obtain the PGP private key in order to forge a control message that would
-pass the cryptographic verification step. If the hierarchy administrators
-properly protect their PGP private keys, the only way a malicious user
-could forge a validly-signed control message would be by breaking the
-public key encryption algorithm, which (at least at this time) is believed
-to be prohibitively difficult for PGP keys of a sufficient bit length.
-
-=head1 HISTORY
-
-B<pgpverify> was written by David C Lawrence <tale@isc.org>. Manual page
-provided by James Ralston. It is currently maintained by Russ Allbery
-<rra@stanford.edu>.
-
-=head1 COPYRIGHT AND LICENSE
-
-David Lawrence wrote: "Our lawyer told me to include the following. The
-upshot of it is that you can use the software for free as much as you
-like."
-
-Copyright (c) 1996 UUNET Technologies, Inc.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-=over 4
-
-=item 1.
-
-Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-
-=item 2.
-
-Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-
-=item 3.
-
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement:
-
- This product includes software developed by UUNET Technologies, Inc.
-
-=item 4.
-
-The name of UUNET Technologies ("UUNET") may not be used to endorse or
-promote products derived from this software without specific prior written
-permission.
-
-=back
-
-THIS SOFTWARE IS PROVIDED BY UUNET "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-NO EVENT SHALL UUNET BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-=head1 SEE ALSO
-
-gpgv(1), pgp(1).
-
-L<ftp://ftp.isc.org/pub/pgpcontrol/> is where the most recent versions of
-B<signcontrol> and B<pgpverify> live, along with PGP public keys used for
-hierarchy administration.
-
-=cut
-
-# Local variables:
-# cperl-indent-level: 2
-# fill-column: 74
-# End:
+++ /dev/null
-#! /usr/bin/perl -w
-# written April 1996, tale@isc.org (David C Lawrence)
-# Currently maintained by Russ Allbery <rra@stanford.edu>
-# Version 1.8, 2003-07-06
-#
-# Changes from 1.6 -> 1.8
-# -- Added support for GnuPG.
-# -- Replace signing code with code from PGP::Sign that generates detached
-# signatures instead. Otherwise, GnuPG signatures with DSA keys could
-# not be verified. Should still work the same as before with RSA keys.
-# -- Thanks to new signing code, no longer uses a temporary file.
-# -- Only lock when using PGP; GnuPG shouldn't need it.
-#
-# Changes from 1.5 -> 1.6
-# -- eliminated subprocess use (except pgp, of course).
-# -- interlock against competing signing processes.
-# -- allow optional headers; see $use_or_add.
-# -- added simple comments about why particular headers are signed.
-# -- made error messages a tad more helpful for situations when it is hard
-# to know what message was trying to be signed (such as via an "at"
-# job).
-# -- set $action, $group, $moderated to "" to prevent unusued variable
-# warnings in the event a Control header can't be parsed.
-# -- moved assignment of $pgpend out of loop.
-#
-# Changes from 1.4 -> 1.5
-# -- need to require Text::Tabs to get 'expand' for tabs in checkgroups.
-#
-# Changes from 1.3 -> 1.4
-# -- added checkgroups checking.
-# -- added group name in several error messages (for help w/batch
-# processing).
-# -- disabled moderator address checking.
-# -- adjusted newsgroups line (ie, tabbing fixed) now correctly
-# substituted into control message.
-#
-# Changes from 1.2.3 -> 1.3
-# -- skip minor pgp signature headers like "charset:" after "version:"
-# header and until the empty line that starts the base64 signature block.
-
-# CONFIGURATION
-
-# PGP variables.
-#
-# $pgp can be set to the path to GnuPG to use GnuPG instead. The program
-# name needs to end in gpg so that signcontrol knows GnuPG is being used.
-#
-# STORING YOUR PASS PHRASE IN A FILE IS A POTENTIAL SECURITY HOLE.
-# make sure you know what you're doing if you do it.
-# if you don't use pgppassfile, you can only use this script interactively.
-# if you DO use pgppassfile, it is possible that someone could steal
-# your passphrase either by gaining access to the file or by seeing
-# the environment of a running pgpverify program.
-#
-# $pgplock is used because pgp does not guard itself against concurrent
-# read/write access to its randseed.bin file. A writable file is needed;
-# The default value is to use the .pgp/config.txt file in the home
-# directory of the user running the program. Note that this will only
-# work to lock against other instances of signcontrol, not all pgp uses.
-# $pgplock is not used if $pgp ends in 'gpg' since GnuPG doesn't need
-# this.
-$pgpsigner = 'INSERT_YOUR_PGP_USERID';
-$pgppassfile = ''; # file with pass phrase for $pgpsigner
-$pgp = "/usr/local/bin/pgp";
-$pgpheader = "X-PGP-Sig";
-$pgplock = (getpwuid($<))[7] . '/.pgp/config.txt';
-
-# this program is strict about always wanting to be consistent about what
-# headers appear in the control messages. the defaults for the
-# @... arrays are reasonable, but you should edit the force values.
-
-# these headers are acceptable in input, but they will be overwritten with
-# these values. no sanity checking is done on what you put here. also,
-# Subject: is forced to be the Control header prepending by "cmsg". also,
-# Newsgroups: is forced to be just the group being added/removed.
-# (but is taken as-is for checkgroups)
-$force{'Path'} = 'bounce-back';
-$force{'From'} = 'YOUR_ADDRESS_AND_NAME';
-$force{'Approved'} = 'ADDRESS_FOR_Approved_HEADER';
-$force{'X-Info'}='ftp://ftp.isc.org/pub/pgpcontrol/README.html'
- . "\n\t"
- . 'ftp://ftp.isc.org/pub/pgpcontrol/README';
-
-# these headers are acceptable in input, or if not present then will be
-# created with the given value. None are enabled by default, because they
-# should not be necessary. Setting one to a null string will pass through
-# any instance of it found in the input, but not generate one if it is
-# missing. If you set any $default{} variables, you must also put it in
-# @orderheaders below.
-#
-# Note that Distribution nearly never works correctly, so use it only if
-# you are really sure the propagation of the article will be limited as
-# you intend. This normally means that you control all servers the
-# distribution will go to with an iron fist.
-#
-# $use_or_add{'Reply-To'} = 'YOUR_REPLY_ADDRESS';
-# $use_or_add{'Oranization'} = 'YOUR_ORGANIZATION';
-# $use_or_add{'Distribution'} = 'MESSAGE_DISTRIBUTION';
-
-# host for message-id; this could be determined automatically based on
-# where it is run, but consistency is the goal here
-$id_host = 'FULL_HOST_NAME';
-
-# headers to sign. Sender is included because non-PGP authentication uses
-# it. The following should always be signed:
-# Subject -- some older news systems use it to identify the control action.
-# Control -- most news systems use this to determine what to do.
-# Message-ID -- guards against replay attacks.
-# Date -- guards against replay attacks.
-# From -- used by news systems as part of authenticating the message.
-# Sender -- used by news systems as part of authenticating the message.
-@signheaders = ('Subject', 'Control', 'Message-ID', 'Date', 'From', 'Sender');
-
-# headers to remove from real headers of final message.
-# If it is a signed header, it is signed with an empty value.
-# set to () if you do not want any headers removed.
-@ignoreheaders = ('Sender');
-
-# headers that will appear in final message, and their order of
-# appearance. all _must_ be set, either in input or via the $force{} and
-# $use_or_add{} variables above.
-# (exceptions: Date, Lines, Message-ID are computed by this program)
-# if header is in use_or_add with a null value, it will not appear in output.
-# several are required by the news article format standard; if you remove
-# these, your article will not propagate:
-# Path, From, Newsgroups, Subject, Message-ID, Date
-# if you take out these, your control message is not very useful:
-# Control, Approved
-# any headers in @ignoreheaders also in @orderheaders are silently dropped.
-# any non-null header in the input but not in @orderheaders or @ignoreheaders
-# is an error.
-# null headers are silently dropped.
-@orderheaders =
- ('Path', 'From', 'Newsgroups', 'Subject', 'Control', 'Approved',
- 'Message-ID', 'Date', 'Lines', 'X-Info', $pgpheader);
-
-# this program tries to help you out by not letting you sign erroneous
-# names, especially ones that are so erroneous they run afoul of naming
-# standards.
-#
-# set to match only hierarchies you will use it on
-# include no '|' for a single hierarchy (eg, "$hierarchies = 'uk';").
-
-$hierarchies = 'HIERARCHIES';
-
-# the draft news article format standard says:
-# "subsequent components SHOULD begin with a letter"
-# where "SHOULD" means:
-# means that the item is a strong recommendation: there may be
-# valid reasons to ignore it in unusual circumstances, but
-# this should be done only after careful study of the full
-# implications and a firm conclusion that it is necessary,
-# because there are serious disadvantages to doing so.
-# as opposed to "MUST" which means:
-# means that the item is an absolute requirement of the specification
-# MUST is preferred, but might not be acceptable if you have legacy
-# newsgroups that have name components that begin with a letter, like
-# news.announce.newgroups does with comp.sys.3b1 and 17 other groups.
-
-$start_component_with_letter = 'MUST';
-
-## END CONFIGURATION
-
-use Fcntl qw(F_SETFD);
-use FileHandle;
-use IPC::Open3 qw(open3);
-use POSIX qw(setlocale strftime LC_TIME);
-use Text::Tabs; # to get 'expand' for tabs in checkgroups
-
-$0 =~ s#^.*/##;
-
-die "Usage: $0 < message\n" if @ARGV > 0;
-
-umask(0022); # flock needs a writable file, if we create it
-if ($pgp !~ /gpg$/) {
- open(LOCK, ">>$pgplock") || die "$0: open $lock: $!, exiting\n";
- flock(LOCK, 2); # block until locked
-}
-
-&setgrouppat;
-
-$die = '';
-
-&readhead;
-&readbody;
-
-if ($die) {
- if ($group) {
- die "$0: ERROR PROCESSING ${action}group $group:\n", $die;
- } elsif ($action eq 'check') {
- die "$0: ERROR PROCESSING checkgroups:\n", $die;
- } elsif ($header{'Subject'}) {
- die "$0: ERROR PROCESSING Subject: $header{'Subject'}\n", $die;
- } else {
- die $die;
- }
-}
-
-&signit;
-
-if ($pgp !~ /gpg$/) {
- close(LOCK) || warn "$0: close $lock: $!\n";
-}
-exit 0;
-
-sub
-setgrouppat
-
-{
- my ($hierarchy, $plain_component, $no_component);
- my ($must_start_letter, $should_start_letter);
- my ($eval);
-
- # newsgroup name checks based on RFC 1036bis (not including encodings) rules:
- # "component MUST contain at least one letter"
- # "[component] MUST not contain uppercase letters"
- # "[component] MUST begin with a letter or digit"
- # "[component] MUST not be longer than 14 characters"
- # "sequences 'all' and 'ctl' MUST not be used as components"
- # "first component MUST begin with a letter"
- # and enforcing "subsequent components SHOULD begin with a letter" as MUST
- # and enforcing at least a 2nd level group (can't use to newgroup "general")
- #
- # DO NOT COPY THIS PATTERN BLINDLY TO OTHER APPLICATIONS!
- # It has special construction based on the pattern it is finally used in.
-
- $plain_component = '[a-z][-+_a-z\d]{0,13}';
- $no_component = '(.*\.)?(all|ctl)(\.|$)';
- $must_start_letter = '(\.' . $plain_component . ')+';
- $should_start_letter = '(\.(?=\d*[a-z])[a-z\d]+[-+_a-z\d]{0,13})+';
-
- $grouppat = "(?!$no_component)($hierarchies)";
- if ($start_component_with_letter eq 'SHOULD') {
- $grouppat .= $should_start_letter;
- } elsif ($start_component_with_letter eq 'MUST') {
- $grouppat .= $must_start_letter;
- } else {
- die "$0: unknown value configured for \$start_component_with_letter\n";
- }
-
- foreach $hierarchy (split(/\|/, $hierarchies)) {
- die "$0: hierarchy name $hierarchy not standards-compliant\n"
- if $hierarchy !~ /^$plain_component$/o;
- }
-
- $eval = "\$_ = 'test'; /$grouppat/;";
- eval $eval;
- die "$0: bad regexp for matching group names:\n $@" if $@;
-}
-
-sub
-readhead
-
-{
- my($head, $label, $value);
- local($_, $/);
-
- $/ = "";
- $head = <STDIN>; # get the whole news header
- $die .= "$0: continuation lines in headers not allowed\n"
- if $head =~ s/\n[ \t]+/ /g; # rejoin continued lines
-
- for (split(/\n/, $head)) {
- if (/^(\S+): (.*)/) {
- $label = $1;
- $value = $2;
-
- $die .= "$0: duplicate header $label\n" if $header{$label};
-
- $header{$label} = $value;
- $header{$label} =~ s/^\s+//;
- $header{$label} =~ s/\s+$//;
- } elsif (/^$/) {
- ; # the empty line separator(s)
- } else {
- $die .= "$0: non-header line:\n $_\n";
- }
- }
-
- $header{'Message-ID'} = '<' . time . ".$$\@$id_host>";
-
- setlocale(LC_TIME, "C");
- $header{'Date'} = strftime("%a, %d %h %Y %T -0000", gmtime);
-
- for (@ignoreheaders) {
- $die .= "ignored header $_ also has forced value set\n" if $force{$_};
- $header{$_} = '';
- }
-
- for (@orderheaders) {
- $header{$_} = $force{$_} if defined($force{$_});
- next if /^(Lines|\Q$pgpheader\E)$/; # these are set later
- unless ($header{$_}) {
- if (defined($use_or_add{$_})) {
- $header{$_} = $use_or_add{$_} if $use_or_add{$_} ne '';
- } else {
- $die .= "$0: missing $_ header\n";
- }
- }
- }
-
- $action = $group = $moderated = "";
- if ($header{'Control'}) {
- if ($header{'Control'} =~ /^(new)group (\S+)( moderated)?$/o ||
- $header{'Control'} =~ /^(rm)group (\S+)()$/o ||
- $header{'Control'} =~ /^(check)groups()()$/o) {
- ($action, $group, $moderated) = ($1, $2, $3);
- $die .= "$0: group name $group is not standards-compliant\n"
- if $group !~ /^$grouppat$/ && $action eq 'new';
- $die .= "$0: no group to rmgroup on Control: line\n"
- if ! $group && $action eq 'rm';
- $header{'Subject'} = "cmsg $header{'Control'}";
- $header{'Newsgroups'} = $group unless $action eq 'check';
- } else {
- $die .= "$0: bad Control format: $header{'Control'}\n";
- }
- } else {
- $die .= "$0: can't verify message content; missing Control header\n";
- }
-}
-
-sub
-readbody
-
-{
- local($_, $/);
- local($status, $ngline, $fixline, $used, $desc, $mods);
-
- undef $/;
- $body = $_ = <STDIN>;
- $header{'Lines'} = $body =~ tr/\n/\n/ if $body;
-
- # the following tests are based on the structure of a
- # news.announce.newgroups newgroup message; even if you comment out the
- # "first line" test, please leave the newsgroups line and moderators
- # checks
- if ($action eq 'new') {
- $status = $moderated ? 'a\smoderated' : 'an\sunmoderated';
- $die .= "$0: nonstandard first line in body for $group\n"
- if ! /^\Q$group\E\sis\s$status\snewsgroup\b/;
-
- my $intro = "For your newsgroups file:\n";
- $ngline =
- (/^$intro\Q$group\E[ \t]+(.+)\n(\n|\Z(?!\n))/mi)[0];
- if ($ngline) {
- $_ = $group;
- $desc = $1;
- $fixline = $_;
- $fixline .= "\t" x ((length) > 23 ? 1 : (4 - ((length) + 1) / 8));
- $used = (length) < 24 ? 24 : (length) + (8 - (length) % 8);
- $used--;
- $desc =~ s/ \(Moderated\)//i;
- $desc =~ s/\s+$//;
- $desc =~ s/\w$/$&./;
- $die .= "$0: $group description too long\n" if $used + length($desc) > 80;
- $fixline .= $desc;
- $fixline .= ' (Moderated)' if $moderated;
- $body =~ s/^$intro(.+)/$intro$fixline/mi;
- } else {
- $die .= "$0: $group newsgroup line not formatted correctly\n";
- }
- # moderator checks are disabled; some sites were trying to
- # automatically maintain aliases based on this, which is bad policy.
- if (0 && $moderated) {
- $die .= "$0: $group submission address not formatted correctly\n"
- if $body !~ /\nGroup submission address: ?\S+@\S+\.\S+\n/m;
- $mods = "( |\n[ \t]+)\\([^)]+\\)\n\n";
- $die .= "$0: $group contact address not formatted correctly\n"
- if $body !~ /\nModerator contact address: ?\S+@\S+\.\S+$mods/m;
- }
- }
- # rmgroups have freeform bodies
-
- # checkgroups have structured bodies
- if ($action eq 'check') {
- for (split(/\n/, $body)) {
- my ($group, $description) = /^(\S+)\t+(.+)/;
- $die .= "$0: no group:\n $_\n" unless $group;
- $die .= "$0: no description:\n $_\n" unless $description;
- $die .= "$0: bad group name \"$group\"\n" if $group !~ /^$grouppat$/;
- $die .= "$0: tab in description\n" if $description =~ /\t/;
- s/ \(Moderated\)$//;
- $die .= "$0: $group line too long\n" if length(expand($_)) > 80;
- }
- }
-}
-
-# Create a detached signature for the given data. The first argument
-# should be a key id, the second argument the PGP passphrase (which may be
-# null, in which case PGP will prompt for it), and the third argument
-# should be the complete message to sign.
-#
-# In a scalar context, the signature is returned as an ASCII-armored block
-# with embedded newlines. In array context, a list consisting of the
-# signature and the PGP version number is returned. Returns undef in the
-# event of an error, and the error text is then stored in @ERROR.
-#
-# This function is taken almost verbatim from PGP::Sign except the PGP
-# style is determined from the name of the program used.
-sub pgp_sign {
- my ($keyid, $passphrase, $message) = @_;
-
- # Ignore SIGPIPE, since we're going to be talking to PGP.
- local $SIG{PIPE} = 'IGNORE';
-
- # Determine the PGP style.
- my $pgpstyle = 'PGP2';
- if ($pgp =~ /pgps$/) { $pgpstyle = 'PGP5' }
- elsif ($pgp =~ /gpg$/) { $pgpstyle = 'GPG' }
-
- # Figure out what command line we'll be using. PGP v6 and PGP v2 use
- # compatible syntaxes for what we're trying to do. PGP v5 would have,
- # except that the -s option isn't valid when you call pgps. *sigh*
- my @command;
- if ($pgpstyle eq 'PGP5') {
- @command = ($pgp, qw/-baft -u/, $keyid);
- } elsif ($pgpstyle eq 'GPG') {
- @command = ($pgp, qw/--detach-sign --armor --textmode -u/, $keyid,
- qw/--force-v3-sigs --pgp2/);
- } else {
- @command = ($pgp, qw/-sbaft -u/, $keyid);
- }
-
- # We need to send the password to PGP, but we don't want to use either
- # the command line or an environment variable, since both may expose us
- # to snoopers on the system. So we create a pipe, stick the password in
- # it, and then pass the file descriptor to PGP. PGP wants to know about
- # this in an environment variable; GPG uses a command-line flag.
- # 5.005_03 started setting close-on-exec on file handles > $^F, so we
- # need to clear that here (but ignore errors on platforms where fcntl or
- # F_SETFD doesn't exist, if any).
- #
- # Make sure that the file handles are created outside of the if
- # statement, since otherwise they leave scope at the end of the if
- # statement and are automatically closed by Perl.
- my $passfh = new FileHandle;
- my $writefh = new FileHandle;
- local $ENV{PGPPASSFD};
- if ($passphrase) {
- pipe ($passfh, $writefh);
- eval { fcntl ($passfh, F_SETFD, 0) };
- print $writefh $passphrase;
- close $writefh;
- if ($pgpstyle eq 'GPG') {
- push (@command, '--batch', '--passphrase-fd', $passfh->fileno);
- } else {
- push (@command, '+batchmode');
- $ENV{PGPPASSFD} = $passfh->fileno;
- }
- }
-
- # Fork off a pgp process that we're going to be feeding data to, and tell
- # it to just generate a signature using the given key id and pass phrase.
- my $pgp = new FileHandle;
- my $signature = new FileHandle;
- my $errors = new FileHandle;
- my $pid = eval { open3 ($pgp, $signature, $errors, @command) };
- if ($@) {
- @ERROR = ($@, "Execution of $command[0] failed.\n");
- return undef;
- }
-
- # Write the message to the PGP process. Strip all trailing whitespace
- # for compatibility with older pgpverify and attached signature
- # verification.
- $message =~ s/[ \t]+\n/\n/g;
- print $pgp $message;
-
- # All done. Close the pipe to PGP, clean up, and see if we succeeded.
- # If not, save the error output and return undef.
- close $pgp;
- local $/ = "\n";
- my @errors = <$errors>;
- my @signature = <$signature>;
- close $signature;
- close $errors;
- close $passfh if $passphrase;
- waitpid ($pid, 0);
- if ($? != 0) {
- @ERROR = (@errors, "$command[0] returned exit status $?\n");
- return undef;
- }
-
- # Now, clean up the returned signature and return it, along with the
- # version number if desired. PGP v2 calls this a PGP MESSAGE, whereas
- # PGP v5 and v6 and GPG both (more correctly) call it a PGP SIGNATURE,
- # so accept either.
- while ((shift @signature) !~ /-----BEGIN PGP \S+-----\n/) {
- unless (@signature) {
- @ERROR = ("No signature from PGP (command not found?)\n");
- return undef;
- }
- }
- my $version;
- while ($signature[0] ne "\n" && @signature) {
- $version = $1 if ((shift @signature) =~ /^Version:\s+(.*?)\s*$/);
- }
- shift @signature;
- pop @signature;
- $signature = join ('', @signature);
- chomp $signature;
- undef @ERROR;
- return wantarray ? ($signature, $version) : $signature;
-}
-
-sub
-signit
-
-{
- my($head, $header, $signheaders, $pgpflags, $pgpbegin, $pgpend);
-
- # Form the message to be signed.
- $signheaders = join(",", @signheaders);
- $head = "X-Signed-Headers: $signheaders\n";
- foreach $header (@signheaders) {
- $head .= "$header: $header{$header}\n";
- }
- my $message = "$head\n$body";
-
- # Get the passphrase if available.
- my $passphrase;
- if ($pgppassfile && -f $pgppassfile) {
- $pgppassfile =~ s%^(\s)%./$1%;
- if (open (PGPPASS, "< $pgppassfile\0")) {
- $passphrase = <PGPPASS>;
- close PGPPASS;
- chomp $passphrase;
- }
- }
-
- # Sign the message, getting the signature and PGP version number.
- my ($signature, $version) = pgp_sign ($pgpsigner, $passphrase, $message);
- unless ($signature) {
- die "@ERROR\n$0: could not generate signature\n";
- }
-
- # GnuPG has version numbers containing spaces, which breaks our header
- # format. Find just some portion that contains a digit.
- ($version) = ($version =~ /(\S*\d\S*)/);
-
- # Put the signature into the headers.
- $signature =~ s/^/\t/mg;
- $header{$pgpheader} = "$version $signheaders\n$signature";
-
- for (@ignoreheaders) {
- delete $header{$_} if defined $header{$_};
- }
-
- $head = '';
- foreach $header (@orderheaders) {
- $head .= "$header: $header{$header}\n" if $header{$header};
- delete $header{$header};
- }
-
- foreach $header (keys %header) {
- die "$0: unexpected header $header left in header array\n";
- }
-
- print STDOUT $head;
- print STDOUT "\n";
- print STDOUT $body;
-}
-
-# Our lawyer told me to include the following. The upshot of it is that
-# you can use the software for free as much as you like.
-
-# Copyright (c) 1996 UUNET Technologies, Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. All advertising materials mentioning features or use of this software
-# must display the following acknowledgement:
-# This product includes software developed by UUNET Technologies, Inc.
-# 4. The name of UUNET Technologies ("UUNET") may not be used to endorse or
-# promote products derived from this software without specific prior
-# written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY UUNET ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL UUNET BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Local variables:
-# cperl-indent-level: 2
-# fill-column: 74
-# End:
+++ /dev/null
-inn2 (2.4.5-5) unstable; urgency=medium
-
- * Added patches u_*: bug fixes from SVN chosen by the upstream maintainer:
- - misc innreport bugs
- - incorrect TLS error handling
- - correctly initialize the status file IP address variables
- - do not send a duplicate reply when TLS negotiation fails
- - correct the permissions checking for XHDR and XPAT
- - do not send a duplicate reply to XOVER/XHDR/XPAT in a empty group
- * Install again our own sasl.conf with the correct paths.
- * Document in README.Debian that STARTTLS and MODE READER do not work
- together. (Closes: #503495)
- * Added patch typo_inn_conf_man fixes a typo in inn.conf(5).
- (Closes: #507256)
- * Updated the md5.c license in debian/copyright.
-
- -- Marco d'Itri <md@linux.it> Mon, 15 Dec 2008 00:50:17 +0100
-
-inn2 (2.4.5-4) unstable; urgency=low
-
- * Backported fixes from SVN: honour the Ad newsfeeds flag and create a
- valid SV for the article body which will correctly match regexps.
-
- -- Marco d'Itri <md@linux.it> Wed, 10 Sep 2008 01:36:04 +0200
-
-inn2 (2.4.5-3) unstable; urgency=medium
-
- * Do not FTBFS with old versions of find. (Closes: #495508)
-
- -- Marco d'Itri <md@linux.it> Thu, 28 Aug 2008 04:21:48 +0200
-
-inn2 (2.4.5-2) unstable; urgency=medium
-
- * Rebuilt with libdb4.6-dev.
-
- -- Marco d'Itri <md@linux.it> Sun, 27 Jul 2008 19:23:55 +0200
-
-inn2 (2.4.5-1) unstable; urgency=low
-
- * New upstream STABLE release.
-
- -- Marco d'Itri <md@linux.it> Tue, 01 Jul 2008 01:18:29 +0200
-
-inn2 (2.4.4r-1) unstable; urgency=low
-
- * New upstream STABLE release. (For real, this time.)
- * On 32 bit architectures, build a new inn2-lfs package with Larges
- Files Support enabled. (Closes: #433751)
- * Enabled support for Kerberos. (Closes: #478775)
- * Rebuilt with perl 5.10. (Closes: #479244)
- * Removed usage of debconf.
-
- -- Marco d'Itri <md@linux.it> Sun, 11 May 2008 12:31:56 +0200
-
-inn2 (2.4.4-1) unstable; urgency=low
-
- * New upstream STABLE snapshot.
- + Rotates innfeed.log. (Closes: #407752)
- + Make inews not fail if MODE READER fails because the connection has
- not been authenticated yet. (Closes: #475059)
- * Removed S from Default-Stop in the init script. (Closes: #471081)
- * Updated debconf translation: pt. (Closes: #444720)
- * Fixed a typo in the name of debian/inn2.logcheck.violations.ignore.
- * Stop overwriting active.times(5) with a symlink, inn now has it.
- * Fixed many minor issues pointed out by Julien Élie. (Closes: #455882)
- * Removed patches merged upstream: daemonize-ovdb_init,
- fix-crash-on-reload, hashfeeds.
- * Remove /var/lib/news/ on purge. (Closes: #455104)
-
- -- Marco d'Itri <md@linux.it> Mon, 14 Apr 2008 22:01:48 +0200
-
-inn2 (2.4.3+20070806-1) unstable; urgency=low
-
- * New upstream STABLE snapshot.
- * Package converted to quilt.
- * Added patch fix-crash-on-reload to fix segfaults when reloading
- incoming.conf (Closes: #361073, #429802, #430190, #430191)
- * Added patch daemonize-ovdb_init to make ovdb_init properly close
- stdin/out/err when it becomes a daemon. (Closes: #433522)
- * Added patch inndstart-sockets-v6only to suppress a startup warning
- about an already opened socket.
- * Fixed the bzip2 path in bunbatch. (Closes: #419429)
- * Removed patches merged upstream: ckpasswd_use_libdb, fix_radius.conf,
- innfeed-fix-getaddrinfo, innfeed-force-ipv4, libdb-4.4.
- * Use --as-needed to not link superfluous libraries.
- * New debconf translations: pt, nl. (Closes: #414921, #415511)
- * Added a logcheck file. (Closes: #405536)
-
- -- Marco d'Itri <md@linux.it> Tue, 07 Aug 2007 16:35:06 +0200
-
-inn2 (2.4.3-1) unstable; urgency=low
-
- * New upstream release. (Closes: #381415)
- + Fixes nnrpd when "localmaxartsize: 0". (Closes: #357370)
- * Removed support for his64v6 and cnfs64, which do not work anyway.
- ****** I am looking for a co-maintainer interested in adding ******
- ****** support to build a inn2-lfs package. ******
- * Switched to libdb4.4.
- * New debconf translations: vi, cs, sv. (Closes: #314245, #315211, #339811)
- * Pre-Depends on debconf-2.0 too. (Closes: #331859)
- * Added to innfeed support for a "force-ipv4" configuration option.
- Based on a patch contributed by Henning Makholm. (Closes: #336264)
- * Added to innfeed support for hashed feeds.
- * pgpverify: try harder to find the home directory. (Closes: #307765)
- * Moved nnrpd-ssl to the main package.
- * Added support for libdb to ckpasswd. (Closes: #380644)
- * Use FHS paths in the perl-nocem documentation. (Closes: #365639)
- * Create /var/run/news in the init script if it does not exist.
-
- -- Marco d'Itri <md@linux.it> Fri, 18 Aug 2006 11:19:21 +0200
-
-inn2 (2.4.2-3) unstable; urgency=high
-
- * Fixed upgrades on systems with a non-default pathdb. (Closes: #306765)
- * Added the showtoken program. (Closes: #306837)
-
- -- Marco d'Itri <md@linux.it> Sat, 14 May 2005 15:03:56 +0200
-
-inn2 (2.4.2-2) unstable; urgency=medium
-
- * New upstream snapshot (20050407).
- * Stop providing the inn package. (Closes: #288659)
- * Made postinst continue when makehistory or makedbz fail. (Closes: #292167)
- * Switched to libdb4.3.
-
- -- Marco d'Itri <md@linux.it> Fri, 8 Apr 2005 14:51:22 +0200
-
-inn2 (2.4.2-1) unstable; urgency=low
-
- * New upstream release.
- + Removed patch innreport_nnrpd-ssl.
- + Fixed news2mail, CNFS buffers reporting. (Closes: #282664, #276819)
-
- -- Marco d'Itri <md@linux.it> Fri, 24 Dec 2004 17:05:33 +0100
-
-inn2 (2.4.1+20040820-2) unstable; urgency=medium
-
- * New upstream snapshot (upstream/patches/20040820-to-20040929.diff).
- + make Norbert Tretkowski happy. (Closes: #255324)
- + fix inn2-ssl segfaults on ia64. (Closes: #270875)
- * Conflict with inn and cnews instead of news-transport-system.
- (Closes: #269874)
-
- -- Marco d'Itri <md@linux.it> Wed, 29 Sep 2004 17:24:18 +0200
-
-inn2 (2.4.1+20040820-1) unstable; urgency=medium
-
- * New upstream snapshot.
- + Fixes headers folding in the overview. (Closes: #190207)
- + Fixes headers for articles mailed to moderators. (Closes: #249151)
- * Added a default CA file name to sasl.conf. (Closes: #250201)
- * New patch innreport_nnrpd-ssl: makes innreport correctly parse the
- nnrpd-ssl log entries. (Closes: #250252)
- * New debconf translations: de, ja. (Closes: #263030, #251100)
-
- -- Marco d'Itri <md@linux.it> Fri, 20 Aug 2004 19:32:20 +0200
-
-inn2 (2.4.1+20040403-1) unstable; urgency=medium
-
- * New upstream snapshot. (Closes: #141750)
- * Switched to db4.2. (Closes: #241584)
- * Added catalan debconf template. (Closes: #236668)
- * Removed the patches fix_bindaddress, default-storage.diff and
- fix_reiserfs26.diff because they have been merged upstream.
- * Removed the patch libdb41-fix.diff because it's not needed anymore.
-
- -- Marco d'Itri <md@linux.it> Sat, 3 Apr 2004 21:00:31 +0200
-
-inn2 (2.4.1-2) unstable; urgency=medium
-
- * Fix bindaddress. (Closes: #183812)
- * Fix paths in inn2-ssl. (Closes: #229181)
-
- -- Marco d'Itri <md@linux.it> Sat, 24 Jan 2004 17:13:43 +0100
-
-inn2 (2.4.1-1) unstable; urgency=high
-
- * New upstream release.
- + Fixes buffer overflow, maybe remotely exploitable. (Closes: #226772)
- * Add workaround for 2.6.x reiserfs brokeness. (Closes: #225940)
- * Use pgpverify from -CURRENT to add useless DSA support. (Closes: #222634)
- * Source package converted to DBS.
-
- -- Marco d'Itri <md@linux.it> Thu, 8 Jan 2004 20:30:49 +0100
-
-inn2 (2.4.0+20031130-1) unstable; urgency=low
-
- * New upstream STABLE snapshot. (Closes: #213946)
- * Added russian and spanish debconf messages. (Closes: #219235, #220884)
- * Replaces: inn2-dev to improve upgrades from woody. (Closes: #217219)
- * Added a new his64v6 history method with LFS support. Untested!
- (Closes: #215877)
-
- -- Marco d'Itri <md@linux.it> Sun, 30 Nov 2003 22:54:02 +0100
-
-inn2 (2.4.0+20030912-1) unstable; urgency=low
-
- * New upstream STABLE snapshot.
- * Add again a default storage method to storage.conf. (Closes: #205001)
- * Fix the getlist command line in actsyncd. (Closes: #206283)
- * Added a new cnfs64 method for large cycbufs. The on disk format is not
- compatible with 32-bit cycbufs. The storage tokens are not compatible
- with the tokens of a standard inn package built with --enable-largefiles
- (but they could be converted, let me know if you want to try this).
- This is basically untested and may trash the data you feed it. Please
- let me know if this works for you or not. (Closes: #206828)
-
- -- Marco d'Itri <md@linux.it> Fri, 12 Sep 2003 14:07:06 +0200
-
-inn2 (2.4.0+20030808-1) unstable; urgency=medium
-
- * New upstream snapshot.
- * Fix readers.conf(5) and ckpasswd(8). (Closes: #202098, #202300)
- * Fix innupgrade invocation in postinst. (Closes: #202978)
- * Misc debconf-related fixes courtesy of Christian Perrier
- <bubulle@debian.org>. (Closes: #200517, #200518)
- * Added polish, spanish and french debconf messages.
- (Closes: #202155, #201627)
-
- -- Marco d'Itri <md@linux.it> Fri, 8 Aug 2003 13:56:23 +0200
-
-inn2 (2.4.0-3) unstable; urgency=medium
-
- * Add db_stop to postinst.
- * Fixed inn.conf path in postinst. (Closes: #198578)
-
- -- Marco d'Itri <md@linux.it> Wed, 25 Jun 2003 15:15:54 +0200
-
-inn2 (2.4.0-2) unstable; urgency=medium
-
- * Install all headers in /usr/include/inn. (Closes: #198463, #198464)
- * Added debconf support, patch by <arturcz@hell.pl>.
-
- -- Marco d'Itri <md@linux.it> Mon, 23 Jun 2003 19:19:37 +0200
-
-inn2 (2.4.0-1) unstable; urgency=medium
-
- * New upstream release. (Closes: #182751, #188740, #193967, #194273, #198395)
- * send-uucp.pl is now send-uucp.
- * Switched from db4.0 to db4.1.
- * postinst should not fail if innd cannot start. (Closes: #189966)
- * Depend on perlapi-5.8.0. (Closes: #187717, #192411)
- * Depend on inn2-inews >= 2.3.999+20030227-1. (Closes: #196137)
- * Do not scare admins with wrong postinsg messages. (Closes: #183103)
- * Corrected typo in innupgrade. (Closes: #194444)
- * Added fr.* to /etc/news/moderators. (Closes: #190202)
-
- -- Marco d'Itri <md@linux.it> Fri, 20 Jun 2003 18:39:21 +0200
-
-inn2 (2.3.999+20030227-1) unstable; urgency=low
-
- * New upstream snapshot:
- * Fix expireover segfaults. (Closes: #180462, #179898)
- * Create /var/log/news/path. (Closes: #180168, #180602)
- * Build-Depends on libssl-dev. (Closes: #180662)
- * Fix missing feed name in the log. (Closes: #178842, #181740)
- * Fix news2mail. (Closes: #181086)
- * Fix minor bugs in the init script. (Closes: #180866, #180867)
-
- -- Marco d'Itri <md@linux.it> Thu, 27 Feb 2003 19:11:57 +0100
-
-inn2 (2.3.999+20030205-2) unstable; urgency=low
-
- * New upstream snapshot. (Closes: #179294)
- * Add a new inn2-ssl package. (Closes: #163672)
- * Move wildmat(3) from inn2-dev to inn2. (Closes: #179441)
- * Downgraded to extra priority.
- Most people do not need a local news server, and definitely not INN 2.x.
- * Create /var/{lib,run}/news in postinst.
-
- -- Marco d'Itri <md@linux.it> Thu, 6 Feb 2003 15:18:02 +0100
-
-inn2 (2.3.999+20030125-3) unstable; urgency=low
-
- * Fix rnews breakage. (Closes: #178673)
- * Remove hardcoded paths of egrep, awk, sed, sort, wget. (Closes: #176749)
-
- -- Marco d'Itri <md@linux.it> Tue, 28 Jan 2003 01:48:03 +0100
-
-inn2 (2.3.999+20030125-2) unstable; urgency=low
-
- * Fix broken ctlinnd. (Closes: #178588)
-
- -- Marco d'Itri <md@linux.it> Mon, 27 Jan 2003 19:41:03 +0100
-
-inn2 (2.3.999+20030125-1) unstable; urgency=low
-
- * BEWARE: this is a -CURRENT snapshot. If it breaks you keep both pieces!
- (Closes: #172212, #174938, #176336).
- * Make innreport generate valid HTML. (Closes: #166372)
- * Pre-Depends on inn2-inews. (Closes: #166804)
- * Update gnu.* data in control.ctl. (Closes: #167581)
- * Do not ship rnews suid root! (Closes: #171757)
- * Install /usr/share/doc/inn2/INSTALL.gz (Closes: #174493)
-
- -- Marco d'Itri <md@linux.it> Thu, 16 Jan 2003 01:12:53 +0100
-
-inn2 (2.3.3+20020922-5) unstable; urgency=medium
-
- * Fixed pathtmp (Closes: #162686).
- * Check if the usenet user exists before adding a mail alias
- (Closes: #162731).
- * Fixed a path in sendinpaths (Closes: #163022).
-
- -- Marco d'Itri <md@linux.it> Mon, 7 Oct 2002 20:24:16 +0200
-
-inn2 (2.3.3+20020922-4) unstable; urgency=low
-
- * Applied OVDB fixes, courtesy of Ian Hastie @clara.net (Closes: #162643).
-
- -- Marco d'Itri <md@linux.it> Sat, 28 Sep 2002 16:46:57 +0200
-
-inn2 (2.3.3+20020922-3) unstable; urgency=low
-
- * Fixed absolute path in Makefile (Closes: #162538).
-
- -- Marco d'Itri <md@linux.it> Fri, 27 Sep 2002 19:12:10 +0200
-
-inn2 (2.3.3+20020922-1) unstable; urgency=low
-
- * New STABLE CVS snapshot (Closes: #128725, #137175, #157808, #159105).
- * Made some changes to make INN compile with perl 5.8.0. May be broken.
- * Fix inndf to convert the "infinite" inodes of reiserfs to 2^31 - 1
- (Closes: #124101).
- * Suggests: gnupg instead of pgp.
- * Brand new init script which uses ctlinnd.
- * Removed debian changes to use mkstemp. INN uses a private temp
- directory anyway.
- * Conflicts+Replaces: ninpaths, added the scripts from the inpaths package.
- * Do not depend anymore on libdb3-util, which is only needed by OVDB.
- * Removed signcontrol.
- * Changed control.* and junk groups to status n.
- * Added gpgverify script (Closes: #131412).
- * Added bunbatch script (Closes: #136860).
- * Added /usr/share/doc/inn2/INSTALL.gz (Closes: #156685).
- * Added buildinnkeyring script which downloads PGP keys from ftp.isc.org
- (Closes: #86989).
-
- -- Marco d'Itri <md@linux.it> Sun, 22 Sep 2002 21:05:18 +0200
+++ /dev/null
-inn2 (2.3.999+20030114-1) unstable; urgency=low
-
- * BEWARE: this is a -CURRENT snapshot. If it breaks you keep both pieces!
- (Closes: #172212, #174938).
- * Make innreport generate valid HTML. (Closes: #166372)
- * Pre-Depends on inn2-inews. (Closes: #166804)
- * Update gnu.* data in control.ctl. (Closes: #167581)
- * Do not ship rnews suid root! (Closes: #171757)
- * Install /usr/share/doc/inn2/INSTALL.gz (Closes: #174493)
-
- -- Marco d'Itri <md@linux.it> Thu, 16 Jan 2003 01:12:53 +0100
-
-inn2 (2.3.3+20020922-5) unstable; urgency=medium
-
- * Fixed pathtmp (Closes: #162686).
- * Check if the usenet user exists before adding a mail alias
- (Closes: #162731).
- * Fixed a path in sendinpaths (Closes: #163022).
-
- -- Marco d'Itri <md@linux.it> Mon, 7 Oct 2002 20:24:16 +0200
-
-inn2 (2.3.3+20020922-4) unstable; urgency=low
-
- * Applied OVDB fixes, courtesy of Ian Hastie @clara.net (Closes: #162643).
-
- -- Marco d'Itri <md@linux.it> Sat, 28 Sep 2002 16:46:57 +0200
-
-inn2 (2.3.3+20020922-3) unstable; urgency=low
-
- * Fixed absolute path in Makefile (Closes: #162538).
-
- -- Marco d'Itri <md@linux.it> Fri, 27 Sep 2002 19:12:10 +0200
-
-inn2 (2.3.3+20020922-1) unstable; urgency=low
-
- * New STABLE CVS snapshot (Closes: #128725, #137175, #157808, #159105).
- * Made some changes to make INN compile with perl 5.8.0. May be broken.
- * Fix inndf to convert the "infinite" inodes of reiserfs to 2^31 - 1
- (Closes: #124101).
- * Suggests: gnupg instead of pgp.
- * Brand new init script which uses ctlinnd.
- * Removed debian changes to use mkstemp. INN uses a private temp
- directory anyway.
- * Conflicts+Replaces: ninpaths, added the scripts from the inpaths package.
- * Do not depend anymore on libdb3-util, which is only needed by OVDB.
- * Removed signcontrol.
- * Changed control.* and junk groups to status n.
- * Added gpgverify script (Closes: #131412).
- * Added bunbatch script (Closes: #136860).
- * Added /usr/share/doc/inn2/INSTALL.gz (Closes: #156685).
- * Added buildinnkeyring script which downloads PGP keys from ftp.isc.org
- (Closes: #86989).
-
- -- Marco d'Itri <md@linux.it> Sun, 22 Sep 2002 21:05:18 +0200
-
-inn2 (2.3.3-1) unstable; urgency=low
-
- * new upstream version
- * use 'unset' not 'declare -x' GZIP to clear environment in innshellvars,
- closes: #136156, #136495, #136557, #142464
- * add a warning to inn.conf comments about avoiding tabs after values,
- closes: #112657, #112665
- * modify cron.d to test for presence of programs before running them,
- closes: #136563
- * modify init.d to redirect rc.news output to /var/log/news/rc.news so that
- inn2 daemonizes properly when run manually with the positive side effect
- that the startup messages now comply with Debian policy,
- closes: #140794, #116716, #134459
- * deliver more upstream doc files, closes: #141963
- * procps is priority required, but not marked essential, so we need to
- depend on it so innwatch can use 'uptime', closes: #146135
- * add a clause to postinst to make sure /var/spool/news has appropriate
- owner/group/perms
-
- -- Bdale Garbee <bdale@gag.com> Fri, 24 May 2002 00:49:08 -0600
-
-inn2 (2.3.2-3) unstable; urgency=low
-
- * apply patch from rene@seindal.dk to pullnews.in to keep a missing group
- from killing a run, closes: #133571
- * apply patch from falcon@wysocki.lodz.pdi.net to dbprocs.in so that ovdb
- will work correctly with libdb3, and add a runtime dependency on
- libdb3-util to the inn2 package, closes: #128855
- * add manpage symlinks, closes: #99543, #99578
- * ensure backoff directory exists during postinst, closes: #127050
- * clean up some of the lintian warnings
-
- -- Bdale Garbee <bdale@gag.com> Sat, 16 Feb 2002 15:06:20 -0700
-
-inn2 (2.3.2-2) unstable; urgency=low
-
- * edit provided buffindexed.conf to reflect our path structure
- * apply patch to mailpost.in provided by Paul Seelig to prevent message
- posting failures by stripping Received lines, closes: #120267
- * add remaining /etc files to conffiles, closes: #110647
- * make sure /var/log/news/OLD is news.news in postinst, closes: #116715
- * slightly tighten permissions on /var/run/news, closes: #117773
- * fix missing quotes around command in init.d,closes: #120105
- * explicitly unexport GZIP in innshellvars before defining it to avoid
- clashes with GZIP set in external environment, closes: #120381
- * eliminate the task-news-server binary package
-
- -- Bdale Garbee <bdale@gag.com> Wed, 26 Dec 2001 16:02:44 -0700
-
-inn2 (2.3.2-1) unstable; urgency=low
-
- * new upstream version, closes: #98247, #101601
- * remove authprogs/pwcheck.c and modify authprogs/Makefile in orig.tar.gz
- since we don't use it and license is non-DFSG-compliant! Closes: #103477
- * make inn2-inews conflict with cnews, closes: #97662
- * modify news.daily to use tempfile(1) for safe tempfile creation,
- closes: #104517
- * improve several instances of unsafe temp file handling using relevant
- patches from the Debian security team, closes: #83734
- * patch to fix expireover seg faults from Andrew Stribblehill, closes: #95096
- * make 'server' in inn.conf be 'localhost' by default, closes: #90908
- * add a note in the sample newsfeeds file indicating that nntplink is not
- part of INN, closes: #88120
- * depend on awk, closes: #87618 Note, I will *not* change the compress
- definition in innshellvars, see README.Debian for details.
- * only execute rnews in cron if it exists, so that removing but not purging
- inn2 doesn't generate excessive email, closes: #89853
- * postinst forces owner of default log files to be correct, closes: #98490
- * enable support for ovdb, closes: #96612
- * remove references to non-existent newslog(8) man page, clean up wildmat(5)
- references, closes: #90993
- * apply patches from Tollef Fog Heen for gnupg use in signcontrol and use
- safer temp file handling, closes: #99021, #99242
- * the inn2 package really can't do anything about the way conffiles are
- handled by dpkg when moving from inn to inn2. inn and inn2 are distinct
- packages to Debian, despite their similar heritage, closes: #97443
-
- -- Bdale Garbee <bdale@gag.com> Fri, 10 Aug 2001 13:48:38 -0600
-
-inn2 (2.3.1-4) unstable; urgency=low
-
- * make /etc/news/filter/* conffiles, closes: #85315
- * update build-depends, changing perl5 to libperl-dev
-
- -- Bdale Garbee <bdale@gag.com> Tue, 20 Feb 2001 15:30:56 -0700
-
-inn2 (2.3.1-3) unstable; urgency=low
-
- * conflict with current and prior versions of suck, since they use innxmit
- in a way that no longer works, resulting in data loss as per bug 83727.
- Reassign that bug to suck for implementation of a real solution.
- * update the init.d script to use rc.news as upstream intends for start and
- stop operations, since it handles the current set of INN daemons better
- than our previous attempt to use start-stop-daemon does, closes: #84438
- * tag /etc/news/send-uucp.cf as a conffile, closes: #83282
-
- -- Bdale Garbee <bdale@gag.com> Mon, 5 Feb 2001 16:04:12 -0700
-
-inn2 (2.3.1-2) unstable; urgency=low
-
- * update send-uucp.pl's idea of where innshellvars.pl is, closes: #83194
- * go back to symlinks instead of moving inews and rnews, closes: #83224
- * have preinst clean up /usr/lib/news/bin/filter dregs, closes: #83515
- * have inn2-inews conflict/replace inn2 prior to 2.3.1 to account for moving
- some files, closes: #83622
-
- -- Bdale Garbee <bdale@gag.com> Tue, 30 Jan 2001 17:32:17 -0700
-
-inn2 (2.3.1-1) unstable; urgency=low
-
- * new upstream release. thank you Marco d'Itri <md@Linux.IT> for help with
- this update
- * revert send-uucp to the upstream version, deliver Perl version as
- send-uucp.pl, closes: #81074
- * add manual page for send-uucp.pl written by Mark Brown, closes: #81073
- * in 2.3.0-1, we accidentally shipped active, active.times, and newsgroups
- as real files in /var/lib/news. Hack the preinst and postinst to protect
- the files in place, and fix the mess. While we're at it, fix a few other
- details in the postinst. Closes: #81274
- * update preinst warning and README.Debian to add an explicit pointer to the
- NEWS file, which documents the 2.2 to 2.3 changes. Fix a few out of date
- items in README.Debian. Closes: #81069
- * fix path of required file in send-uucp.pl, closes: #81075
- * move rnews and dependencies to the inn2-inews package, closes: #81268
- * freshen PGPKEYS file from ftp.isc.org, fixes fr.* key and adds a new one,
- closes: #81272
- * pgpverify: use /etc/news/pgp as pgp/gnupg config dir and the syslog
- socket instead of logger. (Md)
- * innd/cc.c: added perl filter status patch (used by cleanfeed). (Md)
- * debian/cron.d: added entry to reload incoming.conf and sample entries
- for send-nntp and send-uucp.pl. (Md) closes: #81269
- * debian/init.d: first try to gracefully shut down innd with ctlinnd. (Md)
- * Changed /usr/lib/news/bin/filter to /etc/news/filter. (Md) closes: #81273
- * Moved back the whole /etc/news/scripts to the standard location in
- /usr/lib/news, none of these files is a conffile. (Md) This improves the
- postinst questioning considerably, closes: #81072
- * Fixed permissions of many binaries and config files. (Md) closes: #82002
- * inews is not installed suid (suggested by upstream maintainer). (Md)
- * Renamed send-uucp.pl.1 to send-uucp.pl.8. (Md)
- * lose the "Recommends: trn | news-reader" on the inn2 package, it's not
- particularly useful, and gets in the way for dedicated servers
- * drop the "Suggests: inn2-dev" from inn2, the few who need it will find it,
- and it confuses new users
- * minor patch for actsyncd, closes: #80973
- * inews now supports a -p option to set the port, closes: #22242, #68875
- * touch the /var/lib/news/.news.daily file in the postinst to squelch the
- email about it being missing before nightly cron runs begin. closes: #76195
- * suidregister is obsolete. newer dpkg's include 'dpkg-statoverride', which
- is a superior solution requiring nothing from the package. closes: #81310
- * configure storage.conf for tradspool configuration by default
- * modify configure/configure.in slightly so build hostname isn't embedded
- in inn.conf, et al
- * don't force alt.test to exist, not all servers want it
- * add code to the preinst to clean up the scripts tagged as conffiles that
- will still be around from 2.3.0-1. Sigh.
-
- -- Bdale Garbee <bdale@gag.com> Mon, 22 Jan 2001 17:23:45 -0700
-
-inn2 (2.3.0-1) unstable; urgency=low
-
- * new upstream version, closes: #69623
- * sendbatch appears to be fixed now, closes: #69561
- * innreport now appears to use png if gif isn't available, closes: #76169
- * thanks to John Goerzen for help cleaning up this release
- * hack around need to have pgp installed at build time, closes: #69745
- * add sanity checks for syslog files in the postinst, closes: #74707
- * move all the scripts in /usr/lib/news that must be conffiles into /etc,
- backfilling symlinks. Closes: #57150
- * built against perl-5.6, closes: #80703
- * can't duplicate removal problem, closes: #77419
- * update pgpverify's default notion of where to find pgp, closes: #78989
- * ship the Perl send-uucp from Miquel van Smoorenburg, closes: #77836
- * give inews more reasonable owner/group/perms, closes: #70856
- * add another warning to the preinst since some file format changes defy
- reasonable automation across the upgrade from pre-2.3.0 to 2.3.0, and some
- manual actions will likely be required.
- * as of 2.3.0, innshellvars now codes 'compress' as the path for the compress
- program instead of an ugly token reporting that compress wasn't found if
- there is no compress available at build time. This will work if the
- non-free 'ncompress' package is installed. Since some news sites still
- don't use gzip for uucp batches, this is probably the right default. Note
- added to the README.Debian file.
- Closes: #77030
-
- -- Bdale Garbee <bdale@gag.com> Thu, 28 Dec 2000 16:17:47 -0700
-
-inn2 (2.2.3-3) unstable; urgency=low
-
- * leave the real inews executable in /usr/lib/news/bin, and symlink to it
- from /usr/bin instead of moving it, to reduce breakage. Closes: #68999
- * do the same thing with rnews, for good measure
-
- -- Bdale Garbee <bdale@gag.com> Mon, 14 Aug 2000 02:58:39 -0600
-
-inn2 (2.2.3-2) unstable; urgency=medium
-
- * patch from upstream that fixes remote denial of service, closes: #66638
- * provide /usr/sbin/ctlinnd as a symlink so ctlinnd is in root's path,
- closes: #67730
- * update the README.Debian file to explain the situation with 'compress'
- and indicate willingness to receive patch suggestions for making inn2
- work better with uucp article transport, closes: #64284, #67629
-
- -- Bdale Garbee <bdale@gag.com> Sun, 13 Aug 2000 22:39:21 -0600
-
-inn2 (2.2.3-1) unstable; urgency=low
-
- * new upstream release, closes: #67635, #65492, #59345, #64405
- * ensure control.cancel exists since we like usecontrolchan=true,
- closes: #57555
- * add some verbage to the README.Debian about anacron, closes: #59664
- * some of the code proposed by Raphael Bossek for the init.d is only
- relevant for a 1.X to 2.X upgrade, and the rest could take quite a
- while during boot. I therefore don't think this belongs in init.d.
- I'm adding the interesting checks to the postinst, closes: #62045
- * provide PGPKEYS and some text about it in the README.Debian file,
- closes: #66756
-
- -- Bdale Garbee <bdale@gag.com> Tue, 25 Jul 2000 01:23:14 -0600
-
-inn2 (2.2.2.2000.01.31-4) frozen unstable; urgency=low
-
- * add code to the postinst that calls 'hostname --fqdn' to make sure we can
- determine the FQDN before we try to start the daemon. Not doing this
- caused installs to fail on poorly-configured systems. Closes: #64681
- * target frozen since this was tagged important, and could indeed cause an
- install or upgrade to fail in some (relatively rare?) cases.
-
- -- Bdale Garbee <bdale@gag.com> Fri, 26 May 2000 21:32:01 -0600
-
-inn2 (2.2.2.2000.01.31-3) frozen unstable; urgency=low
-
- * target frozen since these are release critical
- * fix a variety of permission problems including /var/lib/news,
- closes: #61077
- * permit world execute of /usr/bin/rnews, closes: #61409
-
- -- Bdale Garbee <bdale@gag.com> Thu, 6 Apr 2000 23:17:56 -0600
-
-inn2 (2.2.2.2000.01.31-2) frozen unstable; urgency=low
-
- * target frozen since one of these is release critical
- * fix owner, group, and permissions of /var/run/news on fresh installs,
- closes: #61030
- * minor tweak to default inn.conf so build host isn't the value of pathhost
- on new installs, closes: #60779
- * fix owner, group, and permissions of /usr/bin/rnews so that it actually
- works, closes: #58964
-
- -- Bdale Garbee <bdale@gag.com> Fri, 24 Mar 2000 01:01:57 -0700
-
-inn2 (2.2.2.2000.01.31-1) frozen unstable; urgency=low
-
- * target frozen since some of the bug fixes here qualify as release critical
- * roll to current stable CVS snapshot to acquire bug fixes (some significant)
- since 2.2.2 release, closes: #55581
- * tag many scripts in /usr/lib/news/ as conffiles, so changes aren't lost on
- upgrades. This makes particularly good sense given the apparent upstream
- attitude that whacking scripts to configure a system is reasonable. Add
- lintian overrides since it calls conffiles under /usr errors.
- Closes: #55723, #56385
- * have inn2 "provide inn" so that other packages that depend on inn don't
- get frustrated with us, closes: #56040
- * add -L to innflags and turn controlchan on in default inn.conf (to match
- what we're shipping in default newsfeeds file), closes: #56383, #56384
- * don't remove /usr/lib/news explicitly in postrm, since other packages need
- it, closes: #55467
-
- -- Bdale Garbee <bdale@gag.com> Mon, 31 Jan 2000 23:48:44 -0700
-
-inn2 (2.2.2-4) frozen unstable; urgency=low
-
- * change package names from inn to inn2 as part of Debian INN peace project,
- which will reinstate 1.7.2 as 'inn'. Target frozen so we ship both 1.7.2
- and 2.2.2 with potato!
- * add suitable conflicts with inn 1.X packages, leaving check for old
- versions in preinst along since it does no harm
- * add task-news-server to help new installs target inn2 by default
-
- -- Bdale Garbee <bdale@gag.com> Wed, 19 Jan 2000 11:07:16 -0700
-
-inn (2.2.2-3) frozen unstable; urgency=low
-
- * target frozen since this fixes multiple release-critical bugs
- * inewsinn needs to provide inews, closes: #55349
- * fix rnews path in all innshellvars flavors, closes: #55307
- * since rnews uses nnrpdpostport, inews should also, closes: #54975
- * allow inews to work when talking to servers that require authentication
- for the "mode reader" command, closes: #31145
- * add some more information to README.Debian, and include an explicit
- pointer to it from the upgrade check in the preinst
- * remove needless leftover example maintainer scripts in debian/Examples
-
- -- Bdale Garbee <bdale@gag.com> Sun, 16 Jan 2000 14:43:12 -0700
-
-inn (2.2.2-2) unstable; urgency=low
-
- * move more config files and related man pages from package inn to inewsinn
- so that inews works correctly, closes: #55159
- * flag /etc/cron.d/inn as a conffile
- * reviewing / closing bugs in inn reported against prior versions that are
- fixed or no longer relevant in 2.2.2 ...
- * innwatch startup is cleaner than it used to be, closes: #21586, #32416
- * logging id different than it used to be, closes: #24504
- * expire.ctl doesn't have sequence problem any more, closes: #37737
- * Old hosts.nntp and hosts.nntp.nolimit are merged, closes: #48739
- * nntpsend.ctl no longer specifies the path, closes: #49673
- * startup works fine now, closes: #51944
- * control.ctl template is new, and correct, closes: #54526
- * crosspost and overview directories are correct, closes: #55062
- * history corruption problem should be long since fixed, closes: #11614
- * client timeout is set to 10 minutes in /etc/news/inn.conf file by default,
- which seems pretty reasonable, and is easy to change. Closes: #12358
- * the ancient problem with ctlinnd rmgroup appears fixed, closes: #12559
- * the current GetFQDN code appears to be coded to work in more cases than
- it once was, closes: #29695
- * we use a cron.d script now, so send-uucp, et al, can be scheduled on any
- desired interval. Closes: #43016
-
- -- Bdale Garbee <bdale@gag.com> Sat, 15 Jan 2000 01:18:17 -0700
-
-inn (2.2.2-1) unstable; urgency=low
-
- * New upstream release. Enough has changed since the 1.7.2 release that
- this is repackaged entirely from scratch.
- Closes: #25936, #26255, #43546, #52672, #43896, #54609, #54759
- * patch lib/parsedate.y to include "y2k fix" relating to acceptance of
- articles with year of 1900. Closes: #53813
- * postinst no longer prompts on upgrades, closes: #26659, #44918, #37888
- * much newer innfeed, now integrated with inn sources, closes: #14326
- * install docs revised, formatted version provided, closes: #43898
- * large warning in preinst about upgrades from prior revisions of Debian
- INN package requiring manual intervention. The degree of assistance
- will improve in future uploads, but may never be fully automatic.
-
- -- Bdale Garbee <bdale@gag.com> Wed, 22 Dec 1999 02:22:33 -0700
-
-inn (1.7.2-12) unstable; urgency=low
-
- * update to reflect current policy
- * inndstart *is* provided setuid root, closes: #51944
- * fix path in nntpsend.ctl.5, closes: #49673
- * if we're upgrading, don't stop to ask user, just use existing config
- information, closes: #44918
- * deliver Install.txt instead of Install.ms into the doc directory,
- closes: #43898
-
- -- Bdale Garbee <bdale@gag.com> Sun, 5 Dec 1999 20:46:07 -0700
-
-inn (1.7.2-11) unstable; urgency=high
-
- * patch to inews.c to fix buffer overrun problem from Martin Schulze
-
- -- Bdale Garbee <bdale@gag.com> Mon, 6 Sep 1999 13:35:19 -0600
-
-inn (1.7.2-10) unstable; urgency=low
-
- * rebuild to depend on perl 5.005, closes 41469, 41925, 41943.
- * update postinst text to eliminate version bogosity, closes 41585.
- * fix sample sendbatch, closes 41596
- * fix source-archive clause in sample newsfeeds file, closes 37862.
- * document nntpport, closes 28588.
- * fix type of inet_addr to reflect current libc.
-
- -- Bdale Garbee <bdale@gag.com> Mon, 2 Aug 1999 01:22:23 -0600
-
-inn (1.7.2-9) unstable; urgency=low
-
- * fold in Roman Hodek's changes from his 6.1 NMU, closing 38621. This
- fixes an ugly i386 dependency in the way inn calls Perl.
- * update perl dependency managment to try and cope with new perl policy
-
- -- Bdale Garbee <bdale@gag.com> Sat, 17 Jul 1999 17:13:05 -0600
-
-inn (1.7.2-6) unstable; urgency=low
-
- * new maintainer
- * clean up a few lintian complaints
- * folding in changes from Christian Kurz that he called -5. We'll call this
- -6 even though his changes were not widely distributed, just to avoid any
- confusion:
-
- Removed X-Server-Date-Patch as it's not needed.
- default moderation address add to /etc/news/moderators (closes: #24549)
- Inn now depends on perl (closes: #27754, #32313)
- Added gunbatch for gzipped batches (closes: #29899)
- Changed debian/rules so inncheck runs without errors.
- Added Perl-Support to Inn (closes: #26254)
- Changed the examples
-
- -- Bdale Garbee <bdale@gag.com> Wed, 26 May 1999 15:18:53 -0600
-
-inn (1.7.2-4) frozen unstable; urgency=medium
-
- * Fixes:
- #21583: inn: inn must replace inewsinn
- #20763: inn sends me `not running' and `now running' each night
- #21342: inn: install probs
- #21582: inn: incorrect prerm fail-upgrade action
- #21584: inn: postinst doesn't know abort-upgrade
- #20048: inn: poison and REMEMBER_TRASH patch
- #21644: inn: a way to not receive certain groups
- * Wrt bug #20763: the ctlinnd timeout in innwatch has been increased
- to 300 seconds (5 minutes). Hopefully that is enough.. There is no
- good alternative, the fact that INN is slow while renumbering is
- a basic design flaw. (Though the abp-scheduler patch might help)
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Fri, 22 May 1998 19:52:55 +0200
-
-inn (1.7.2-3) frozen unstable; urgency=medium
-
- * Move moderators from inewsinn to inn. The server should keep the
- moderators data, not inews.
- * Fix lib/clientactive.c (still yucky, but should work..)
- * Include latest pgpverify script, 1.9, and manpage
- * Fix security hole (/tmp/pgp$$) in pgpverify script
- * Fixes:
- #18579: I can't uninstall INN package
- #19776: inn.prerm buggy typos bah!
- #18724: inn: /etc/init.d/inn contains sed that never terminates
- #19206: inn: Crontab modifications not preserved
- #20423: inn: error in removing
- #20653: inn: Bug in send-uucp.pl, patch included
- #20792: INN: Wrong sfnet maintainer
- #20436: inn: on line 16 of the prerm script there is "fi" instead of "esac"
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 15 Apr 1998 17:34:23 +0200
-
-inn (1.7.2-2) unstable; urgency=low
-
- * Change over to new crontab -l method
- * Fix (pre|post)(inst|rm) scripts in several ways
- * Fix inewsinn inn.conf installation
- * Set NNRP_DBZINCORE_DELAY to -1
- * Fix lintian warnings
- Fixes:
- #18120: inn: Inn's crontab file should be a conffile
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 19 Feb 1998 22:46:25 +0100
-
-inn (1.7.2-1) unstable; urgency=low
-
- * New upstream version
- * Fix crontab -l | tail +4
- * Fixes bugs:
- #15889: /etc/news/inn.conf missing
- #16128: manpage uncompressed
- #15103: egrep incorrectly searched in /bin by innshellvars*
- #14404: /usr/doc/$(PACKAGE)/copyright should not be compressed
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 5 Feb 1998 12:52:14 +0100
-
-inn (1.7-1) unstable; urgency=low
-
- * New upstream version
- * Fixed bugs:
- #9264: Unresolved dependency report for inn
- #9315: inn: /etc/news/innshellvars* add /usr/ucb to the PATH
- #9832: INN 1.5.1-1 throttled rmgroup really shreds active file ?
- #10196: inn: inews complains about missnig subject header when there is one
- #10505: Moderated postings fail
- #11042: error in /usr/doc/inn/inn-README
- #11057: inn: Confusing/dangerous instructions
- #11453: inn: max signature length
- #11691: libc6
- #11851: inn: Documentation for send-uucp.pl
- #11852: inn: nntpsend looks for wrong config file
- #11900: INN creates `local.*' by default
- #11948: inn: nntpsend does not works
- #12513: inewsinn should insert a linebreak
- #13161: inn-makehistory - Bus error
- #13425: inn: egrep moved to /bin
- #13488: inewsinn: directs user to docs in a package it doesn't require
- #13616: /etc/init.d/inn, /etc/news/hosts.nntp.nolimit are not conffiles
- #13781: Can't feed by send-uucp.pl with ihave/sendme.
- #13831: inn: scanlogs depends on hard coded path for egrep
- #13899: inn: inn uses /usr/bin/egrep, grep doesn't provide that any longer
- * Added BUFFSET fix
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 22 Oct 1997 14:08:37 +0200
-
-inn (1.5.1-5) unstable; urgency=high
-
- * Fixed sendbatch script (comment in between backtics is illegal)
- * libc6 version
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 10 Sep 1997 16:31:37 +0200
-
-inn (1.5.1-4) stable unstable; urgency=high
-
- * Add new security patch (with fixed STRCPY): inn-1.5.1-bufferoverflow.patch4
- * Applied null-pointer.patch from Michael Shields
- * Upped SIG_MAXLINES in configdata.h to 8
- * Fix inn-README (perl example). Fixes bug #11042
- * Update inn-README and postinst to fix bug #11057
- * Make ctlinnd addhist work in paused mode, and fail in throttled mode
- * Change ID string
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 21 Aug 1997 12:37:48 +0200
-
-inn (1.5.1-3) stable unstable; urgency=high
-
- * Add changelogs to docdir
- * innshellvars*: change /usr/ucb -> /usr/sbin (Bug#9315)
- * Changed Recommends: pgp to Suggests: (Bug#9264)
- * Fix inews to fallback on local moderators file (Bug#10505)
- * Fix buffer overruns all over the place
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Thu, 24 Jul 1997 18:29:33 +0200
-
-inn (1.5.1-2) frozen unstable; urgency=high
-
- * Added security-patch.05 (mailx tilde exploit)
- * inewsinn no longer conflicts: inn so installation should no
- longer remove your original inn-1.4 package (and configuration).
- Expect some dpkg trouble when upgrading from 1.4unoff4 to 1.5.1-2 though.
- * Always create .incoming/.outgoing symlinks for backwards compat.
- * Do not change ownerships/modes of existing directories
- * Fix ownerships/modes of rnews, innd, inndstart, in.nnrpd
- * Fix /etc/init.d/inn to comply with console messages standard
- * Fix /usr/lib/news/bin/sendbatch
- * Fix scanlogs not to nuke active file if log/news/OLD isn't there
- * Console messages are a bit more standard now
- * Use start-stop-daemon to kill innwatch in /etc/init.d/inn
- * Fixed up inncheck - it almost doesn't complain anymore
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Mon, 28 Apr 1997 13:58:16 +0200
-
-inn (1.5.1-1) unstable; urgency=low
-
- * Upgraded to 1.5.1
- * Fixed Bug#6387: expire-with-symlinks problem
- * Fixed Bug#6246: inewsinn reconfigures on update
- * Moved /var/spool/news,/var/lib/news back into package
- * Saves removed conffiles in preinst, restores in postinst
- * Set LIKE_PULLERS to DO
- * Remove manpage stubs that are now real manpages
- * Fix options to sendmail in _PATH_SENDMAIL
- * Removed subdirectories from debian/
- * create /var/log/news/OLD in postinst
- * Fixed most if not all other outstanding bugs
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 5 Feb 1997 10:58:16 +0100
-
-inn (1.5-1) unstable; urgency=low
-
- * Upgraded to 1.5
- * Undid most patches to 1.4unoff4 because they are in 1.5 proper.
- * Added security patch
- * Added X-Server-Date: patch
- * inn now depends on inewsinn
- * Fixed all other outstanding bugs (well, almost).
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Tue, 17 Dec 1996 16:56:37 +0100
-
-inn (1.4unoff4-2) unstable; urgency=low
-
- * Added inn-dev package for libinn.a and manpages.
- * Increased hash table size in expire.c to 2048 (was 128)
- * Moved ctlinnd to /usr/sbin
- * Moved to new source packaging scheme
-
- -- Miquel van Smoorenburg <miquels@cistron.nl> Wed, 06 Oct 1996 15:38:30 +0200
-
-INN (1.4unoff4-1) - Miquel van Smoorenburg <miquels@cistron.nl>
-
- * Took out the Linux 1.2 patches I put in unoff3.
- * added the 64 bits patch (for Linux/Alpha)
- * There are some other minor patches for Linux/Alpha
- * Added "xmode" as alias for "mode"
- * Using MMAP and setsockopt() now - NEEDS 1.3 kernel !
-
-INN (1.4unoff3-1) - Miquel van Smoorenburg <miquels@cistron.nl>
-
- * Took inn1.4sec-8 and 1.4unoff3, folded in some Linux and
- other patches.
- * Changed all makefiles to support a "prefix" variable for install
- * Removed the hacks in debian.rules for installation
- * Locks are in /var/run/innd
- * Rewrote post install script.
-
-inn (1.4sec-8); priority=MEDIUM
-
- * postinst configuration completely redone. It now sets up a minimal
- local installation for you.
- * prerm now exists and shuts the server down.
- * init scripts changed to System V scheme.
- * Descriptions in control files expanded.
- * Package now contains /var/lock/news, and uses /var/log (not /var/adm).
- * inewsinn postinst looks at and can write /etc/mailname.
-
-INN 1.4sec Debian 7 - iwj
-
-* libinn.a, <inn/*.h>, inn-sys2nf and inn-feedone installed
- (in /usr/lib, /usr/include and /usr/bin).
-
-INN 1.4sec Debian 6 - iwj
-
-* innwatch now started by /etc/rc.misc/news.
-* inewsinn postinst minor typos fixed.
-* Leftover file `t' removed from source and diff distributions.
-
-INN 1.4sec Debian 5 - iwj
-
-* Added documentation about making active and history files.
-* Added monthly makehistory -ru crontab run.
-* Made postinst always do crontab -u news /etc/news/crontab .
-* Removed HAVE_UNIX_DOMAIN - AF_UNIX+SOCK_DGRAM still broken in Linux.
-* Fixed /usr/lib/news/bin/inncheck to conform to our permissions scheme.
-* Added manpage links for makeactive(8), makehistory(8), newsrequeue(8).
-* /var/adm/news now part of package.
-
-INN 1.4sec Debian 4 - iwj
-
-* Added $|=1 to inewsinn postinst script; a few cosmetic fixes.
-
-INN 1.4sec Debian 3 - iwj
-
-* Removed `inet' groups from distrib.pats.
-* Put more version number information in ../*.{deb,gz} filenames.
-* Added Package_Revision field to `control' file.
-* Rationalised debian.rules somewhat, and added `build' stamp file.
-* Permissions rationalised.
-* Changed /etc/rc.d/rc.news to /etc/rc.misc/news.
-* postinst calls Perl as /usr/bin/perl.
-* Added this Changelog.
-
-INN 1.4sec Debian 2 - iwj
-* inews moved to /usr/bin; rnews moved to /usr/sbin.
-* fixed nntpsend not to use PPID variable (it's a bash builtin).
-
-INN 1.4sec Debian 1 - iwj
-Initial release, completely untested.
+++ /dev/null
-usr/include/inn/
-usr/share/man/man3/
-usr/lib/news/libinn.a
-usr/lib/news/libstorage.a
-usr/lib/news/libinnhist.a
+++ /dev/null
-usr/share/man/man3/dbz.3 usr/share/man/man3/dbzclose.3
-usr/share/man/man3/dbz.3 usr/share/man/man3/dbzinit.3
-usr/share/man/man3/dbz.3 usr/share/man/man3/dbzfetch.3
-usr/share/man/man3/dbz.3 usr/share/man/man3/dbzstore.3
+++ /dev/null
-etc/news/distrib.pats
-etc/news/inn.conf
-etc/news/moderators
-etc/news/passwd.nntp
-usr/lib/news/bin/inews
-usr/lib/news/bin/rnews
-usr/lib/news/bin/rnews.libexec
-usr/share/man/man1/inews.1
-usr/share/man/man1/rnews.1
-usr/share/man/man5/distrib.pats.5
-usr/share/man/man5/inn.conf.5
-usr/share/man/man5/moderators.5
-usr/share/man/man5/passwd.nntp.5
+++ /dev/null
-usr/lib/news/bin/inews usr/bin/inews
-usr/lib/news/bin/rnews usr/bin/rnews
+++ /dev/null
-Some random notes about the Debian INN 2.X package.
-
-If you are upgrading from a previous version, please review the information
-near the top of the NEWS file to learn what has changed, and what you may
-need to do to update your system.
-
-If you plan to use INN at home you should really consider running INN 1.x,
-which you can find in the inn package.
-
-INN 2.X is substantially different in terms of configuration file contents
-and filesystem layout than previous versions. The Debian INN package installs
-a minimal but functional local-only server configuration. Configuring feeds
-to/from other servers, and many other details, is up to you.
-
-You will want to review the information in /usr/share/doc/inn2 to get started
-on configuring the installation for your needs. All of the configuration files
-in /etc/news are flagged as 'conffiles' in the packaging system, so your work
-should not be overwritten without your permission if/when you upgrade the inn
-package in the future. In particular, make sure to update /etc/news/inn.conf
-to put in your organization name and related information before you establish
-any network connections if you don't want to be embarrassed.
-
-Also, if you are moving over from INN 1.X, please note that the directory
-structure under /var/spool/news has changed. At a minimum, you will need to
-move the article database subdirectories from /var/spool/news to
-/var/spool/news/articles. The set of directories that belong in
-/var/spool/news for 2.2.2 and later are:
-
- archive articles incoming innfeed outgoing overview
-
-Anything else is left over from a previous version, and probably should be
-moved or removed.
-
-It has been pointed out that inn2's use of /etc/cron.d/inn2 instead of
-separate files in /etc/cron.daily and so forth poses a problem for users of
-anacron on boxes that are not run continuously. Since the primary target
-for an INN installation is a fully-connected system that might easily need
-a variety of cron entries with different intervals, I don't intend to change
-this default. However, if you're bothered by this, feel free to change the
-cron configuration to suite your needs.
-
-If you want to use pgpverify (and you do if you're getting a real feed!),
-you can use the /usr/lib/news/bin/buildinnkeyring program to download the
-keys for some hierarchies from ftp.isc.org and add them to the gnupg
-keyring used by pgpverify.
-This package does not support the non-free PGP program anymore.
-
-The program 'compress' is not a part of Debian GNU/Linux due to patent issues
-with the algorithm. By default, the innshellvars* files will try to call
-'compress' if you try to transport compressed batches over UUCP. This will
-work if you install the non-free 'ncompress' package. Since it's non-free,
-this might be as unacceptable to you as it is to me! If you know that all of
-your neighbors can handle gzip, a better solution might be to edit the
-innshellvars* files to use '/bin/gzip -9' for the COMPRESS variable. I do not
-intend to change this default to differ from the upstream source.
-
-Log files in /var/log/news need to be owned by user 'news' for the news
-scanlogs tool to be able to rotate them properly.
-
-If you want to use the ckpasswd program you need to install the libgdbm3
-package.
-
-
-SSL
-~~~
-To enable SSL you need to start /usr/lib/news/bin/nnrpd-ssl with the -S
-flag from inetd or the command line.
-See nnrpd(8) and sasl.conf(5) for details.
-
-You need a certificate authority (CA) certificate in
-/etc/news/nnrpd-ca-cert.pem. You will also need a certificate/key pair,
-named /etc/news/nnrpd-cert.pem and /etc/news/nnrpd-key.pem respectively.
-
-If you do not already have a PKI in place, you can create them with a
-command like:
-
-openssl req -new -x509 -nodes -days 1825 \
- -keyout /etc/news/nnrpd-key.pem -out /etc/news/nnrpd-cert.pem
-
-The private key must have the correct permissions:
-
-chown root:news /etc/news/nnrpd-key.pem
-chmod 640 /etc/news/nnrpd-key.pem
-
-
-STARTTLS
-~~~~~~~~
-STARTTLS support will not work when nnrpd is started by innd using
-"MODE READER" unless the nnrpd binary is replaced by nnrpd-ssl (e.g.
-by using dpkg-divert(8)).
-The upstream maintainer recommends running nnrpd as a standalone process.
-
-
-Large Files Support
-~~~~~~~~~~~~~~~~~~~
-On 32 bit architectures, the inn2-lfs package is built.
-There is no transition procedure, so if you want to convert an existing
-installation (this may or may not be possible depending on your choice
-of storage and overview formats) then you are on your own.
-When attempting such conversion do not forget that the package will
-delete /var/{spool,lib,log}/news/ when removed so they should be renamed.
-
+++ /dev/null
-SHELL=/bin/sh
-PATH=/usr/lib/news/bin:/sbin:/bin:/usr/sbin:/usr/bin
-
-# Expire old news and overview entries nightly, generate reports.
-
-15 4 * * * news test -x /usr/lib/news/bin/news.daily && news.daily expireover lowmark delayrm
-
-# Refresh the cached IP addresses every day.
-
-2 3 * * * news [ -x /usr/sbin/ctlinnd ] && ctlinnd -t 300 -s reload incoming.conf "flush cache"
-
-# Every hour, run an rnews -U. This is not only for UUCP sites, but
-# also to process queud up articles put there by in.nnrpd in case
-# innd wasn't accepting any articles.
-
-10 * * * * news [ -x /usr/bin/rnews ] && rnews -U
-
-# Enable this entry to send posted news back to your upstream provider.
-# Also edit /etc/news/nntpsend.ctl !
-# Not if you use innfeed, of course.
-
-#*/15 * * * * news nntpsend
-
-
-# Enable this if you want to send news by uucp to your provider.
-# Also edit /etc/news/send-uucp.cf !
-
-#22 * * * * news send-uucp.pl
-
-# NINPATHS ###################################################################
-# To enable ninpaths please add this line to /etc/news/newsfeeds:
-# inpaths!:*:Tc,WP:/usr/lib/news/bin/ginpaths2
-#
-#6 6 * * * news ctlinnd -s -t 60 flush inpaths!
-#8 6 1 * * news sendinpaths
-# NINPATHS ###################################################################
-
+++ /dev/null
-CONTRIBUTORS
-INSTALL
-NEWS
-README
-doc/checklist
-doc/external-auth
-doc/history
-doc/hook-perl
-doc/IPv6-info
-doc/compliance-nntp
+++ /dev/null
-extra/active
-extra/newsgroups
+++ /dev/null
-#!/bin/sh -e
-### BEGIN INIT INFO
-# Provides: inn2
-# Required-Start: $local_fs $remote_fs $syslog
-# Required-Stop: $local_fs $remote_fs $syslog
-# Default-Start: 2 3 4 5
-# Default-Stop: 0 1 6
-# Short-Description: INN news server
-# Description: The InterNetNews news server.
-### END INIT INFO
-#
-# Start/stop the news server.
-#
-
-test -f /usr/lib/news/bin/rc.news || exit 0
-
-start () {
- if [ ! -d /var/run/news ]; then
- mkdir -p /var/run/news
- chown news:news /var/run/news
- chmod 775 /var/run/news
- fi
- su news -c /usr/lib/news/bin/rc.news > /var/log/news/rc.news 2>&1
- # su news -c '/usr/lib/news/bin/nnrpd -D -c /etc/news/readers-ssl.conf -p 563 -S'
-}
-
-stop () {
- su news -c '/usr/lib/news/bin/rc.news stop' >> /var/log/news/rc.news 2>&1
- # start-stop-daemon --stop --name nnrpd --quiet --oknodo
-}
-
-case "$1" in
- start)
- echo -n "Starting news server: "
- start
- echo "done."
- ;;
- stop)
- echo -n "Stopping news server: "
- stop
- echo "done."
- ;;
- reload|force-reload)
- echo -n "Reloading most INN configuration files: "
- ctlinnd -t 20 reload '' /etc/init.d/inn2
- ;;
- restart)
- echo -n "Restarting innd: "
- if [ -f /var/run/news/innd.pid ]; then
- ctlinnd -t 20 throttle "init script" > /dev/null || true
- ctlinnd -t 20 xexec inndstart > /dev/null || start
- else
- start
- fi
- echo "done."
- ;;
- *)
- echo "Usage: /etc/init.d/inn start|stop|restart|reload">&2
- exit 1
- ;;
-esac
-
-exit 0
+++ /dev/null
-usr/lib/news/bin/ctlinnd usr/sbin/ctlinnd
-usr/lib/news/bin/innstat usr/sbin/innstat
-usr/lib/news/bin/send-uucp usr/lib/news/bin/send-uucp.pl
-usr/share/man/man3/uwildmat.3 usr/share/man/man3/wildmat.3
-usr/share/man/man8/send-uucp.8 usr/share/man/man8/send-ihave.8
-usr/share/man/man8/send-uucp.8 usr/share/man/man8/send-nntp.8
+++ /dev/null
-\w{3} [ :0-9]{11} [._[:alnum:]-]+ (rnews|innd|batcher): Reading config from /etc/news/inn\.conf$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ (expire|expireover|ctlinnd|nnrpd)\[[0-9]+\]: Reading config from /etc/news/inn\.conf$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: offered <[^[:space:]]+> [._[:alnum:]-]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: localhost connected [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]:$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]:[-[:alnum:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]:Expiring process [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]:Flushing log and syslog files$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [[:alpha:]]:/var/log/news/expire\.lowmark$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+ flush$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+ opened [^[:space:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+ closed$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+:[0-9]+ readclose$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+:[0-9]+ inactive [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+:[0-9]+ NCmode \"mode stream\" received$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [._[:alnum:]-]+ connected [0-9]+ streaming allowed$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: ME HISstats [0-9]+ hitpos [0-9]+ hitneg [0-9]+ missed [0-9]+ dne$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: ME time [0-9]+ hishave [0-9]+\([0-9]+\) hiswrite [0-9]+\([0-9]+\) hissync [0-9]+\([0-9]+\) idle [0-9]+\([0-9]+\) artclean [0-9]+\([0-9]+\) artwrite [0-9]+\([0-9]+\) artcncl [0-9]+\([0-9]+\) hishave/artcncl [0-9]+\([0-9]+\) his(grep|write)/artcncl [0-9]+\([0-9]+\) artlog/artcncl [0-9]+\([0-9]+\) his(write|grep)/artcncl [0-9]+\([0-9]+\) sitesend [0-9]+\([0-9]+\) overv [0-9]+\([0-9]+\) perl [0-9]+\([0-9]+\) nntpread [0-9]+\([0-9]+\) artparse [0-9]+\([0-9]+\)( artlog/artparse [0-9]+\([0-9]+\))? artlog [0-9]+\([0-9]+\) datamove [0-9]+\([0-9]+\)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: SERVER (servermode|flushlogs) (running|paused)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: SERVER paused Flushing log and syslog files$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: SERVER running$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: SERVER paused Expiring process [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ batcher\[[0-9]+\]: batcher [[:alnum:]]+ times user [.0-9]+ system [.0-9]+ elapsed [.0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ batcher\[[0-9]+\]: batcher [[:alnum:]]+ stats batches [0-9]+ articles [0-9]+ bytes [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: Reading access from /etc/news/readers\.conf$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: SERVER perl filtering enabled$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ \([.0-9]+\) connect$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ timeout$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ group [.[:alnum:]+-]+ [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: Auth strategy '[[:alnum:]]+' does not match client\. Removing\.$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ (no_)?match_user [<>_[:alnum:]-]+(@[._[:alnum:]-]+)? [<>,_,\*,\![:alnum:][:punct:]-]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ res <[_[:alnum:]-]+>(@[._[:alnum:]-]+)?$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ time [0-9]+ (hisgrep [0-9]+\([0-9]+\) )?idle [0-9]+\([0-9]+\) (readart [0-9]+\([0-9]+\) )?nntpwrite [0-9]+\([0-9]+\)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ times user [.0-9]+ system [.0-9]+ idle [.0-9]+ elapsed [.0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ exit articles [0-9]+ groups [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ artstats get [0-9]+ time [0-9]+ size [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ post ok <[[:graph:]]+@[._[:alnum:]-]+>$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ \(unknown\) posttrack ok [[:graph:]]+<[[:graph:]]+@[._[:alnum:]-]+>$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ user [[:alnum:][:punct:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ Tracking Disabled \(unknown\)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ auth authenticator successful, user [[:alnum:][:punct:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ auth starting authenticator [[:alnum:][:space:][:punct:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [._[:alnum:]-]+ no_access_realm$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ cnfsstat\[[0-9]+\]: Class [[:alnum:]]+ for groups matching \"[^[:space:]]+\" Buffer [[:alnum:]]+, len: [0-9]+ Mbytes, used: [0-9]+\.[0-9]+ Mbytes \([0-9 ]+\.[0-9]%\) [ 0-9]+ cycles$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ send-uucp\[[0-9]+\]: checking site [^[:space:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ send-uucp\[[0-9]+\]: no articles for [^[:space:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ send-uucp\[[0-9]+\]: Flushing [^[:space:]]+ for site [^[:space:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ send-uucp\[[0-9]+\]: batched articles for [^[:space:]]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: ME time [0-9]+ idle [0-9]+\([0-9]+\) blstats [0-9]+\([0-9]+\) stsfile [0-9]+\([0-9]+\) newart [0-9]+\([0-9]+\) readart [0-9]+\([0-9]+\) prepart [0-9]+\([0-9]+\) read [0-9]+\([0-9]+\) write [0-9]+\([0-9]+\) cb [0-9]+\([0-9]+\)$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+ spooling no active connections$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+:[0-9]+ connected$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+ remote MODE STREAM$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+ (final|checkpoint) seconds [0-9]+ spooled [0-9]+ on_close [0-9]+ sleeping [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+ hostChkCxns - maxConnections was [0-9]+ now [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: ME articles (active|total) [0-9]+ bytes [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+:[0-9]+ cxnsleep connect: Connection refused$
+++ /dev/null
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: [-[:alnum:].]+:[0-9]+ (closed|checkpoint) seconds [0-9]+ accepted [0-9]+ refused [0-9]+ rejected [0-9]+ duplicate [0-9]+ accepted size [0-9]+ duplicate size [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innd: rejecting\[perl\] <[[:alnum:][:punct:]]+@[.[:alnum:]-]+> [0-9]+ [[:alnum:] ]+( \([._[:alnum:]-]+\))?$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: rejected [0-9]+ Unwanted (newsgroup|distribution) "[._,[:alnum:]-]+"$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: rejected [0-9]+ Too old -- "\w{3}, [0-9 ]+ \w{3} [0-9]{4} [0-9:]{8} (\+|-)[0-9]{4}"$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: rejected [0-9]+ Too old -- "[0-9]+ \w{3} [0-9]{4} [0-9:]{8} ([[:upper:]]+|(\+|-)[0-9]{4})"$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: rejected [0-9]+ No colon-space in "("|x-no-archive:yes)" header$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ rnews: offered <[^[:space:]]+> [._[:alnum:]-]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: [^[:space:]]+ posts received [0-9]+ rejected [0-9]+$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ nnrpd\[[0-9]+\]: \? reverse lookup for [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} failed: Unknown host -- using IP address for access$
-^\w{3} [ :0-9]{11} [._[:alnum:]-]+ innfeed\[[0-9]+\]: [._[:alnum:]-]+(:[0-9]+)? (final|global|checkpoint) seconds [0-9]+ offered [0-9]+ accepted [0-9]+ refused [0-9]+ rejected [0-9]+ (missing [0-9]+ )?accsize [0-9]+ rejsize [0-9]+( spooled [0-9]+ (on_close [0-9]+ )?unspooled [0-9]+)?( deferred [0-9]+/[0-9.]+ requeued [0-9]+ queue [0-9.]+/[0-9\:\,]+)?$
+++ /dev/null
-#!/bin/sh -e
-
-init_inn_files() {
- PATHDB=$(/usr/lib/news/bin/innconfval pathdb)
- if [ -z "$PATHDB" ]; then
- echo "Cannot determine the database path, aborting."
- exit 1
- fi
- cd $PATHDB
-
- local package='inn2'
- if [ -e /usr/share/doc/inn2-lfs/ ]; then
- package='inn2-lfs'
- fi
-
- for file in active newsgroups; do
- if [ ! -f $file ]; then
- echo "Installing initial content for $PATHDB/$file"
- install -m 644 -o news -g news \
- /usr/share/doc/$package/examples/$file .
- fi
- done
-
- if [ ! -f history.dir ]; then
- echo -n "Building history database in $PATHDB... "
- if ! /usr/lib/news/bin/makehistory; then
- echo "failed!"
- return
- fi
- if ! /usr/lib/news/bin/makedbz -i -o -s 300000; then
- echo "failed!"
- return
- fi
- chown news:news history*
- chmod 664 history*
- echo "done."
- fi
-
- if [ ! -f active.times ]; then
- touch active.times
- chown news:news active.times
- chmod 644 active.times
- fi
-
- # squelch initial noise in email if this isn't present
- if [ ! -f .news.daily ]; then
- touch .news.daily
- chown news:news .news.daily
- fi
-
- # make sure typical log files exist, and can be rotated
- if [ ! -d /var/log/news ]; then
- install -d -m 775 -o news -g news /var/log/news
- fi
- cd /var/log/news
- [ -f news.notice ] || touch news.crit news.err news.notice
- chown news:news . OLD path news.crit news.err news.notice
-
- if [ -x /etc/init.d/inn2 ]; then
- update-rc.d inn2 defaults > /dev/null
- fi
-}
-
-check_usenet_alias() {
- # must have an alias for user usenet, point it to root by default
- if [ -f /etc/aliases ] && ! grep -q '^usenet:' /etc/aliases \
- && ! getent passwd usenet; then
- echo "Adding alias for pseudo-user usenet to /etc/aliases."
- echo "usenet: root" >> /etc/aliases
- [ -x /usr/bin/newaliases ] && /usr/bin/newaliases
- fi
-}
-
-upgrade_inn_conf() {
- cd /etc/news
- if [ "$2" ] && dpkg --compare-versions "$2" lt "2.3.999+20030125-1"; then
- /usr/lib/news/bin/innupgrade -f inn.conf
- fi
-}
-
-rebuild_history_index() {
- [ -f /var/lib/news/must-rebuild-history-index ] || return 0
-
- cd /var/lib/news
- HLINES=$(tail -1 history.dir | awk '{ print $1 }')
- [ "$HLINES" ] || HLINES=1000000
- echo "Rebuilding the history index for $HLINES lines, please wait..."
- rm history.hash history.index history.dir
- su news -c "/usr/lib/news/bin/makedbz -s $HLINES -f history"
-
- rm /var/lib/news/must-rebuild-history-index
-}
-
-rebuild_overview() {
- [ -f /var/lib/news/must-rebuild-overview ] || return 0
-
- OVENABLED=$(/usr/lib/news/bin/innconfval enableoverview)
- if [ -z "$OVENABLED" ]; then
- echo "Cannot determine the overview method used, stopping."
- exit 1
- fi
- if [ $OVENABLED = no -o $OVENABLED = false ]; then
- return 0
- fi
-
- OVMETHOD=$(/usr/lib/news/bin/innconfval ovmethod)
- if [ -z "$OVMETHOD" ]; then
- echo "Cannot determine the overview method used, stopping."
- exit 1
- elif [ $OVMETHOD = tradindexed -o $OVMETHOD = ovdb ]; then
- OVPATH=$(/usr/lib/news/bin/innconfval pathoverview)
- if [ -z "$OVPATH" ]; then
- echo "Cannot determine the overview path, aborting."
- exit 1
- fi
- echo "Deleting the old overview database, please wait..."
- find $OVPATH -type f -not -name DB_CONFIG -print0 | xargs -0 -r rm -f
- elif [ $OVMETHOD = buffindexed ]; then
- echo "Deleting the old overview database, please wait..."
- awk -F : '/^[0-9]/ { print $2 }' < /etc/news/buffindexed.conf | \
- while read name size; do
- dd if=/dev/zero of="$name" bs=1024 count="$size"
- done
- else
- echo "Unknown overview method '$OVMETHOD', aborting."
- exit 1
- fi
-
- echo "Rebuilding the overview database, please wait..."
- su news -c "/usr/lib/news/bin/makehistory -F -O -x"
-
- rm /var/lib/news/must-rebuild-overview
-}
-
-start_innd() {
-# make sure we can determine the FQDN, since innd won't launch if we can't
-if hostname --fqdn > /dev/null 2>&1; then
- invoke-rc.d inn2 start || echo "Could not start INN!"
-else
-cat <<END
-
-
-Not starting innd. The daemon needs to be able to determine the name of
-this machine, and your /etc/hosts and/or DNS config is apparently not
-allowing this to happen. After you have fixed things so that 'hostname
---fqdn' returns a reasonable value, you can start the daemon by running
-'/etc/init.d/inn2 start'.
-
-
-END
-fi
-}
-
-case "$1" in
- configure)
- init_inn_files
- check_usenet_alias
- upgrade_inn_conf "$@"
- rebuild_history_index
- rebuild_overview
- if [ -z "$2" -o ! -e /var/run/news/innd.pid ]; then # first install
- start_innd
- else
- ctlinnd -t 20 throttle "upgrade" > /dev/null || true
- ctlinnd -t 20 xexec inndstart > /dev/null \
- || echo "Could not restart INN!"
- fi
- ;;
-
- abort-upgrade|abort-remove|abort-deconfigure)
- ;;
-
- *)
- echo "postinst called with unknown argument '$1'" >&2
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
-
+++ /dev/null
-#!/bin/sh -e
-
-if [ "$1" = "purge" ]; then
- update-rc.d inn2 remove >/dev/null
- if [ -e /var/lib/news/ ]; then
- rm -f /var/lib/news/.news.daily /var/lib/news/active* \
- /var/lib/news/newsgroups /var/lib/news/history*
- rmdir --ignore-fail-on-non-empty /var/lib/news/
- fi
-fi
-
-#DEBHELPER#
-
-exit 0
+++ /dev/null
-#!/bin/sh -e
-
-if [ "$2" ] && dpkg --compare-versions $2 gt 2.0.0 \
- && dpkg --compare-versions $2 lt 2.3.0; then
- echo "Some configuration files have changed in INN 2.4 and will need to"
- echo "be adjusted, most notably nnrp.access has mutated into readers.conf."
- echo "Also, note that you may need to rebuild the history database."
- echo "For more information, read the /usr/share/doc/inn2/NEWS.gz file."
-fi
-
-if [ "$2" ] && dpkg --compare-versions $2 eq 2.3.0-1; then
- echo 'Upgrade from 2.3.0-1 to >= 2.3.999+20030125-4 is not supported.'
- echo 'Aborting inn upgrade.'
- exit 1
-fi
-
-if [ "$2" ] && dpkg --compare-versions $2 lt 2.3.1-2; then
- # remove any remaining symlinks under /usr/lib/news/bin/filter, then remove
- # the directory if it's empty
- if [ -d /usr/lib/news/bin/filter ]; then
- find /usr/lib/news/bin/filter -type l -exec rm {} \;
- rmdir /usr/lib/news/bin/filter 2> /dev/null || true
- fi
-fi
-
-#DEBHELPER#
-
-exit 0
+++ /dev/null
-#!/bin/sh -e
-
-kill_innd() {
- if [ -x /etc/init.d/inn2 ]; then
- invoke-rc.d inn2 stop
- fi
-}
-
-case "$1" in
- remove|deconfigure|failed-upgrade)
- kill_innd
- ;;
-
- upgrade)
- ;;
-
- *)
- echo "$0 called with unknown argument '$1'" >&2
- exit 1
- ;;
-esac
-
-#DEBHELPER#
-
-exit 0
+++ /dev/null
---- a/samples/buffindexed.conf
-+++ b/samples/buffindexed.conf
-@@ -7,5 +7,5 @@
- # index(0-65535) : path to buffer file :
- # length of buffer in kilobytes in decimal (1KB = 1024 bytes)
-
--0:/var/news/spool/overview/OV1:1536000
--1:/var/news/spool/overview/OV2:1536000
-+0:/var/spool/news/overview/OV1:1536000
-+1:/var/spool/news/overview/OV2:1536000
+++ /dev/null
-honour the Ad flag in newsfeeds
-
-http://inn.eyrie.org/viewcvs/branches/2.4/innd/art.c?r1=7748&r2=7936&pathrev=7936&view=patch
-
---- 2.4/innd/art.c 2008/04/06 13:49:56 7748
-+++ 2.4/innd/art.c 2008/07/20 10:20:41 7936
-@@ -1725,7 +1725,7 @@
- !DISTwantany(sp->Distributions, list))
- /* Not in the site's desired list of distributions. */
- continue;
-- if (sp->DistRequired && list == NULL)
-+ if (sp->DistRequired && (list == NULL || *list == NULL))
- /* Site requires Distribution header and there isn't one. */
- continue;
-
+++ /dev/null
-Fix the correct handling of bodies (Perl regexps were sometimes
-not properly working on SV * bodies). We now use a shared string.
-For Perl < 5.7.1, fall back to a copy of such bodies. At least,
-that method is reliable, even though it were 17% slower.
-
-http://inn.eyrie.org/viewcvs/branches/2.4/include/ppport.h?r1=7237&r2=7951&pathrev=7951&view=patch
-http://inn.eyrie.org/viewcvs/branches/2.4/innd/perl.c?r1=7815&r2=7951&pathrev=7951&view=patch
-
---- 2.4/innd/perl.c 2008/05/05 08:43:58 7815
-+++ 2.4/innd/perl.c 2008/08/05 19:41:17 7951
-@@ -69,7 +69,6 @@
- CV * filter;
- int i, rc;
- char * p;
-- static SV * body = NULL;
- static char buf[256];
-
- if (!PerlFilterActive) return NULL;
-@@ -87,23 +86,19 @@
- }
-
- /* Store the article body. We don't want to make another copy of it,
-- since it could potentially be quite large. Instead, stash the
-- pointer in the static SV * body. We set LEN to 0 and inc the
-- refcount to tell Perl not to free it (either one should be enough).
-- Requires 5.004. In testing, this produced a 17% speed improvement
-- over making a copy of the article body for a fairly heavy filter. */
-+ * since it could potentially be quite large. In testing, this produced
-+ * a 17% speed improvement over making a copy of the article body
-+ * for a fairly heavy filter.
-+ * Available since Perl 5.7.1, newSVpvn_share allows to avoid such
-+ * a copy (getting round its use for older versions of Perl leads
-+ * to unreliable SV * bodies as for regexps). And for Perl not to
-+ * compute a hash for artBody, we give it "42". */
- if (artBody) {
-- if (!body) {
-- body = newSV(0);
-- (void) SvUPGRADE(body, SVt_PV);
-- }
-- SvPVX(body) = artBody;
-- SvCUR_set(body, artLen);
-- SvLEN_set(body, 0);
-- SvPOK_on(body);
-- (void) SvREADONLY_on(body);
-- (void) SvREFCNT_inc(body);
-- hv_store(hdr, "__BODY__", 8, body, 0);
-+#if (PERL_REVISION == 5) && ((PERL_VERSION < 7) || ((PERL_VERSION == 7) && (PERL_SUBVERSION < 1)))
-+ hv_store(hdr, "__BODY__", 8, newSVpv(artBody, artLen), 0);
-+#else
-+ hv_store(hdr, "__BODY__", 8, newSVpvn_share(artBody, artLen, 42), 0);
-+#endif /* Perl < 5.7.1 */
- }
-
- hv_store(hdr, "__LINES__", 9, newSViv(lines), 0);
---- 2.4/include/ppport.h 2005/06/05 21:57:50 7237
-+++ 2.4/include/ppport.h 2008/08/05 19:41:17 7951
-@@ -150,6 +150,7 @@
- # endif
- #endif
- #ifndef PERL_VERSION
-+# define PERL_REVISION (5)
- # ifdef PERL_PATCHLEVEL
- # define PERL_VERSION PERL_PATCHLEVEL
- # else
-@@ -162,7 +163,7 @@
- # define ERRSV perl_get_sv("@",false)
- #endif
-
--#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 4))
-+#if (PERL_REVISION == 5) && ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 4)))
- # define PL_sv_undef sv_undef
- # define PL_sv_yes sv_yes
- # define PL_sv_no sv_no
-@@ -174,7 +175,7 @@
- # define PL_copline copline
- #endif
-
--#if (PERL_VERSION < 5)
-+#if (PERL_REVISION == 5) && (PERL_VERSION < 5)
- # undef dTHR
- # ifdef WIN32
- # define dTHR extern int Perl___notused
+++ /dev/null
---- a/site/Makefile
-+++ b/site/Makefile
-@@ -116,7 +116,7 @@ config: $(ALL)
- ## Don't use parallel rules -- we want this to be viewed carefully.
- install: all $(PAUSE) install-config $(RELOAD_AND_GO)
- reload-install: all pause install-config reload go
--install-config: update $(REST_INSTALLED) $(SPECIAL)
-+install-config: update $(REST_INSTALLED) #$(SPECIAL)
-
- ## Install scripts, not per-host config files.
- update: all $(MOST_INSTALLED)
+++ /dev/null
---- a/control/perl-nocem.in
-+++ b/control/perl-nocem.in
-@@ -521,7 +521,9 @@ Processing NoCeM notices is easy to set
- Import the keys of the NoCeM issuers you trust in order to check
- the authenticity of their notices. You can do:
-
-- gpg --no-default-keyring --primary-keyring <pathetc>/pgp/ncmring.gpg --import <key-file>
-+ gpg --no-default-keyring --primary-keyring <pathetc>/pgp/ncmring.gpg \
-+ --no-options --allow-non-selfsigned-uid --no-permission-warning \
-+ --batch --import <key-file>
-
- where <pathetc> is the value of the I<pathetc> parameter set in F<inn.conf>
- and <key-file> the file containing the key(s) to import. The keyring
---- a/doc/man/perl-nocem.8
-+++ b/doc/man/perl-nocem.8
-@@ -157,8 +157,10 @@ Processing NoCeM notices is easy to set
- Import the keys of the NoCeM issuers you trust in order to check
- the authenticity of their notices. You can do:
- .Sp
--.Vb 1
--\& gpg \-\-no\-default\-keyring \-\-primary\-keyring <pathetc>/pgp/ncmring.gpg \-\-import <key\-file>
-+.Vb 3
-+\& gpg \-\-no\-default\-keyring \-\-primary\-keyring=/etc/news/pgp/ncmring.gpg \e
-+\& \-\-no\-options \-\-allow\-non\-selfsigned\-uid \-\-no\-permission\-warning \e
-+\& \-\-batch \-\-import <key\-file>
- .Ve
- .Sp
- where <pathetc> is the value of the \fIpathetc\fR parameter set in \fIinn.conf\fR
+++ /dev/null
-# backported fixes
-fix_ad_flag
-fix_body_regexps
-
-# waiting to be merged upstream
-
-# debian-specific
-nocem-gpg-import
-debian-paths
-
-# packaging-related
-configure-hostname
-no-makedbz-on-install
-u_innreport_misc
-u_right_length
-u_status_init_ip
-u_tls_duplicate_reply
-u_xhdr_permissions
-u_xover_duplicate_reply
-typo_inn_conf_man
+++ /dev/null
---- a/doc/man/inn.conf.5
-+++ b/doc/man/inn.conf.5
-@@ -480,7 +480,7 @@ this parameter must be set if \fIenableo
- .el .IP "\f(CWbuffindexed\fR" 4
- .IX Item "buffindexed"
- Stores overview data and index information into buffers, which are
--preconfigured files defined in \fIbuffinedexed.conf\fR. \f(CW\*(C`buffindexed\*(C'\fR never
-+preconfigured files defined in \fIbuffindexed.conf\fR. \f(CW\*(C`buffindexed\*(C'\fR never
- consumes additional disk space beyond that allocated to these buffers.
- .ie n .IP """tradindexed""" 4
- .el .IP "\f(CWtradindexed\fR" 4
+++ /dev/null
-Bug-fixes for innreport:
- - Test for the existence of 'img_dir' instead of 'html_dir' in innreport;
- - Trailing comma after %innfeed_spooled with "Outgoing feeds (innfeed)
- by Articles";
- - Column "Total" of "Outgoing feeds (innfeed) by Volume" tries to add
- two hashes which evaluates to a constant 0;
- - Gracefully handle undefined hash elements in "NNRP readership statistics
- (by domain)";
- - Also added two error messages generated by perl-nocem.
-
-http://inn.eyrie.org/viewcvs/branches/2.4/scripts/innreport.in?r1=8142&r2=8141&pathrev=8142&view=patch
-http://inn.eyrie.org/viewcvs/branches/2.4/samples/innreport.conf.in?r1=7945&r2=7944&pathrev=7945&view=patch
-http://inn.eyrie.org/viewcvs/branches/2.4/scripts/innreport_inn.pm?r1=7945&r2=7944&pathrev=7945&view=patch
-
---- 2.4/scripts/innreport.in 2008/10/05 23:47:25 8141
-+++ 2.4/scripts/innreport.in 2008/10/07 17:08:32 8142
-@@ -212,7 +212,7 @@
- $IMG_pth = $ref{'webpath'} if defined $ref{'webpath'};
-
- $IMG_dir = $HTML_dir . "/" . $IMG_pth
-- if (defined $output{'default'}{'html_dir'} ||
-+ if (defined $output{'default'}{'img_dir'} ||
- defined $ref{'w'} || defined $ref{'webpath'})
- &&
- (defined $output{'default'}{'html_dir'} ||
---- 2.4/samples/innreport.conf.in 2008/08/03 07:30:03 7944
-+++ 2.4/samples/innreport.conf.in 2008/08/03 07:47:10 7945
-@@ -1267,7 +1267,7 @@
- data {
- name "Spooled";
- color "#AF00FF";
-- value "%innfeed_spooled,";
-+ value "%innfeed_spooled";
- };
- };
- };
-@@ -1347,12 +1347,6 @@
- color "#FFAF00";
- value "%innfeed_rejected_size";
- };
-- data {
-- name "Total";
-- color "#00FF00";
-- value "%innfeed_accepted_size +
-- %innfeed_rejected_size";
-- };
- };
- };
-
-@@ -2116,8 +2110,8 @@
- name "Rej";
- format_name "%4s";
- format "%4d";
-- value "$nnrpd_post_rej{$key} +
-- $nnrpd_post_error{$key}";
-+ value "($nnrpd_post_rej{$key}||0) +
-+ ($nnrpd_post_error{$key}||0)";
- total "total(%nnrpd_post_rej) +
- total(%nnrpd_post_error)";
- };
-@@ -2179,8 +2173,8 @@
- name "Rej";
- format_name "%4s";
- format "%4d";
-- value "$nnrpd_dom_post_rej{$key} +
-- $nnrpd_dom_post_error{$key}";
-+ value "($nnrpd_dom_post_rej{$key}||0) +
-+ ($nnrpd_dom_post_error{$key}||0)";
- total "total(%nnrpd_dom_post_rej) +
- total(%nnrpd_dom_post_error)";
- };
---- 2.4/scripts/innreport_inn.pm 2008/08/03 07:30:03 7944
-+++ 2.4/scripts/innreport_inn.pm 2008/08/03 07:47:10 7945
-@@ -440,8 +440,8 @@
- # The exact timers change from various versions of INN, so try to deal
- # with this in a general fashion.
- if ($left =~ m/^\S+\s+ # ME
-- time\ (\d+)\s+ # time
-- ((?:\S+\ \d+\(\d+\)\s*)+) # timer values
-+ time\s(\d+)\s+ # time
-+ ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $innd_time_times += $1;
- my $timers = $2;
-@@ -719,8 +719,8 @@
- # ME time X nnnn X(X) [...]
- return 1 if $left =~ m/backlogstats/;
- if ($left =~ m/^\S+\s+ # ME
-- time\ (\d+)\s+ # time
-- ((?:\S+\ \d+\(\d+\)\s*)+) # timer values
-+ time\s(\d+)\s+ # time
-+ ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $innfeed_time_times += $1;
- my $timers = $2;
-@@ -1459,8 +1459,8 @@
- # The exact timers change from various versions of INN, so try to deal
- # with this in a general fashion.
- if ($left =~ m/^\S+\s+ # ME
-- time\ (\d+)\s+ # time
-- ((?:\S+\ \d+\(\d+\)\s*)+) # timer values
-+ time\s(\d+)\s+ # time
-+ ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $nnrpd_time_times += $1;
- my $timers = $2;
-@@ -1683,13 +1683,28 @@
- $nocem_totalids{$nocem_lastid} += $2;
- return 1;
- }
-- if ($left =~ /bad signature from (.*)/o) {
-+ if ($left =~ /Article <[^>]*>: (.*) \(ID [[:xdigit:]]*\) not in keyring/o) {
-+ $nocem_badsigs{$1}++;
-+ $nocem_goodsigs{$1} = 0 unless ($nocem_goodsigs{$1});
-+ $nocem_totalbad++;
-+ $nocem_lastid = $1;
-+ return 1;
-+ }
-+ if ($left =~ /Article <[^>]*>: bad signature from (.*)/o) {
- $nocem_badsigs{$1}++;
- $nocem_goodsigs{$1} = 0 unless ($nocem_goodsigs{$1});
- $nocem_totalbad++;
- $nocem_lastid = $1;
- return 1;
- }
-+ if ($left =~ /Article <[^>]*>: malformed signature/o) {
-+ $nocem_badsigs{'N/A'}++;
-+ $nocem_goodsigs{'N/A'} = 0 unless ($nocem_goodsigs{'N/A'});
-+ $nocem_totalbad++;
-+ $nocem_lastid = 'N/A';
-+ return 1;
-+ }
-+
- return 1;
- }
-
+++ /dev/null
-Bug-fix for TLS: return 1 when length is right.
-
-http://inn.eyrie.org/viewcvs/branches/2.4/nnrpd/tls.c?r1=8058&r2=8057&pathrev=8058&view=patch
-
---- 2.4/nnrpd/tls.c 2008/09/26 23:11:47 8057
-+++ 2.4/nnrpd/tls.c 2008/09/26 23:12:49 8058
-@@ -257,7 +257,7 @@
- X509_verify_cert_error_string(err));
-
- if (verify_depth >= depth) {
-- ok = 0;
-+ ok = 1;
- verify_error = X509_V_OK;
- } else {
- ok = 0;
+++ /dev/null
-Fix a bug in the IP address displayed for localhost in innd's status file.
-It was not correctly initialized (it is a local connection which does not
-use any IP address).
-
-http://inn.eyrie.org/viewcvs/branches/2.4/innd/status.c?r1=7947&r2=7946&pathrev=7947&view=patch
-
---- 2.4/innd/status.c 2008/08/03 07:50:03 7946
-+++ 2.4/innd/status.c 2008/08/03 07:55:20 7947
-@@ -153,9 +153,14 @@
- status = xmalloc(sizeof(STATUS));
- peers++; /* a new peer */
- strlcpy(status->name, TempString, sizeof(status->name));
-- strlcpy(status->ip_addr,
-- sprint_sockaddr((struct sockaddr *)&cp->Address),
-- sizeof(status->ip_addr));
-+ if (cp->Address.ss_family == 0) {
-+ /* Connections from lc.c do not have an IP address. */
-+ memset(&status->ip_addr, 0, sizeof(status->ip_addr));
-+ } else {
-+ strlcpy(status->ip_addr,
-+ sprint_sockaddr((struct sockaddr *)&cp->Address),
-+ sizeof(status->ip_addr));
-+ }
- status->can_stream = cp->Streaming;
- status->seconds = status->Size = status->DuplicateSize = 0;
- status->Ihave = status->Ihave_Duplicate =
+++ /dev/null
-Do not send 580 when negotiation fails (382 has already been sent).
-
-http://inn.eyrie.org/viewcvs/branches/2.4/nnrpd/misc.c?r1=8057&r2=8056&pathrev=8057&view=patch
-
---- 2.4/nnrpd/misc.c 2008/09/26 23:02:08 8056
-+++ 2.4/nnrpd/misc.c 2008/09/26 23:11:47 8057
-@@ -544,7 +544,7 @@
- result=tls_start_servertls(0, /* read */
- 1); /* write */
- if (result==-1) {
-- Reply("%d Starttls failed\r\n", NNTP_STARTTLS_BAD_VAL);
-+ /* No reply because we have already sent NNTP_STARTTLS_NEXT_VAL. */
- return;
- }
- nnrpd_starttls_done = 1;
+++ /dev/null
-XHDR and XPAT were not checking the permissions the user has to read
-articles when using a message-ID. Now fixed, as well as calls to ARTclose().
-
-http://inn.eyrie.org/viewcvs/branches/2.4/nnrpd/article.c?r1=8004&r2=8003&pathrev=8004&view=patch
-
---- 2.4/nnrpd/article.c 2008/09/05 19:13:28 8003
-+++ 2.4/nnrpd/article.c 2008/09/06 08:49:55 8004
-@@ -688,6 +688,7 @@
- if (ac > 1)
- ARTnumber = tart;
- if ((msgid = GetHeader("Message-ID")) == NULL) {
-+ ARTclose();
- Reply("%s\r\n", ARTnoartingroup);
- return;
- }
-@@ -745,9 +746,9 @@
- if (!ARTopen(ARTnumber))
- continue;
- msgid = GetHeader("Message-ID");
-+ ARTclose();
- } while (msgid == NULL);
-
-- ARTclose();
- Reply("%d %d %s Article retrieved; request text separately.\r\n",
- NNTP_NOTHING_FOLLOWS_VAL, ARTnumber, msgid);
- }
-@@ -1008,6 +1009,12 @@
- Printf("%d No such article.\r\n", NNTP_DONTHAVEIT_VAL);
- break;
- }
-+ if (!PERMartok()) {
-+ ARTclose();
-+ Printf("%s\r\n", NOACCESS);
-+ break;
-+ }
-+
- Printf("%d %s matches follow (ID)\r\n", NNTP_HEAD_FOLLOWS_VAL,
- header);
- if ((text = GetHeader(header)) != NULL
-@@ -1047,8 +1054,8 @@
- SendIOb(buff, strlen(buff));
- SendIOb(p, strlen(p));
- SendIOb("\r\n", 2);
-- ARTclose();
- }
-+ ARTclose();
- }
- SendIOb(".\r\n", 3);
- PushIOb();
+++ /dev/null
-Fix a bug in the replies of XOVER/XHDR/XPAT when the group is empty.
-Two initial replies were sent.
-
-http://inn.eyrie.org/viewcvs/branches/2.4/nnrpd/article.c?r1=8000&r2=7999&pathrev=8000&view=patch
-
---- 2.4/nnrpd/article.c 2008/09/03 05:41:27 7999
-+++ 2.4/nnrpd/article.c 2008/09/04 17:06:51 8000
-@@ -854,9 +854,7 @@
-
- /* Parse range. */
- if (!CMDgetrange(ac, av, &range, &DidReply)) {
-- if (!DidReply) {
-- Reply("%d data follows\r\n", NNTP_OVERVIEW_FOLLOWS_VAL);
-- Printf(".\r\n");
-+ if (DidReply) {
- return;
- }
- }
-@@ -1028,10 +1026,7 @@
-
- /* Range specified. */
- if (!CMDgetrange(ac - 1, av + 1, &range, &DidReply)) {
-- if (!DidReply) {
-- Reply("%d %s no matches follow (range)\r\n",
-- NNTP_HEAD_FOLLOWS_VAL, header ? header : "\"\"");
-- Printf(".\r\n");
-+ if (DidReply) {
- break;
- }
- }
+++ /dev/null
-#!/usr/bin/make -f
-SHELL+= -e
-
-QUILT_STAMPFN := .stamp-patched
-include /usr/share/quilt/quilt.make
-
-D-std := $(CURDIR)/debian/inn2
-D-lfs := $(CURDIR)/debian/inn2-lfs
-D = $(D-$*)
-B = $(CURDIR)/build-$*
-
-##############################################################################
-# this code deals with building a second inn2-lfs package from the same
-# source, but only on 32 bit architectures
-# Ideally new future 32 bit architectures should not bother with inn2-lfs
-# and just enable LFS by default.
-
-DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
-ifeq ($(DEB_HOST_ARCH),$(filter $(DEB_HOST_ARCH),amd64 ia64 ppc64 s390x))
-# 64 bit std package
-FLAVORS := std
-else ifeq ($(DEB_HOST_ARCH),$(filter $(DEB_HOST_ARCH),armel))
-# 32 bit LFS std package
-FLAVORS := std
-std_configure_flags = --enable-largefiles
-else
-# 32 bit std package and 32 bit LFS lfs package
-FLAVORS := std lfs
-lfs_configure_flags = --enable-largefiles
-endif
-
-std_dh_clean_opts = -pinn2 -pinn2-inews -p inn2-dev
-lfs_dh_clean_opts = -pinn2-lfs
-std_dh_movefiles_opts = -pinn2 -pinn2-inews -p inn2-dev
-lfs_dh_movefiles_opts = -pinn2-lfs -pinn2-lfs-inews -p inn2-lfs-dev
-
-ifeq ($(FLAVORS),std)
-no_package := --no-package=inn2-lfs
-endif
-
-# the upstream source needs to be copied in the flavor-specific build dirs
-src_files := $(shell find . -maxdepth 1 \
- -not -name . -and -not -name debian -and -not -name .pc \
- -and -not -name 'build-*' -and -not -name '.stamp-*')
-
-##############################################################################
-DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE))
- configure_flags += --build $(DEB_HOST_GNU_TYPE)
-else
- configure_flags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
-endif
-
-clean: unpatch
- rm -rf .stamp-* build-*
- [ ! -f Makefile.global ] || $(MAKE) distclean
- # delete packages which are not in control but are built anyway
- rm -rf debian/inn2-lfs-dev/ debian/inn2-lfs-inews/
- # delete the cloned debhelper configuration and logs
- find debian -maxdepth 1 -name 'inn2-lfs*' -not -type d -print0 \
- | xargs --no-run-if-empty -0 rm
- dh_clean
-
-configure: $(addprefix .stamp-configure-, $(FLAVORS))
-.stamp-configure-%: $(QUILT_STAMPFN)
- dh_testdir
- mkdir -p $B
- for dir in $(src_files); do cp -ldpR $$dir $B; done
- cd $B && \
- _PATH_PERL=/usr/bin/perl \
- ac_cv_path__PATH_AWK=awk \
- ac_cv_path__PATH_EGREP=egrep \
- ac_cv_path__PATH_SED=sed \
- ac_cv_path__PATH_SORT=sort \
- ac_cv_path__PATH_UUX=uux \
- ac_cv_path_PATH_GPGV=/usr/bin/gpgv \
- ac_cv_path_GETFTP=wget \
- ac_cv_search_dbm_open=-ldb \
- LDFLAGS="-Wl,--as-needed $(LDFLAGS)" \
- ./configure \
- --with-perl \
- --enable-ipv6 \
- --prefix=/usr/lib/news \
- --mandir=/usr/share/man \
- --includedir=/usr/include/inn \
- --with-db-dir=/var/lib/news \
- --with-etc-dir=/etc/news \
- --with-filter-dir=/etc/news/filter \
- --with-lib-dir=/usr/lib/news \
- --with-log-dir=/var/log/news \
- --with-run-dir=/var/run/news \
- --with-spool-dir=/var/spool/news \
- --with-tmp-dir=/var/spool/news/incoming/tmp \
- --with-berkeleydb=/usr \
- --with-kerberos=/usr \
- --with-sendmail=/usr/sbin/sendmail \
- $($*_configure_flags) $(configure_flags)
- cd $B && \
- mkdir ssl/ ssl/nnrpd/ && \
- cd ssl/ && \
- ln -s ../Makefile.global ../include ../storage ../history . && \
- cd nnrpd/ && ln -s ../../nnrpd/* .
- touch $@
-
-build: $(addprefix .stamp-build-, $(FLAVORS))
-.stamp-build-%: .stamp-configure-%
- dh_testdir
- cd $B && $(MAKE)
- cd $B/ssl/nnrpd/ && $(MAKE) \
- SSLLIB='-L/usr/lib -lssl -lcrypto -ldl' SSLINC='-DHAVE_SSL=1'
- touch $@
-
-install1-%: .stamp-build-%
- dh_testdir
- dh_testroot
- dh_clean -k $($*_dh_clean_opts)
-
- cd $B && $(MAKE) install DESTDIR=$D
- sh -e extra/dh_cloneconf inn2 inn2-lfs
-
- dh_movefiles $($*_dh_movefiles_opts) --sourcedir=$(subst $(CURDIR)/,,$D)
-
-# move back this one
- mv $D-dev/usr/share/man/man3/uwildmat.3 $D/usr/share/man/man3/
-
-# remove assorted crap and
-# make sure we don't ship active, active.times, newsgroups in place!
- cd $D/etc/news/filter && rm -f *.py *.tcl
- rm -rf $D/usr/lib/news/bin/simpleftp $D/usr/share/man/man1/simpleftp.1\
- $D/usr/lib/news/doc/ $D/var/lib/news/* \
- $D/usr/include/
-
- mv $D/usr/share/man/man1/startinnfeed.1 \
- $D/usr/share/man/man8/startinnfeed.8
-
- cp $B/ssl/nnrpd/nnrpd $D/usr/lib/news/bin/nnrpd-ssl
- install -m 755 extra/buildinnkeyring extra/ginpaths2 \
- $D/usr/lib/news/bin/
- install -m 755 contrib/showtoken.in $D/usr/lib/news/bin/showtoken
- install -m 755 extra/bunbatch $D-inews/usr/lib/news/bin/rnews.libexec/
-
- install -m 644 extra/send-uucp.cf extra/sasl.conf $D/etc/news/
-
- mkdir $D/var/log/news/path
-
-install2: $(addprefix install1-, $(FLAVORS))
- dh_link
- dh_installchangelogs NEWS
- dh_installdocs
- dh_installexamples
- dh_installinit --noscripts --init-script=inn2
- dh_installcron
- dh_installlogcheck
- dh_compress
- dh_fixperms \
- -Xusr/lib/news/bin/inndstart -Xusr/lib/news/bin/startinnfeed
- # some files are not writeable when installed by make install
- dh_strip
-
-install3-%: install2
- chown root:news $D-inews/etc/news/passwd.nntp
- chmod 640 $D-inews/etc/news/passwd.nntp
-
- chmod -x $D/usr/lib/news/bin/control/*.pl
- chmod +rw \
- $D/usr/lib/news/bin/inndstart \
- $D/usr/lib/news/bin/startinnfeed
-
- chown news:uucp $D-inews/usr/lib/news/bin/rnews
- chmod 4755 $D-inews/usr/lib/news/bin/rnews
-
- chown -R news:news $D/var/spool/news/ $D/var/lib/news/ \
- $D/var/run/news/ $D/var/log/news/
- chmod -R g+w $D/var/spool/news/ $D/var/lib/news/ \
- $D/var/run/news/ $D/var/log/news/
-
-install4-std: install3-std
-
-# lfs-specific: rename some files installed by debhelper
-install4-lfs: install3-lfs
- for file in /etc/logcheck/ignore.d.server/inn2 /etc/logcheck/violations.ignore.d/inn2 /etc/cron.d/inn2; do \
- mv $(D-lfs)$$file-lfs $(D-lfs)$$file; \
- done
-
-install5: $(addprefix install4-, $(FLAVORS))
- dh_installdeb
- dh_md5sums
- dh_shlibdeps
- dh_gencontrol $(no_package) -- \
- -VPERLAPI=$$(perl -MConfig -e 'print "perlapi-$$Config{version}"')
- dh_builddeb $(no_package)
-
-binary-arch: install5
-
-binary: binary-arch
-
-.PHONY: clean configure build binary-arch binary install%
+++ /dev/null
-version=3
-opts=dversionmangle=s/r$// \
-ftp://ftp.isc.org/isc/inn/inn-([\d\.]+)\.tar\.gz
+++ /dev/null
-[ Please note that the only portions of INN covered by this license are
- those files explicitly noted as being under the GPL in LICENSE. It is
- a requirement of the GPL, however, that a copy of it be distributed
- with software licensed under it, and some stand-alone programs that
- are distributed with INN are covered under the GPL. ]
-
-
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-\f
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
+++ /dev/null
-Notes about IPv6 support in INN:
-
- This is $Revision: 5416 $, dated $Date: 2002-04-14 07:05:36 -0700 (Sun, 14 Apr 2002) $.
-
- This document contains some notes about the status of IPv6 support in
- INN (see also the parts of the code marked FIXME):
-
-
-Things that will break if you compile with --enable-ipv6:
-
- * innd can only be started via inndstart
- * IP_OPTIONS are not cleared for any incoming connections to innd even
- over IPv4
-
-
-
-Some comments as of the completion of the original patch:
-
- Date: Wed, 13 Feb 2002 00:10:59 -0500 (EST)
- From: Nathan Lutchansky <lutchann@litech.org>
- To: Jeffrey M. Vinocur <jeff@litech.org>
- Subject: IPv6 patch notes
-
- The IPv6 patch is based directly on Marco d'Itri's IPv6 patch of
- 2001-03-01 that was posted last year to the inn-workers list. The
- patch applied fairly cleanly to a working copy from 2002-02-04, and
- the resulting tree was used as the basis for my work.
-
- Modifications by Marco and myself were made so that if IPv6 support is
- not explicitly enabled with the --enable-ipv6 flag to the configure
- script, the old networking code will be used. Hopefully, nobody will
- notice any problems with the default configuration, although some
- changes have been made to data structures even when IPv6 is disabled.
-
- The original patch added IPv6 support to innd and inndstart, and the
- auth_pass program. I have added support to nnrpd, innfeed, and the
- ident auth program. There is no IPv6 support for imapfeed and other
- auxiliary programs like the radius auth backend.
-
- Marco's patch made use of several preprocessor defines for
- configuration but the defines were hand-coded, so I added the
- corresponding tests the the configuration script. I make no
- guarantees that the configure script will catch all possible
- non-portable behavior; the IPv6 API standardization process has left
- quite a wake of incompatible API implementations over the years.
- -Nathan
-
+++ /dev/null
-Introduction
-
- $Id: checklist 5912 2002-12-03 05:31:11Z vinocur $
-
- This is an installation checklist written by Rebecca Ore, intended to be
- the beginning of a different presentation of the information in INSTALL,
- since getting started with installing INN can be complex. Further
- clarifications, updates, and expansion are welcome.
-
-Setup
-
- * Make sure there is a "news" user (and a "news" group)
-
- * Create a home directory for news (perhaps /usr/local/news/) and make
- sure it (and subdirectories) are owned by "news", group "news".
-
- You want to be careful that things in that directory stay owned by
- "news" -- but you can't just "chown -R news.news" after the install,
- because you may have binaries that are SUID root. You can do the
- build as any user, because "make install" will set the permissions
- correctly. After that point, though, you may want to "su news" to
- avoid creating any files as root. (For routine maintenance once INN
- is working, you can generally be root.)
-
- * If necessary, add ~news/bin to the news user's path and ~news/man to
- the news user's manpath in your shell config files. (You may want
- to do this, especially the second part, on your regular account; the
- manpages are very useful.)
-
- You can do this now or later, but you will certainly want the
- manpages to help with configuring INN.
-
- For bash, try:
-
- PATH=~news/bin:$PATH
- export PATH
- MANPATH=~news/man:$MANPATH
- export MANPATH
-
- or csh:
-
- setenv PATH ~news/bin:$PATH
- setenv MANPATH ~news/man:$MANPATH
-
- although if you don't already have MANPATH set, the above may give
- an error or override your defaults (making it so you can only read
- the news manpages); if "echo $MANPATH" does not give some reasonable
- path, you'll need to look up what the default is for your system
- (such as /usr/man or /usr/share/man).
-
-Compile
-
- * Download the INN tarball and unpack.
-
- * Work out configure options ("./configure --help" for a list). If
- you aren't working out of /usr/local/news, or want to put some files
- on a different partition, you can set the directories now (or later
- in inn.conf if you change your mind).
-
- You probably want "--with-perl". If you're not using NetBSD with
- cycbuffs or OpenBSD, perhaps "--with-tagged-hash". You might want
- to compile in SSL and Berkeley DB, if your system supports them.
-
- ./configure --with-perl ...
- make
-
- su
- make install
-
- (If you do the last step as root, all of the ownerships and
- permissions will be correct.)
-
-Configure
-
- * Find INSTALL and open a separate window for it. A printout is
- probably a good idea -- it's long but very helpful. Any time the
- instructions below ask you to make a decision, you can probably find
- help in INSTALL.
-
- * Now it's time to work on the files in ~news/etc/. Start with
- inn.conf; you must fill in the default moderators address, your
- fully qualified domain names and path. Fill in all the blanks.
- Change the file descriptor limits to something like 500.
-
- * If using cycbuffs (the CNFS storage method), open cycbuff.conf in
- one window and a shell in another to create the cycbuff as described
- in INSTALL. As you create them, record in cycbuff.conf the paths
- and sizes. Save paths and sizes in a separate text file on another
- machine in case you ever blow away the wrong file.
-
- Name the metacycbuff, then configure storage.conf.
-
- * In storage.conf, be sure that all sizes of articles can be
- accomodated. If you want to throw away large articles, do it
- explicitly by using the "trash" storage method.
-
- * The default options in expire.ctl work fine if you have cycbuffs, if
- not, configure to suit.
-
- * Check over moderators and control.ctl.
-
- * Run ~news/bin/inncheck and fix anything noted.
-
- Inncheck gives a rough check on the appropriateness of the
- configuration files as you go. (It's the equivalent of "perl -cw
- yourfile.pl" for perl scripts.)
-
- Note that inncheck is very conservative about permissions; there's
- no reason most of the config files can't be world-readable if you
- prefer that.
-
- * Import an active file (~news/db/active) and run inncheck again.
- Change where noted (there's a gotcha in the ISC's active list 000000
- 000000 (whatever number of zeros) should be 0000000 00000001).
-
- * Create empty initial db files. Be sure these end up owned by news.
-
- cd ~news/db
-
- touch newsgroups
- touch active.times
-
- touch history
- ~news/bin/makedbz -i
- mv history.n.hash history.hash
- mv history.n.index history.index
- mv history.n.dir history.dir
-
- chmod 644 *
-
- * Create the cron jobs and make the changes to your system's
- syslog.conf as noted in INSTALL. Also create the cron job for
- nntpsend if you've chosen that over innfeed.
-
- Create the log files.
-
- * For the time being, we can see if everything initially works without
- worrying about feeds or reader access.
-
-Run
-
- * Start inn by running ~news/bin/rc.news *as the news user*.
-
- Check ~news/log/news.notice to see if everything went well, also use
- "ps" to see if innd is running.
-
- "telnet localhost 119" and you should see either a welcome banner or
- a "no permission to talk" message. If not, investigate.
-
- * "man ctlinnd" now; you'll use "ctlinnd reload" as you complete your
- configuration.
-
-Feeds
-
- All of this can be done while INN is running.
-
- * To get your incoming feeds working, edit incoming.conf. When done,
- "ctlinnd reload incoming.conf reason" (where "reason" is some text
- that will show up in the logs, anything will do).
-
- * To get your outgoing feeds working, decide whether to use innfeed or
- nntpsend. Edit newsfeeds and either innfeed.conf or nntpsend.ctl.
-
- In newsfeeds, if using innfeed, use the option which doens't require
- you to do a separate innfeed configuration unless you know more than
- I do.
-
- Then "ctlinnd reload newsfeeds reason".
-
- * In readers.conf, remember that auth and access can be separated.
-
- Begin with auth. Your auth for password users could look like this:
-
- auth "foreignokay" {
- auth: "ckpasswd -d ~news/db/newsusers"
- default: "<unauthenticated>"
- }
-
- There is a perl script in the ckpasswd man page if you want to do
- authentications by password and have the appropriate libraries.
- Copy it to ~news/bin, name the file something like makepasswd.pl and
- change the internal paths to whatever you're using and wherever
- you're putting the newsusers database. The standard Apache
- "htpasswd" tool also works just fine to create INN password files.
-
- Follow with the access stanzas. Something for people with
- passwords:
-
- access "generalpeople" {
- users: "*"
- newsgroups: "*,!junk,!control,!control.*"
- }
-
- And then something like one of the following two, depending on
- whether unauthenticated users get any access:
-
- access "restrictive" {
- users: "<unauthenticated>"
- newsgroups: "!*"
- }
-
- access "readonly" {
- users: "<unauthenticated>"
- read: "local.*"
- post: "!*"
- }
-
- You don't need to reload anything after modifying readers.conf;
- every time an nnrpd launches it reads its configuration from disk.
-
+++ /dev/null
-$Id: compliance-nntp 6817 2004-05-18 09:25:55Z rra $
-
-The following are outstanding issues regarding INN's compliance with the
-NNTP standard. The reference documents used in this analysis are the
-current NNTP IETF Working Group draft (draft-ietf-nntpext-base-15.txt at
-the time of the last check of this audit) or RFC 2980, not RFC 977 (which
-is woefully out of date).
-
-This file documents only compliance issues with the latest version of the
-standard NNTP protocol. It does not cover INN's private extensions or
-INN's implementation of widely available extensions not documented in the
-NNTP standard. Specifically, it does not cover the extensions listed in
-RFC 2980.
-
-------------------------------
-
- Summary: innd doesn't require whitespace between commands and arguments
- Standard: draft-ietf-nntpext-base-15.txt, section 4
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c NCproc() and command handlers
- Severity: Accepts invalid input
-
-The standard states:
-
- Keywords and arguments MUST be each separated by one or more US-ASCII
- SPACE or US-ASCII TAB characters.
-
-This is not checked in NCproc or in the individual command handlers in
-innd. Commands followed immediately by their argument will be accepted by
-innd. For example:
-
- stat<9k6vjk.hg0@example.com>
- 223 0 @0301543531000000000000079AAE0000006A@
-
-Impact: Should one command be a prefix of another, innd could dispatch
-the handling of the command to the wrong handler, treating the remainder
-of the command verb as an argument. This laxness also encourages sloppy
-client code. Internally, the lack of argument parsing in NCproc also
-results in code duplication in all of the command handlers.
-
-Suggested fix: Lift the argument parsing code into a function called from
-NCproc, breaking the command line into a vector of command and arguments.
-This will work for all commands implemented by innd and will simplify the
-implementation of command handlers, as well as fixing this problem. This
-is what nnrpd already does.
-
-Impact of fix: It's possible that some serving code is relying on this
-behavior and not sending spaces after commands. Fixing this problem would
-break interoperability with that code.
-
-------------------------------
-
- Summary: INN doesn't check argument length
- Standard: draft-ietf-nntpext-base-15.txt, section 4
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c and nnrpd/nnrpd.c
- Severity: Accepts invalid input
-
-The standard says:
-
- Arguments MUST NOT exceed 497 octets.
-
-This is not checked by either innd or nnrpd, although both do check that
-the command itself does not exceed 512 octets.
-
-Impact: Small. May accept invalid commands in extremely rare edge cases.
-
-Suggested fix: Probably not worth fixing separately, although if standard
-command parsing code is written to handle both innd and nnrpd, it wouldn't
-hurt to check this along with everything else.
-
-------------------------------
-
- Summary: Reply codes other than x9x used for private extensions
- Standard: draft-ietf-nntpext-base-15.txt, section 4.1
- Version: 1.0 to CURRENT 2002-12-26
-Reference: include/nntp.h
- Severity: Violates SHOULD
-
-The standard says:
-
- Response codes not specified in this standard MAY be used for any
- installation-specific additional commands also not specified. These
- SHOULD be chosen to fit the pattern of x9x specified above.
-
-INN uses quite a few response codes that do not fit this pattern for
-various extensions. Some of these will likely later be standardized with
-the response codes that INN uses (the streaming commands, the
-authentication reply codes, and possibly the STARTTLS reply codes), but
-the rest (XGTITLE, MODE CANCEL, and XBATCH) should have used response
-codes in the x9x range.
-
-Impact: Additional ambiguity over the meaning of reply codes, as those
-reply codes could later be standardized as the reply codes for other
-commands.
-
-Suggested fix: For XGTITLE and probably XBATCH, there is no way to fix
-this now. Changing the reply codes would break all existing
-implementations. It may still be possible to change the reply codes for
-MODE CANCEL (which should probably be MODE XCANCEL), but it may not be
-worth the effort.
-
-------------------------------
-
- Summary: innd may return 480 instead of 500 for unrecognized commands
- Standard: draft-ietf-nntpext-base-15.txt, section 4.1.1
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c NCauthinfo()
- Severity: Violates MUST
-
-The standard says:
-
- If the command is not recognized, or it is an optional command or
- extension that is not implemented by the server, the response code 500
- MUST be returned.
-
-In innd, if the connection is determined to need authentication, all
-incoming commands other than MODE are handed off to NCauthinfo() rather
-than their normal command handlers. NCauthinfo() responds with a 480
-reply code to anything other than AUTHINFO USER, AUTHINFO PASS, or QUIT.
-
-Impact: Unlikely to cause problems in practice, but may confuse clients
-that don't understand the rarely used innd-level authentication
-mechanisms.
-
-Suggested fix: Restructure the command table so that each command also
-has a flag indicating whether it requires authentication for peers that
-are required to authenticate. (Some commands, like HELP and MODE READER,
-should be allowed without authentication.) Then eliminate the special
-casing of the state CSgetauth (it may be better to store whether the peer
-has authenticated in the channel rather than in the channel state) and the
-special handling in NCauthinfo. This should also simplify the code.
-
-------------------------------
-
- Summary: innd always sends 200 for an accepted connection
- Standard: draft-ietf-nntpext-base-15.txt, section 7.1
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c NCsetup() and rc.c RCreader()
- Severity: Violates MUST
-
-The standard says:
-
- If the server will accept further commands from the client including
- POST, the server MUST present a 200 greeting code. If the server will
- accept further commands from the client, but it is not authorized to
- post articles using the POST command, the server MUST present a 201
- greeting code.
-
-The implication is that the greeting code from innd (which doesn't
-implement POST and therefore is never going to allow it) should always be
-201, at least for the case where innd never spawns nnrpd. In the case
-where innd spawns nnrpd, it's unclear what the greeting code should be.
-
-The current implementation nevers send 201 unless one knows for certain
-that the connection will never be allowed to issue a POST command, which
-means that innd always sends 200.
-
-It's unknown whether there is any transit news software that would have
-difficulties with a 201 greeting. Both innxmit and innfeed handle it
-correctly in CURRENT 2001-07-04 and NNTPconnect() handles it correctly in
-INN 1.0, so it seems likely that if any such software exists, it's rare.
-
-Impact: It's almost certain that the current innd behavior isn't hurting
-anything. Even a confused client that thought 200 meant that it could
-send a POST command would then try and be rejected with no damage done.
-
-Suggested fix: The purpose of this return code is to give a hint to a
-reading client indicating whether it should even attempt POST, since
-attempting it may involve a lot of work by the user only to have the post
-rejected. It's only relevant to reading connections, not to transit
-connections.
-
-It's known that some clients, upon seeing a 201 response, will never
-attempt POST, even if MODE READER then returns 200. Therefore innd, when
-handing off connections to nnrpd, must return 200 to not confuse a client
-that will later send MODE READER. For connections where innd won't do
-that handoff, it makes sense to always send 201 if all transit feeds can
-handle that and won't interpret it as unwillingness to accept IHAVE or
-streaming feeds.
-
-RCreader() should therefore be modified to send 201 if noreader is set,
-and otherwise send 200.
-
-Impact of fix: Any feeding software that didn't consider 201 to be a
-valid greeting would be unable to feed a fixed innd unless that innd also
-allowed reading connections.
-
-------------------------------
-
- Summary: innd doesn't support LIST EXTENSIONS
- Standard: draft-ietf-nntpext-base-15.txt, section 8.1
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c NClist()
- Severity: Not a violation
-
-Support for LIST EXTENSIONS is optional, and innd's current behavior
-(returning a 500 response) is permitted by the standard, but it means that
-innd cannot advertise any of the extensions that it supports. Since this
-will eventually include streaming, support should be added.
-
-Suggested fix: Add support for LIST EXTENSIONS to NClist() as soon as
-innd supports a registered extension or as soon as there is documentation
-for INN's extensions that specify an extension name (beginning with X).
-
-------------------------------
-
- Summary: nnrpd doesn't return 423 errors when there is no overview info
- Standard: draft-ietf-nntpext-base-17.txt, section 10.5.1.2
- Version: 1.4 to CURRENT 2003-05-04
-Reference: nnrpd/article.c CMDxover()
- Severity: Violates a MUST
-
-The standard says:
-
- If there are no articles in the range specified, a 423 response MUST be
- returned.
-
-nnrpd (from the beginning of the XOVER command) has always returned a 224
-response with an empty multiline response instead. INN doesn't support
-OVER yet so this isn't actually a bug in INN, but eventually the XOVER
-implementation will also be used for OVER.
-
-Impact: Less information is communicated to the client about why there
-are no overview records returned. An error response indicating there are
-no valid articles in that range is possibly more informative.
-
-Suggested fix: Don't print out the initial 224 message until at least one
-overview entry has been found, so that CMDxover() can print a 420 response
-instead if no overview records are found.
-
-Impact of fix: May confuse some clients that don't expect to get 420
-errors back from overview queries. It may be necessary to do something
-different for OVER (where clients should expect this behavior since OVER
-is a new command) than for XOVER (where clients may be relying on the
-existing behavior.
-
-------------------------------
-
- Summary: HDR can return message IDs rather than article numbers
- Standard: draft-ietf-nntpext-base-17.txt, section 10.6.1.2
- Version: 1.0 to CURRENT 2003-05-04
-Reference: nnrpd/article.c CMDpat()
- Severity: Violates a protocol description
-
-The standard says:
-
- The line consists of the article number, a US-ASCII space, and then the
- contents of the header (without the header name or the colon and space
- that follow it) or metadata item. If the article is specified by
- message-id rather than by article range, the article number is given as
- "0".
-
-nnrpd instead returns the message ID as the first word of the line when
-HDR is given a message ID argument.
-
-Impact: A client may not be able to parse the output of HDR correctly,
-since the first word is not a number.
-
-Suggested fix: Change the code to return 0 as the first word instead of
-the message ID, per the standard.
-
-Impact of fix: Clients that are expecting the message ID may be
-confused.
-
-------------------------------
-
- Summary: innd improperly caches DNS returns
- Standard: draft-ietf-nntpext-base-15.txt, section 14.4
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/rc.c RCreadfile() and elsewhere
- Severity: Violates a MUST
-
-The standard says:
-
- If NNTP clients or servers cache the results of host name lookups in
- order to achieve a performance improvement, they MUST observe the TTL
- information reported by DNS.
-
-innd caches DNS lookups when reading incoming.conf and doesn't refresh its
-knowledge of DNS except when incoming.conf is reloaded.
-
-Impact: An explicit reload is required whenever the IP address of any
-peer changes, and in the presence of network renumbering innd is
-vulnerable to spoofing if DNS is the only authentication mechanism used.
-
-Suggested fix: This is hard to fix without unacceptable performance
-impact. The only good fix is to either fork a separate helper process to
-do DNS lookups (since gethostbyname may block for essentially an
-arbitrarily long period) or to use the direct resolver library so that one
-can get access to a file descriptor and throw it into the select loop.
-Either way, this requires keeping a DNS file descriptor in the main select
-loop and updating knowledge of DNS periodically, which is a substantial
-amount of additional complexity.
-
-------------------------------
-
- Summary: innd doesn't diagnose repeated AUTHINFO USER commands
- Standard: RFC 2980, section 3.1.1
- Version: 1.0 to CURRENT 2002-12-26
-Reference: innd/nc.c NCauthinfo()
- Severity: Violates a protocol description
-
-RFC 2980 says:
-
- The 482 code will also be returned when the AUTHINFO commands are not
- entered in the correct sequence (like two AUTHINFO USERs in a row, or
- AUTHINFO PASS preceding AUTHINFO USER).
-
-innd ignores AUTHINFO USER and just always returns a 381 response, however,
-since it doesn't care about the username.
-
-Impact: Probably none.
-
-Suggested fix: A long-term solution would be to add real authentication
-to innd, in which case it would start caring about the authenticated
-identity (and perhaps use that identity to map to an incoming.conf entry).
-It's unclear if this would be worthwhile. Failing that, innd would need
-to keep internal state to know whether AUTHINFO USER had already been
-sent.
+++ /dev/null
-$Id: config-design 4805 2001-06-21 10:52:27Z rra $
-
-This file is documentation of the design principles that went into INN's
-configuration file syntax, and some rationale for why those principles
-were chosen.
-
- 1. All configuration files used by INN should have the same syntax.
- This was the root reason why the project was taken on in the first
- place; INN developed a proliferation of configuration files, all of
- which had a slightly (or greatly) different syntax, forcing the
- administrator to learn several different syntaxes and resulting in a
- proliferation of parsers, all with their own little quirks.
-
- 2. Adding a new configuration file or a new set of configuration options
- should not require writing a single line of code for syntax parsing.
- Code that analyzes the semantics of the configuration will of course
- be necessary, but absolutely no additional code to read files, parse
- files, build configuration trees, or the like should be required.
- Ideally, INN should have a single configuration parser that
- everything uses.
-
- 3. The syntax should look basically like the syntax of readers.conf,
- incoming.conf, and innfeed.conf in INN 2.3. After extensive
- discussion on the inn-workers mailing list, this seemed to be the
- most generally popular syntax of the ones already used in INN, and
- inventing a completely new syntax didn't appear likely to have gains
- outweighing the effort involved. This syntax seemed sufficiently
- general to represent all of the configuration information that INN
- needed.
-
- 4. The parsing layer should *not* attempt to do semantic analysis of the
- configuration; it should concern itself solely with syntax (or very
- low-level semantics that are standard across all conceivable INN
- configuration files). In particular, the parsing layer should not
- know what parameters are valid, what groups are permitted, what types
- the values for parameters should have, or what default values
- parameters have.
-
- This principle requires some additional explanation, since it is very
- tempting to not do things this way. However, the more semantic
- information the parser is aware of, the less general the parser is,
- and it's very easy to paint oneself into a corner. In particular,
- it's *not* a valid assumption that all clients of the parsing code
- will want to reduce the configuration to a bunch of structs; this
- happens to be true for most clients of inn.conf, for example, but
- inndstart doesn't want the code needed to reduce everything to a
- struct and set default values to necessarily be executed in a
- security-critical context.
-
- Additionally, making the parser know more semantic information either
- complicates (significantly) the parser interface or means that the
- parser has to be modified when the semantics change. The latter is
- not acceptable, and the parser interface should be as straightforward
- as possible (to encourage all parts of INN to use it).
-
- 5. The result of a parse of the configuration file may be represented as
- a tree of dictionaries, where each dictionary corresponds to a group
- and each key corresponds to a parameter setting. (Note that this does
- not assume that the underlying data structure is a hash table, just
- that it has dictionary semantics, namely a collection of key/value
- pairs with the keys presumed unique.)
-
- 6. Parameter values inherit via group nesting. In other words, if a
- group is nested inside another group, all parameters defined in the
- enclosing group are inherited by the nested group unless they're
- explicitly overriden within the nested group. (This point and point
- 5 are to some degree just corollaries of point 3.)
-
- 7. The parsing library must permit writing as well as reading. It must
- be possible for a program to read in a configuration file, modify
- parameters, add and delete groups, and otherwise change the
- configuration, and then write back out to disk a configuration file
- that preserves those changes and still remains as faithful to the
- original (possibly human-written) configuration file as possible.
- (Ideally, this would extend to preserving comments, but that may be
- too difficult to do and therefore isn't required.)
-
- 8. The parser must not limit the configuration arbitrarily. In
- particular, unlimited length strings (within available memory) must
- be supported for string values, and if allowable line length is
- limited, line continuation must be supported everywhere that there's
- any reasonable expectation that it might be necessary. One common
- configuration parameter is a list of hosts or host wildmats that can
- be almost arbitrarily long, and the syntax and parser must support
- that.
-
- 9. The parser should be reasonably efficient, enough so as to not cause
- an annoying wait for command-line tools like sm and grephistory to
- start. In general, though, efficiency in either time or memory is
- not as high of a priority as readable, straightforward code; it's
- safe to assume that configuration parsing is only done on startup and
- at rare intervals and is not on any critical speed paths.
-
-10. Error reporting is a must. It must be possible to clearly report
- errors in the configuration files, including at minimum the file name
- and line number where the error occurred.
-
-11. The configuration parser should not trust its input, syntax-wise. It
- must not segfault, infinitely loop, or otherwise explode on malformed
- or broken input. And, as a related point, it's better to be
- aggressively picky about syntax than to be lax and attempt to accept
- minor violations. The intended configuration syntax is simple and
- unambiguous, so it should be unnecessary to accept violations.
-
-12. It must be possible to do comprehensive semantic checks of a
- configuration file, including verifying that all provided parameters
- are known ones, all parameter values have the correct type, group
- types that are not expected to be repeated are not, and only expected
- group types are used. This must *not* be done by the parser, but the
- parser must provide sufficient hooks that the client program can do
- this if it chooses.
-
-13. The parser must be re-entrant and thread-safe.
-
-14. The grammar shouldn't require any lookahead to parse. This is in
- order to keep the parser extremely simple and therefore maintainable.
- (It's worth noting that this design principle leads to the
- requirement that parameter keys end in a colon; the presence of the
- colon allows parameter keys to be distinguished from other syntactic
- elements allowed in the same scope, like the beginning of a nested
- group.)
+++ /dev/null
-$Id: config-semantics 4792 2001-06-21 08:59:39Z rra $
-
-Groups in a configuration file have a well-defined order, namely the order
-in which the groups would be encountered in a depth-first traversal of the
-parse tree.
-
-The supported operations on a configuration file parse tree for reading
-are:
-
- * Search. Find the first group of a given type in a given tree. This is
- done via depth-first search.
-
- * Next. Find the next group of a given type, starting from some group.
- This is done via depth-first search.
-
- * Query. Look up the value of a given parameter in a given group (with
- inheritance). Note that the expected type of the parameter value must
- be provided by the caller; the parsing library doesn't know the types
- of parameters.
-
- * Prune. Limit one's view of the configuration file to only a given set
- of group types and everything underneath them; any other group types
- encountered won't be parsed (and therefore everything under them, even
- groups of the wanted type, won't be seen).
-
-Therefore, the *only* significance of nested group structure is parameter
-inheritence and pruning. In the absence of pruning, it would always be
-possible, by duplicating parameter settings that were inherited and laying
-out the groups in depth-first traversal order, to transform any
-configuration file into an entirely equivalent one that contains no nested
-groups. This isn't true in the presence of pruning, but pruning is
-intended to be used primarily for performance (ignoring the parts of the
-configuration that don't apply to a given parsing library client).
-
-The expected way for clients to use the parsing library is to follow one
-of these two access patterns:
-
- * Search for a particular configuration group and then query it for a set
- of parameters (either one by one as they're used, or all at once to
- collapse the parameters into a struct for faster access later). This
- is expected to be the common pattern for finding and looking up
- settings for a particular program. There will generally only be a
- single group per group type for groups of this sort; it doesn't make
- sense to have multiple groups setting general configuration options for
- a program and have to iterate through them and merge them in some
- fashion.
-
- * Iterate through all groups of a given type, building a list of them (or
- of the data they contain). This is the model used by, for example,
- storage classes; each storage class has a set of parameters, and the
- storage subsystem needs to know about the full list of classes.
-
-Note that neither of these operations directly reveal the tree structure;
-the tree structure is intended for the convenience of the user in setting
-defaults for various parameters so that they don't have to be repeated in
-each group, and to allow some top-level pruning. It's not intended to be
-semantically significant other than that.
-
-Here are some suggested general conventions:
-
- * General options for a particular program should be separated out into a
- their own group. For example, a group innwatch in inn.conf to set the
- various options only used by innwatch. Note that pruning is inclusive
- rather than exclusive, so programs should ideally only need to care
- about a short list of groups.
-
- * Groups used only for grouping and setting default parameters, ones that
- won't be searched for explicitly by any program, should use the type
- "group". This can be used uniformly in all configuration files so that
- whenever a user sees a group of type "group", they know that it's just
- syntactic convenience to avoid having to repeat a bunch of parameter
- settings and isn't otherwise significant.
-
- * Groups that are searched for or iterated through shouldn't be nested;
- for example, if a configuration file defines a list of access groups,
- nesting one access group inside another is discouraged (in favor of
- putting both groups inside an enclosing group of type "group" that sets
- the parameters they have in common). This is to cut down on user
- confusion, since otherwise the nesting appears to be significant.
+++ /dev/null
-$Id: config-syntax 5843 2002-11-19 00:08:18Z rra $
-
-This file documents the standardized syntax for INN configuration files.
-This is the syntax that the parsing code in libinn will understand and the
-syntax towards which all configuration files should move.
-
-The basic structure of a configuration file is a tree of groups. Each
-group has a type and an optional tag, and may contain zero or more
-parameter settings, an association of a name with a value. All parameter
-names and group types are simple case-sensitive strings composed of
-printable ASCII characters and not containing whitespace or any of the
-characters "\:;{}[]<>" or the double-quote. A group may contain another
-group (and in fact the top level of the file can be thought of as a
-top-level group that isn't allowed to contain parameter settings).
-
-Supported parameter values are booleans, integers, real numbers, strings,
-and lists of strings.
-
-The basic syntax looks like:
-
- group-type tag {
- parameter: value
- parameter: [ string string ... ]
- # ...
-
- group-type tag {
- # ...
- }
- }
-
-Tags are strings, with the same syntax as a string value for a parameter;
-they are optional and may be omitted. A tag can be thought of as the name
-of a particular group, whereas the <group-type> says what that group is
-intended to specify and there may be many groups with the same type.
-
-The second parameter example above has as its value a list. The square
-brackets are part of the syntax of the configuration file; lists are
-enclosed in square brackets and the elements are space-separated.
-
-As seen above, groups may be nested.
-
-Multiple occurances of the same parameter in the parameter section of a
-group is an error. In practice, the second parameter will take precedent,
-but an error will be reported when such a configuration file is parsed.
-
-Parameter values inherit. In other words, the structure:
-
- first {
- first-parameter: 1
- second {
- second-parameter: 1
- third { third-parameter: 1 }
- }
-
- another "tag" { }
- }
-
-is parsed into a tree that looks like:
-
- +-------+ +--------+ +-------+
- | first |-+-| second |---| third |
- +-------+ | +--------+ +-------+
- |
- | +---------+
- +-| another |
- +---------+
-
-where each box is a group. The type of the group is given in the box;
-none of these groups have tags except for the only group of type
-"another", which has the tag "tag". The group of type "third" has three
-parameters set, namely "third-parameter" (set in the group itself),
-"second-parameter" (inherited from the group of type "second"), and
-"first-parameter" (inherited from "first" by "second" and then from
-"second" by "third").
-
-The practical meaning of this is that enclosing groups can be used to set
-default values for a set of subgroups. For example, consider the
-following configuration that defines three peers of a news server and
-newsgroups they're allowed to send:
-
- peer news1.example.com { newsgroups: * }
- peer news2.example.com { newsgroups: * }
- peer news3.example.com { newsgroups: * }
-
-This could instead be written as:
-
- group {
- newsgroups: *
-
- peer news1.example.com { }
- peer news2.example.com { }
- peer news3.example.com { }
- }
-
-or as:
-
- peer news1.example.com {
- newsgroups: *
-
- peer news2.example.com { }
- peer news3.example.com { }
- }
-
-and for a client program that only cares about the defined list of peers,
-these three structures would be entirely equivalent; all questions about
-what parameters are defined in the peer groups would have identical
-answers either way this configuration was written.
-
-Note that the second form above is preferred as a matter of style to the
-third, since otherwise it's tempting to derive some significance from the
-nesting structure of the peer groups. Also note that in the second
-example above, the enclosing group *must* have a type other than "peer";
-to see why, consider the program that asks the configuration parser for a
-list of all defined peer groups and uses the resulting list to build some
-internal data structures. If the enclosing group in the second example
-above had been of type peer, there would be four peer groups instead of
-three and one of them wouldn't have a tag, probably provoking an error
-message.
-
-Boolean values may be given as yes, true, or on, or as no, false, or off.
-Integers must be between -2,147,483,648 and +2,147,483,647 inclusive (the
-same as the minimums for a C99 signed long). Floating point numbers must
-be between 0 and 1e37 in absolute magnitude (the same as the minimums for
-a C99 double) and can safely expect eight digits of precision.
-
-Strings are optionally enclosed in double quotes, and must be quoted if
-they contain any whitespace, double-quote, or any characters in the set
-"\:;[]{}<>". Escape sequences in strings (sequences beginning with \) are
-parsed the same as they are in C. Strings can be continued on multiple
-lines by ending each line in a backslash, and the newline is not
-considered part of such a continued string (to embed a literal newline in
-a string, use \n).
-
-Lists of strings are delimited by [] and consist of whitespace-separated
-strings, which must follow the same quoting rules as all other strings.
-Group tags are also strings and follow the same quoting rules.
-
-There are two more bits of syntax. Normally, parameters must be separated
-by newlines, but for convenience it's possible to put multiple parameters
-on the same line separated by semicolons:
-
- parameter: value; parameter: value
-
-Finally, the body of a group may be defined in a separate file. To do
-this, rather than writing the body of the group enclosed in {}, instead
-give the file name in <>:
-
- group tag <filename>
-
-(The filename is also a string and may be double-quoted if necessary, but
-since file names rarely contain any of the excluded characters it's rarely
-necessary.)
-
-Here is the (almost) complete ABNF for the configuration file syntax.
-The syntax is per RFC 2234.
-
-First the basic syntax elements and possible parameter values:
-
- newline = %d13 / %d10 / %d13.10
- ; Any of CR, LF, or CRLF are interpreted
- ; as a newline.
-
- comment = *WSP "#" *(WSP / VCHAR / %x8A-FF) newline
-
- WHITE = WSP / newline [comment]
-
- boolean = "yes" / "on" / "true" / "no" / "off" / "false"
-
- integer = ["-"] 1*DIGIT
-
- real-number = ["-"] 1*DIGIT "." 1*DIGIT [ "e" ["-"] 1*DIGIT ]
-
- non-special = %x21 / %x23-39 / %x3D / %x3F-5A / %x5E-7A
- / %x7C / %x7E / %x8A-FF
- ; All VCHAR except "\:;<>[]{}
-
- quoted-string = DQUOTE 1*(WSP / VCHAR / %x8A-FF) DQUOTE
- ; DQUOTE within the quoted string must be
- ; written as 0x5C.22 (\"), and backslash
- ; sequences are interpreted as in C
- ; strings.
-
- string = 1*non-special / quoted-string
-
- list-body = string *( 1*WHITE string )
-
- list = "[" *WHITE [ list-body ] *WHITE "]"
-
-Now the general structure:
-
- parameter-name = 1*non-special
-
- parameter-value = boolean / integer / real-number / string / list
-
- parameter = parameter-name ":" 1*WSP parameter-value
-
- parameter-list = parameter [ *WHITE (";" / newline) *WHITE parameter ]
-
- group-list = group *( *WHITE group )
-
- group-body = parameter-list [ *WHITE newline *WHITE group-list ]
- / group-list
-
- group-file = string
-
- group-contents = "{" *WHITE [ group-body ] *WHITE "}"
- / "<" group-file ">"
-
- group-type = 1*non-special
-
- group-tag = string
-
- group-name = group-type [ 1*WHITE group-tag ]
-
- group = group-name 1*WHITE group-contents
-
- file = *WHITE *( group *WHITE )
-
-One implication of this grammar is that any line outside a quoted string
-that begins with "#", optionally preceded by whitespace, is regarded as a
-comment and discarded. The line must begin with "#" (and optional
-whitespace); comments at the end of lines aren't permitted. "#" has no
-special significance in quoted strings, even if it's at the beginning of a
-line. Note that comments cannot be continued to the next line in any way;
-each comment line must begin with "#".
-
-It's unclear the best thing to do with high-bit characters (both literal
-characters with value > 0x7F in a configuration file and characters with
-such values created in quoted strings with \<octal>, \x, \u, or \U). In
-the long term, INN should move towards assuming UTF-8 everywhere, as this
-is the direction that all of the news standards are heading, but in the
-interim various non-Unicode character sets are in widespread use and there
-must be some way of encoding those values in INN configuration files (so
-that things like the default Organization header value can be set
-appropriately).
-
-As a compromise, the configuration parser will pass unaltered any literal
-characters with value > 0x7F to the calling application, and \<octal> and
-\x escapes will generate eight-bit characters in the strings (and
-therefore cannot be used to generate UTF-8 strings containing code points
-greater than U+007F). \u and \U, in contrast, will generate characters
-encoded in UTF-8.
+++ /dev/null
-NNRPD External Authentication Support
-
- This is $Revision: 7880 $ dated $Date: 2005-03-17 12:42:46 +0100 (Thu,
- 17 Mar 2005) $.
-
- A fundamental part of the readers.conf(5)-based authorization mechanism
- is the interface to external authenticator and resolver programs. This
- interface is documented below.
-
- INN ships with a number of such programs (all written in C, although any
- language can be used). Code for them can be found in authprogs/ of the
- source tree; the authenticators are installed to *pathbin*/auth/passwd,
- and the resolvers are installed to *pathbin*/auth/resolv.
-
-Reading information from nnrpd
-
- When nnrpd spawns an external auth program, it passes information on
- standard input as a sequence of "key: value" lines. Each line ends with
- CRLF, and a line consisting of only "." indicates the end of the input.
- The order of the fields is not significant. Additional fields not
- mentioned below may be included; this should not be cause for alarm.
-
- (For robustness as well as ease of debugging, it is probably wise to
- accept line endings consisting only of LF, and to treat EOF as
- indicating the end of the input even if "." has not been received.)
-
- Code which reads information in the format discussed below and parses it
- into convenient structures is available authenticators and resolvers
- written in C; see libauth(3) for details. Use of the libauth library
- will make these programs substantially easier to write and more robust.
-
- For authenticators
-
- When nnrpd calls an authenticator, the lines it passes are
-
- ClientAuthname: user\r\n
- ClientPassword: pass\r\n
-
- where *user* and *pass* are the username and password provided by the
- client (e.g. using AUTHINFO). In addition, nnrpd generally also passes
- the fields mentioned as intended for resolvers; it rare instances this
- data may be useful for authenticators.
-
- For resolvers
-
- When nnrpd calls a resolver, the lines it passes are
-
- ClientHost: hostname\r\n
- ClientIP: IP-address\r\n
- ClientPort: port\r\n
- LocalIP: IP-address\r\n
- LocalPort: port\r\n
- .\r\n
-
- where *hostname* indicates a string representing the hostname if
- available, *IP-address* is a numeric IP address (dotted-quad for IPv4,
- equivalent for IPv6 if appropriate), and *port* is a numeric port
- number. (The *LocalIP* paramter may be useful for determining which
- interface was used for the incoming connection.)
-
- If information is not available, nnrpd will omit the corresponding
- fields. In particular, this applies to the unusual situation of nnrpd
- not being connected to a socket; TCP-related information is not
- available for standard input.
-
-Returning information to nnrpd
-
- Exit status and signals
-
- The external auth program must exit with a status of 0 to indicate
- success; any other exit status indicates failure. (The non-zero exit
- value will be logged.)
-
- If the program dies due to catching a signal (for example, a
- segmentation fault occurs), this will be logged and treated as a
- failure.
-
- Returning a username and domain
-
- If the program succeeds, it must return a username string (optionally
- with a domain appended) by writing to standard output. The line it
- should write is exactly:
-
- user:username\r\n
-
- where *username* is the string that nnrpd should use in matching
- readers.conf access blocks.
-
- There should be no extra spaces in lines sent from the hook to nnrpd;
- "user:aidan" is read by nnrpd as a different username than "user:
- aidan".
-
-Error messages
-
- As mentioned above, errors can be indicated by a non-zero exit value, or
- termination due to an unhandled signal; both cases are logged by nnrpd.
- However, external auth programs may wish to log error messages
- separately.
-
- Although nnrpd will syslog() anything an external auth program writes to
- standard error, it is generally better to use the messages.h functions,
- such as warn() and die().
-
- Please use the ckpasswd.c program as an example for any authenticators
- you write, and ident.c as an example for any resolvers.
-
-HISTORY
-
- Written by Aidan Cully for InterNetNews. This documentation rewritten
- in POD by Jeffrey M. Vinocur <jeff@litech.org>.
-
+++ /dev/null
-$Revision: 4165 $
-This file contains a few messages of historical interest. Some of the
-information in these messages is out of date (e.g., you don't need any
-other software, ihave/sendme is suported, etc); see the README and
-installation manual.
-
-The first is a mail message I sent as soon as I got the idea.
-
-Six months later I had something to beta, and I posted the second message
-to Usenet. My ship date was optimistic.
-
-The third message is the application that I required all beta sites to
-fill out.
-
-The fourth is a copy of the release notice.
-\f
-From: Rich Salz <rsalz@bbn.com>
-Date: Sat, 8 Dec 90 15:23:20 EST
-Message-Id: <9012082023.AA13441@litchi.bbn.com>
-To: newsgurus@ucsd.edu, nntp-managers@ucbarpa.Berkeley.EDU
-Subject: Speed idea.
-
-Suppose inews, nntp, "rnews -U", newsunbatch, etc., all just fed their
-articles to a single daemon?
-
-An idea I started kicking around yesterday. This is intended only for
-sites supporting BSD networking. I believe that anyone else who needs
-this kind of speed would find Cnews good enough.
-
-A multi-threaded server that used non-blocking IO to read all incoming
-articles on several sockets (don't forker a server, select on the
-connection socket will return READOK when a connection request comes in).
-All articles are read into memory, then written out to the filesystem
-using a single writev call (easy way to splice the path).
-
-Hash the active file and compile the sys file so as soon as an article was
-accepted we can write out the batchfile entries. As one special case,
-write entries to another socket for articles that should be fed out via
-NNTPLINK or something.
-
-Put the socket inside a group-access-only directory, so that only trusted
-front-ends like inews "rnews -U" etc can connect to it.
-
-Oh yeah, for things like nntp use sendmsg/recvmesg to hand off the
-feeding site to the demon once it's authenticated the incoming call and
-recognized it as an "xfer no" site.
-
-I've a few pages of notes and code fragments to type in.
-
-No locks of any kind. active file is mmap'd or periodically flushed.
-Keep it all in core and blat it out with a single write.
-
-When you want to expire, or add a group, you send a special message
-on a control port, or perhaps a sighup/sigusr1 to force it to resynch.
-
-Any feedback?
- /r$
-\f
-Path: papaya.bbn.com!rsalz
-From: rsalz@bbn.com (Rich Salz)
-Newsgroups: news.software.nntp,news.admin,comp.org.usenix
-Subject: Seeking beta-testers for a new NNTP transfer system
-Message-ID: <3632@litchi.bbn.com>
-Date: 18 Jun 91 15:47:21 GMT
-Followup-To: poster
-Organization: Bolt, Beranek and Newman, Inc.
-Lines: 72
-Xref: papaya.bbn.com news.software.nntp:1550 news.admin:15565 comp.org.usenix:418
-
-InterNetNews, or INN, is a news transport system. The core part of the
-package is a single long-running daemon that handles all incoming NNTP
-connections. It files the articles and arranges for them to be forwarded
-to downstream sites. Because it is long-running, it can be directed to
-spawn other long-running processes, telling them exactly when an article
-should be sent to a feed. This can replace the "watch the logfile" mode
-of nntplink, for example, with a much cleaner mechanism: read the
-batchfile on standard input.
-
-InterNetNews assumes that memory is cheap and fast while disks are slow.
-No temporary files are used while incoming articles are being received,
-and once processed the entire article is written out using a single
-writev(2) call (this includes updating the Path and Xref headers). The
-active file is kept in memory (a compile-time option can be set to use
-mmap(2)), and the newsfeeds file is parsed once to build a complete matrix
-of which sites receive which newsgroups.
-
-InterNetNews uses many features of standard BSD sockets including
-non-blocking I/O and Unix-domain stream and datagram sockets. It is
-highly doubtful that the official version will ever provide support for
-TLI, DECNET, or other facilities.
-
-INN is fast. Not many hard numbers are available (that is one requirement
-of being a beta-site), but some preliminary tests show it to be at least
-twice as fast as the current standard NNTP/C News combination. For
-example, Jim Thompson at Sun has had 20 nntpxmits feeding into a 4/490,
-and was getting over 14 articles per second, with the CPU 11% utilized. I
-was getting 10 articles/second feeding into a DECstations 3100, with the
-program (running profiled!) 50% idle and the load average under .7. (It
-is a scary thing to see several articles filed with the same timestamp.)
-
-The sys file format is somewhat different, and has been renamed. The
-arcane "foo.all" syntax is gone, replaced with a set of order-dependant
-shell patterns. For example, instead of "comp,comp.sys.sun,!comp.sys" you
-would write "comp.*,!comp.sys.*,comp.sys.sun"; to not get any groups
-related to binaries or pictures, you write "!*pictures*,!*binaries*".
-
-There are other incompatibilities as well. For example, ihave/sendme
-control messages are not supported. Also the philosophy is that that
-invalid articles are dropped, rather than filed into "junk." (A log
-message is written with the reason, and also sent back to the upstream
-feed as part of the NNTP reject reply.) The active file is taken to be
-the definitive list of groups that an article wants to recieve, and if
-none of an article's newsgroups are mentioned in the active file, then the
-article is invalid, logged, and dropped.
-
-The history and log files are intended to be compatible with those created
-by C News. I want to thank Henry and Geoff for their kind permission to
-use DBZ and SUBST. You will need to be running C News expire or a B2.11
-expire that has been modified to use DBZ.
-
-The InterNetNews daemon does not implement all NNTP commands. If sites
-within your campus are going to post or read news via NNTP, you will need
-the standard NNTP distribution. The daemon will spawn the standard nntpd
-if any site not mentioned in its "hosts.nntp" file connects to the TCP
-port. InterNetNews includes a replacement for the "mini-inews" that comes
-with the standard NNTP distribution. This can be used on any machine that
-posts news and connects to an NNTP server somewhere; its use is not
-limited to INN. At some point I hope to have a replacement nntpd
-optimized for newsreaders, and an NNTP transmission program. These will
-remove the need for any external software beyond the C News expire program.
-
-If you would like to beta-test this version, please FTP the file
-pub/usenet/INN.BETA from cronus.bbn.com for directions. It will be a
-fairly tightly-screened beta: DO NOT ASK ME FOR COPIES! Once the system
-is stable, it will be freely redistributable. I hope to have the official
-release by August 7, so that schools can bring the system up before the
-semester starts.
- /rich $alz
---
-Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
-Use a domain-based address or give alternate paths, or you may lose out.
-\f
-Thanks for your interest in InterNetNews. I want to run a fairly
-tightly-controlled beta test of the software before I make it generally
-available. This means that I'm going to screen the sites which will be
-able to participate in the test. Please don't be offended or upset by
-this whole procedure. I want to make the final package as stable as soon
-as possible so that the entire net can benefit (it will be freely
-redistributable). I've set up this mechanism because I think it's the
-best way for me to get the best test results as quickly as possible.
-
-I would therefore appreciate your answers to the following questions.
-If you think the answers to some of them will be obvious to me (e.g.,
-"Describe your organization" --> "UUNET" :-) then feel free to leave it
-blank. If you have any other feedback or comments, please add them.
-
-Email your results to <rsalz@bbn.com>
- /r$
-
-What software (transport, batching, readers, etc.) do you currently run?
-
-How much experience do you have with Usenet and NNTP?
-
-Describe your organization.
-
-How do you plan on testing InterNetNews? Be specific, describing the
-machine hardware, any test servers, etc. [The answers to this one
-won't be obvious to me -- you gotta write something.]
-
-What are the rough counts of the upstream and downstream feeds, and how do
-they break down by category (UUCP, NNTP, etc.)?
-
-What special news functions does your server perform (gatewaying,
-archiving, etc.)?
-
-Do you understand that by participating in the beta-test you agree not to
-redistribute the software outside of your administrative domain, and that
-you promise to upgrade to the official release in a timely manner?
-\f
-From: Rich Salz <rsalz@uunet.uu.net>
-Message-Id: <inn-announce@uunet.uu.net>
-Newsgroups: news.software.b,news.protocols.nntp
-Subject: Announcing the release of InterNetNews
-
-I am pleased to announce the official release of InterNetNews.
-
-InterNetNews, or INN, is a news transport system. The core part of the
-package is a single long-running daemon that handles all incoming NNTP
-connections. It files the articles and arranges for them to be forwarded
-to downstream sites. Because it is long-running, it can be directed to
-spawn other long-running processes, telling them exactly when an article
-should be sent to a feed.
-
-INN is a complete Usenet system. It provides article expiration and
-archiving, NNTP transport, and UUCP support. Nntplink works fine.
-
-INN does not include a newsreader. It does provide a version of the NNTP
-reference implementation "clientlib" routines so that rrn and other
-newsreaders compile with little trouble. The next release of xrn will
-include INN support.
-
-The spool directory is unchanged while the history database is
-upwardly-compatible with that of C News and the log file is very similar.
-All system configuration files are different.
-
-INN assumes that memory is cheap and fast while disks are slow. No
-temporary files are used while incoming articles are being received, and
-once processed the entire article is written out using a single system
-call (this includes updating the Path and Xref headers). The active file
-is kept in memory, and the newsfeeds file is parsed at start-up to build a
-complete matrix of which sites receive which newsgroups. A paper
-describing the implementation was presented at the June 1992 Usenix
-conference.
-
-INN uses many features of standard BSD sockets including non-blocking
-I/O. It is highly doubtful that the official version will ever provide
-support for TLI, DECNET, or other facilities. Among others, INN beta
-sites include ATT Unix System V Release 4, Apple A/UX, BSDI BSD/386 0.3.3,
-DEC Ultrix 3.x and 4.x, HP-UX s800 8.0, IBM AIX 3.1 and 3.2, Next NeXT-OS
-2.1, Pyramid OSx 5.1, SCO Xenix 2.3.4, SGI Irix 4.0, Sequent Dynix 3.0.4
-and 3.0.12, and Sun SunOS 3.5 and 4.x.
-
-Almost all of the beta-testers have reported faster performance and less
-load once they installed INN. Many people find it easy to maintain.
-
-A number of sites have graciously agreed to provide FTP access to this
-release. The machine names and directories are listed below. Within
-those directories you will find one or more of the following files:
- README Intro and unpacking instructions;
- -or- a copy appears at the end of this
- README.INN article.
- inn1.0.tar.Z The full distribution
- inn.usenix.ps.Z The Usenix paper on INN
-
-The sites providing access are:
- cs.utexas.edu /pub/inn
- ftp.cs.widener.edu /pub/inn.tar.Z (or wherever).
- ftp.germany.eu.net /pub/news/inn
- ftp.ira.uka.de pub/network/news
- ftp.msen.com /pub/packages/inn
- ftp.uu.net /pub/news/nntp/inn
- gatekeeper.dec.com /pub/news/inn
- grasp1.univ-lyon1.fr /pub/unix/news/inn
- munnari.oz.au /pub/news/inn
- sparky.Sterling.COM /news/inn
- src.doc.ic.ac.uk /computing/usenet/software/transport
- stasys.sta.sub.org /pub/src/inn
- (Stasys also has anonymous UUCP; contact <fkk@sta.sub.org>.
- ucsd.edu /INN
- usc.edu /pub/inn
-
-Discussion about INN should be posted to news.software.b and
-news.software.nntp. Email should be sent to <rsalz@uunet.uu.net>. Please
-do NOT send it to <rsalz@osf.org> -- it will only just delay your response
-since I will have to forward it to UUNET.
-
-The README follows after the formfeed.
- /r$
+++ /dev/null
-INN Perl Filtering and Authentication Support
-
- This is $Revision: 7880 $ dated $Date: 2008-06-07 14:46:49 +0200 (Sat,
- 07 Jun 2008) $.
-
- This file documents INN's built-in support for Perl filtering and reader
- authentication. The code is based very heavily on work by Christophe
- Wolfhugel <wolf@pasteur.fr>, and his work was in turn inspired by the
- existing TCL support. Please send any bug reports to inn-bugs@isc.org,
- not to Christophe, as the code has been modified heavily since he
- originally wrote it.
-
- The Perl filtering support is described in more detail below.
- Basically, it allows you to supply a Perl function that is invoked on
- every article received by innd from a peer (the innd filter) or by nnrpd
- from a reader (the nnrpd filter). This function can decide whether to
- accept or reject the article, and can optionally do other, more
- complicated processing (such as add history entries, cancel articles,
- spool local posts into a holding area, or even modify the headers of
- locally submitted posts). The Perl authentication hooks allow you to
- replace or supplement the readers.conf mechanism used by nnrpd.
-
- For Perl filtering support, you need to have Perl version 5.004 or
- newer. Earlier versions of Perl will fail with a link error at
- compilation time. http://language.perl.com/info/software.html should
- have the latest Perl version.
-
- To enable Perl support, you have to specify --with-perl when you run
- configure. See INSTALL for more information.
-
-The innd Perl Filter
-
- When innd starts, it first loads the file _PATH_PERL_STARTUP_INND
- (defined in include/paths.h, by default startup_innd.pl) and then loads
- the file _PATH_PERL_FILTER_INND (also defined in include/paths.h, by
- default filter_innd.pl). Both of these files must be located in the
- directory specified by pathfilter in inn.conf
- (/usr/local/news/bin/filter by default). The default directory for
- filter code can be specified at configure time by giving the flag
- --with-filter-dir to configure.
-
- INN doesn't care what Perl functions you define in which files. The
- only thing that's different about the two files is when they're loaded.
- startup_innd.pl is loaded only once, when innd first starts, and is
- never reloaded as long as innd is running. Any modifications to that
- file won't be noticed by innd; only stopping and restarting innd can
- cause it to be reloaded.
-
- filter_innd.pl, on the other hand, can be reloaded on command (with
- "ctlinnd reload filter.perl 'reason'"). Whenever filter_innd.pl is
- loaded, including the first time at innd startup, the Perl function
- filter_before_reload() is called before it's reloaded and the function
- filter_after_reload() is called after it's reloaded (if the functions
- exist). Additionally, any code in either startup_innd.pl or
- filter_innd.pl at the top level (in other words, not inside a sub { })
- is automatically executed by Perl when the files are loaded.
-
- This allows one to do things like write out filter statistics whenever
- the filter is reloaded, load a cache into memory, flush cached data to
- disk, or other similar operations that should only happen at particular
- times or with manual intervention. Remember, any code not inside
- functions in startup_innd.pl is executed when that file is loaded, and
- it's loaded only once when innd first starts. That makes it the ideal
- place to put initialization code that should only run once, or code to
- load data that was preserved on disk across a stop and restart of innd
- (perhaps using filter_mode() -- see below).
-
- As mentioned above, "ctlinnd reload filter.perl 'reason'" (or "ctlinnd
- reload all 'reason'") will cause filter_innd.pl to be reloaded. If the
- function filter_art() is defined after the file has been reloaded,
- filtering is turned on. Otherwise, filtering is turned off. (Note that
- due to the way Perl stores functions, once you've defined filter_art(),
- you can't undefine it just by deleting it from the file and reloading
- the filter. You'll need to replace it with an empty sub.)
-
- The Perl function filter_art() is the heart of a Perl filter. Whenever
- an article is received from a peer, via either IHAVE or TAKETHIS,
- filter_art() is called if Perl filtering is turned on. It receives no
- arguments, and should return a single scalar value. That value should
- be the empty string to indicate that INN should accept the article, or
- some rejection message to indicate that the article should be rejected.
-
- filter_art() has access to a global hash named %hdr, which contains all
- of the standard headers present in the article and their values. The
- standard headers are:
-
- Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock,
- Content-Base, Content-Disposition, Content-Transfer-Encoding,
- Content-Type, Control, Date, Date-Received, Distribution, Expires,
- Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info,
- Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups,
- NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator,
- Path, Posted, Posting-Version, Received, References, Relay-Version,
- Reply-To, Sender, Subject, Supersedes, User-Agent,
- X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face,
- X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace,
- X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID,
- X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig,
- X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To,
- X-Trace, X-Usenet-Provider, Xref.
-
- Note that all the above headers are as they arrived, not modified by
- your INN (especially, the Xref: header, if present, is the one of the
- remote site which sent you the article, and not yours).
-
- For example, the Newsgroups: header of the article is accessible inside
- the Perl filter as $hdr{'Newsgroups'}. In addition, $hdr{'__BODY__'}
- will contain the full body of the article and $hdr{'__LINES__'} will
- contain the number of lines in the body of the article.
-
- The contents of the %hdr hash for a typical article may therefore look
- something like this:
-
- %hdr = (Subject => 'MAKE MONEY FAST!!',
- From => 'Joe Spamer <him@example.com>',
- Date => '10 Sep 1996 15:32:28 UTC',
- Newsgroups => 'alt.test',
- Path => 'news.example.com!not-for-mail',
- Organization => 'Spammers Anonymous',
- Lines => '5',
- Distribution => 'usa',
- 'Message-ID' => '<6.20232.842369548@example.com>',
- __BODY__ => 'Send five dollars to the ISC, c/o ...',
- __LINES__ => 5
- );
-
- Note that the value of $hdr{Lines} is the contents of the Lines: header
- of the article and may bear no resemblence to the actual length of the
- article. $hdr{__LINES__} is the line count calculated by INN, and is
- guaranteed to be accurate.
-
- The %hdr hash should not be modified inside filter_art(). Instead, if
- any of the contents need to be modified temporarily during filtering
- (smashing case, for example), copy them into a seperate variable first
- and perform the modifications on the copy. Currently, $hdr{__BODY__} is
- the only data that will cause your filter to die if you modify it, but
- in the future other keys may also contain live data. Modifying live INN
- data in Perl will hopefully only cause a fatal exception in your Perl
- code that disables Perl filtering until you fix it, but it's possible
- for it to cause article munging or even core dumps in INN. So always,
- always make a copy first.
-
- As mentioned above, if filter_art() returns the empty string (''), the
- article is accepted. Note that this must be the empty string, not 0 or
- undef. Otherwise, the article is rejected, and whatever scalar
- filter_art() returns (typically a string) will be taken as the reason
- why the article was rejected. This reason will be returned to the
- remote peer as well as logged to the news logs. (innreport, in its
- nightly report, will summarize the number of articles rejected by the
- Perl filter and include a count of how many articles were rejected with
- each reason string.)
-
- One other type of filtering is also supported. If Perl filtering is
- turned on and the Perl function filter_messageid() is defined, that
- function will be called for each message ID received from a peer (via
- either CHECK or IHAVE). The function receives a single argument, the
- message ID, and like filter_art() should return an empty string to
- accept the article or an error string to refuse the article. This
- function is called before any history lookups and for every article
- offered to innd with CHECK or IHAVE (before the actual article is sent).
- Accordingly, the message ID is the only information it has about the
- article (the %hdr hash will be empty). This code would sit in a
- performance-critical hot path in a typical server, and therefore should
- be as fast as possible, but it can do things like refuse articles from
- certain hosts or cancels for already rejected articles (if they follow
- the $alz convention) without having to take the network bandwidth hit of
- accepting the entire article first.
-
- Note that you cannot rely on filter_messageid() being called for every
- incoming article; articles sent via TAKETHIS without an earlier CHECK
- will never pass through filter_messageid() and will only go through
- filter_art().
-
- Finally, whenever ctlinnd throttle, ctlinnd pause, or ctlinnd go is run,
- the Perl function filter_mode() is called if it exists. It receives no
- arguments and returns no value, but it has access to a global hash %mode
- that contains three values:
-
- Mode The current server mode (throttled, paused, or running)
- NewMode The new mode the server is going to
- reason The reason that was given to ctlinnd
-
- One possible use for this function is to save filter state across a
- restart of innd. There isn't any Perl function which is called when INN
- shuts down, but using filter_mode() the Perl filter can dump it's state
- to disk whenever INN is throttled. Then, if the news administrator
- follows the strongly recommended shutdown procedure of throttling the
- server before shutting it down, the filter state will be safely saved to
- disk and can be reloaded when innd restarts (possibly by
- startup_innd.pl).
-
- The state of the Perl interpretor in which all of these Perl functions
- run is preserved over the lifetime of innd. In other words, it's
- permissible for the Perl code to create its own global Perl variables,
- data structures, saved state, and the like, and all of that will be
- available to filter_art() and filter_messageid() each time they're
- called. The only variable INN fiddles with (or pays any attention to at
- all) is %hdr, which is cleared after each call to filter_art().
-
- Perl filtering can be turned off with "ctlinnd perl n" and back on again
- with "ctlinnd perl y". Perl filtering is turned off automatically if
- loading of the filter fails or if the filter code returns any sort of a
- fatal error (either due to Perl itself or due to a "die" in the Perl
- code).
-
-Supported innd Callbacks
-
- innd makes seven functions available to any of its embedded Perl code.
- Those are:
-
- INN::addhist(*messageid*, *arrival*, *articledate*, *expire*, *paths*)
- Adds *messageid* to the history database. All of the arguments
- except the first one are optional; the times default to the current
- time and the paths field defaults to the empty string. (For those
- unfamiliar with the fields of a history(5) database entry, the
- *arrival* is normally the time at which the server accepts the
- article, the *articledate* is from the Date header of the article,
- the *expire* is from the Expires header of the article, and the
- *paths* field is the storage API token. All three times as measured
- as a time_t since the epoch.) Returns true on success, false
- otherwise.
-
- INN::article(*messageid*)
- Returns the full article (as a simple string) identified by
- *messageid*, or undef if it isn't found. Each line will end with a
- simple \n, but leading periods may still be doubled if the article
- is stored in wire format.
-
- INN::cancel(*messageid*)
- Cancels *messageid*. (This is equivalent to "ctlinnd cancel"; it
- cancels the message on the local server, but doesn't post a cancel
- message or do anything else that affects anything other than the
- local server.) Returns true on success, false otherwise.
-
- INN::filesfor(*messageid*)
- Returns the *paths* field of the history entry for the given
- *messageid*. This will be the storage API token for the message.
- If *messageid* isn't found in the history database, returns undef.
-
- INN::havehist(*messageid*)
- Looks up *messageid* in the history database and returns true if
- it's found, false otherwise.
-
- INN::head(*messageid*)
- Returns the header (as a simple string) of the article identified by
- *messageid*, or undef if it isn't found. Each line will end with a
- simple \n (in other words, regardless of the format of article
- storage, the returned string won't be in wire format).
-
- INN::newsgroup(*newsgroup*)
- Returns the status of *newsgroup* (the last field of the active file
- entry for that newsgroup). See active(5) for a description of the
- possible values and their meanings (the most common are "y" for an
- unmoderated group and "m" for a moderated group). If *newsgroup*
- isn't in the active file, returns undef.
-
- These functions can only be used from inside the innd Perl filter;
- they're not available in the nnrpd filter.
-
-Common Callbacks
-
- The following additional function is available from inside filters
- embedded in innd, and is also available from filters embedded in nnrpd
- (see below):
-
- INN::syslog(level, message)
- Logs a message via syslog(2). This is quite a bit more reliable and
- portable than trying to use Sys::Syslog from inside the Perl filter.
- Only the first character of the level argument matters; the valid
- letters are the first letters of ALERT, CRIT, ERR, WARNING, NOTICE,
- INFO, and DEBUG (case-insensitive) and specify the priority at which
- the message is logged. If a level that doesn't match any of those
- levels is given, the default priority level is LOG_NOTICE. The
- second argument is the message to log; it will be prefixed by
- "filter: " and logged to syslog with facility LOG_NEWS.
-
-The nnrpd Posting Filter
-
- Whenever Perl support is needed in nnrpd, it first loads the file
- _PATH_PERL_FILTER_NNRPD (defined in include/paths.h, by default
- filter_nnrpd.pl). This file must be located in the directory specified
- by pathfilter in inn.conf (/usr/local/news/bin/filter by default). The
- default directory for filter code can be specified at configure time by
- giving the flag --with-filter-dir to configure.
-
- If filter_nnrpd.pl loads successfully and defines the Perl function
- filter_post(), Perl filtering is turned on. Otherwise, it's turned off.
- If filter_post() ever returns a fatal error (either from Perl or from a
- "die" in the Perl code), Perl filtering is turned off for the life of
- that nnrpd process and any further posts made during that session won't
- go through the filter.
-
- While Perl filtering is on, every article received by nnrpd via the POST
- command is passed to the filter_post() Perl function before it is passed
- to INN (or mailed to the moderator of a moderated newsgroup). If
- filter_post() returns an empty string (''), the article is accepted and
- normal processing of it continues. Otherwise, the article is rejected
- and the string returned by filter_post() is returned to the client as
- the error message (with some exceptions; see below).
-
- filter_post() has access to a global hash %hdr, which contains all of
- the headers of the article. (Unlike the innd Perl filter, %hdr for the
- nnrpd Perl filter contains *all* of the headers, not just the standard
- ones. If any of the headers are duplicated, though, %hdr will contain
- only the value of the last occurance of the header. nnrpd will reject
- the article before the filter runs if any of the standard headers are
- duplicated.) It also has access to the full body of the article in the
- variable $body, and if the poster authenticated via AUTHINFO (or if
- either Perl authentication or a readers.conf authentication method is
- used and produces user information), it has access to the authenticated
- username of the poster in the variable $user.
-
- Unlike the innd Perl filter, the nnrpd Perl filter can modify the %hdr
- hash. In fact, if the Perl variable $modify_headers is set to true
- after filter_post() returns, the contents of the %hdr hash will be
- written back to the article replacing the original headers.
- filter_post() can therefore make any modifications it wishes to the
- headers and those modifications will be reflected in the article as it's
- finally posted. The article body cannot be modified in this way; any
- changes to $body will just be ignored.
-
- Be careful when using the ability to modify headers. filter_post() runs
- after all the normal consistency checks on the headers and after server
- supplied headers (like Message-ID: and Date:) are filled in. Deleting
- required headers or modifying headers that need to follow a strict
- format can result in nnrpd trying to post nonsense articles (which will
- probably then be rejected by innd). If $modify_headers is set,
- *everything* in the %hdr hash is taken to be article headers and added
- to the article.
-
- If filter_post() returns something other than the empty string, this
- message is normally returned to the client as an error. There are two
- exceptions: If the string returned begins with "DROP", the post will be
- silently discarded and success returned to the client. If the string
- begins with "SPOOL", success is returned to the client, but the post is
- saved in a directory named "spam" under the directory specified by
- pathincoming in inn.conf (in a directory named "spam/mod" if the post is
- to a moderated group). This is intended to allow manual inspection of
- the suspect messages; if they should be posted, they can be manually
- moved out of the subdirectory to the directory specified by pathincoming
- in inn.conf, where they can be posted by running "rnews -U". If you use
- this functionality, make sure those directories exist.
-
-Changes to Perl Authentication Support for nnrpd
-
- The old authentication functionality has been combined with the new
- readers.conf mechanism by Erik Klavon <erik@eriq.org>; bug reports
- should however go to inn-bugs@isc.org, not Erik.
-
- The remainder of this section is an introduction to the new mechanism
- (which uses the perl_auth: and perl_access: readers.conf parameters)
- with porting/migration suggestions for people familiar with the old
- mechanism (identifiable by the nnrpperlauth: parameter in inn.conf).
-
- Other people should skip this section.
-
- The perl_auth parameter allows the use of Perl to authenticate a user.
- Scripts (like those from the old mechanism) are listed in readers.conf
- using perl_auth in the same manner other authenticators are using auth:
-
- perl_auth: "/path/to/script/auth1.pl"
-
- The file given as argument to perl_auth should contain the same
- procedures as before. The global hash %attributes remains the same,
- except for the removal of the "type" entry which is no longer needed in
- this modification and the addition of several new entries (port,
- intipaddr, intport) described below. The return array now only contains
- either two or three elements, the first of which is the NNTP return
- code. The second is an error string which is passed to the client if the
- error code indicates that the authentication attempt has failed. This
- allows a specific error message to be generated by the perl script in
- place of "Authentication failed". An optional third return element if
- present will be used to match the connection with the users: parameter
- in access groups and will also be the username logged. If this element
- is absent, the username supplied by the client during authentication
- will be used as was the previous behavior.
-
- The perl_access parameter (described below) is also new; it allows the
- dynamic generation of an access group for an incoming connection using a
- Perl script. If a connection matches an auth group which has a
- perl_access parameter, all access groups in readers.conf are ignored;
- instead the procedure described below is used to generate an access
- group. This concept is due to Jeffrey M. Vinocur.
-
- The new functionality should provide all of the existing capabilities of
- the Perl hook, in combination with the flexibility of readers.conf and
- the use of other authentication and resolving programs. To use Perl
- authentication code that predates the readers.conf mechanism, you would
- need to modify the code slightly (see below for the new specification)
- and supply a simple readers.conf file. If you don't want to modify your
- code, the samples directory has nnrpd_auth_wrapper.pl and
- nnrpd_access_wrapper.pl which should allow you to use your old code
- without needing to change it.
-
- However, before trying to use your old Perl code, you may want to
- consider replacing it entirely with non-Perl authentication. (With
- readers.conf and the regular authenticator and resolver programs, much
- of what once required Perl can be done directly.) Even if the
- functionality is not available directly, you may wish to write a new
- authenticator or resolver (which can be done in whatever language you
- prefer to work in).
-
-Perl Authentication Support for nnrpd
-
- Support for authentication via Perl is provided in nnrpd by the
- inclusion of a perl_auth: parameter in a readers.conf auth group.
- perl_auth: works exactly like the auth: parameter in readers.conf,
- except that it calls the script given as argument using the Perl hook
- rather then treating it as an external program.
-
- If the processing of readers.conf requires that a perl_auth: statement
- be used for authentication, Perl is loaded (if it has yet to be) and the
- file given as argument to the perl_auth: parameter is loaded as well. If
- a Perl function auth_init() is defined by that file, it is called
- immediately after the file is loaded. It takes no arguments and returns
- nothing.
-
- Provided the file loads without errors, auth_init() (if present) runs
- without fatal errors, and a Perl function authenticate() is defined,
- authenticate() will then be called. authenticate() takes no arguments,
- but it has access to a global hash %attributes which contains
- information about the connection as follows: $attributes{hostname} will
- contain the hostname (or the IP address if it doesn't resolve) of the
- client machine, $attributes{ipaddress} will contain its IP address (as a
- string), $attributes{port} will contain the client port (as an integer),
- $attributes{interface} contains the hostname of the interface the client
- connected on, $attributes{intipaddr} contains the IP address (as a
- string) of the interface the client connected on, $attributes{intport}
- contains the port (as an integer) on the interface the client connected
- on, $attributes{username} will contain the provided username and
- $attributes{password} the password.
-
- authenticate() should return a two or three element array. The first
- element is the NNTP response code to return to the client, the second
- element is an error string which is passed to the client if the response
- code indicates that the authentication attempt has failed. An optional
- third return element if present will be used to match the connection
- with the users: parameter in access groups and will also be the username
- logged. If this element is absent, the username supplied by the client
- during authentication will be used for matching and logging.
-
- The NNTP response code should probably be either 281 (authentication
- successful) or 502 (authentication unsuccessful). If the code returned
- is anything other than 281, nnrpd will print an authentication error
- message and drop the connection and exit.
-
- If authenticate() dies (either due to a Perl error or due to calling
- die), or if it returns anything other than the two or three element
- array described above, an internal error will be reported to the client,
- the exact error will be logged to syslog, and nnrpd will drop the
- connection and exit.
-
-Dynamic Generation of Access Groups
-
- A Perl script may be used to dynamically generate an access group which
- is then used to determine the access rights of the client. This occurs
- whenever the perl_access: is specified in an auth group which has
- successfully matched the client. Only one perl_access: statement is
- allowed in an auth group. This parameter should not be mixed with a
- python_access: statement in the same auth group.
-
- When a perl_access: parameter is encountered, Perl is loaded (if it has
- yet to be) and the file given as argument is loaded as well. Provided
- the file loads without errors, and a Perl function access() is defined,
- access() will then be called. access() takes no arguments, but it has
- access to a global hash %attributes which contains information about the
- connection as follows: $attributes{hostname} will contain the hostname
- (or the IP address if it doesn't resolve) of the client machine,
- $attributes{ipaddress} will contain its IP address (as a string),
- $attributes{port} will contain the client port (as an integer),
- $attributes{interface} contains the hostname of the interface the client
- connected on, $attributes{intipaddr} contains the IP address (as a
- string) of the interface the client connected on, $attributes{intport}
- contains the port (as an integer) on the interface the client connected
- on, $attributes{username} will contain the provided username and domain
- (in username@domain form).
-
- access() returns a hash, containing the desired access parameters and
- values. Here is an untested example showing how to dynamically generate
- a list of newsgroups based on the client's username and domain.
-
- my %hosts = ( "example.com" => "example.*", "isc.org" => "isc.*" );
-
- sub access {
- %return_hash = (
- "max_rate" => "10000",
- "addnntppostinghost" => "true",
- # ...
- );
- if( defined $attributes{username} &&
- $attributes{username} =~ /.*@(.*)/ )
- {
- $return_hash{"virtualhost"} = "true";
- $return_hash{"path"} = $1;
- $return_hash{"newsgroups"} = $hosts{$1};
- } else {
- $return_hash{"read"} = "*";
- $return_hash{"post"} = "local.*"
- }
- return %return_hash;
- }
-
- Note that both the keys and values are quoted strings. These values are
- to be returned to a C program and must be quoted strings. For values
- containing one or more spaces, it is not necessary to include extra
- quotes inside the string.
-
- While you may include the users: parameter in a dynamically generated
- access group, some care should be taken (unless your pattern is just *
- which is equivalent to leaving the parameter out). The group created
- with the values returned from the Perl script is the only one considered
- when nnrpd attempts to find an access group matching the connection. If
- a users: parameter is included and it doesn't match the connection, then
- the client will be denied access since there are no other access groups
- which could match the connection.
-
- If access() dies (either due to a Perl error or due to calling die), or
- if it returns anything other than a hash as described above, an internal
- error will be reported to the client, the exact error will be logged to
- syslog, and nnrpd will drop the connection and exit.
-
-Notes on Writing Embedded Perl
-
- All Perl evaluation is done inside an implicit eval block, so calling
- die in Perl code will not kill the innd or nnrpd process. Neither will
- Perl errors (such as syntax errors). However, such errors will have
- negative effects (fatal errors in the innd or nnrpd filter will cause
- filtering to be disabled, and fatal errors in the nnrpd authentication
- code will cause the client connection to be terminated).
-
- Calling exit directly, however, *will* kill the innd or nnrpd process,
- so don't do that. Similarly, you probably don't want to call fork (or
- any other function that results in a fork such as system,
- IPC::Open3::open3(), or any use of backticks) since there are possibly
- unflushed buffers that could get flushed twice, lots of open state that
- may not get closed properly, and innumerable other potential problems.
- In general, be aware that all Perl code is running inside a large and
- complicated C program, and Perl code that impacts the process as a whole
- is best avoided.
-
- You can use print and warn inside Perl code to send output to STDOUT or
- STDERR, but you probably shouldn't. Instead, open a log file and print
- to it instead (or, in the innd filter, use INN::syslog() to write
- messages via syslog like the rest of INN). If you write to STDOUT or
- STDERR, where that data will go depends on where the filter is running;
- inside innd, it will go to the news log or the errlog, and inside nnrpd
- it will probably go nowhere but could go to the client. The nnrpd
- filter takes some steps to try to keep output from going across the
- network connection to the client (which would probably result in a very
- confused client), but best not to take the chance.
-
- For similar reasons, try to make your Perl code -w clean, since Perl
- warnings are written to STDERR. (INN won't run your code under -w, but
- better safe than sorry, and some versions of Perl have some mandatory
- warnings you can't turn off.)
-
- You *can* use modules in your Perl code, just like you would in an
- ordinary Perl script. You can even use modules that dynamically load C
- code. Just make sure that none of the modules you use go off behind
- your back to do any of the things above that are best avoided.
-
- Whenever you make any modifications to the Perl code, and particularly
- before starting INN or reloading filter.perl with new code, you should
- run perl -wc on the file. This will at least make sure you don't have
- any glaring syntax errors. Remember, if there are errors in your code,
- filtering will be disabled, which could mean that posts you really
- wanted to reject will leak through and authentication of readers may be
- totally broken.
-
- The samples directory has example startup_innd.pl, filter_innd.pl,
- filter_nnrpd.pl, and nnrpd_auth.pl files that contain some simplistic
- examples. Look them over as a starting point when writing your own.
-
-Available Packages
-
- This is an unofficial list of known filtering packages at the time of
- publication. This is not an endorsement of these filters by the ISC or
- the INN developers, but is included as assistance in locating packages
- which make use of this filter mechanism.
-
- CleanFeed Jeremy Nixon <jeremy@exit109.com>
- <URL:http://www.exit109.com/~jeremy/news/cleanfeed.html>
- A spam filter catching excessive multi-posting and a host of
- other things. Uses filter_innd.pl exclusively, requires the MD5
- Perl module. Probably the most popular and widely-used Perl
- filter around.
-
- Usenet II Filter Edward S. Marshall <emarshal@xnet.com>
- <URL:http://www.xnet.com/~emarshal/inn/filter_nnrpd.pl>
- Checks for "soundness" according to Usenet II guidelines in the
- net.* hierarchy. Designed to use filter_nnrpd.pl.
-
- News Gizmo Aidan Cully <aidan@panix.com>
- <URL:http://www.panix.com/gizmo/>
- A posting filter for helping a site enforce Usenet-II soundness,
- and for quotaing the number of messages any user can post to
- Usenet daily.
+++ /dev/null
-INN Python Filtering and Authentication Support
-
- This file documents INN's built-in optional support for Python article
- filtering. It is patterned after the Perl and (now obsolete) TCL hooks
- previously added by Bob Heiney and Christophe Wolfhugel.
-
- For this filter to work successfully, you will need to have at least
- Python 1.5.2 installed. You can obtain it from
- <http://www.python.org/>.
-
- The innd Python interface and the original Python filtering
- documentation were written by Greg Andruk (nee Fluffy)
- <gerglery@usa.net>. The Python authentication and authorization support
- for nnrpd as well as the original documentation for it were written by
- Ilya Etingof <ilya@glas.net> in December 1999.
-
-Installation
-
- Once you have built and installed Python, you can cause INN to use it by
- adding the --with-python switch to your "configure" command. You will
- need to have all the headers and libraries required for embedding Python
- into INN; they can be found in Python development packages, which
- include header files and static libraries.
-
- You will then be able to use Python authentication, dynamic access group
- generation and dynamic access control support in nnrpd along with
- filtering support in innd.
-
- See the ctlinnd(8) manual page to learn how to enable, disable and
- reload Python filters on a running server (especially "ctlinnd mode",
- "ctlinnd python y|n" and "ctlinnd reload filter.python 'reason'").
-
- Also, see the filter_innd.py, nnrpd_auth.py, nnrpd_access.py and
- nnrpd_dynamic.py samples in your filters directory for a demonstration
- of how to get all this working.
-
-Writing an innd Filter
-
- Introduction
-
- You need to create a filter_innd.py module in INN's filter directory
- (see the *pathfilter* setting in inn.conf). A heavily-commented sample
- is provided; you can use it as a template for your own filter. There is
- also an INN.py module there which is not actually used by INN; it is
- there so you can test your module interactively.
-
- First, define a class containing the methods you want to provide to
- innd. Methods innd will use if present are:
-
- __init__(*self*)
- Not explicitly called by innd, but will run whenever the filter
- module is (re)loaded. This is a good place to initialize constants
- or pick up where "filter_before_reload" or "filter_close" left off.
-
- filter_before_reload(*self*)
- This will execute any time a "ctlinnd reload all 'reason'" or
- "ctlinnd reload filter.python 'reason'" command is issued. You can
- use it to save statistics or reports for use after reloading.
-
- filter_close(*self*)
- This will run when a "ctlinnd shutdown 'reason'" command is
- received.
-
- filter_art(*self*, *art*)
- *art* is a dictionary containing an article's headers and body.
- This method is called every time innd receives an article. The
- following can be defined:
-
- Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock,
- Content-Base, Content-Disposition, Content-Transfer-Encoding,
- Content-Type, Control, Date, Date-Received, Distribution, Expires,
- Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info,
- Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups,
- NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator,
- Path, Posted, Posting-Version, Received, References, Relay-Version,
- Reply-To, Sender, Subject, Supersedes, User-Agent,
- X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face,
- X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace,
- X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID,
- X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig,
- X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To,
- X-Trace, X-Usenet-Provider, Xref, __BODY__, __LINES__.
-
- Note that all the above values are as they arrived, not modified by
- your INN (especially, the Xref: header, if present, is the one of
- the remote site which sent you the article, and not yours).
-
- These values will be buffer objects holding the contents of the same
- named article headers, except for the special "__BODY__" and
- "__LINES__" items. Items not present in the article will contain
- "None".
-
- "art('__BODY__')" is a buffer object containing the article's entire
- body, and "art('__LINES__')" is an int holding innd's reckoning of
- the number of lines in the article. All the other elements will be
- buffers with the contents of the same-named article headers.
-
- The Newsgroups: header of the article is accessible inside the
- Python filter as "art['Newsgroups']".
-
- If you want to accept an article, return "None" or an empty string.
- To reject, return a non-empty string. The rejection strings will be
- shown to local clients and your peers, so keep that in mind when
- phrasing your rejection responses.
-
- filter_messageid(*self*, *msgid*)
- *msgid* is a buffer object containing the ID of an article being
- offered by IHAVE or CHECK. Like with "filter_art", the message will
- be refused if you return a non-empty string. If you use this
- feature, keep it light because it is called at a rather busy place
- in innd's main loop. Also, do not rely on this function alone to
- reject by ID; you should repeat the tests in "filter_art" to catch
- articles sent with TAKETHIS but no CHECK.
-
- filter_mode(*self*, *oldmode*, *newmode*, *reason*)
- When the operator issues a ctlinnd "pause", "throttle", "go",
- "shutdown" or "xexec" command, this function can be used to do
- something sensible in accordance with the state change. Stamp a log
- file, save your state on throttle, etc. *oldmode* and *newmode*
- will be strings containing one of the values in ("running",
- "throttled", "paused", "shutdown", "unknown"). *oldmode* is the
- state innd was in before ctlinnd was run, *newmode* is the state
- innd will be in after the command finishes. *reason* is the comment
- string provided on the ctlinnd command line.
-
- How to Use these Methods with innd
-
- To register your methods with innd, you need to create an instance of
- your class, import the built-in INN module, and pass the instance to
- "INN.set_filter_hook". For example:
-
- class Filter:
- def filter_art(self, art):
- ...
- blah blah
- ...
-
- def filter_messageid(self, id):
- ...
- yadda yadda
- ...
-
- import INN
- myfilter = Filter()
- INN.set_filter_hook(myfilter)
-
- When writing and testing your Python filter, don't be afraid to make use
- of "try:"/"except:" and the provided "INN.syslog" function. stdout and
- stderr will be disabled, so your filter will die silently otherwise.
-
- Also, remember to try importing your module interactively before loading
- it, to ensure there are no obvious errors. One typo can ruin your whole
- filter. A dummy INN.py module is provided to facilitate testing outside
- the server. To test, change into your filter directory and use a
- command like:
-
- python -ic 'import INN, filter_innd'
-
- You can define as many or few of the methods listed above as you want in
- your filter class (it is fine to define more methods for your own use;
- innd will not be using them but your filter can). If you *do* define
- the above methods, GET THE PARAMETER COUNTS RIGHT. There are checks in
- innd to see whether the methods exist and are callable, but if you
- define one and get the parameter counts wrong, innd WILL DIE. You have
- been warned. Be careful with your return values, too. The "filter_art"
- and "filter_messageid" methods have to return strings, or "None". If
- you return something like an int, innd will *not* be happy.
-
- A Note regarding Buffer Objects
-
- Buffer objects are cousins of strings, new in Python 1.5.2. Using
- buffer objects may take some getting used to, but we can create buffers
- much faster and with less memory than strings.
-
- For most of the operations you will perform in filters (like
- "re.search", "string.find", "md5.digest") you can treat buffers just
- like strings, but there are a few important differences you should know
- about:
-
- # Make a string and two buffers.
- s = "abc"
- b = buffer("def")
- bs = buffer("abc")
-
- s == bs # - This is false because the types differ...
- buffer(s) == bs # - ...but this is true, the types now agree.
- s == str(bs) # - This is also true, but buffer() is faster.
- s[:2] == bs[:2] # - True. Buffer slices are strings.
-
- # While most string methods will take either a buffer or a string,
- # string.join (in the string module) insists on using only strings.
- import string
- string.join([str(b), s], '.') # Returns 'def.abc'.
- '.'.join([str(b), s]) # Returns 'def.abc' too.
- '.'.join([b, s]) # This raises a TypeError.
-
- e = s + b # This raises a TypeError, but...
-
- # ...these two both return the string 'abcdef'. The first one
- # is faster -- choose buffer() over str() whenever you can.
- e = buffer(s) + b
- f = s + str(b)
-
- g = b + '>' # This is legal, returns the string 'def>'.
-
- Functions Supplied by the Built-in innd Module
-
- Besides "INN.set_filter_hook" which is used to register your methods
- with innd as it has already been explained above, the following
- functions are available from Python scripts:
-
- addhist(*message-id*)
- article(*message-id*)
- cancel(*message-id*)
- havehist(*message-id*)
- hashstring(*string*)
- head(*message-id*)
- newsgroup(*groupname*)
- syslog(*level*, *message*)
-
- Therefore, not only can innd use Python, but your filter can use some of
- innd's features too. Here is some sample Python code to show what you
- get with the previously listed functions.
-
- import INN
-
- # Python's native syslog module isn't compiled in by default,
- # so the INN module provides a replacement. The first parameter
- # tells the Unix syslogger what severity to use; you can
- # abbreviate down to one letter and it's case insensitive.
- # Available levels are (in increasing levels of seriousness)
- # Debug, Info, Notice, Warning, Err, Crit, and Alert. (If you
- # provide any other string, it will be defaulted to Notice.) The
- # second parameter is the message text. The syslog entries will
- # go to the same log files innd itself uses, with a 'python:'
- # prefix.
- syslog('warning', 'I will not buy this record. It is scratched.')
- animals = 'eels'
- vehicle = 'hovercraft'
- syslog('N', 'My %s is full of %s.' % (vehicle, animals))
-
- # Let's cancel an article! This only deletes the message on the
- # local server; it doesn't send out a control message or anything
- # scary like that. Returns 1 if successful, else 0.
- if INN.cancel('<meow$123.456@solvangpastries.edu>'):
- cancelled = "yup"
- else:
- cancelled = "nope"
-
- # Check if a given message is in history. This doesn't
- # necessarily mean the article is on your spool; cancelled and
- # expired articles hang around in history for a while, and
- # rejected articles will be in there if you have enabled
- # remembertrash in inn.conf. Returns 1 if found, else 0.
- if INN.havehist('<z456$789.abc@isc.org>'):
- comment = "*yawn* I've already seen this article."
- else:
- comment = 'Mmm, fresh news.'
-
- # Here we are running a local spam filter, so why eat all those
- # cancels? We can add fake entries to history so they'll get
- # refused. Returns 1 on success, 0 on failure.
- cancelled_id = buffer('<meow$123.456@isc.org>')
- if INN.addhist("<cancel." + cancelled_id[1:]):
- thought = "Eat my dust, roadkill!"
- else:
- thought = "Darn, someone beat me to it."
-
- # We can look at the header or all of an article already on spool,
- # too. Might be useful for long-memory despamming or
- # authentication things. Each is returned (if present) as a
- # string object; otherwise you'll end up with an empty string.
- artbody = INN.article('<foo$bar.baz@bungmunch.edu>')
- artheader = INN.head('<foo$bar.baz@bungmunch.edu>')
-
- # As we can compute a hash digest for a string, we can obtain one
- # for artbody. It might be of help to detect spam.
- digest = INN.hashstring(artbody)
-
- # Finally, do you want to see if a given newsgroup is moderated or
- # whatever? INN.newsgroup returns the last field of a group's
- # entry in active as a string.
- froupflag = INN.newsgroup('alt.fan.karl-malden.nose')
- if froupflag == '':
- moderated = 'no such newsgroup'
- elif froupflag == 'y':
- moderated = "nope"
- elif froupflag == 'm':
- moderated = "yep"
- else:
- moderated = "something else"
-
-Writing an nnrpd Filter
-
- Changes to Python Authentication and Access Control Support for nnrpd
-
- The old authentication and access control functionality has been
- combined with the new readers.conf mechanism by Erik Klavon
- <erik@eriq.org>; bug reports should however go to <inn-bugs@isc.org>,
- not Erik.
-
- The remainder of this section is an introduction to the new mechanism
- (which uses the *python_auth*, *python_access*, and *python_dynamic*
- readers.conf parameters) with porting/migration suggestions for people
- familiar with the old mechanism (identifiable by the now deprecated
- *nnrpperlauth* parameter in inn.conf).
-
- Other people should skip this section.
-
- The *python_auth* parameter allows the use of Python to authenticate a
- user. Authentication scripts (like those from the old mechanism) are
- listed in readers.conf using *python_auth* in the same manner other
- authenticators are using *auth*:
-
- python_auth: "nnrpd_auth"
-
- It uses the script named nnrpd_auth.py (note that ".py" is not present
- in the *python_auth* value).
-
- Scripts should be placed as before in the filter directory (see the
- *pathfilter* setting in inn.conf). The new hook method "authen_init"
- takes no arguments and its return value is ignored; its purpose is to
- provide a means for authentication specific initialization. The hook
- method "authen_close" is the more specific analogue to the old "close"
- method. These two method hooks are not required, contrary to
- "authenticate", the main method.
-
- The argument dictionary passed to "authenticate" remains the same,
- except for the removal of the *type* entry which is no longer needed in
- this modification and the addition of several new entries (*port*,
- *intipaddr*, *intport*) described below. The return tuple now only
- contains either two or three elements, the first of which is the NNTP
- response code. The second is an error string which is passed to the
- client if the response code indicates that the authentication attempt
- has failed. This allows a specific error message to be generated by the
- Python script in place of the generic message "Authentication failed".
- An optional third return element, if present, will be used to match the
- connection with the *user* parameter in access groups and will also be
- the username logged. If this element is absent, the username supplied
- by the client during authentication will be used, as was the previous
- behaviour.
-
- The *python_access* parameter (described below) is new; it allows the
- dynamic generation of an access group of an incoming connection using a
- Python script. If a connection matches an auth group which has a
- *python_access* parameter, all access groups in readers.conf are
- ignored; instead the procedure described below is used to generate an
- access group. This concept is due to Jeffrey M. Vinocur and you can add
- this line to readers.conf in order to use the nnrpd_access.py Python
- script in *pathfilter*:
-
- python_access: "nnrpd_access"
-
- In the old implementation, the authorization method allowed for access
- control on a per-group basis. That functionality is preserved in the
- new implementation by the inclusion of the *python_dynamic* parameter in
- readers.conf. The only change is the corresponding method name of
- "dynamic" as opposed to "authorize". Additionally, the associated
- optional housekeeping methods "dynamic_init" and "dynamic_close" may be
- implemented if needed. In order to use nnrpd_dynamic.py in
- *pathfilter*, you can add this line to readers.conf:
-
- python_dynamic: "nnrpd_dynamic"
-
- This new implementation should provide all of the previous capabilities
- of the Python hooks, in combination with the flexibility of readers.conf
- and the use of other authentication and resolving programs (including
- the Perl hooks!). To use Python code that predates the new mechanism,
- you would need to modify the code slightly (see below for the new
- specification) and supply a simple readers.conf file. If you do not
- want to modify your code, the sample directory has
- nnrpd_auth_wrapper.py, nnrpd_access_wrapper.py and
- nnrpd_dynamic_wrapper.py which should allow you to use your old code
- without needing to change it.
-
- However, before trying to use your old Python code, you may want to
- consider replacing it entirely with non-Python authentication. (With
- readers.conf and the regular authenticator and resolver programs, much
- of what once required Python can be done directly.) Even if the
- functionality is not available directly, you may wish to write a new
- authenticator or resolver (which can be done in whatever language you
- prefer).
-
- Python Authentication Support for nnrpd
-
- Support for authentication via Python is provided in nnrpd by the
- inclusion of a *python_auth* parameter in a readers.conf auth group.
- *python_auth* works exactly like the *auth* parameter in readers.conf,
- except that it calls the script given as argument using the Python hook
- rather then treating it as an external program. Multiple, mixed use of
- *python_auth* with other *auth* statements including *perl_auth* is
- permitted. Each *auth* statement will be tried in the order they appear
- in the auth group until either one succeeds or all are exhausted.
-
- If the processing of readers.conf requires that a *python_auth*
- statement be used for authentication, Python is loaded (if it has yet to
- be) and the file given as argument to the *python_auth* parameter is
- loaded as well (do not include the ".py" extension of this file in the
- value of *python_auth*). If a Python object with a method "authen_init"
- is hooked in during the loading of that file, then that method is called
- immediately after the file is loaded. If no errors have occurred, the
- method "authenticate" is called. Depending on the NNTP response code
- returned by "authenticate", the authentication hook either succeeds or
- fails, after which the processing of the auth group continues as usual.
- When the connection with the client is closed, the method "authen_close"
- is called if it exists.
-
- Dynamic Generation of Access Groups
-
- A Python script may be used to dynamically generate an access group
- which is then used to determine the access rights of the client. This
- occurs whenever the *python_access* parameter is specified in an auth
- group which has successfully matched the client. Only one
- *python_access* statement is allowed in an auth group. This parameter
- should not be mixed with a *perl_access* statement in the same auth
- group.
-
- When a *python_access* parameter is encountered, Python is loaded (if it
- has yet to be) and the file given as argument is loaded as well (do not
- include the ".py" extension of this file in the value of
- *python_access*). If a Python object with a method "access_init" is
- hooked in during the loading of that file, then that method is called
- immediately after the file is loaded. If no errors have occurred, the
- method "access" is called. The dictionary returned by "access" is used
- to generate an access group that is then used to determine the access
- rights of the client. When the connection with the client is closed,
- the method "access_close" is called, if it exists.
-
- While you may include the *users* parameter in a dynamically generated
- access group, some care should be taken (unless your pattern is just "*"
- which is equivalent to leaving the parameter out). The group created
- with the values returned from the Python script is the only one
- considered when nnrpd attempts to find an access group matching the
- connection. If a *users* parameter is included and it does not match
- the connection, then the client will be denied access since there are no
- other access groups which could match the connection.
-
- Dynamic Access Control
-
- If you need to have access control rules applied immediately without
- having to restart all the nnrpd processes, you may apply access control
- on a per newsgroup basis using the Python dynamic hooks (as opposed to
- readers.conf, which does the same on per user basis). These hooks are
- activated through the inclusion of the *python_dynamic* parameter in a
- readers.conf auth group. Only one *python_dynamic* statement is allowed
- in an auth group.
-
- When a *python_dynamic* parameter is encountered, Python is loaded (if
- it has yet to be) and the file given as argument is loaded as well (do
- not include the ".py" extension of this file in the value of
- *python_dynamic*). If a Python object with a method "dynamic_init" is
- hooked in during the loading of that file, then that method is called
- immediately after the file is loaded. Every time a reader asks nnrpd to
- read or post an article, the Python method "dynamic" is invoked before
- proceeding with the requested operation. Based on the value returned by
- "dynamic", the operation is either permitted or denied. When the
- connection with the client is closed, the method "access_close" is
- called if it exists.
-
- Writing a Python nnrpd Authentication Module
-
- You need to create a nnrpd_auth.py module in INN's filter directory (see
- the *pathfilter* setting in inn.conf) where you should define a class
- holding certain methods depending on which hooks you want to use.
-
- Note that you will have to use different Python scripts for
- authentication and access: the values of *python_auth*, *python_access*
- and *python_dynamic* have to be distinct for your scripts to work.
-
- The following methods are known to nnrpd:
-
- __init__(*self*)
- Not explicitly called by nnrpd, but will run whenever the auth
- module is loaded. Use this method to initialize any general
- variables or open a common database connection. This method may be
- omitted.
-
- authen_init(*self*)
- Initialization function specific to authentication. This method may
- be omitted.
-
- authenticate(*self*, *attributes*)
- Called when a *python_auth* statement is reached in the processing
- of readers.conf. Connection attributes are passed in the
- *attributes* dictionary. Returns a response code, an error string,
- and an optional string to be used in place of the client-supplied
- username (both for logging and for matching the connection with an
- access group).
-
- authen_close(*self*)
- This method is invoked on nnrpd termination. You can use it to save
- state information or close a database connection. This method may
- be omitted.
-
- access_init(*self*)
- Initialization function specific to generation of an access group.
- This method may be omitted.
-
- access(*self*, *attributes*)
- Called when a *python_access* statement is reached in the processing
- of readers.conf. Connection attributes are passed in the
- *attributes* dictionary. Returns a dictionary of values
- representing statements to be included in an access group.
-
- access_close(*self*)
- This method is invoked on nnrpd termination. You can use it to save
- state information or close a database connection. This method may
- be omitted.
-
- dynamic_init(*self*)
- Initialization function specific to dynamic access control. This
- method may be omitted.
-
- dynamic(*self*, *attributes*)
- Called when a client requests a newsgroup, an article or attempts to
- post. Connection attributes are passed in the *attributes*
- dictionary. Returns "None" to grant access, or a non-empty string
- (which will be reported back to the client) otherwise.
-
- dynamic_close(*self*)
- This method is invoked on nnrpd termination. You can use it to save
- state information or close a database connection. This method may
- be omitted.
-
- The *attributes* Dictionary
-
- The keys and associated values of the *attributes* dictionary are
- described below.
-
- *type*
- "read" or "post" values specify the authentication type; only valid
- for the "dynamic" method.
-
- *hostname*
- It is the resolved hostname (or IP address if resolution fails) of
- the connected reader.
-
- *ipaddress*
- The IP address of the connected reader.
-
- *port*
- The port of the connected reader.
-
- *interface*
- The hostname of the local endpoint of the NNTP connection.
-
- *intipaddr*
- The IP address of the local endpoint of the NNTP connection.
-
- *intport*
- The port of the local endpoint of the NNTP connection.
-
- *user*
- The username as passed with AUTHINFO command, or "None" if not
- applicable.
-
- *pass*
- The password as passed with AUTHINFO command, or "None" if not
- applicable.
-
- *newsgroup*
- The name of the newsgroup to which the reader requests read or post
- access; only valid for the "dynamic" method.
-
- All the above values are buffer objects (see the notes above on what
- buffer objects are).
-
- How to Use these Methods with nnrpd
-
- To register your methods with nnrpd, you need to create an instance of
- your class, import the built-in nnrpd module, and pass the instance to
- "nnrpd.set_auth_hook". For example:
-
- class AUTH:
- def authen_init(self):
- ...
- blah blah
- ...
-
- def authenticate(self, attributes):
- ...
- yadda yadda
- ...
-
- import nnrpd
- myauth = AUTH()
- nnrpd.set_auth_hook(myauth)
-
- When writing and testing your Python filter, don't be afraid to make use
- of "try:"/"except:" and the provided "nnrpd.syslog" function. stdout
- and stderr will be disabled, so your filter will die silently otherwise.
-
- Also, remember to try importing your module interactively before loading
- it, to ensure there are no obvious errors. One typo can ruin your whole
- filter. A dummy nnrpd.py module is provided to facilitate testing
- outside the server. It is not actually used by nnrpd but provides the
- same set of functions as built-in nnrpd module. This stub module may be
- used when debugging your own module. To test, change into your filter
- directory and use a command like:
-
- python -ic 'import nnrpd, nnrpd_auth'
-
- Functions Supplied by the Built-in nnrpd Module
-
- Besides "nnrpd.set_auth_hook" used to pass a reference to the instance
- of authentication and authorization class to nnrpd, the nnrpd built-in
- module exports the following function:
-
- syslog(*level*, *message*)
- It is intended to be a replacement for a Python native syslog. It
- works like "INN.syslog", seen above.
-
- $Id: hook-python 7926 2008-06-29 08:27:41Z iulius $
-
+++ /dev/null
-NOTE: The Tcl support described in this file is disabled. The code is
-all still there, but you have to define DO_TCL manually while compiling to
-enable it. Compiling in Tcl filtering was causing random innd segfaults
-even if no Tcl filters were defined, so it's been turned off to prevent
-confusion.
-
-The Tcl code will be removed in the next major release of INN since no one
-appears to be using it and the code is unmaintained and has no champion.
-If you want to resurrect it, it may be better to start from scratch, since
-a lot has changed about INN since the filters were originally written and
-the Perl and Python filters have far more capabilities.
-
-
-Note, you need tcl 7.4. Rumour has it that 7.5 won't work.
----------------------------------------------------------------------------
-Subject: TCL-based Filtering for INN 1.5
-Date: Mon, 07 Feb 94 12:36:47 -0800
-From: Bob Heiney <heiney@pa.dec.com>
-
-
-Several times in the past few months, a site or two has started posting
-the same article over and over again, but with a different message id.
-Usually this is caused by broken software (e.g. mail <-> news gateways,
-which many have written, but few have written correctly).
-Occasionally, however, the reposting is intentional. A recent example
-would be the "Global Alert: Jesus Is Coming" message which was posted
-to over 2200 newsgroups (each copy with its own message id).
-
-I expect this to happen more often as the Internet continues its explosive
-growth. Although my site (decwrl) usually has enough excess capacity to
-weather these problems, many other sites cannot. One problem on
-comp.sys.sgi.misc several months ago spewed 40MB of duplicate articles
-before the offending sites were fixed, and this overflowed the spool at
-many sites. Even for sites with lots of resources, there's still no need
-to propagate erroneous or malicious duplicates.
-
-I wanted a way to protect my site that was highly specific, flexible, and
-quick.
-
-Examination of duplicated articles showed that although the message ids
-were different, it was usually easy for a news admin to come up with a
-few rules based on the headers of the article that could be used to
-differentiate the duplicates from other articles. (E.g. from
-John.Doe@foo.com to comp.sys.sgi.misc with 'foobar' in the subject".)
-I concluded that modifying innd to let me say "kill things that look
-like _this_" would solve my problem.
-
-I also wanted to allow enough flexibilty in the design that I could
-later work on automatic detection and elimination of excessive
-duplicates (using a body checksum instead of headers).
-
-Since I needed a fairly powerful language to do all this, and since the
-world doesn't need yet another special language, my solution was to add TCL
-support to INN. I then modified "ARTpost" to call a TCL procedure which
-could then accept or reject the article. The TCL code has access to an
-associative array called "Headers", which contains all of the articles
-headers. The TCL code may also call a 32-bit article-body checksum
-procedure (this is to aid in future automatic detection of duplicates).
-
-Here's what a sample TCL filter procedure looks like:
-
-proc filter_news {} {
- global o Headers
- set sum [checksum_article]
- puts $o "$Headers(Message-ID) $sum"
- set newsgroups [split $Headers(Newsgroups) ,]
- foreach i $newsgroups {
- if {$i=="alt.test" && [string match "*heiney@pa.dec.com*" $Headers(From)]} {
- return "dont like alt.test from heiney"
- }
- }
- return "accept"
-}
-
-The above TCL code does a few things. First it computes a 32-bit
-checksum and writes it and the message ID to a file. It then rejects
-articles from me to alt.test.
-
-The work I've done is totally integrated into the INN build and runtime
-environments. For example, to turn filtering off, you'd just type
-
- ctlinnd filter n
-
-To reload the TCL code that does the filtering, you just say
-
- ctlinnd reload filter.tcl 'your comment here'
-
-(You may specify TCL callbacks to be executed right before and/or right
-after reloading, in case your filter is doing fancy stuff.) See the
-ctlinnd man page for more info.
-
-Filtering capability that's this powerful can be used for many
-purposes, some benign and useful (excessive duplicate detections,
-on-the-fly statistics), others abusive. I would ask that news admins
-think carefully about any filtering they do.
-
-/Bob
-
-
+++ /dev/null
-## $Id: Makefile 7458 2005-12-12 00:25:05Z eagle $
-
-include ../../Makefile.global
-
-top = ../..
-
-## Edit these if you need to.
-MANFLAGS = -c $(OWNER) -m 0444 -B .OLD
-
-SEC1 = convdate.1 fastrm.1 getlist.1 grephistory.1 inews.1 innconfval.1 \
- innfeed.1 innmail.1 nntpget.1 pgpverify.1 pullnews.1 rnews.1 \
- shlock.1 shrinkfile.1 simpleftp.1 sm.1 startinnfeed.1
-
-SEC3 = clientlib.3 dbz.3 inndcomm.3 libauth.3 libinn.3 libinnhist.3 \
- libstorage.3 list.3 parsedate.3 qio.3 tst.3 uwildmat.3
-
-SEC5 = active.5 active.times.5 buffindexed.conf.5 control.ctl.5 \
- cycbuff.conf.5 distrib.pats.5 expire.ctl.5 history.5 incoming.conf.5 \
- inn.conf.5 innfeed.conf.5 innwatch.ctl.5 moderators.5 motd.news.5 \
- newsfeeds.5 nnrpd.track.5 newslog.5 nntpsend.ctl.5 ovdb.5 \
- overview.fmt.5 passwd.nntp.5 radius.conf.5 readers.conf.5 sasl.conf.5 \
- storage.conf.5 subscriptions.5
-
-SEC8 = actsync.8 actsyncd.8 archive.8 auth_smb.8 batcher.8 buffchan.8 \
- ckpasswd.8 cnfsheadconf.8 cnfsstat.8 controlchan.8 ctlinnd.8 \
- cvtbatch.8 domain.8 expire.8 expireover.8 expirerm.8 filechan.8 \
- ident.8 inncheck.8 innd.8 inndf.8 inndstart.8 innreport.8 innstat.8 \
- innupgrade.8 innwatch.8 innxbatch.8 innxmit.8 mailpost.8 makedbz.8 \
- makehistory.8 mod-active.8 news.daily.8 news2mail.8 ninpaths.8 \
- nnrpd.8 nntpsend.8 ovdb_init.8 ovdb_monitor.8 ovdb_server.8 \
- ovdb_stat.8 overchan.8 perl-nocem.8 prunehistory.8 radius.8 \
- rc.news.8 scanlogs.8 send-nntp.8 send-uucp.8 sendinpaths.8 \
- tally.control.8 tdx-util.8 writelog.8
-
-COPY = $(SHELL) ./putman.sh $(MANPAGESTYLE) "$(MANFLAGS)"
-
-all:
-clobber clean distclean:
-tags ctags:
-profiled:
-
-install: install-man1 install-man3 install-man5 install-man8
-
-install-man1:
- for M in $(SEC1) ; do \
- $(COPY) $$M $D$(MAN1)/$$M ; \
- done
-
-install-man3:
- for M in $(SEC3) ; do \
- $(COPY) $$M $D$(MAN3)/$$M ; \
- done
-
-install-man5:
- for M in $(SEC5) ; do \
- $(COPY) $$M $D$(MAN5)/$$M ; \
- done
-
-# auth_krb5 is conditionally compiled, so handle it specially.
-install-man8:
- for M in $(SEC8) ; do \
- $(COPY) $$M $D$(MAN8)/$$M ; \
- done
- if [ x"$(KRB5_AUTH)" != x ] ; then \
- $(COPY) auth_krb5.8 $D$(MAN8)/auth_krb5.8 ; \
- fi
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "ACTIVE 5"
-.TH ACTIVE 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-active \- List of newsgroups carried by the server
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpathdb\fR/active lists the newsgroups carried by \s-1INN\s0. This file
-is generally maintained using \fIctlinnd\fR\|(8) to create and remove groups, or
-by letting \fIcontrolchan\fR\|(8) do so on the basis of received control messages.
-This file should not be edited directly without throttling \fBinnd\fR, and
-must be reloaded using \fBctlinnd\fR before \fBinnd\fR is unthrottled. Editing
-it directly even with those precautions may make it inconsistent with the
-overview database and won't update \fIactive.times\fR, so \fBctlinnd\fR should
-be used to make modifications whenever possible.
-.PP
-Each newsgroup should be listed only once. Each line specifies one group.
-The order of groups does not matter. Within each newsgroup, received
-articles for that group are assigned monotonically increasing numbers as
-unique names. If an article is posted to newsgroups not mentioned in this
-file, those newsgroups are ignored.
-.PP
-If none of the newsgroups listed in the Newsgroups header of an article
-are present in this file, the article is either rejected (if \fIwanttrash\fR
-is false in \fIinn.conf\fR), or is filed into the newsgroup \f(CW\*(C`junk\*(C'\fR and only
-propagated to sites that receive the \f(CW\*(C`junk\*(C'\fR newsgroup (if \fIwanttrash\fR is
-true).
-.PP
-Each line of this file consists of four fields separated by a space:
-.PP
-.Vb 1
-\& <name> <high> <low> <flag>
-.Ve
-.PP
-The first field is the name of the newsgroup. The newsgroup \f(CW\*(C`junk\*(C'\fR is
-special, as mentioned above. The newsgroup \f(CW\*(C`control\*(C'\fR and any newsgroups
-beginning with \f(CW\*(C`control.\*(C'\fR are also special; control messages are filed
-into a control.* newsgroup named after the type of control message if that
-group exists, and otherwise are filed into the newsgroup \f(CW\*(C`control\*(C'\fR
-(without regard to what newsgroups are listed in the Newsgroups header).
-If \fImergetogroups\fR is set to true in \fIinn.conf\fR, newsgroups that begin
-with \f(CW\*(C`to.\*(C'\fR are also treated specially; see \fIinnd\fR\|(8).
-.PP
-The second field is the highest article number that has been used in that
-newsgroup. The third field is the lowest article number in the group;
-this number is not guaranteed to be accurate, and should only be taken to
-be a hint. It is normally updated nightly as part of the expire process;
-see \fInews.daily\fR\|(8) and look for \f(CW\*(C`lowmark\*(C'\fR or \f(CW\*(C`renumber\*(C'\fR for more details.
-Note that because of article cancellations, there may be gaps in the
-numbering sequence. If the lowest article number is greater then the
-highest article number, then there are no articles in the newsgroup. In
-order to make it possible to update an entry in-place without rewriting
-the entire file, the second and third fields are padded out with leading
-zeros to make them a fixed width.
-.PP
-The fourth field contains one of the following flags:
-.PP
-.Vb 6
-\& y Local postings are allowed.
-\& m The group is moderated and all postings must be approved.
-\& n No local postings are allowed, only articles from peers.
-\& j Articles are filed in the junk group instead.
-\& x No local postings and ignored for articles from peers.
-\& =foo.bar Articles are filed in the group foo.bar instead.
-.Ve
-.PP
-If a newsgroup has the \f(CW\*(C`j\*(C'\fR flag, no articles will be filed in that
-newsgroup, and local postings to that group will be rejected. If an
-article for that newsgroup is received from a remote site, and it is not
-crossposted to some other valid group, it will be filed into the \f(CW\*(C`junk\*(C'\fR
-newsgroup instead. This is different than simply not listing the group,
-since the article will still be accepted and can be propagated to other
-sites, and the \f(CW\*(C`junk\*(C'\fR group can be made available to readers if wished.
-.PP
-If the <flag> field begins with an equal sign, the newsgroup is an alias.
-Articles cannot be posted to that newsgroup, but they can be received from
-other sites. Any articles received from peers for that newsgroup are
-treated as if they were actually posted to the group named after the equal
-sign. Note that the Newsgroups header of the articles are not modified.
-(Alias groups are typically used during a transition and are typically
-created manually with \fIctlinnd\fR\|(8).) An alias should not point to another
-alias.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Converted to
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: active.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive.times\fR\|(5), \fIcontrolchan\fR\|(8), \fIctlinnd\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8),
-\&\fInews.daily\fR\|(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "ACTIVE.TIMES 5"
-.TH ACTIVE.TIMES 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-active.times \- List of local creation times of newsgroups
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpathdb\fR/active.times provides a chronological record of when
-newsgruops were created on the local server. This file is normally
-updated by \fBinnd\fR whenever a newgroup control message is processed or a
-\&\f(CW\*(C`ctlinnd newgroup\*(C'\fR command is issued, and is used by \fBnnrpd\fR to answer
-\&\s-1NEWGROUPS\s0 requests.
-.PP
-Each line consists of three fields:
-.PP
-.Vb 1
-\& <name> <time> <creator>
-.Ve
-.PP
-The first field is the name of the newsgroup. The second field is the
-time it was created, expressed as the number of seconds since the epoch.
-The third field is the e\-mail addrses of the person who created the group,
-as specified in the control message or on the \fBctlinnd\fR command line, or
-the newsmaster specified at configure time if no creator argument was
-given to \fBctlinnd\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Converted to
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>
-.PP
-$Id: active.times.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive\fR\|(5), \fIctlinnd\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInnrpd\fR\|(8)
+++ /dev/null
-.\" By: Landon Curt Noll chongo@toad.com (chongo was here /\../\)
-.\"
-.\" Copyright (c) Landon Curt Noll, 1993.
-.\" All rights reserved.
-.\"
-.\" Permission to use and modify is hereby granted so long as this
-.\" notice remains. Use at your own risk. No warranty is implied.
-.\"
-.\" @(#) $Id: actsync.8 6731 2004-05-16 22:00:46Z rra $
-.\" @(#) Under RCS control in /usr/local/news/src/inn/local/RCS/actsync.8,v
-.\"
-.TH ACTSYNC 8
-.SH NAME
-actsync, actsyncd \- synchronize newsgroups
-.SH SYNOPSIS
-.B actsync
-[\fB\-A\fP] [\fB\-b\fP\fI hostid\fP] [\fB\-d\fP\fI hostid\fP] [\fB\-g\fP\fI max\fP]
-.br
- [\fB\-i\fP\fI ignore_file\fP] [\fB\-I\fP\fI hostid\fP] [\fB\-k\fP] [\fB\-l\fP\fI hostid\fP] [\fB\-m\fP]
-.br
- [\fB\-n\fP\fI name\fP] [\fB\-o\fP\fI fmt\fP] [\fB\-p\fP\fI min_%_unchg\fP] [\fB\-q\fP\fI hostid\fP]
-.br
- [\fB\-s\fP\fI size\fP] [\fB\-t\fP\fI hostid\fP] [\fB\-T\fP] [\fB\-v\fP\fI verbosity\fP]
-.br
- [\fB\-z\fP\fI sec\fP] [\fIhost1\fP] \fIhost2\fP
-.sp 1
-.B actsyncd
-[\fB\-x\fP] \fIactsync.cfg\fP [\fIdebug_level\fP [\fIdebug_outfmt\fP] ]
-.SH DESCRIPTION
-.IR Actsync (8)
-permits one to synchronize, compare, or merge two
-.I active
-files.
-With this utility one may add, change, or remove newsgroups on the
-local news server to make it similar to the list the newsgroups
-found on another system or file.
-The synchronization need not be exact.
-Local differences in newsgroup lists may be maintained and preserved.
-Certain newsgroup errors may be detected and optionally corrected.
-.PP
-There are several reasons to run
-.IR actsync (8)
-(or
-.IR actsyncd (8)),
-on a periodic basis.
-Among the reasons are:
-.in +0.5i
-.sp 1
-A control message to add, change or remove a newsgroup
-may fail to reach your site.
-.sp 1
-Your
-.I control.ctl
-may be out of date or incomplete.
-.sp 1
-News articles for a new newsgroup can arrive ahead (sometimes days ahead)
-of the control message.
-.sp 1
-Control messages may be forged, thus bypassing the restrictions
-found in
-.I control.ctl .
-.sp 1
-Your
-.I active
-file may have been trashed.
-.sp 1
-.in -0.5i
-.PP
-If
-.I host1
-or
-.I host2
-begins with a
-.B ``.''
-or
-.BR ``/'' ,
-then it is assumed to be a name of a file containing information in the
-.IR active (5)
-format.
-The
-.IR getlist (1)
-utility may be used to obtain copy a remote system's active file
-via its NNTP server, or an FTP client program can retrieve such a
-file from an FTP archive (such as
-ftp://ftp.isc.org/pub/usenet/CONFIG/active; see more about this below).
-Newsgroup information from a file
-may be treated as if it was obtained from a host.
-In this man page
-.I host1
-and
-.I host2
-are called hosts, even though they may be file names.
-.PP
-If a host argument does not begin with
-.B ``.''
-or
-.BR ``/'' ,
-is assumed to be a
-hostname or Internet address.
-In this case,
-.IR actsync (8)
-will attempt to use the
-.B NNTP
-protocol to obtain a copy of the the specified system's active file.
-If the host argument contains a
-.B ``:'' ,
-the right side will be considerd the port to connect to on the remote system.
-If no port number is specified,
-.IR actsync (8)
-will connect to port 119.
-.PP
-Regardless how the active file information is obtained,
-the actions of
-.IR actsync (8)
-remain the same.
-.PP
-If only one host is specified, it is assumed to be
-.IR host2 ;
-if
-.IR host1
-is not specified, it assumed to be the default local
-NNTP server as specified by the
-.B NNTPSERVER
-environment variable, or by the
-.B server
-value found in
-.IR inn.conf .
-.PP
-The newsgroup synchronization, by default, involves all newsgroups
-found on both hosts.
-One may also synchronize a subset of newsgroups by directing
-.IR actsync (8)
-to ignore certain newsgroups from both systems. Only newsgroups with
-valid names will be synchronized. To be valid, a newsgroup name must
-consist only of alphanumeric characters, ``.'', ``+'', ``-'', and ``_''.
-One may not have two ``.''s in a row. The first character must be
-alphanumeric, as must any character following a ``.''. The name may not
-end in a ``.'' character.
-.PP
-The
-.IR actsyncd (8)
-daemon provides a convenient interface to configure and run
-.IR actsync (8).
-If a host is not initially reachable,
-the daemon will retry up to 9 additional times, waiting 6 minutes before
-each retry.
-This daemon runs in the foreground, sending output to standard output
-and standard error.
-.PP
-If the \fB\-x\fP flag is given to
-.IR actsyncd (8),
-then a
-.IR ctlinnd\ xexec
-will be used instead of a
-.IR ctlinnd\ reload
-to load the newly modified active file.
-.PP
-The configuration filename for the daemon is given as a
-commandline argument, usually
-.I <pathetc in inn.conf>/actsync.cfg
-The config file can contain the following options:
-.sp 1
-.in +0.5i
-.nf
-\fBhost=\fP\fIhost2\fP
-\fBftppath=\fP\fI/remote/path/to/active/file\fP
-\fBspool=\fP\fI<normally patharticles in inn.conf>\fP
-\fBignore_file=\fP\fIignore_file\fP
-\fBflags=\fP\fIactsyncd\fP(8) options
-.fi
-.in -0.5i
-.sp 1
-The \fBhost\fP, \fBignore_file\fP, and \fBflags\fP lines are mandatory.
-.sp 1
-The keyword must start at the beginning of the line, and there
-may be no whitespace before the
-.B ``=''
-character.
-Blank lines are ignored.
-Comment lines start with
-.B ``#''
-and are ignored.
-Any other lines may produce undefined results.
-.sp 1
-The \fBhost\fP config file line refers to the \fIhost2\fP parameter to
-.IR actsync (8).
-The \fBftppath\fP directive causes the machine named in the \fBhost\fP
-line to accessed as an ftp server, retrieving the file named. If
-the filename ends in \fB.gz\fP or \fB.Z\fP, then it will automatically
-be uncompressed after retrieval.
-The \fBspool\fP config file lines determines where the top of the
-news spool tree is to be found.
-The \fBignore_file\fP config file line names the ignore file to be
-used by
-.IR actsync (8).
-The \fBflags\fP config file line contains any flags that you wish to pass to
-.IR actsync (8).
-.sp 1
-Note that the \fB\-i ignore_file\fP option
-and the \fB-o format\fP option
-should not be given
-in the \fBflags=\fP line because they are automatically taken care of by
-.IR actsyncd (8).
-.sp 1
-INN is shipped with default values of \fIftp.isc.org\fP for \fBhost\fP
-and \fI/pub/usenet/CONFIG/active\fP for \fBftppath\fP. You can read
-about the policies used for maintaining that active file at
-\fIftp://ftp.isc.org/pub/usenet/CONFIG/README\fP. Consider
-sychronizing from this file on a daily basis by using
-.IR cron (8).
-.SH OPTIONS
-The options to
-.IR actsync (8)
-are as follows:
-.PP
-.TP
-.B \-A
-.IR actsync (8)
-tries to authenticate before issuing LIST command.
-.TP
-.BI \-b " hostid"
-This flag causes
-.IR actsync (8)
-to ignore newsgroups with ``bork.bork.bork'' style names.
-That is, newsgroups whose last 3 components are identical.
-For example, the following newsgroups have bork style names:
-.sp 1
-.in +0.5i
-.nf
-alt.helms.dork.dork.dork
-alt.auto.accident.sue.sue.sue
-alt.election.vote.vote.vote
-.fi
-.in -0.5i
-.sp 1
-The value
-.I hostid
-determines on which hosts this action is performed:
-.sp 1
-.in +0.5i
-.nf
-0 neither host
-1 local default server
-2 remove server
-12 both servers
-21 both servers
-.fi
-.in -0.5i
-.sp 1
-The default is
-.BR "\-b 0" ;
-no newsgroups are ignored because of bork-style names.
-.TP
-.BI \-d " hostid"
-This flag causes
-.IR actsync (8)
-to ignore newsgroups that have all numeric path components.
-The
-.B hostid
-value is interpreted the same as in
-.BR \-b .
-For example, the following newsgroups have numeric path components:
-.sp
-.in +0.5i
-.nf
-alt.prime.chongo.23209
-391581.times.2.to_the.216193.power.-1
-99.bottles.of.treacle.on.the.wall
-linfield.class.envio_bio.101.d
-.fi
-.in -0.5i
-.sp 1
-The newsgroups directory of a newsgroups with a all numeric component
-could conflict with an article from another group if stored using the
-``tradspool'' storage method; see
-.IR storage.conf (5).
-For example, the directory for the first newsgroup listed above
-is the same path as article number 23209 from the newsgroup:
-.sp
-.in +0.5i
-.nf
-alt.prime.chongo
-.fi
-.in -0.5i
-.sp 1
-The default is
-.BR "\-d 0" ;
-all numeric newsgroups from both hosts will be processed.
-.TP
-.BI \-g " max"
-Ignore any newsgroup with more than
-.B max
-levels. For example,
-.BI \-g " 6"
-would ignore:
-.sp 1
-.in +0.5i
-.nf
-alt.feinstien.votes.to.trash.freedom.of.speech
-alt.senator.exon.enemy.of.the.internet
-alt.crypto.export.laws.dumb.dumb.dumb
-.fi
-.in -0.5i
-.sp 1
-but would not ignore:
-.sp 1
-.in +0.5i
-.nf
-alt.feinstien.acts.like.a.republican
-alt.exon.amendment
-alt.crypto.export.laws
-.fi
-.in -0.5i
-.sp 1
-If
-.B max
-is 0, then the max level feature is disabled.
-.sp 1
-By default,
-the max level feature is disabled.
-.TP
-.BI \-i " ignore_file"
-The
-.I ignore_file ,
-usually
-.I <pathetc in inn.conf>/actsync.ign ,
-allows one to have a fine degree of control over which newsgroups are ignored.
-It contains a set of rules that specifies
-which newsgroups will be checked and which will be ignored.
-.sp 1
-By default, these rules apply to both hosts.
-This can be modified by using the
-.BI \-I " hostid"
-flag.
-.sp 1
-By default, all newsgroups are checked.
-If no
-.I ignore_file
-if specified, or if the ignore file contains no rule lines,
-all newsgroups will be checked.
-.sp 1
-Blank lines and text after a
-.B ``#''
-are considered comments and are ignored.
-.sp 1
-Rule lines consist of tokens separated by whitespace.
-Rule lines may be one of two forms:
-.sp 1
-.in +0.5i
-.nf
-\fBc newsgroup [type ...]\fP
-\fBi newsgroup [type ...]\fP
-.fi
-.in -0.5i
-.sp 1
-If the rule begins with a
-.B c
-then the rule requests certain newsgroups to be checked.
-If the rule begins with an
-.B i
-then the rule requests certain newsgroups to be ignored.
-The
-.B newsgroup
-field may be a specific newsgroup, or a
-.IR uwildmat (3)
-pattern.
-.sp 1
-If one or more
-.BR type s
-are specified, then the rule applies to the newsgroup only if
-is of the specified type.
-Types refer to the 4th field of the
-.I active
-file; that is, a type may be one of:
-.sp 1
-.in +0.5i
-.nf
-\fBy\fP
-\fBn\fP
-\fBm\fP
-\fBj\fP
-\fBx\fP
-\fB=group.name\fP
-.fi
-.in -0.5i
-.sp 1
-Unlike active files, the
-.B group.name
-in an alias type may be a newsgroup name or a
-.IR uwildmat (3)
-pattern.
-Also,
-.B ``=''
-is equivalent to
-.BR ``=*'' .
-.sp 1
-On each rule line, no pattern type may not be repeated.
-For example, one may not have more than one type that begins with
-.BR ``='' ,
-per line.
-However, one may achieve an effect equivalent to using multiple
-.B ``=''
-types by using multiple rule lines affecting the same newsgroup.
-.sp 1
-By default, all newsgroups are candidates to be checked.
-If an ignore file is used, each newsgroup in turn is checked
-against the ignore file.
-If multiple lines match a given newsgroup, the last line
-in the ignore file is used.
-.sp 1
-For example, consider the following ignore file lines:
-.sp 1
-.in +0.5i
-.nf
-i *.general
-c *.general m
-i nsa.general
-.fi
-.in -0.5i
-.sp 1
-The newsgroups
-.B ba.general
-and
-.B mod.general
-would be synchronized if moderated and ignored if not moderated.
-The newsgroup
-.B nsa.general
-would be ignored regardless of moderation status.
-All newsgroups not matching
-.B *.general
-would be synchronized by default.
-.TP
-.BI \-I " hostid"
-This flag restricts which hosts are affected by the ignore file.
-The
-.B hostid
-value is interpreted the same as in
-.BR \-b
-described above.
-.sp 1
-This flag may be useful in conjunction with the
-.B \-m
-merge flag.
-For example:
-.sp 1
-.in +0.5i
-actsync \-i actsync.ign \-I 2 \-m
-.I host1
-.I host2
-.in -0.5i
-.sp 1
-will keep all newsgroups currently on
-.I host1 .
-It will also will only compare
-.I host1
-groups with non-ignored newsgroups from
-.I host2 .
-.sp 1
-The default is
-.BR "\-I 12" ,
-newsgroups from both hosts to be ignored per the
-.I \-i " actsync.ign"
-file.
-.TP
-.B \-k
-By default, any newsgroup on
-.I host1
-that is in error will be considered for removal.
-This causes
-.IR actsync (8)
-simply ignore such newsgroups.
-This flag, used in combination with
-.I \-m ,
-will prevent any newsgroup from being scheduled for removal.
-.TP
-.BR \-l " hostid"
-This flag causes ``problem newsgroups'' of type
-.B ``=''
-from
-.B host1
-or
-.B host2
-to be considered as errors.
-The
-.B hostid
-value is interpreted the same as in
-.BR \-b .
-Newsgroups of type
-.B ``=''
-are newsgroups active entries that have 4th field
-that begins with
-.BR ``='' ,
-i.e. newsgroups that are equivalent to other newsgroups. A ``problem''
-newsgroup is one which is:
-.sp 1
-.in +0.5i
-.nf
-* equivalent to itself
-* in an equivalence chain that loops around
- to itself
-* in an equivalence chain longer than 16 groups
-* equivalent to a non-existant newsgroup
-* equivalent to a newsgroup that has an error
- of some kind
-.fi
-.in -0.5i
-.sp 1
-However, a newsgroup that is equivalent to an ignored newsgroup is
-not a problem.
-.sp 1
-By default, problem newsgroups from both hosts are
-marked as errors.
-.TP
-.B \-m
-Merge newsgroups instead of sync.
-By default, if a newsgroup exists on
-.B host1
-but not
-.BR host2 ,
-it will be scheduled to be removed.
-This flag disables this process, permitting newsgroups unique to
-.B host1
-to be kept.
-.TP
-.B \-n " name"
-The
-.IR ctlinnd (8)
-command is used to create newsgroups as necessary.
-By default, the creator name used is
-.BR "actsync" .
-This flag changes the creator name to
-.BR "name" .
-.TP
-.B \-o " fmt"
-Determine the output / action format of this utility.
-The
-.B "fmt"
-may one of:
-.sp 1
-.in +0.5i
-.nf
-\fBa\fP output in \fIactive\fP\fR(5)\fP\fR format\fP
-\fBa1\fP output in \fIactive\fP\fR(5)\fP\fR format,\fP
- and output host1 non-error ignored groups
-\fBak\fP output in \fIactive\fP\fR(5)\fP\fR format, but use host2\fP
- hi & low (2nd & 3rd active fields) values
- for any newsgroup being created
-\fBaK\fP output in \fIactive\fP\fR(5)\fP\fR format, but use host2\fP
- hi & low (2nd & 3rd active fields) values
- for all newsgroups found in host2
-\fBa1k\fP output in \fIactive\fP\fR(5)\fP\fR format, but use host2\fP
- hi & low (2nd & 3rd active fields) values
- for any newsgroup being created,
- and output host1 non-error ignored groups
-\fBa1K\fP output in \fIactive\fP\fR(5)\fP\fR format, but use host2\fP
- hi & low (2nd & 3rd active fields) values
- for all newsgroups found in host2,
- and output host1 non-error ignored groups
-\fBak1\fP same as \fBa1k\fP
-\fBaK1\fP same as \fBa1K\fP
-\fBc\fP output in \fIctlinnd\fP\fR(8)\fP\fR format\fP
-\fBx\fP no output, directly exec \fIctlinnd\fP\fR(8)\fP\fR commands\fP
-\fBxi\fP no output, directly exec \fIctlinnd\fP\fR(8)\fP\fR commands,\fP
- in an interactive mode
-.fi
-.in -0.5i
-.sp 1
-The \fBa\fP, \fBa1\fP, \fBak\fP, \fBaK\fP, \fBa1k\fP,
-\fBa1K\fP, \fBak1\fP and \fBaK1\fP style formats allow one to form
-a new active file instead of producing
-.IR ctlinnd (8)
-commands.
-They use hi & low values of
-.B 0000000000
-and
-.B 0000000001
-respectively for newsgroups that are created.
-The \fBak\fP and \fBaK\fP variants change the the hi & low (2nd & 3rd
-active fields).
-In the case of \fBak\fP, newsgroups created take their hi & low values from
-.BR host2 .
-In the case of \fBaK\fP, all newsgroups found on host2 take their
-hi & low values from
-.BR host2 .
-.sp 1
-The \fBc\fP format produces
-.IR ctlinnd (8)
-commands.
-No actions are taken because
-.IR actsync (8)
-simply prints
-.IR ctlinnd (8)
-commands on standard output.
-The sync (or merge) with
-.B host2
-may be accomplished by piping this output into
-.IR sh (1).
-A paranoid person might prefer to use \fBx\fP or \fBxi\fP
-in case a newsgroup name or type contains bogus characters
-that might be interpreted by
-.IR sh (1).
-Even so, this output format is useful to let you see how
-.B host1
-will be affected by the sync (or merge) with
-.BR host2 .
-.sp 1
-The sync (or merge) may be accomplished directly
-by use of the \fBx\fP format.
-With this format,
-.IR actsync (8)
-uses the
-.IR execl (2)
-system call to directly execute
-.IR ctlinnd (8)
-commands.
-Because of the exec, there is no risk
-of bogus newsgroups containing bogus characters causing
-a shell to do bogus (or dangerous) things.
-The output of such exec calls may be seen if the verbosity level
-is at least
-.BR 2 .
-.sp 1
-The
-.IR actsync (8)
-utility will pause for
-.B 4
-seconds before each command is executed if
-.BI \-o " x"
-is selected.
-See the
-.BR \-z " sec"
-flag below for discussion of this delay and how to customize it.
-.sp 1
-The \fBxi\fP format interactively prompts on standard output
-and reads directives on standard input.
-One may pick and choose changes using this format.
-.sp 1
-Care should be taken when producing
-\fIactive\fP\fR(5)\fP\fR formatted output\fP.
-One should check to be sure that
-.IR actsync (8)
-exited with a zero status prior to using such output.
-Also one should realize that such output will not
-contain lines ignored due to
-.BI \-i " ignore_file"
-even if
-.BI \-p " 100"
-is used.
-.sp 1
-By default,
-.BI \-o " c"
-is assumed.
-.TP
-.BI \-p " min_%_unchg"
-By default, the
-.IR actsync (8)
-utility has safeguards against performing massive changes.
-If fewer than
-.B min_%_unchg
-percent of the non-ignored lines from
-.B host1
-remain unchanged, no actions (output, execution, etc.)
-are performed and
-.IR actsync (8)
-exits with a non-zero exit status.
-The
-.B min_%_unchg
-may be a floating point value such as
-.BR 66.667 .
-.sp 1
-A change is considered a
-.B host1
-line that was removed, added, changed, or found to be in error.
-Changing the 2nd or 3rd active fields via
-.BI \-o "ak"
-or
-.BI \-o " aK"
-are not considered changes by
-.BR \-p .
-.sp 1
-To force
-.IR actsync (8)
-to accept any amount of change, use the
-.BI \-p " 0"
-option.
-To force
-.IR actsync (8)
-to reject any changes, use the
-.BI \-p " 100"
-option.
-.sp 1
-Care should be taken when producing
-\fIactive\fP\fR(5)\fP\fR-formatted output\fP;
-be sure to check that
-.IR actsync (8)
-exited with a zero status prior to using such output.
-Also one should realize that such output will not
-contain lines ignored by the
-.BI \-i " ignore_file"
-process even if
-.BI \-p " 100"
-is used.
-.sp 1
-By default, 96% of the lines not ignored in host1 must
-be unchanged.
-That is, by default,
-.BI \-p " 96"
-is assumed.
-.TP
-.BI \-q " hostid"
-By default, all newsgroup errors are reported on standard error.
-This flag quiets errors from
-.B host1
-or
-.BR host2 .
-The
-.B hostid
-value is interpreted the same as in
-.BR \-b .
-.TP
-.BR \-s " size"
-If
-.BR size\ >\ 0,
-then ignore newsgroups with names longer than
-.BR size ,
-and ignore newsgroups equivalent (by following
-.B ``=''
-chains) to names longer than
-.BR size .
-Length checking is performed on both the local and remote hosts.
-.sp 1
-By default,
-.B size
-is 0 and thus no length checking is performed.
-.TP
-.BR \-t " hostid"
-Ignore improper newsgroups consisting of only a top component
-from
-.B host1
-or
-.BR host2 .
-The
-.B hostid
-value is interpreted the same as in
-.BR \-b .
-The following newsgroups are considered proper newsgroups
-despite top only names and therefore are exempt from this flag:
-.sp 1
-.in +0.5i
-.nf
-control
-general
-junk
-test
-to
-.fi
-.in -0.5i
-.sp 1
-For example, the following newsgroup names are improper because they
-only contain a top level component:
-.sp 1
-.in +0.5i
-.nf
-dole_for_pres
-dos
-microsoft
-windows95
-.fi
-.in -0.5i
-.sp 1
-The default is
-.BR "\-t 2" ,
-that is, all improper top-level-only newsgroups from the remote
-are ignored.
-.TP
-.B \-T
-This flag causes
-.B host2
-newsgroups from new hierarchies to be ignored.
-Normally a newsgroup which only exists on
-.B host2 ,
-for example
-.B chongo.was.here ,
-will be created for
-.BR host1 .
-However, if this flag is given and
-.B host1
-does not have any other newsgroups in the same hierarchy,
-e.g. ``\fBchongo.*\fP'', then the newsgroup in question
-will be ignored and will not be created on
-.BR host1 .
-.TP
-.BI \-v " verbosity"
-By default,
-.IR actsync (8)
-is not verbose.
-This flag controls the verbosity level as follows:
-.sp 1
-.in +0.5i
-.nf
-\fB0\fP no debug or status reports (default)
-\fB1\fP print summary,
- but only if work was needed or done
-\fB2\fP print actions, exec output, and summary,
- but only if work was needed or done
-\fB3\fP print actions, exec output, and summary
-\fB4\fP full debug output
-.fi
-.TP
-.BI \-z " sec"
-If
-.BI \-o " x"
-is selected,
-.IR actsync (8)
-will pause for
-.B sec
-seconds before each command is executed.
-This helps prevent
-.IR innd (8)
-from being busied-out if a large number of
-.IR ctlinnd (8)
-commands are needed.
-One can entirely disable this sleeping by using
-.BI \-z " 0".
-.sp 1
-By default,
-.IR actsync (8)
-will pause for
-.B 4
-seconds before each command is executed if
-.BI \-o " x"
-is selected.
-.in -0.5i
-.SH EXAMPLES
-Determine the difference (but don't change anything) between your
-newsgroup set and uunet's set:
-.PP
-.in +0.5i
-actsync news.uu.net
-.in -0.5i
-.PP
-Same as above, with full debug and progress reports:
-.PP
-.in +0.5i
-actsync \-v 4 news.uu.net
-.in -0.5o
-.PP
-Force a site to have the same newsgroups some other site:
-.PP
-.in +0.5i
-actsync \-o x master
-.in -0.5i
-.PP
-This may be useful to sync a slave site to its master, or
-to sync internal site to a gateway.
-.PP
-Compare your site with uunet, disregarding local groups and
-certain local differences with uunet.
-Produce a report if
-any differences were encountered:
-.PP
-.in +0.5i
-actsync \-v 2 \-i actsync.ign news.uu.net
-.in -0.5i
-.PP
-where
-.B actsync.ign
-contains:
-.PP
-.in +0.5i
-.nf
-# Don't compare to.* groups as they will differ.
-#
-i to.*
-
-# These are our local groups that nobody else
-# (should) carry. So ignore them for the sake
-# of the compare.
-#
-i nsa.*
-
-# These groups are local favorites, so keep them
-# even if uunet does not carry them.
-#
-i ca.dump.bob.dorman
-i ca.keep.bob.dorman
-i alt.tv.dinosaurs.barney.die.die.die
-i alt.tv.dinosaurs.barney.love.love.love
-i alt.sounds.* =alt.binaries.sounds.*
-.PP
-.fi
-.in -0.5i
-.PP
-To interactively sync against news.uu.net, using the same
-ignore file:
-.PP
-.in +0.5i
-actsync \-o xi \-v 2 \-i actsync.ign news.uu.net
-.in -0.5i
-.PP
-Based on newsgroups that you decided to keep, one could
-make changes to the
-.B actsync.ign
-file:
-.PP
-.in +0.5i
-.nf
-# Don't compare to.* groups as they will differ.
-#
-i to.*
-
-# These are our local groups that nobody else
-# (should) carry. So ignore them for the sake
-# of the compare.
-#
-i nsa.*
-
-# These groups are local favorites, so keep them
-# even if uunet does not carry them.
-#
-i ca.dump.bob.dorman
-i alt.tv.dinosaurs.barney.die.die.die
-i alt.sounds.* =alt.binaries.sounds.*
-
-# Don't sync test groups, except for ones that are
-# moderated or that are under the gnu hierarchy.
-i *.test
-c *.test m # check moderated test groups
-c gnu.*.test
-c gnu.test # just in case it ever exists
-.PP
-.fi
-.in -0.5i
-.PP
-Automatic processing may be setup by using the following
-.B actsync.cfg
-file:
-.PP
-.in +0.5i
-.nf
-# host to sync off of (host2)
-host=news.uu.net
-
-# location of the ignore file
-ignore_file=<pathetc in inn.conf>/actsync.ign
-
-# where news articles are kept
-spool=<patharticles in inn.conf>
-
-# actsync(8) flags
-#
-# Automatic execs, report if something was done,
-# otherwise don't say anything, don't report
-# uunet active file problems, just ignore
-# the affected entries.
-flags=\-o x \-v 2 \-q 2
-.fi
-.in -0.5i
-.PP
-and then by running
-.IR actsyncd (8)
-with the path to the config
-file:
-.PP
-.in +0.5i
-actsyncd <pathetc in inn.conf>/actsync.cfg
-.in -0.5i
-.PP
-One may produce a trial
-.IR actsyncd (8)
-run without changing anything
-on the server by supplying the \fBdebug_level\fP arg:
-.sp 1
-.in +0.5i
-actsyncd <pathetc in inn.conf>/actsync.cfg 2
-.in -0.5i
-.PP
-The \fBdebug_level\fP causes
-.IR actsyncd (8)
-to run
-.IR actsync (8)
-with an \fB\-v debug_level\fP (overriding any \fB\-v\fP
-flag on the \fBflags\fP line),
-not make any changes to the
-.I active
-file, write a new active file to \fIstandard output\fP,
-and write debug messages to \fIstandard error\fP.
-.PP
-If the \fBdebug_outfmt\fP arg is also given to
-.IR actsyncd (8)
-then the data written to \fIstandard output\fP will
-be in \fB\-o debug_outfmt\fP instead of in \fB\-o a1\fP format.
-The /bin/sh command
-.sp 1
-.in +0.5i
-.nf
-actsyncd <pathetc in inn.conf>/actsync.cfg 4 \\
- >cmd.log 2>dbg.log
-.fi
-.in -0.5i
-.PP
-will operate in debug mode,
-not change the
-.I active
-file, write
-.IR ctlinnd (8)
-style commands to \fBcmd.log\fP, and
-write debug statements to \fBdbg.log\fP.
-.PP
-To check only the major hierarchies against news.uu,net, use the following
-.B actsync.ign
-file:
-.PP
-.in +0.5i
-.nf
-# by default, ignore everything
-i *
-
-# check the major groups
-c comp.*
-c gnu.*
-c sci.*
-c alt.*
-c misc.*
-c news.*
-c rec.*
-c soc.*
-c talk.*
-.fi
-.in -0.5i
-.PP
-and the command:
-.PP
-.in +0.5i
-actsync \-i actsync.ign news.uu.net
-.in -0.5i
-.PP
-To determine the differences between your old active and
-your current default server:
-.PP
-.in +0.5i
-actsync <pathetc in inn.conf>/active.old \-
-.in -0.5i
-.PP
-To report but not fix any newsgroup problems with the current active file:
-.PP
-.in +0.5i
-actsync \- \-
-.in -0.5i
-.PP
-To detect any newsgroup errors on your local server, and
-to remove any
-.B *.bork.bork.bork
-style silly newsgroup names:
-.PP
-.in +0.5i
-actsync \-b 2 \- \-
-.in -0.5i
-.PP
-The active file produced by:
-.PP
-.in +0.5i
-actsync ...flags... \-o x erehwon.honey.edu
-.in -0.5i
-.PP
-or by:
-.PP
-.in +0.5i
-actsync ...flags... \-o c erehwon.honey.edu | sh
-.in -0.5i
-.PP
-is effectively the same as the active file produced by:
-.PP
-.nf
-.in +0.5i
-ctlinnd pause 'running actsync'
-rm -f active.new
-actsync ...flags... \-o a1 erehwon.honey.edu > active.new
-rm -f active.old
-ln active active.old
-mv active.new active
-ctlinnd reload active 'running actsync'
-ctlinnd go 'running actsync'
-.in -0.5i
-.fi
-.PP
-It should be noted that the final method above, pausing the server
-and simply replacing the
-.I active
-file, is faster.
-.PP
-.SH CAUTION
-Careless use of this tool may result in the unintended
-addition, change, or removal of newsgroups.
-You should avoid using the \fRx\fP output format until
-you are sure it will do what you want.
-.SH BUGS
-If a newsgroup appears multiple times,
-.IR actsync (8)
-will treat all copies as errors.
-However, if the group is marked for removal, only
-one rmgroup will be issued.
-.PP
-The timeout for
-.IR ctlinnd (8)
-commands is fixed at 30 seconds when
-running in ``\fRx\fP'' or ``\fRxi\fP'' output format.
-Perhaps the timeout value should be controlled via a command line option?
-.SH "SEE ALSO"
-.IR active (5),
-.br
-.IR simpleftp (1),
-.br
-.IR mod-active (8),
-.br
-.IR ctlinnd (8),
-.br
-.IR getlist (8),
-.br
-.IR inn.conf (5).
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> for InterNetNews.
-Updated to support ftp fetching by David Lawrence <tale@isc.org>.
+++ /dev/null
-.TH ACTSYNCD 8
-.SH NAME
-actsyncd \- run actsync to synchronize newsgroups
-.SH SYNOPSIS
-Please see the
-.IR actsync (8)
-manual page.
-.SH "SEE ALSO"
-actsync(8)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH ARCHIVE 8
-.SH NAME
-archive \- Usenet article archiver
-.SH SYNOPSIS
-.B archive
-[
-.BI \-a " archive"
-]
-[
-.B \-c
-]
-[
-.B \-f
-]
-[
-.BI \-i " index"
-]
-[
-.BI \-p " newsgroup-list"
-]
-[
-.B \-r
-]
-[
-.I input
-]
-.SH DESCRIPTION
-.I Archive
-makes copies of files specified on its standard input.
-It is normally run either as a channel feed under
-.IR innd (8),
-or by a script before
-.IR expire (8)
-is run.
-.PP
-.I Archive
-reads the named
-.I input
-file, or standard input if no file is given.
-The input is taken as a sequence of lines;
-blank lines and lines starting with a number sign (``#'') are ignored.
-All other lines should specify the token of an article to archive.
-Every article is retrieved from a token,
-and the Xref: header is used to determine the target file in the
-archive directory.
-You can limit the targets taken from the Xref: header with the ``\-p'' option.
-.PP
-Files are copied to a directory within the archive directory,
-.IR <patharchive\ in\ inn.conf> .
-The default is to create a hierarchy that mimics the input files;
-intermediate directories will be created as needed.
-For example, if the input token represents article 2211 in the newsgroup
-comp.sources.unix,
-.IR archive
-will generate a copy in
-.IR <patharchive\ in\ inn.conf>/comp/sources/unix/2211 .
-.SH OPTIONS
-.TP
-.B \-a\ archive
-If the ``\-a'' flag is used then its argument specifies the directory to
-archive in instead of
-.IR <patharchive\ in\ inn.conf> .
-.TP
-.B \-c
-If the ``\-c'' flag is used, then directory names will be flattened as if
-by the ``\-f'' flag; additionally, all posts will be concatenated into a
-.B single\ file ,
-appending if the file already exists, with the final component of the
-filename being YYYYMM based on the local execution time of
-.IR archive.
-In this case, on December 14, 1998, the file would be copied to
-.IR <patharchive\ in\ inn.conf>/comp.sources.unix/199812 .
-.TP
-.B \-f
-If the ``\-f'' flag is used, then all directory names will be
-flattened out, replacing the slashes with periods.
-In this case, the file would be copied to
-.IR <patharchive\ in\ inn.conf>/comp.sources.unix/2211 .
-.TP
-.B \-i
-If the ``\-i'' flag is used, then
-.I archive
-will append one line to the specified
-.I index
-file for each article that it copies.
-This line will contain the destination name as well as the Message-ID and
-Subject headers.
-.TP
-.B \-p newsgroup-list
-Limits the targets taken from the Xref: header to the groups specified in
-.I newsgroup-list.
-The
-.I newsgroup-list
-is a comma-separated
-.IR uwildmat (3)
-list of newsgroups you wish to have
-.IR archive
-handle.
-.TP
-.B \-r
-By default,
-.I archive
-sets its standard error to
-.IR <pathlog\ in\ inn.conf>/errlog .
-To suppress this redirection, use the ``\-r'' flag.
-.SH EXIT STATUS
-If the input is exhausted,
-.I archive
-will exit with a zero status.
-If an I/O error occures, it will try to spool its input, copying it to a file.
-If there was no input filename, the standard input will be copied to
-.I <pathoutgoing in inn.conf>/archive
-and the program will exit.
-If an input filename was given, a temporary file named
-.IR input .bch
-(if
-.I input
-is an absolute pathname)
-or
-.I <pathoutgoing in inn.conf>/input.bch
-(if the filename does not begin with a slash) is created.
-Once the input is copied,
-.I archive
-will try to rename this temporary file to be the name of the input file,
-and then exit.
-
-.SH EXAMPLES
-A typical
-.IR newsfeeds (5)
-entry to archive most source newsgroups is as follows:
-.PP
-.RS
-.nf
-source-archive\e
- :!*,*sources*,!*wanted*,!*.d\e
- :Tc,Wn\e
- :<pathbin in inn.conf>/archive \-f \-i \e
- <patharchive in inn.conf>/INDEX
-.fi
-.RE
-
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: archive.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5),
-newsfeeds(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "AUTH_KRB5 8"
-.TH AUTH_KRB5 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-auth_krb5 \- nnrpd Kerberos v5 authenticator
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBauth_krb5\fR [\fB\-i\fR \fIinstance\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This program does authentication for \fBnnrpd\fR against a Kerberos v5 \s-1KDC\s0.
-This is \s-1NOT\s0 real Kerberos authentication using service tickets; instead, a
-username and password is used to attempt to obtain a Kerberos v5 \s-1TGT\s0 to
-confirm that they are valid. As such, this authenticator assumes that
-\&\fBnnrpd\fR has been given the user's username and password, and therefore is
-not as secure as real Kerberos authentication. It generally should only
-be used with \s-1NNTP\s0 over \s-1SSL\s0 to protect the password from sniffing.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-i\fR \fIinstance\fR" 4
-.IX Item "-i instance"
-If this option is given, \fIinstance\fR will be used as the instance of the
-principal received from \fBnnrpd\fR and authentication will be done against
-that principal instead of the base principal. In other words, a principal
-like \f(CW\*(C`user\*(C'\fR, when passed to \fBauth_krb5\fR invoked with \f(CW\*(C`\-i nntp\*(C'\fR, will be
-transformed into \f(CW\*(C`user/nntp\*(C'\fR before attempting Kerberos authentication.
-.Sp
-Since giving one's password to \fBnnrpd\fR is not as secure as normal
-Kerberos authentication, this option supports a configuration where all
-users are given a separate instance just for news authentication with its
-own password, so their regular account password isn't exposed via \s-1NNTP\s0.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-The following \fIreaders.conf\fR\|(5) fragment tells nnrpd to authenticate users
-by attempting to obtain Kerberos v5 TGTs for them, appending an instance
-of \f(CW\*(C`nntp\*(C'\fR to usernames before doing so:
-.PP
-.Vb 3
-\& auth kerberos {
-\& auth: "auth_krb5 \-i nntp"
-\& }
-.Ve
-.PP
-.Vb 4
-\& access kerberos {
-\& users: "*/nntp"
-\& newsgroups: example.*
-\& }
-.Ve
-.PP
-Access is granted to the example.* groups for all users who successfully
-authenticate.
-.SH "BUGS"
-.IX Header "BUGS"
-Currently, any username containing realm information (containing \f(CW\*(C`@\*(C'\fR) is
-rejected. This is to prevent someone from passing in a username
-corresponding to a principal in another realm that they have access to and
-gaining access to the news server via it. However, this is also something
-that people may wish to do under some circumstances, so there should be a
-better way of handling it (such as, perhaps, a list of acceptable realms
-or a \-r flag specifying the realm in which to attempt authentication).
-.PP
-It's not clear the right thing to do when the username passed in contains
-a \f(CW\*(C`/\*(C'\fR and \fB\-i\fR was also given. Right now, \fBauth_krb5\fR will create a
-malformed Kerberos principal with multiple instances and attempt to
-authenticate against it, which will fail but perhaps not with the best
-error message.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Originally written by Christopher P. Lindsey. This documentation was
-written by Russ Allbery <rra@stanford.edu> based on Christopher's original
-\&\s-1README\s0 file.
-.PP
-$Id: auth_krb5.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5)
-.PP
-The latest version of Christopher's original \fBnnrpkrb5auth\fR may be found
-on his web site at <http://www.mallorn.com/tools/>.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "AUTH_SMB 8"
-.TH AUTH_SMB 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-auth_smb \- nnrpd Samba authenticator
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBauth_smb\fR \fBserver\fR [\fBbackup_server\fR] \fBdomain\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This program does authentication for \fBnnrpd\fR against an \s-1SMB\s0 server. It
-passes the received username and password to \fBserver\fR for validation in
-the specified \s-1SMB\s0 \fBdomain\fR. A backup server may optionally be
-supplied; if it is missing, only \fBserver\fR is used.
-.PP
-If authentication is successful, the original username is returned as
-the authentication identity. Brief errors, including incorrect password
-and failure contacting the server, are logged.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-The following \fIreaders.conf\fR\|(5) fragment grants access to users who can
-authenticate against an \s-1SMB\s0 server:
-.PP
-.Vb 4
-\& auth windows {
-\& auth: "auth_smb pdc.example.com bdc.example.com USERS"
-\& default\-domain: "users.example.com"
-\& }
-.Ve
-.PP
-.Vb 4
-\& access internal {
-\& users: "*@users.example.com"
-\& newsgroups: example.*
-\& }
-.Ve
-.PP
-Access is granted to the example.* groups after successful
-authentication.
-.SH "BUGS"
-.IX Header "BUGS"
-We should link against an external \s-1SMB\s0 library rather than maintain one
-within the \s-1INN\s0 source tree.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Originally written October 2000 by Krischan Jodies <krischan@jodies.cx>,
-based heavily on pam_smb v1.1.6 by David Airlie <airlied@samba.org>.
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-.PP
-$Id: auth_smb.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5)
+++ /dev/null
-.\" $Revision: 6491 $
-.TH BATCHER 8
-.SH NAME
-batcher \- article-batching backend for InterNetNews
-.SH SYNOPSIS
-.B batcher
-[
-.BI \-a " arts"
-]
-[
-.BI \-A " total_arts"
-]
-[
-.BI \-b " size"
-]
-[
-.BI \-B " total_size"
-]
-[
-.BI \-i " string"
-]
-[
-.BI \-N " num_batches"
-]
-[
-.BI \-p " process"
-]
-[
-.B \-r
-]
-[
-.BI \-s " separator"
-]
-[
-.BI \-S " alt_spool"
-]
-[
-.B \-v
-]
-.I host
-[
-.I input
-]
-.SH DESCRIPTION
-.I Batcher
-reads uses a list of files to prepare news batches for the specified
-.IR host .
-It is normally invoked by a script run out of
-.IR cron (8)
-that uses
-.IR shlock (1)
-to lock the host name, followed by a
-.IR ctlinnd (8)
-command to flush the batchfile.
-.PP
-.I Batcher
-reads the named
-.I input
-file, or standard input if no file is given.
-Relative pathnames are interpreted from the
-.I <pathoutgoing in inn.conf>
-directory.
-The input is taken as a sequence of lines;
-blank lines and lines starting with a number sign (``#'') are ignored.
-All other lines should consist of one or two fields separated by a single space.
-The first field is either the storage token of an article or the
-name of a file holding an article; if it is not an an absolute
-pathname or storage token, it is taken relative to
-.IR <patharticles\ in\ inn.conf> .
-The second field, if present, specifies the size of the article in bytes.
-.SH OPTIONS
-.TP
-.B \-S alt_spool
-The ``\-S'' flag may be used to specify an alternate spool directory to
-use if the article is not found; this would perhaps be an NFS-mounted
-spool directory of a master server with longer expiration times.
-.TP
-.B \-r
-By default, the program reports errors to
-.IR <pathlog\ in\ inn.conf>/errlog .
-To suppress this redirection and report errors to standard error,
-use the ``\-r'' flag.
-.TP
-.B \-v
-Upon exit,
-.I batcher
-reports statistics via
-.IR syslog (3).
-If the ``\-v'' flag is used, they will also be printed on the standard
-output.
-.TP
-.B \-b size
-.I Batcher
-collects the text of the named articles into batches.
-To limit the size of each batch, use the ``\-b'' flag.
-The default size is 60 kilobytes.
-Using ``\-b\ 0'' allows unlimited batch sizes.
-.TP
-.B \-a arts
-To limit the number of articles in each batch, use the ``\-a'' flag.
-The default is no limit.
-A new batch will be started when either the byte count or number of
-articles written exceeds the specified limits.
-.TP
-.B \-B total_size
-To limit the total number of bytes written for all batches, use the ``\-B''
-flag.
-.TP
-.B \-A total_arts
-To limit the total number of articles that can be batched use the ``\-A''
-flag.
-.TP
-.B \-N num_batches
-To limit the total number of batches that should be created use the ``\-N''
-flag.
-.IP
-In all three of the above cases, the default is zero, that is, no limit.
-.TP
-.B \-i string
-A batch starts with an identifying line to specify the unpacking method
-to be used on the receiving end.
-When the ``\-i'' flag is used, the initial string,
-.IR string ,
-followed by a newline, will be output at the start of every batch.
-The default is to have no initial string.
-.TP
-.B \-s separator
-Each article starts with a separator line to indicate the size of the article.
-To specify the separator use the ``\-s'' flag.
-This is a
-.IR sprintf (3)
-format string which can have a single ``%ld'' parameter which will be given
-the size of the article.
-If the separator is not empty, then the string and a newline will be output
-before every article.
-The default separator is ``#!\ rnews\ %ld''.
-.TP
-.B \-p process
-By default, batches are written to standard output, which
-is not useful when more than one output batch is created.
-Use the ``\-p'' flag to specify the shell command that should be
-created (via
-.IR popen (3))
-whenever a new batch is started.
-The process is a
-.IR sprintf (3)
-format string which can have a single ``%s'' parameter which will be given
-the host name.
-A common value is:
-.PP
-.RS
-.nf
-( echo '#! cunbatch' ; exec compress ) | uux \- \-r \-z %s!rnews
-.fi
-.RE
-.SH EXIT STATUS
-.PP
-If the input is exhausted,
-.I batcher
-will exit with a zero status.
-If any of the limits specified with the ``\-B'', ``\-A'', or ``\-N'' flags
-is reached, or if there is an error writing the batch, then
-.I batcher
-will try to spool the remaining input, copying it to a file.
-If there was no input filename, standard input will be copied to
-.I <pathoutgoing in inn.conf>/host
-and the program will exit.
-If an input filename was given, the input will be copied to
-a temporary file named
-.IR input .bch
-(if
-.I input
-is an absolute pathname)
-or
-.I <pathoutgoing in inn.conf>/input.bch
-(if the filename does not begin with a slash).
-Once the input is copied,
-.I batcher
-will try to rename this temporary file to be the name of the input file,
-and then exit.
-.PP
-Upon receipt of an interrupt or termination signal,
-.I batcher
-will finish sending the current article, close the batch, and then
-rewrite the batchfile according as described in the previous paragraph.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: batcher.8 6491 2003-10-18 05:56:37Z rra $
-.SH "SEE ALSO"
-ctlinnd(8),
-inn.conf(5),
-newsfeeds(5),
-shlock(1).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH BUFFCHAN 8
-.SH NAME
-buffchan \- buffered file-writing backend for InterNetNews
-.SH SYNOPSIS
-.B buffchan
-[
-.B \-b
-]
-[
-.BI \-c " lines"
-]
-[
-.BI \-C " seconds"
-]
-[
-.BI \-d " directory"
-]
-[
-.BI \-f " num_fields"
-]
-[
-.BI \-m " map"
-]
-[
-.BI \-p " pidfile"
-]
-[
-.BI \-l " lines"
-]
-[
-.BI \-L " seconds"
-]
-[
-.B \-r
-]
-[
-.BI \-s " filename_format"
-]
-[
-.B \-u
-]
-.SH DESCRIPTION
-.I Buffchan
-reads lines from standard input and copies certain fields in
-each line into files named by other fields within the line.
-.I Buffchan
-is intended to be called by
-.IR innd (8)
-as an exploder feed.
-.SH OPTIONS
-.TP
-.B \-b
-Once
-.I buffchan
-opens a file it keeps it open.
-The input must therefore never specify more files than the
-number of available descriptors can keep open.
-If the ``\fB\-b\fP'' flag is used, the program will allocate a buffer and
-attach it to the file using
-.IR setbuf (3).
-.TP
-.B \-c lines
-If the ``\fB\-c\fP'' flag is used,
-.I buffchan
-will close, and re-open, a file after every
-.I lines
-lines are written to a file.
-.TP
-.B \-C seconds
-Similarly, the ``\fB\-C\fP'' flag may be used to specify that all files should
-be closed and re-opened every
-.I seconds
-seconds.
-.TP
-.B \-d directory
-The ``\fB\-d\fP'' flag may be used to specify a directory the program should
-change to before starting.
-If this flag is used, then the default for the ``\fB\-s\fP'' flag is changed to
-be a simple ``%s''.
-.TP
-.B \-f num_fields
-Buffchan
-input is interpreted as a sequence of lines.
-Each line contains a fixed number of initial fields, followed by a
-variable number of filename fields.
-All fields in a line are separated by whitespace.
-The default number of initial fields is one; the ``\fB\-f\fP''
-flag may be
-used to specify a different number of fields.
-.TP
-.B \-m map
-Map files specify short names as aliases for domain names; see
-.IR filechan (8)
-for details and an example.
-.TP
-.B \-p pidfile
-If the ``\fB\-p\fP'' flag is used, the program will write a line containing
-its process ID (in text) to the specified file.
-.TP
-.B \-l lines
-If the ``\fB\-l\fP'' flag is used,
-.I buffchan
-will call
-.IR fflush (3)
-after every
-.I lines
-lines are written to a file.
-.TP
-.B \-L seconds
-If the ``\fB\-L\fP'' flag is used,
-all files will be flushed every
-.I n
-seconds.
-.TP
-.B \-r
-By default, the program sends its error messages to
-.IR <pathlog\ in\ inn.conf>/errlog .
-To suppress this redirection and send error messages to standard error,
-use the ``\fB\-r\fP'' flag.
-.TP
-.B \-s filename_format
-After the initial fields, each remaining field names a file to
-write.
-The ``\fB\-s\fP'' flag may be used to specify a format string that maps
-the field to a file name.
-This is a
-.IR sprintf (3)
-format string which should have a single ``%s'' parameter which will be given
-the contents of a non-initial field.
-The default value is
-.IR <pathoutgoing\ in\ inn.conf>/%s .
-See the description of this flag in
-.IR filechan (8).
-.TP
-.B \-u
-If the ``\fB\-u\fP'' flag is used, the program will request unbuffered output.
-.PP
-.I Buffchan
-can be invoked as an exploder feed (see
-.IR newsfeeds (5)).
-As such, if a line starts with an exclamation point it will be treated
-as a command.
-There are three commands, described below:
-.TP
-.B flush
-The ``flush'' command closes and re-opens
-all open files; ``flush\ xxx'' which flushes only the specified site.
-These are analogous to the
-.IR ctlinnd (8)
-\&``flush'' command,
-and can be achieved by doing a ``send\ "flush\ xxx"'' command.
-Applications can tell that the ``flush'' has completed by renaming the
-file before issuing the command;
-.I buffchan
-has completed the command when the original filename re-appears.
-If
-.I <$ac_cv_func_fchmod in config.cache>
-is ``yes'', then
-.I buffchan
-also changes the access permissions of the file from read-only for
-everyone to read-write for owner and group as it flushes or closes each
-output file. It will change the modes back to read-only if it re-opens
-the same file.
-.TP
-.B drop
-The ``drop'' command is similar to the ``flush'' command except that no
-files are re-opened.
-If given an argument, then the specified site is dropped, otherwise all
-sites are dropped.
-(Note that the site will be restarted if the input stream mentions the
-site.)
-When a
-.I ctlinnd
-\&``drop site'' command is sent,
-.I innd
-will automatically forward the command to
-.I buffchan
-for sites listed as funnels feeding into this exploder.
-To drop all sites, use the
-.I ctlinnd
-\&``send buffchan-site drop'' command.
-.TP
-.B readmap
-The map file (specified with the ``\-m'' flag) is reloaded.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: buffchan.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-ctlinnd(8),
-filechan(8),
-inn.conf(5),
-innd(8),
-newsfeeds(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH BUFFINDEXED.CONF 5
-.SH NAME
-buffindexed.conf \- configuration file for buffindexed ovmethod
-.SH DESCRIPTION
-The file
-.I <pathetc in inn.conf>/buffindexed.conf
-is required if buffindexed ovmethod is used.
-.PP
-Buffindexed is one of ovmethod which is specified in
-.IR inn.conf .
-It uses preconfigured buffer files to store overview data and index, and
-never needs more disk space other than those files. The files are divided
-into 8 KB blocks internally; a given block is allocated for either overview
-index or overview data. A block is never shared among multiple newsgroups.
-There is a database file:
-.I <pathdb in inn.conf>/group.index
-that includes information about each newsgroup: the pointer to the index
-block for the group, high mark, low mark, flag of the group, the number of
-articles, and etc. This file is created automatically when all buffers
-are initialized and must not be edited manually. If all buffers are filled up,
-.IR innd (8)
-throttles itself. Note that the buffer files are never rolled over and
-overwritten the way CNFS does. You need to append another buffer file in
-this event. You can see the buffer usage with
-.IR inndf (8)
-with ``-o'' option.
-.PP
-The file consists of a series of lines;
-blank lines and lines beginning with a number sign (``#'') are ignored.
-There is only one kind of configuration line.
-The order of lines in this file is not important.
-.PP
-.RS
-.nf
-index:file_name:buffer_size
-.fi
-.RE
-.PP
-\&``Index'' is an index of overview buffer.
-\&``Index'' must be between 0 and 65535.
-\&``File_name'' is the path to overview buffer file.
-The length of this path should be not more than 63 characters.
-\&``Buffer_size'' is the length of buffer file in kilobytes
-in decimal (1 KB = 1024 bytes). If the ``file_name'' is not a special
-device, the actual file size must be buffer_size * 1024 bytes.
-You can NOT use buffers over 2 GB even if you specify
-.IR <\-\-with\-largefiles\ at\ configure> ,
-or buffers will be broken. It'll be fixed in the future.
-.PP
-When creating new overview buffer, there are two different methods for
-creating the files.
-.TP
-.BR 1. " Create a big file on top of a standard filesystem."
-.sp 1
-Use "dd" to create the overview buffer
-files, such as "dd if=/dev/zero of=/path/to/ovbuff bs=1024 count=N"
-where N is the buffer_size.
-.TP
-.BR 2. " Use block disk devices directly."
-.sp 1
-If your operating system will allow you to
-.I mmap()
-block disk devices (Solaris does, FreeBSD does not), this is the
-recommended method. But note that Solaris (at least 2.6) seems to
-have a problem in regional locking of block disk devices, and should
-not be used as overview data will be corrupted.
-.sp 1
-Partition the disks to make each partition slightly larger (a few MB larger)
-than the intended size of each overview buffer.
-It is not recommend to use the block device files already located in
-``/dev''; instead, use "mknod" to create a new set of block device files.
-In order to do this, do an "ls -Ll" of the /dev/dsk partition.
-The major and minor device numbers are in the fifth and sixth columns (right
-before the date), respectively. This information should be fed to "mknod"
-to make a "block-type special file" (b).
-Here is a short script that accomplishes this when fed the name of the
-partition as listed in ``/dev/dsk/'':
-.sp 1
-.nf
-.in +0.5i
-#!/bin/sh
-disk=$1
-major=`ls -l /dev/dsk/$disk | awk '{print $5}' | tr -d ,`
-minor=`ls -l /dev/dsk/$disk | awk '{print $6}`
-mkdir /ovbuff
-mknod /ovbuff/$disk b $major $minor
-.in -0.5i
-.fi
-.sp 1
-The created device files themselves consume very little space.
-.PP
-In either case, make certain that each overview buffer file is owned by
-.IR <USER\ specified\ with\ \-\-with\-news\-user\ at\ configure> ,
-.IR <GROUP\ specified\ with\ \-\-with\-news\-group\ at\ configure> ,
-and has read/write modes for the owner and group (mode ``0664'' or ``0660'').
-.PP
-When you first start
-.IR innd (8)
-and everything is configured properly, you should see messages in
-.I <pathlog in inn.conf>/news.notice
-which look like:
-.sp 1
-.nf
-.in +0.5i
-Aug 27 00:00:00 kevlar innd: buffindexed: No magic cookie found for buffindexed 0, initializing
-.in -0.5i
-.fi
-.PP
-You MUST entirely recreate overview if you remove or relpace buffers.
-You need not recreate if you just append new buffers. And whenever you
-recreate the overview data base, you need to clean all the buffers.
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: buffindexed.conf.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "CKPASSWD 8"
-.TH CKPASSWD 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ckpasswd \- nnrpd password authenticator
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBckpasswd\fR [\fB\-gs\fR] [\fB\-d\fR \fIdatabase\fR] [\fB\-f\fR \fIfilename\fR]
-[\fB\-u\fR \fIusername\fR \fB\-p\fR \fIpassword\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBckpasswd\fR is the basic password authenticator for nnrpd, suitable for
-being run from an auth stanza in \fIreaders.conf\fR. See \fIreaders.conf\fR\|(5) for
-more information on how to configure an nnrpd authenticator.
-.PP
-\&\fBckpasswd\fR accepts a username and password from nnrpd and tells \fInnrpd\fR\|(8)
-whether that's the correct password for that username. By default, when
-given no arguments, it tries to check the password using \s-1PAM\s0 if support
-for \s-1PAM\s0 was found when \s-1INN\s0 was built. Failing that, it tries to check the
-password against the password field returned by \fIgetpwnam\fR\|(3). Note that
-these days most systems no longer make real passwords available via
-\&\fIgetpwnam\fR\|(3) (some still do if and only if the program calling \fIgetpwnam\fR\|(3)
-is running as root).
-.PP
-When using \s-1PAM\s0, \fBckpasswd\fR identifies itself as \f(CW\*(C`nnrpd\*(C'\fR, not as
-\&\f(CW\*(C`ckpasswd\*(C'\fR, and the \s-1PAM\s0 configuration must be set up accordingly. The
-details of \s-1PAM\s0 configuration are different on different operating systems
-(and even different Linux distributions); see \s-1EXAMPLES\s0 below for help
-getting started, and look for a \fIpam\fR\|(7) or \fIpam.conf\fR\|(4) manual page on your
-system.
-.PP
-When using any method other than \s-1PAM\s0, \fBckpasswd\fR expects all passwords to
-be stored encrypted by the system \fIcrypt\fR\|(3) function and calls \fIcrypt\fR\|(3) on
-the supplied password before comparing it to the expected password. \s-1IF\s0
-you're using a different password hash scheme (like \s-1MD5\s0), you must use
-\&\s-1PAM\s0.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-d\fR \fIdatabase\fR" 4
-.IX Item "-d database"
-Read passwords from a database (ndbm or dbm format depending on what your
-system has) rather than by using \fIgetpwnam\fR\|(3). \fBckpasswd\fR expects
-\&\fIdatabase\fR.dir and \fIdatabase\fR.pag to exist and to be a database keyed by
-username with the encrypted passwords as the values.
-.Sp
-While \s-1INN\s0 doesn't come with a program intended specifically to create such
-databases, on most systems it's fairly easy to write a Perl script to do
-so. Something like:
-.Sp
-.Vb 16
-\& #!/usr/bin/perl
-\& use NDBM_File;
-\& use Fcntl;
-\& tie (%db, 'NDBM_File', '/path/to/database', O_RDWR|O_CREAT, 0640)
-\& or die "Cannot open /path/to/database: $!\en";
-\& $| = 1;
-\& print "Username: ";
-\& my $user = <STDIN>;
-\& chomp $user;
-\& print "Password: ";
-\& my $passwd = <STDIN>;
-\& chomp $passwd;
-\& my @alphabet = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
-\& my $salt = join '', @alphabet[rand 64, rand 64];
-\& $db{$user} = crypt ($passwd, $salt);
-\& untie %db;
-.Ve
-.Sp
-Note that this will echo back the password when typed; there are obvious
-improvements that could be made to this, but it should be a reasonable
-start. Sometimes a program like this will be available with the name
-\&\fBdbmpasswd\fR.
-.Sp
-This option will not be available on systems without dbm or ndbm
-libraries.
-.IP "\fB\-f\fR \fIfilename\fR" 4
-.IX Item "-f filename"
-Read passwords from the given file rather than using \fIgetpwnam\fR\|(3). The
-file is expected to be formatted like a system password file, at least
-vaguely. That means each line should look something like:
-.Sp
-.Vb 1
-\& username:pdIh9NCNslkq6
-.Ve
-.Sp
-(and each line may have an additional colon after the encrypted password
-and additional data; that data will be ignored by \fBckpasswd\fR). Lines
-starting with a number sign (`#') are ignored. \s-1INN\s0 does not come with a
-utility to create the encrypted passwords, but \fBhtpasswd\fR (which comes
-with Apache) can do so and it's a quick job with Perl (see the example
-script under \fB\-d\fR). If using Apache's \fBhtpasswd\fR program, be sure to
-give it the \fB\-d\fR option so that it will use \fIcrypt\fR\|(3).
-.IP "\fB\-g\fR" 4
-.IX Item "-g"
-Attempt to look up system group corresponding to username and return a
-string like \*(L"user@group\*(R" to be matched against in \fIreaders.conf\fR. This
-option is incompatible with the \fB\-d\fR and \fB\-f\fR options.
-.IP "\fB\-p\fR \fIpassword\fR" 4
-.IX Item "-p password"
-Use \fIpassword\fR as the password for authentication rather than reading a
-password using the nnrpd authenticator protocol. This option is useful
-only for testing your authentication system (particularly since it
-involves putting a password on the command line), and does not work when
-\&\fBckpasswd\fR is run by \fBnnrpd\fR. If this option is given, \fB\-u\fR must also
-be given.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-Check passwords against the result of \fIgetspnam\fR\|(3) instead of \fIgetpwnam\fR\|(3).
-This function, on those systems that supports it, reads from /etc/shadow
-or similar more restricted files. If you want to check passwords supplied
-to \fInnrpd\fR\|(8) against system account passwords, you will probably have to
-use this option on most systems.
-.Sp
-Most systems require special privileges to call \fIgetspnam\fR\|(3), so in order
-to use this option you may need to make \fBckpasswd\fR setgid to some group
-(like group \*(L"shadow\*(R") or even setuid root. \fBckpasswd\fR has not been
-specifically audited for such uses! It is, however, a very small program
-that you should be able to check by hand for security.
-.Sp
-This configuration is not recommended if it can be avoided, for serious
-security reasons. See \*(L"\s-1SECURITY\s0 \s-1CONSIDERATIONS\s0\*(R" in readers.conf\&(5) for
-discussion.
-.IP "\fB\-u\fR \fIusername\fR" 4
-.IX Item "-u username"
-Authenticate as \fIusername\fR. This option is useful only for testing (so
-that you can test your authentication system easily) and does not work
-when \fBckpasswd\fR is run by \fBnnrpd\fR. If this option is given, \fB\-p\fR must
-also be given.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-See \fIreaders.conf\fR\|(5) for examples of \fInnrpd\fR\|(8) authentication configuration
-that uses \fBckpasswd\fR to check passwords.
-.PP
-An example \s-1PAM\s0 configuration for \fI/etc/pam.conf\fR that tells \fBckpasswd\fR
-to check usernames and passwords against system accounts is:
-.PP
-.Vb 2
-\& nnrpd auth required pam_unix.so
-\& nnrpd account required pam_unix.so
-.Ve
-.PP
-Your system may want you to instead create a file named \fInnrpd\fR in
-\&\fI/etc/pam.d\fR with lines like:
-.PP
-.Vb 2
-\& auth required pam_unix.so
-\& account required pam_unix.so
-.Ve
-.PP
-This is only the simplest configuration. You may be able to include
-common shared files, and you may want to stack other modules, either to
-allow different authentication methods or to apply restrictions like lists
-of users who can't authenticate using \fBckpasswd\fR. The best guide is the
-documentation for your system and the other \s-1PAM\s0 configurations you're
-already using.
-.PP
-To test to make sure that \fBckpasswd\fR is working correctly, you can run it
-manually and then give it the username (prefixed with \f(CW\*(C`ClientAuthname:\*(C'\fR)
-and password (prefixed with \f(CW\*(C`ClientPassword:\*(C'\fR) on standard input. For
-example:
-.PP
-.Vb 2
-\& (echo 'ClientAuthname: test' ; echo 'ClientPassword: testing') \e
-\& | ckpasswd \-f /path/to/passwd/file
-.Ve
-.PP
-will check a username of \f(CW\*(C`test\*(C'\fR and a password of \f(CW\*(C`testing\*(C'\fR against the
-username and passwords stored in \fI/path/to/passwd/file\fR. On success,
-\&\fBckpasswd\fR will print \f(CW\*(C`User:test\*(C'\fR and exit with status 0. On failure,
-it will print some sort of error message and exit a non-zero status.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: ckpasswd.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIreaders.conf\fR\|(5), \fInnrpd\fR\|(8)
-.PP
-Linux users who want to use \s-1PAM\s0 should read the Linux-PAM System
-Administrator's Guide at
-<http://www.kernel.org/pub/linux/libs/pam/Linux\-PAM\-html/Linux\-PAM_SAG.html>.
+++ /dev/null
-.\" $Revision: 6312 $
-.TH CLIENTLIB 3
-.SH NAME
-clientlib \- NNTP clientlib part of InterNetNews library
-.SH SYNOPSIS
-.nf
-.ta \w' unsigned long 'u
-.B "extern FILE *ser_rd_fp;"
-.B "extern FILE *ser_wr_fp;"
-.B "extern char ser_line[];"
-
-.B "char *"
-.B "getserverbyfile(file)"
-.B " char *file;"
-
-.B "int"
-.B "server_init(host)"
-.B " char *host;"
-
-.B "int"
-.B "handle_server_response(response, host)"
-.B " int reponse;"
-.B " char *host;"
-
-.B "void"
-.B "put_server(text)"
-.B " char *text;"
-
-.B "int"
-.B "get_server(buff, buffsize)"
-.B " char *buff;"
-.B " int buffsize;"
-
-.B "void"
-.B "close_server()"
-.fi
-.SH DESCRIPTION
-The routines described in this manual page are part of the InterNetNews
-library,
-.IR libinn (3).
-They are replacements for the ``clientlib'' part of the NNTP distribution,
-and are intended to be used in building programs like
-.IR rrn .
-.PP
-.I Getserverbyfile
-calls
-.I GetConfigValue
-to get the name of the local NNTP server.
-It returns a pointer to static space.
-The
-.I file
-parameter is ignored.
-.PP
-.I Server_init
-opens a connect to the NNTP server at the specified
-.IR host .
-It returns the server's response code or \-1 on error.
-If a connection was made, then
-.I ser_rd_fp
-and
-.I ser_wr_fp
-can be used to read from and write to the server, respectively, and
-.I ser_line
-will contain the server's response.
-.I Ser_line
-can also be used in other routines.
-.PP
-.I Handle_server_response
-decodes the
-.IR response ,
-which comes from the server on
-.IR host.
-If the client is authorized, it returns 0.
-A client that is only allowed to read is authorized, but
-.I handle_server_response
-will print a message on the standard output.
-If the client is not authorized to talk to the server, then a message is
-printed and the routine returns \-1.
-.PP
-.I Put_server
-sends the text in
-.I buff
-to the server, adding the necessary NNTP line terminators, and flushing
-the I/O buffer.
-.PP
-.I Get_server
-reads a line of text from the server into
-.IR buff ,
-reading at most
-.I buffsize
-characters.
-Any trailing \er\en terminators are stripped off.
-.I Get_server
-returns \-1 on error.
-.PP
-.I Close_server
-sends a ``quit'' command to the server and closes the connection.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: clientlib.3 6312 2003-05-04 21:40:11Z rra $
-.SH "SEE ALSO"
-libinn(3).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH CNFSHEADCONF 8
-.SH NAME
-cnfsheadconf \- set CNFS header
-.SH SYNOPSIS
-.B cnfsheadconf
-[
-.B \-c CLASS
-]
-[
-.B \-h
-]
-[
-.B \-w
-]
-.SH DESCRIPTION
-.I Cnfsheadconf
-reads
-.I <pathetc in inn.conf>/cycbuff.conf
-and
-.I <pathetc in inn.conf>/storage.conf
-to determine which cycbuffs are available, reads the specified cycbuff, and
-modifies the header as directed by the interactive user.
-.SH OPTIONS
-.TP
-.B \-c CLASS
-.I Cnfsheadconf
-prints status of (and modifies, if appropriate) the specified class.
-.TP
-.B \-h
-.I Cnfsheadconf
-prints usage information.
-.TP
-.B \-w
-.I Cnfsheadconf
-prompts for modifications to make to cycbuff header.
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: cnfsheadconf.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-cycbuff.conf(5),
-inn.conf(5),
-storage.conf(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH CNFSSTAT 8
-.SH NAME
-cnfsstat \- show usage of cycbuffs
-.SH SYNOPSIS
-.B cnfsstat
-[
-.B \-a
-]
-[
-.B \-c CLASS
-]
-[
-.B \-h
-]
-[
-.B \-l
-[
-seconds
-]
-]
-[
-.B \-m BUFFER
-]
-[
-.B \-P
-]
-[
-.B \-p
-]
-[
-.B \-s
-]
-.SH DESCRIPTION
-.I Cnfsstat
-reads
-.I <pathetc in inn.conf>/cycbuff.conf
-and
-.I <pathetc in inn.conf>/storage.conf
-to determine which cycbuffs are available, read the specified cycbuffs, and
-shows their usage status.
-.PP
-.I Cnfsstat
-can be invoked from
-.IR rc.news (8),
-if
-.I <docnfsstat in inn.conf>
-is ``true'', and the result is written to
-.IR syslog (3).
-.SH OPTIONS
-.TP
-.B \-a
-.I Cnfsstat
-prints also the age of the oldest article in the cycbuff.
-.TP
-.B \-c CLASS
-.I Cnfsstat
-prints information only for the specified class.
-.TP
-.B \-h
-.I Cnfsstat
-prints usage information.
-.TP
-.B \-l [ seconds ]
-.I Cnfsstat
-prints a status snapshot every
-.IR seconds ,
-and only exits if there is an error.
-The default interval is 600 seconds.
-.TP
-.B \-m BUFFER
-.I Cnfsstat
-prints information about the specified buffer in a format suitable
-for mrtg.
-.TP
-.B \-P
-.I Cnfsstat
-writes PID into
-.IR <pathrun\ in\ inn.conf>/cnfsstat.pid .
-.TP
-.B \-p
-.I Cnfsstat
-prints an mrtg config file.
-.TP
-.B \-s
-.I Cnfsstat
-writes output to
-.IR syslog (3)
-instead of standard output.
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: cnfsstat.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-cycbuff.conf(5),
-inn.conf(5),
-rc.news(8),
-storage.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "CONTROL.CTL 5"
-.TH CONTROL.CTL 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-control.ctl \- Specify handling of Usenet control messages
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fIcontrol.ctl\fR in \fIpathetc\fR is used to determine what action is taken
-when a control message is received. It is read by \fBcontrolchan\fR, which
-is normally invoked as a channel program by \fBinnd\fR. When \fIcontrol.ctl\fR
-is modified, \fBcontrolchan\fR notices this automatically and reloads it.
-.PP
-Blank lines and lines beginning with a number sign (\f(CW\*(C`#\*(C'\fR) are ignored.
-All other lines should consist of four fields separated by colons:
-.PP
-.Vb 1
-\& <type>:<from>:<newsgroups>:<action>
-.Ve
-.PP
-The first field, <type>, is the type of control message for which this
-line is valid. It should either be the name of a control message or the
-word \f(CW\*(C`all\*(C'\fR to indicate that it applies to all control messages.
-.PP
-The second field, <from>, is a shell-style pattern that matches the e\-mail
-address of the person posting the message (with the address first
-converted to lowercase). The matching is done with rules equivalent to
-those of the shell's \fIcase\fR statement; see \fIsh\fR\|(1) for more details.
-.PP
-If the control message is a newgroup or rmgroup, the third field,
-<newsgroups>, is a shell-style pattern matching the newsgroup affected by
-the control message. If the control message is a checkgroups, the third
-field is a shell-style pattern matching the newsgroups that should be
-processed for checking. If the control message is of any other type, the
-third field is ignored.
-.PP
-The fourth field, <action>, specifies what action to take with control
-messages that match this line. The following actions are understood:
-.IP "\fBdoit\fR" 4
-.IX Item "doit"
-The action requested by the control message should be performed. For
-checkgroups messages, this means that the shell commands that should
-be run will be mailed to the news administrator (the argument to
-\&\fB\-\-with\-news\-master\fR given at configure time, \f(CW\*(C`usenet\*(C'\fR by default); for
-other commands, this means that the change will be silently performed. If
-you always want notification of actions taken, use \f(CW\*(C`doit=mail\*(C'\fR instead (see
-below).
-.IP "\fBdoifarg\fR" 4
-.IX Item "doifarg"
-If the control message has an argument, this is equivalent to \fBdoit\fR. If
-it does not have an argument, this is equivalent to \fBmail\fR. This is only
-useful for entries for sendsys control messages, allowing a site to
-request its own \fInewsfeeds\fR entry by posting a \f(CW\*(C`sendsys mysite\*(C'\fR control
-message, but not allowing the entire \fInewsfeeds\fR file to be sent. This
-was intended to partially counter so-called \*(L"sendsys bombs,\*(R" where forged
-sendsys control messages were used to mailbomb people.
-.Sp
-Processing sendsys control messages is not recommended even with this
-work-around unless they are authenticated in some fashion. The risk of
-having news servers turned into anonymous mail bombing services is too
-high.
-.IP "\fBdoit\fR=\fIfile\fR" 4
-.IX Item "doit=file"
-The action is performed as in \fBdoit\fR, and additionally a log entry is
-written to the specified log file \fIfile\fR. If \fIfile\fR is the word
-\&\f(CW\*(C`mail\*(C'\fR, the log entry is mailed to the news administrator instead. An
-empty string is equivalent to \fI/dev/null\fR and says to log nothing.
-.Sp
-If \fIfile\fR starts with a slash, it is taken as the absolute filename to
-use for the log file. Otherwise, the filename is formed by prepending
-\&\fIpathlog\fR and a slash and appending \f(CW\*(C`.log\*(C'\fR. In other words, an action
-of \f(CW\*(C`doit=newgroup\*(C'\fR will log to \fIpathlog\fR/newgroup.log.
-.IP "\fBdrop\fR" 4
-.IX Item "drop"
-No action is taken and the message is ignored.
-.IP "\fBverify\-*\fR" 4
-.IX Item "verify-*"
-If the action starts with the string \f(CW\*(C`verify\-\*(C'\fR, as in:
-.Sp
-.Vb 1
-\& verify\-news.announce.newgroups
-.Ve
-.Sp
-then \s-1PGP\s0 verification of the control message will be done and the user \s-1ID\s0
-of the key of the authenticated signer will be checked against the
-expected identity defined by the rest of the string
-(\f(CW\*(C`news.announce.newgroups\*(C'\fR in the above example. This verification is
-done via \fBpgpverify\fR; see \fIpgpverify\fR\|(8) for more details.
-.Sp
-If no logging is specified (with =\fIfile\fR as mentioned below), logging will
-be done the same as with \fBdoit\fR as described above.
-.IP "\fBverify\-*\fR=\fBmail\fR" 4
-.IX Item "verify-*=mail"
-\&\s-1PGP\s0 verification is done as for the \fBverify\-*\fR action described above, and
-notification of successful newgroup and rmgroup control messages and the
-output of checkgroups messages will be mailed to the news administrator.
-(In the case of checkgroups messages, this means that the shell script that
-should be run will be mailed to the administrator.)
-.IP "\fBverify\-*\fR=\fIfile\fR" 4
-.IX Item "verify-*=file"
-\&\s-1PGP\s0 verification is done as for the \fBverify\-*\fR action described above,
-and a log entry is written to the specified file as described in
-\&\fBdoit\fR=\fIfile\fR above. (In the case of checkgroups messages, this means
-that the shell script output of the checkgroups message will be written to
-that file.)
-.IP "\fBlog\fR" 4
-.IX Item "log"
-A one-line log message is sent to standard error. \fBinnd\fR normally
-directs this to \fIpathlog\fR/errlog.
-.IP "\fBlog\fR=\fIfile\fR" 4
-.IX Item "log=file"
-A log entry is written to the specified log file, which is interpreted as
-in \fBdoit\fR=\fIfile\fR described above.
-.IP "\fBmail\fR" 4
-.IX Item "mail"
-A mail message is sent to the news administrator without taking any other
-action.
-.PP
-Processing of a checkgroups message will never actually change the
-\&\fIactive\fR file (the list of groups carried by the server). The difference
-between a \fBdoit\fR or \fBverify\fR action and a \fBmail\fR action for a
-checkgroups control message lies only in what e\-mail is sent; \fBdoit\fR or
-\&\fBverify\fR will mail the news administrator a shell script to create,
-delete, or modify newsgroups to match the checkgroups message, whereas
-\&\fBmail\fR will just mail the entire message. In either case, the news
-administrator will have to take action to implement the checkgroups
-message, and if that mail is ignored, nothing will be changed.
-.PP
-Lines are matched in order and the last matching line in the file will be
-used.
-.PP
-Use of the \fBverify\fR action for processing newgroup, rmgroup, and
-checkgroups messages is \s-1STRONGLY\s0 recommended. Abuse of control messages
-is rampant, and authentication via \s-1PGP\s0 signature is currently the only
-reliable way to be sure that a control message comes from who it claims to
-be from. Most major hierarchies are now issuing PGP-authenticated control
-messages.
-.PP
-In order to use \fBverify\fR actions, the \s-1PGP\s0 key ring of the news user must
-be populated with the \s-1PGP\s0 keys of the hierarchy maintainers whose control
-messages you want to honor. For more details on PGP-authenticated control
-messages and the \s-1URL\s0 for downloading the \s-1PGP\s0 keys of major hierarchies,
-see \fIpgpverify\fR\|(8).
-.PP
-Control messages of type cancel are handled internally by \fBinnd\fR and
-cannot be affected by any of the mechanisms described here.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-With the following three lines in \fIcontrol.ctl\fR:
-.PP
-.Vb 3
-\& newgroup:*:*:drop
-\& newgroup:group\-admin@isc.org:comp.*:verify\-news.announce.newgroups
-\& newgroup:kre@munnari.oz.au:aus.*:mail
-.Ve
-.PP
-a newgroup coming from \f(CW\*(C`group\-admin@isc.org\*(C'\fR will be honored if it is for
-a newsgroup in the comp.* hierarchy and if it has a valid signature
-corresponding to the \s-1PGP\s0 key with a user \s-1ID\s0 of \f(CW\*(C`news.announce.newgroups\*(C'\fR.
-If any newgroup claiming to be from \f(CW\*(C`kre@munnari.oz.au\*(C'\fR for a newsgroup
-in the aus.* hierarchy is received, it too will be honored. All other
-newgroup messages will be ignored.
-.SH "WARNINGS"
-.IX Header "WARNINGS"
-The third argument for a line affecting checkgroups does \fBnot\fR affect
-whether the line matches. It is only used after a matching line is found,
-to filter out which newsgroups listed in the checkgroups will be
-processed. This means that a line like:
-.PP
-.Vb 1
-\& checkgroups:*:*binaries*:drop
-.Ve
-.PP
-will cause \fBall\fR checkgroups control messages to be dropped unless they
-match a line after this one in \fIcontrol.ctl\fR, not just ignore newsgroups
-containing \f(CW\*(C`binaries\*(C'\fR in the name. The general rule is to never use \f(CW\*(C`*\*(C'\fR
-in the second field for a line matching checkgroups messages. There is
-unfortunately no way to do what the author of a line like the above
-probably intended to do (yet).
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: control.ctl.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIcontrolchan\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInewsfeeds\fR\|(5), \fIpgpverify\fR\|(8), \fIsh\fR\|(1).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH CONTROLCHAN 8
-.SH NAME
-controlchan \- channel\-fed control message handler
-.SH SYNOPSIS
-.B controlchan
-.SH DESCRIPTION
-.I Controlchan
-removes the responsibility for handling control messages
-(except cancels) from
-.IR innd (8)
-and instead processes them from a channel or file feed.
-To reduce load,
-.I controlchan
-keeps a copy of
-.I control.ctl
-in memory and checks permissions (including any required PGP headers) before any
-scripts are called. Also, the default (``bad message'') case is handled
-internally. The ``drop'' case is handled with far less fuss.
-.PP
-Normally,
-.I controlchan
-is invoked by
-.IR innd (8)
-as configured in
-.IR newsfeeds .
-An example entry is below. Make sure that you've created the newsgroup
-control.cancel so that
-.I controlchan
-doesn't have to scan through cancels, which it won't process anyway.
-.sp 1
-.in +0.5i
-.nf
-controlchan!\\
- :!*,control,control.*,!control.cancel\\
- :Tc,Wnsm\\
- :<pathbin in inn.conf>/controlchan
-.fi
-.in -0.5i
-.sp 1
-Note that in the (very, very unlikely) event that you need to process
-ihave/sendme control messages, be sure that
-.I logipaddr
-is set to false in
-.IR inn.conf ,
-because in this case controlchan needs a site name, not an IP address.
-.sp 1
-.I Controlchan
-tries to report all log messages through
-.IR syslog (3),
-unless connected to an interactive terminal. To enable
-.IR syslog (3)'ing
-for versions of Perl prior to 5.6.0,
-you will need to have run ``h2ph'' on your
-system include files at some point (this is required to
-make ``Sys::Syslog'' work). If you have not done so, do this:
-.sp 1
-.nf
-.in +0.5i
-cd /usr/include
-h2ph * sys/*
-.in -0.5i
-.fi
-.sp 1
-If you run FreeBSD, you will need to run the following in addition:
-.sp 1
-.nf
-.in +0.5i
-h2ph machine/*
-.in -0.5i
-.fi
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: controlchan.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-control.ctl(5),
-inn.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "CONVDATE 1"
-.TH CONVDATE 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-convdate \- Convert time/date strings and numbers
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBconvdate\fR [\fB\-dhl\fR] [\fB\-c\fR | \fB\-n\fR | \fB\-s\fR] [\fIdate\fR ...]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBconvdate\fR translates the date/time strings given on the command line,
-outputting the results one to a line. The input can either be a date in
-some format that \fIparsedate\fR\|(3) can parse or the number of seconds since
-epoch (if \fB\-c\fR is given). The output is either \fIctime\fR\|(3) results, the
-number of seconds since epoch, or a Usenet Date: header, depending on the
-options given.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-c\fR" 4
-.IX Item "-c"
-Each argument is taken to be the number of seconds since epoch (a time_t)
-rather than a date.
-.IP "\fB\-d\fR" 4
-.IX Item "-d"
-Output a valid Usenet Date: header instead of the results of \fIctime\fR\|(3) for
-each date given on the command line. This is useful for testing the
-algorithm used to generate Date: headers for local posts. Normally, the
-date will be in \s-1UTC\s0, but see the \fB\-l\fR option.
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Print usage information and exit.
-.IP "\fB\-l\fR" 4
-.IX Item "-l"
-Only makes sense in combination with \fB\-d\fR. If given, Date: headers
-generated will use the local time zone instead of \s-1UTC\s0.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-Rather than outputting the results of \fIctime\fR\|(3) or a Date: header, output
-each date given as the number of seconds since epoch (a time_t). This
-option doesn't make sense in combination with \fB\-d\fR.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-Pass each given date to \fIparsedate\fR\|(3) and print the results of \fIctime\fR\|(3) (or
-a Date: header if \fB\-d\fR is given). This is the default behavior.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Note that relative times or times with partial information use the current
-time to fill in the rest of the date, so dates like \*(L"12pm\*(R" are taken to be
-12pm of the day when convdate is run. This is a property of \fIparsedate\fR\|(3);
-see the man page for more information. Most of these examples are from
-the original man page dating from 1991 and were run in the \-0400 time
-zone.
-.PP
-.Vb 2
-\& % convdate 'feb 10 10am'
-\& Sun Feb 10 10:00:00 1991
-.Ve
-.PP
-.Vb 3
-\& % convdate 12pm 5/4/90
-\& Fri Dec 13 00:00:00 1991
-\& Fri May 4 00:00:00 1990
-.Ve
-.PP
-Note that 12pm and 5/4/90 are two *separate* arguments and therefore
-result in two results. Note also that a date with no time is taken to be
-at midnight.
-.PP
-.Vb 3
-\& % convdate \-n 'feb 10 10am' '12pm 5/4/90'
-\& 666198000
-\& 641880000
-.Ve
-.PP
-.Vb 2
-\& % convdate \-c 666198000
-\& Sun Feb 10 10:00:00 1991
-.Ve
-.PP
-\&\fIctime\fR\|(3) results are in the local time zone. Compare to:
-.PP
-.Vb 2
-\& % convdate \-dc 666198000
-\& Sun, 10 Feb 1991 15:00:00 +0000 (UTC)
-.Ve
-.PP
-.Vb 2
-\& % env TZ=PST8PDT convdate \-dlc 666198000
-\& Sun, 10 Feb 1991 07:00:00 \-0800 (PST)
-.Ve
-.PP
-.Vb 2
-\& % env TZ=EST5EDT convdate \-dlc 666198000
-\& Sun, 10 Feb 1991 10:00:00 \-0500 (EST)
-.Ve
-.PP
-The system library functions generally use the environment variable \s-1TZ\s0 to
-determine (or at least override) the local time zone.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net>, rewritten and updated by Russ
-Allbery <rra@stanford.edu> for the \fB\-d\fR and \fB\-l\fR flags.
-.PP
-$Id: convdate.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIparsedate\fR\|(3).
+++ /dev/null
-.\" $Revision: 7062 $
-.TH CTLINND 8
-.SH NAME
-ctlinnd \- control the InterNetNews daemon
-.SH SYNOPSIS
-.B ctlinnd
-[
-.B \-h
-]
-[
-.B \-s
-]
-[
-.BI \-t " timeout"
-]
-.I command
-[
-.I argument...
-]
-.SH DESCRIPTION
-.I Ctlinnd
-sends a message to the control channel of
-.IR innd (8),
-the InterNetNews server.
-.PP
-In the normal mode of behavior, the message is sent to the server, which
-then performs the requested action and sends back a reply with a text
-message and the exit code for
-.IR ctlinnd .
-If the server successfully performed the command,
-.I ctlinnd
-will exit with a status of zero and print the reply on standard output.
-If the server could not perform the command (for example, it was told to
-remove a newsgroup that does not exist), it will direct
-.I ctlinnd
-to exit with a status of one. (Note that
-.I ctlinnd
-need not always exit immediately, see the ``\fB-t\fP'' flag.)
-The ``shutdown'', ``xabort'', and ``xexec'' commands do not generate a
-reply (because once
-.I innd
-has successfully exited, it is too late to send a reply to
-.IR ctlinnd );
-after these commands,
-.I ctlinnd
-will always exit silently with a status of zero.
-.SH OPTIONS
-.TP
-.B \-s
-If the ``\fB\-s\fP'' flag is
-used, then no message will be printed if the command was successful.
-.TP
-.B \-t timeout
-The ``\fB\-t\fP'' flag can be used to specify how long to wait for the reply
-from the server (for commands other than ``shutdown'', ``xabort'', and
-``xexec'').
-The timeout value specifies the number of seconds to wait.
-A value of zero waits forever, and a value less
-than zero indicates that no reply is needed (that is, exit immediately
-with status zero).
-When waiting for a reply,
-.I ctlinnd
-will try every two minutes to see if the server is still running, so it
-is unlikely that ``\fB\-t0\fP'' will hang.
-The default is set as
-.I <CTLINND_TIMEOUT in include/config.h>
-(typically
-.IR 0 ).
-.TP
-.B \-h
-To see a command summary, use the ``\fB\-h\fP'' flag.
-If a command is included when
-.I ctlinnd
-is invoked with the ``\fB\-h\fP'' flag, then only the usage for that command
-will be given.
-.PP
-The complete list of commands follows.
-Note that all commands have a fixed number of arguments.
-If a parameter can be an empty string, then it is necessary to
-specify it as two adjacent quotes, like "".
-.TP
-.BI addhist " <Message-ID> arr exp post token"
-Add an entry to the history database.
-This directs the server to create a history line for
-.IR Message-ID .
-The angle brackets are optional.
-.IR Arr ,
-.IR exp ,
-and
-.I post
-specify when the article arrived, what its expiration date is, and
-when it was posted.
-All three values are numbers indicating the number of seconds since the
-epoch.
-.I Exp
-being zero indicates the article does not have an Expires header.
-.I Token
-is the storage API token indicating where the article is stored.
-If the server is throttled manually, this command causes it to briefly
-open the history database.
-If the server is paused or throttled for any other reason, this command
-is rejected.
-.TP
-.BI allow " reason"
-Remote connections are allowed.
-The
-.I reason
-must be the same text given with an earlier ``reject'' command, or an
-empty string.
-.TP
-.BI begin " site"
-Begin feeding
-.IR site .
-This will cause the server to rescan the
-.I newsfeeds
-file to find the specified site and set up a newsfeed for it.
-If the site already exists, a ``drop'' is done first.
-This command is forwarded; see NOTES below.
-.TP
-.BI cancel " <Message-ID>"
-Remove the article with the specified Message-ID from the local system.
-This does
-.I not
-generate a cancel message.
-The angle brackets are optional.
-If the server is throttled manually, this command causes it to briefly
-open the history database.
-If the server is paused or throttled for any other reason, this command
-is rejected.
-.TP
-.BI changegroup " group rest"
-The newsgroup
-.I group
-is changed so that its fourth field in the
-.I active
-file becomes the value specified by the
-.I rest
-parameter.
-This may be used to make an existing group moderated or unmoderated,
-for example.
-This command can only be used while the server is running (not throttled),
-unlike
-.B newgroup
-or
-.BR rmgroup .
-.TP
-.B checkfile
-Check the syntax of the
-.I newsfeeds
-file, and display a message if any errors are found.
-The details of the errors are reported to
-.IR syslog (3).
-.TP
-.BI drop " site"
-Flush and drop
-.I site
-from the server's list of active feeds.
-This command is forwarded; see NOTES below.
-.TP
-.BI feedinfo " site"
-Print detailed information about the state of the
-feed to
-.I site
-or more brief status of all feeds if
-.I site
-is an empty string.
-.TP
-.BI flush " site"
-Flush the buffer for the specified site.
-The actions taken depend on the type of feed the site receives; see
-.IR newsfeeds (5).
-This is useful when the site is fed by a file and batching is about to start.
-If
-.I site
-is an empty string, then all sites are flushed and the
-.I active
-file and history databases are also written out.
-This command is forwarded; see NOTES below.
-.TP
-.B flushlogs
-Close the log and error log files and rename them to have a
-.I \&.old
-extension.
-The history database and
-.I active
-file are also written out.
-.TP
-.BI go " reason"
-Re-open the history database and start accepting articles after a ``pause''
-or ``throttle'' command.
-The
-.I reason
-must either be an empty string or match the text that was given
-in the earlier ``pause'' or ``throttle'' command.
-If a ``reject'' command was done, this will also do an ``allow'' command
-if the
-.I reason
-matches the text that was given in the ``reject.''
-If a ``reserve'' command was done, this will also clear the reservation if
-the
-.I reason
-matches the text that was given in the ``reserve.''
-Note that if only the history database has changed while the server is
-paused or throttled, it is not necessary to send it a ``reload'' command
-before sending it a ``go'' command.
-If the server throttled itself because it accumulated too many I/O
-errors, this command will reset the error count.
-If the server was not started with the ``\fB\-ny\fP'' flag, then this command also
-does a ``readers'' command with ``yes'' as the flag and
-.I reason
-as the text.
-.TP
-.BI hangup " channel"
-Close the socket on the specified incoming channel.
-This is useful when an incoming connection appears to be hung.
-.TP
-.BI help " [command]"
-Print a command summary for all commands, or just
-.I command
-if specified.
-.TP
-.BI kill " signal site"
-Signal
-.I signal
-is sent to the specified
-.IR site ,
-which must be a channel or exploder feed.
-.I Signal
-can be a numeric signal number or the word ``hup'', ``int'', or ``term'';
-case is not significant.
-.TP
-.BI lowmark " file"
-Reset the lowmarks in the
-.I active
-file based on the contents of the given
-file. Each line in the file must be of the form:
-.IP
-.RS
-.nf
- group low-value
-.fi
-.RE
-.IP
-for example
-.IP
-.RS
-.nf
- comp.lang.c++ 243
-.fi
-.RE
-.TP
-.BI logmode
-Cause the server to log its current operating mode to
-.IR syslog .
-.TP
-.BI mode
-Print the server's operating mode as a multi-line summary of the parameters
-and operating state.
-.TP
-.BI name " nnn"
-Print the name and relevant information of channel number
-.IR nnn ,
-or of all channels if it is an empty string. The response is formatted as:
-.sp 1
-.in +0.5i
-.nf
-f1:f2:f3:f4:f5
-.fi
-.in -0.5i
-.sp 1
-Where the meanings of the fields are:
-.sp 1
-.in +0.5i
-.nf
-f1 name of this channel
-f2 channel number
-f3 channel type
-f4 idle time for this channel (nntp type)
- or process id (process type)
-f5 channel status (nntp type)
-.fi
-.in -0.5i
-.sp 1
-The channel type (f3) is one of following:
-.sp 1
-.in +0.5i
-.nf
-control control channel which is used
- for ctlinnd
-file file channel which is used for
- file feed
-localconn local channel which is used for
- nnrpd or rnews
-nntp nntp channel which is used for
- current remote connection
-proc process channel which is used
- for process feed
-remconn remote channel which will be
- used for nntp
-.fi
-.in -0.5i
-.sp 1
-Channel status indicates whether the channel is paused or not. Nothing is
-shown unless the channel is paused, in which case ``paused'' is shown.
-A channel is paused if the number of remote connection for that label in
-.I incoming.conf
-is beyond ``max-connections'' within ``hold-time'' seconds of connection.
-.TP
-.BI newgroup " group rest creator"
-Create the specified newsgroup.
-The
-.I rest
-parameter should be the fourth field as described in
-.IR active (5);
-if it is not an equal sign, only the first letter is used.
-The
-.I creator
-should be the identity of the person creating the group as described in
-.IR active (5).
-If the newsgroup already exists, this is equivalent to the ``changegroup''
-command.
-This is the only command that has defaults.
-The
-.I creator
-can be omitted and will default to the newsmaster (as specified at configure
-time, ``usenet'' by default), and the
-.I rest
-parameter can be omitted and will default to ``y''.
-This command can only be done while the server is throttled manually
-or running; it will
-update its internal state when a ``go'' command is sent.
-This command updates the
-.I active.times
-file (see
-.IR active.times (5)).
-This command is forwarded; see NOTES below.
-.TP
-.BI param " letter value"
-Change the command-line parameters of the server.
-The combination of defaults make it possible to use the text of the Control
-header directly.
-.I Letter
-is the
-.I innd
-command-line option to set, and
-.I value
-is the new value.
-For example, ``i 5'' directs the server to allow only five incoming
-connections.
-To enable or disable the action of the ``\fB\-n\fP'' flag, use the letter ``y''
-or ``n'', respectively, for the
-.IR value .
-.TP
-.BI pause " reason"
-Pause the server so that no incoming articles are accepted.
-No existing connections are closed, but the history database is closed.
-This command should be used for short-term locks, such as when replacing
-the history files.
-If the server was not started with the ``\fB\-ny\fP'' flag, then this command also
-does a ``readers'' command with ``no'' as the flag and
-.I reason
-as the text.
-.TP
-.BI perl " flag"
-Enable or disable perl news filtering, if
-.IR <\-\-with\-perl\ is\ specified\ at\ configure> .
-If
-.I flag
-starts with the letter ``y'' then filtering is enabled. If it starts with
-``n'', then filtering is disabled.
-.TP
-.BI python " flag"
-Enable or disable Python news filtering, if
-.IR <\-\-with\-python\ is\ specified\ at\ configure> .
-If
-.I flag
-starts with the letter ``y'' then filtering is enabled. If it starts with
-``n'', then filtering is disabled.
-.TP
-.BI readers " flag text"
-Allow or disallow newsreaders.
-If
-.I flag
-starts with the letter ``n'' then newsreading is disallowed, by
-causing the server to pass the
-.I text
-as the value of the
-.IR nnrpd (8)
-\&`\fB`\-r\fP'' flag.
-If
-.I flag
-starts with the letter ``y'' and
-.I text
-is either an empty string, or the same string that was used when newsreading
-was disallowed, then newsreading will be allowed.
-.\".TP
-.\".BI refile " path group"
-.\"The article specified by
-.\".I path
-.\"is refiled as if it were posted to the newsgroup
-.\".IR group .
-.TP
-.BI reject " reason"
-Remote connections (those that would not be handed off to
-.IR nnrpd )
-are rejected, with
-.I reason
-given as the explanation.
-.TP
-.BI reload " what reason"
-The server updates its in-memory copies of various configuration files.
-.I What
-identifies what should be reloaded.
-The
-.I reason
-is reported to
-.IR syslog .
-.sp 1
-There is no way to reload the
-.I inn.conf
-file; use
-.I "ctlinnd xexec innd"
-instead.
-.sp 1
-If
-.I what
-is an empty string or the word ``all'' then everything is reloaded;
-if it is the word ``history'' then the history database is closed and opened,
-if it is the word ``incoming.conf'' then the
-.I incoming.conf
-file is reloaded; if it is the word ``active'' or ``newsfeeds'' then both
-the
-.I active
-and
-.I newsfeeds
-files are reloaded; if it is the word ``overview.fmt'' then the
-.I overview.fmt
-file is reloaded.
-.sp 1
-If
-.I <\-\-with\-perl is specified at configure>
-and it is the word ``filter.perl'' then the
-.IR filter_innd.pl
-file is reloaded. If a Perl procedure named ``filter_before_reload'' exists,
-it will be called prior to rereading
-.IR filter_innd.pl .
-If a Perl procedure named ``filter_after_reload'' exists, it will be called
-after
-.IR filter_innd.pl .
-has been reloaded. Reloading the Perl filter does not enable filtering if
-it is disabled; use
-.I perl y
-to do this. The
-.I startup_innd.pl
-file cannot be reloaded.
-.sp 1
-If
-.I <\-\-with\-python is specified at configure>
-and it is the word ``filter.python'' then the
-.I filter_innd.py
-file is reloaded. If a Python method named ``filter_before_reload'' exists,
-it will be called prior to rereading
-.IR filter_innd.py .
-If a Python method named ``__init__'' exists, it will be called
-after
-.IR filter_innd.py .
-has been reloaded. Reloading the Python filter does not enable filtering if
-it is disabled; use
-.I python y
-to do this.
-If
-.I <\-\-with\-tcl is specified at configure>
-and it is the word ``filter.tcl'' then the
-.I filter.tcl
-file is reloaded. If a TCL procedure named ``filter_before_reload'' exists,
-it will be called prior to rereading
-.IR filter.tcl.
-If a TCL procedure named ``filter_after_reload'' exists, it will be called
-after
-.I filter.tcl
-has been reloaded. Reloading the Tcl filter does not enable filtering if
-it is disabled; use
-.IR filter
-to do this.
-The
-.I startup.tcl
-file cannot be reloaded.
-.TP
-.BI renumber " group"
-Scan overview database for the specified newsgroup and update the
-low-water mark and hi-water mark in the
-.I active
-file. Regardless of the content of the overview database, the hi-water
-mark will not be decreased (decreasing it may cause duplicate article
-numbers to be assigned after a crash, which can cause serious problems
-with the tradspool storage method).
-If
-.I group
-is an empty string then all newsgroups are scanned.
-Renumber only works if overview data has been created.
-(See the description of ``enableoverview'' in
-.IR inn.conf (5)
-for details about overview creation.)
-.TP
-.BI renumberlow " file"
-This command does same as ``lowmark'' command.
-.TP
-.BI reserve " reason"
-The next ``pause'' or ``throttle'' command must use
-.I reason
-as its reason.
-This ``reservation'' is cleared by giving an empty string for the
-.IR reason .
-This command is used by programs like
-.IR expire (8)
-that want to avoid running into other instances of each other.
-.TP
-.BI rmgroup " group"
-Remove the specified newsgroup.
-This is done by editing the
-.I active
-file.
-The spool directory is not touched, and any articles in the group will
-still be expired using the default expiration parameters.
-Unlike the ``newgroup'' command, this command does not update the
-.I active.times
-file.
-This command can be done while the server is only throttled manually or running.
-This command is forwarded; see NOTES below.
-.TP
-.BI send " feed text..."
-The specified
-.I text
-is sent as a control line to the exploder
-.IR feed .
-.TP
-.BI shutdown " reason"
-The server is shut down, with the specified reason recorded in the log
-and sent to all open connections.
-.sp 1
-It is a good idea to send a ``throttle'' command first.
-.sp 1
-If Perl, Python, or TCL filtering is compiled in and enabled, certain
-functions are called at ``throttle'' or ``shutdown'' (for example, to
-save filter state to disk), consult the embedded filter documentation
-for details.
-.TP
-.BI stathist " off|filename"
-Enable or disable generation of history performance statistics. If the
-parameter is ``off'', no statistics are gathered. Otherwise statistics
-are written to the specified file. The file can be parsed by
-.IR contrib/stathist.pl .
-.TP
-.BI status " off|interval"
-Adjust frequency in seconds at which
-.I innd
-reports status informatoin to syslog. Status reporting is turned off if
-``off'' or ``0'' is specified. See ``status'' in
-.IR inn.conf (5)
-for information on how to set the startup default.
-.TP
-.BI tcl " flag"
-Enable or disable Tcl news filtering, if
-.IR <\-\-with\-tcl\ is\ specified\ at\ configure> .
-If
-.I flag
-starts with the letter ``y'' then filtering is enabled. If it starts with
-``n'', then filtering is disabled.
-.TP
-.BI throttle " reason"
-Input is throttled so that all existing connections are closed and new
-connections are rejected.
-The history database is closed.
-This should be used for long-term locks, such as when
-.I expire
-is being run.
-If the server was not started with the ``\-ny'' flag, then this command also
-does a ``readers'' command with ``no'' as the flag and
-.I reason
-as the text.
-.TP
-.BI timer " off|interval"
-Performance monitoring is turned off if ``off'' or ``0'' is specified,
-otherwise, statistics will be reported every
-.I interval
-seconds to syslog. See ``timer'' in
-.IR inn.conf (5)
-for information on how to set the startup default.
-.TP
-.BI trace " item flag"
-Tracing is turned on or off for the specified
-.IR item .
-.I Flag
-should start with the letter ``y'' or ``n'' to turn tracing on or off.
-If
-.I item
-starts with a number, then tracing is set for the specified
-.I innd
-channel, which must be for an incoming NNTP feed.
-If it starts with the letter ``i'' then general
-.I innd
-tracing is turned on or off.
-If it starts with the letter ``n'' then future
-.IR nnrpd 's
-will or will not have the ``\-t'' flag enabled, as appropriate.
-The ``n'' flag does not affect
-.IR nnrpd 's
-already running or using ``-D'' (running as a daemon).
-.TP
-.BI xabort " reason"
-The server logs the specified
-.I reason
-and then invokes the
-.IR abort (3)
-routine.
-.TP
-.BI xexec " path"
-The server gets ready to shut itself down, but instead of exiting it
-.IR exec 's
-.I <pathbin in inn.conf>/inndstart
-with all of its original arguments except for ``\fB\-r\fP''.
-.I Path
-can be any of ``innd'', ``inndstart'', or an empty string, although all
-three valid parameters have exactly the same effect.
-Any other value is an error.
-.SH NOTES
-In addition to being acted upon within the server, certain commands can
-be forwarded to the appropriate child process.
-If the site receiving the command is an exploder (such as
-.IR buffchan (8)),
-or it is a funnel that feeds into an exploder, then the
-command can be forwarded.
-In this case, the server will send a command line to the exploder that
-consists of the
-.I ctlinnd
-command name.
-If the site funnels into an exploder that has an asterisk (``*'') in its ``W''
-flag (see
-.IR newsfeeds (5)),
-then the site name will be appended to the command; otherwise no argument
-is appended.
-.SH BUGS
-.I Ctlinnd
-uses the
-.IR inndcomm (3)
-library, and is therefore limited to server replies no larger than 4k.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: ctlinnd.8 7062 2004-12-19 21:41:05Z rra $
-.SH "SEE ALSO"
-active(5),
-active.times(5),
-expire(8),
-innd(8),
-inndcomm(3),
-inn.conf(5),
-newsfeeds(5),
-overview.fmt(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH CVTBATCH 8
-.SH NAME
-cvtbatch \- convert Usenet batch file to INN format
-.SH SYNOPSIS
-.I cvtbatch
-[
-.BI \-w " items"
-]
-.SH DESCRIPTION
-.I Cvtbatch
-reads standard input as a sequence of lines, converts each line, and
-writes it to standard output.
-It is used to convert simple batchfiles that contain just the article
-name to INN batchfiles that contain additional information about each
-article.
-.PP
-Each line is taken as a storage API token indicating a Usenet article.
-(Only the first word of each line is parsed; anything following
-whitespace is ignored. Lines not starting with a valid token are also
-silently ignored.)
-.PP
-If the input file consists of a series of Message-ID's, then use
-.IR grephistory (1)
-with the `\fB`\-s\fP'' flag piped into
-.IR cvtbatch .
-.SH OPTIONS
-.TP
-.B \-w
-The `\fB`\-w\fP'' flag specifies how each output line should be written.
-The items for this flag should be chosen from the ``W'' flag items as
-specified in
-.IR newsfeeds (5).
-They may be chosen from the following set:
-.PP
-.RS
-.nf
- b Size of article in bytes
- f full pathname of article
- m article message-id
- n relative pathname of article
-.fi
-.RE
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: cvtbatch.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-grephistory(1),
-inn.conf(5),
-newsfeeds(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "CYCBUFF.CONF 5"
-.TH CYCBUFF.CONF 5 "2008-06-07" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-cycbuff.conf \- Configuration file for INN CNFS storage method
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This file defines the cyclical buffers that make up the storage pools for
-\&\s-1CNFS\s0 (Cyclic News File System). Some options controlling the behavior of
-the \s-1CNFS\s0 storage system can also be set here. \fIcycbuff.conf\fR is required
-if the \s-1CNFS\s0 (Cyclic News File System) storage method is used. \s-1INN\s0 will
-look for it in \fIpathetc\fR (as set in \fIinn.conf\fR).
-.PP
-For information about how to configure \s-1INN\s0 to use \s-1CNFS\s0, see
-\&\fIstorage.conf\fR\|(5).
-.PP
-Blank lines and lines beginning with a hash sign (\f(CW\*(C`#\*(C'\fR) are ignored. All
-other lines must be of one of the following forms:
-.PP
-.Vb 4
-\& cycbuffupdate:<interval>
-\& refreshinterval:<interval>
-\& cycbuff:<name>:<file>:<size>
-\& metacycbuff:<name>:<buffer>[,<buffer>,...][:<mode>]
-.Ve
-.PP
-(where items enclosed in [] are optional). Order is mostly not
-significant, but all \fIcycbuff\fR lines must occur before all \fImetacycbuff\fR
-lines. Long lines can be continued on the next line by ending the line
-with a backslash (\f(CW\*(C`\e\*(C'\fR).
-.IP "cycbuffupdate:<interval>" 4
-.IX Item "cycbuffupdate:<interval>"
-Sets the number of articles are written before the cycbuff header is
-written back to disk to <interval>. Under most operating systems, the
-header doesn't have to be written to disk for the updated data to be
-available to other processes on the same system that are reading articles
-out of \s-1CNFS\s0, but any accesses to the \s-1CNFS\s0 cycbuffs over \s-1NFS\s0 will only see
-the data present at the last write of the header. After a system crash,
-all updates since the last write of the \s-1CNFS\s0 header may be lost. The
-default value, if this line is omitted, is 25, meaning that the header is
-written to disk after every 25 articles stored in that cycbuff.
-.IP "refreshinterval:<interval>" 4
-.IX Item "refreshinterval:<interval>"
-Sets the interval (in seconds) between re-reads of the cycbuff header to
-<interval>. This primarily affects \fBnnrpd\fR and controls the frequency
-with which it updates its knowledge of the current contents of the \s-1CNFS\s0
-cycbuffs. The default value, if this line is omitted, is 30.
-.IP "cycbuff:<name>:<file>:<size>" 4
-.IX Item "cycbuff:<name>:<file>:<size>"
-Configures a particular \s-1CNFS\s0 cycbuff. <name> is a symbolic name for the
-buffer, to be used later in a metacycbuff line. It must be no longer than
-seven characters. <file> is the full path to the buffer file or block
-device, and must be no longer than 63 characters. <size> is the length of
-the buffer in kilobytes (1KB is 1024 bytes). If <file> is not a block
-device, it should be <size> * 1024 bytes long.
-.IP "metacycbuff:<name>:<buffer>[,<buffer>,...][:<mode>]" 4
-.IX Item "metacycbuff:<name>:<buffer>[,<buffer>,...][:<mode>]"
-Specifies a collection of \s-1CNFS\s0 buffers that make up a single logical
-storage location from the perspective of \s-1INN\s0. Metacycbuffs are referred
-to in \fIstorage.conf\fR as storage locations for articles, so in order to
-actually put articles in a cycbuff, it has to be listed as part of some
-metacycbuff which is then referenced in \fIstorage.conf\fR.
-.Sp
-<name> is the symbolic name of the metacycbuff, referred to in the options
-field of cnfs entries in \fIstorage.conf\fR. <buffer> is the name of a
-cycbuff (the <name> part of a cycbuff line), and any number of cycbuffs
-may be specified, separated by commas.
-.Sp
-If there is more than one cycbuff in a metacycbuff, there are two ways
-that \s-1INN\s0 can distribute articles between the cycbuffs. The default mode,
-\&\s-1INTERLEAVE\s0, stores the articles in each cycbuff in a round-robin fashion,
-one article per cycbuff in the order listed. If the cycbuffs are of
-wildly different sizes, this can cause some of them to roll over much
-faster than others, and it may not give the best performance depending on
-your disk layout. The other storage mode, \s-1SEQUENTIAL\s0, instead writes to
-each cycbuff in turn until that cycbuff is full and then moves on to the
-next one, returning to the first and starting a new cycle when the last
-one is full. To specify a mode rather than leaving it at the default, add
-a colon and the mode (\s-1INTERLEAVE\s0 or \s-1SEQUENTIAL\s0) at the end of the
-metacycbuff line.
-.PP
-\&\fBinnd\fR only reads \fIcycbuff.conf\fR on startup, so if you change anything
-in this file and want \fBinnd\fR to pick up the changes, you have to stop and
-restart it. \f(CW\*(C`ctlinnd reload all ''\*(C'\fR is not sufficient.
-.PP
-When articles are stored, the cycbuff into which they're stored is saved
-as part of the article token. In order for \s-1INN\s0 to retrieve articles from
-a cycbuff, that cycbuff must be listed in \fIcycbuff.conf\fR. However, if
-\&\s-1INN\s0 should not write to a cycbuff, it doesn't need to be (and shouldn't
-be) listed in a metacycbuff.
-.PP
-This provides an easy way to retire a cycbuff. Just remove it from its
-metacycbuff, leaving in the cycbuff line, and restart \fBinnd\fR (with, for
-example, \f(CW\*(C`ctlinnd xexec innd\*(C'\fR). No new articles will be put into the
-cycbuff, but neither will any articles expire from it. After you no
-longer need the articles in the cycbuff, just remove it entirely from
-\&\fIcycbuff.conf\fR. Then all of the articles will appear to have been
-deleted to \s-1INN\s0, and the next nightly expire run will clean up any
-remaining references to them.
-.PP
-Adding a new cycbuff just requires creating it (see below), adding a
-cycbuff line, adding it to a metacycbuff, and then restarting \fBinnd\fR.
-.SH "CREATING CYCBUFFS"
-.IX Header "CREATING CYCBUFFS"
-When creating a new cycbuff, there are two different methods for creating
-the buffers in which the articles will be stored.
-.IP "1." 4
-Create a large file on top of a regular file system. The easiest way to
-do this is probably with \fIdd\fR\|(1), using a command like:
-.Sp
-.Vb 1
-\& dd if=/dev/zero of=/path/to/cycbuff bs=1024 count=<size>
-.Ve
-.Sp
-where <size> is the size from the cycbuff line in \fIcycbuff.conf\fR.
-\&\fI\s-1INSTALL\s0\fR contains a script that will generate these commands for you
-from your \fIcycbuff.conf\fR file.
-.Sp
-This is the simplest method, but has the disadvantage that very large
-files on regular file systems can be fairly slow to access, particularly
-at the end of the file, and \s-1INN\s0 incurs unnecessary file system overhead
-when accessing the cycbuff.
-.IP "2." 4
-Use block devices directly. If your operating system allows you to call
-\&\fImmap()\fR on block devices (Solaris and recent versions of Linux do, FreeBSD
-at last report does not), this is the recommended method since you can
-avoid all of the native file system overhead. Note, however, that each
-cycbuff cannot be larger than 2GB with this method, so if you need a lot
-of spool space, you may have to go back to disk files.
-.Sp
-Partition the disk to make each partition equal to or smaller than 2GB.
-If you're using Solaris, set up your partitions to avoid the first
-cylinder of the disk (or otherwise the cycbuff header will overwrite the
-disk partition table and render the cycbuffs inaccessible). Then, create
-device files for each block device you're going to use.
-.Sp
-It's not recommended to use the block device files in \fI/dev\fR, since the
-news system doesn't have permission to write to them and changing the
-permissions of the system device files may affect something else.
-Instead, use \fImknod\fR\|(1) to create a new set of block devices (in somewhere
-like \fIpathspool\fR/cycbuffs that's only writable by the news user). To do
-this, run \f(CW\*(C`ls \-Ll\*(C'\fR on the devices in \fI/dev\fR that correspond to the block
-devices that you want to use. The major and minor device numbers are in
-the fifth and sixth columns (right before the date), respectively. Then
-run mknod like:
-.Sp
-.Vb 1
-\& mknod <file> b <major> <minor>
-.Ve
-.Sp
-where <file> is the path to the device to create (matching the <file> part
-of the cycbuff line) and <major> and <minor> are the major and minor
-device numbers as discovered above.
-.Sp
-Here's a short script to do this when given the path to the system device
-file as an argument:
-.Sp
-.Vb 8
-\& #!/bin/sh
-\& base=`echo "$1" | sed 's%.*/%%'`
-\& major=`ls \-Ll "$1" | awk '{print $5}' | tr \-d ,`
-\& minor=`ls \-Ll "$1" | awk '{print $6}`
-\& mkdir \-p /usr/local/news/spool/cycbuffs
-\& mknod /usr/local/news/spool/cycbuffs/"$base" b "$major" "$minor"
-\& chown news:news /usr/local/news/spool/cycbuffs/"$base"
-\& chmod 644 /usr/local/news/spool/cycbuffs/"$base"
-.Ve
-.Sp
-Make sure that the created files are owned by the news user and news
-group, as specified at configure time (the default being \f(CW\*(C`news\*(C'\fR for
-both). Also make sure that the permissions on the devices allow the news
-user to read and write, and if you want other users on the system to be
-able to use \fBsm\fR to retrieve articles, make sure they're world\-readable.
-.PP
-Once you have everything configured properly and you start \fBinnd\fR, you
-should see messages in \fInews.notice\fR that look like:
-.PP
-.Vb 1
-\& innd: CNFS\-sm No magic cookie found for cycbuff ONE, initializing
-.Ve
-.PP
-where \s-1ONE\s0 will be whatever you called your cycbuff.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-Rewritten into \s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: cycbuff.conf.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIctlinnd\fR\|(8), \fIinnd\fR\|(8), \fInnrpd\fR\|(8), \fIsm\fR\|(1), \fIstorage.conf\fR\|(5)
+++ /dev/null
-.TH DBZ 3 "6 Sep 1997"
-.BY "INN"
-.SH NAME
-dbzinit, dbzfresh, dbzagain, dbzclose, dbzexists, dbzfetch, dbzstore, dbzsync, dbzsize, dbzgetoptions, dbzsetoptions, dbzdebug \- database routines
-.SH SYNOPSIS
-.nf
-.B #include <dbz.h>
-.PP
-.B "bool dbzinit(const char *base)"
-.PP
-.B "bool dbzclose(void)"
-.PP
-.B "bool dbzfresh(const char *base, long size)"
-.PP
-.B "bool dbzagain(const char *base, const char *oldbase)"
-.PP
-.B "bool dbzexists(const HASH key)"
-.PP
-.B "off_t dbzfetch(const HASH key)"
-.B "bool dbzfetch(const HASH key, void *ivalue)"
-.PP
-.B "bool dbzstore(const HASH key, off_t offset)"
-.B "bool dbzstore(const HASH key, void *ivalue)"
-.PP
-.B "bool dbzsync(void)"
-.PP
-.B "long dbzsize(long nentries)"
-.PP
-.B "void dbzgetoptions(dbzoptions *opt)"
-.PP
-.B "void dbzsetoptions(const dbzoptions opt)"
-.PP
-.SH DESCRIPTION
-These functions provide an indexing system for rapid random access to a
-text file (the
-.I base
-.IR file ).
-.PP
-.I Dbz
-stores offsets into the base text file for rapid retrieval. All retrievals
-are keyed on a hash value that is generated by the
-.I HashMessageID()
-function.
-.PP
-.I Dbzinit
-opens a database,
-an index into the base file
-.IR base ,
-consisting of files
-.IB base .dir
-,
-.IB base .index
-, and
-.IB base .hash
-which must already exist.
-(If the database is new, they should be zero-length files.)
-Subsequent accesses go to that database until
-.I dbzclose
-is called to close the database.
-.PP
-.I Dbzfetch
-searches the database for the specified
-.IR key ,
-returning the corresponding
-.I value
-if any, if
-.I <\-\-enable\-tagged\-hash at configure>
-is specified. If
-.I <\-\-enable\-tagged\-hash at configure>
-is not specified, it returns true and content of
-.I ivalue
-is set.
-.I Dbzstore
-stores the
-.I key - value
-pair in the database, if
-.I <\-\-enable\-tagged\-hash at configure>
-is specified. If
-.I <\-\-enable\-tagged\-hash at configure>
-is not specified, it stores the content of
-.IR ivalue .
-.I Dbzstore
-will fail unless the database files are writable.
-.I Dbzexists
-will verify whether or not the given hash exists or not. Dbz is
-optimized for this operation and it may be significantly faster than
-.IR dbzfetch() .
-.PP
-.I Dbzfresh
-is a variant of
-.I dbzinit
-for creating a new database with more control over details.
-.PP
-.IR Dbzfresh 's
-.I size
-parameter specifies the size of the first hash table within the database,
-in key-value pairs.
-Performance will be best if the number of key-value pairs stored in the
-database does not exceed about 2/3 of
-.IR size .
-(The
-.I dbzsize
-function, given the expected number of key-value pairs,
-will suggest a database size that meets these criteria.)
-Assuming that an
-.I fseek
-offset is 4 bytes,
-the
-.B .index
-file will be
-.I 4 * size
-bytes. The
-.B .hash
-file will be
-.I DBZ_INTERNAL_HASH_SIZE * size
-bytes
-(the
-.B .dir
-file is tiny and roughly constant in size)
-until
-the number of key-value pairs exceeds about 80% of
-.IR size .
-(Nothing awful will happen if the database grows beyond 100% of
-.IR size ,
-but accesses will slow down quite a bit and the
-.B .index
-and
-.B .hash
-files will grow somewhat.)
-.PP
-.I Dbz
-stores up to
-.SM DBZ_INTERNAL_HASH_SIZE
-bytes of the message-id's hash in the
-.B .hash
-file to confirm a hit. This eliminates the need to read the base file to
-handle collisions. This replaces the tagmask feature in previous dbz
-releases.
-.PP
-A
-.I size
-of ``0''
-given to
-.I dbzfresh
-is synonymous with the local default;
-the normal default is suitable for tables of 5,000,000
-key-value pairs.
-Calling
-.I dbzinit(name)
-with the empty name is equivalent to calling
-.IR dbzfresh(name,\ 0) .
-.PP
-When databases are regenerated periodically, as in news,
-it is simplest to pick the parameters for a new database based on the old one.
-This also permits some memory of past sizes of the old database, so that
-a new database size can be chosen to cover expected fluctuations.
-.I Dbzagain
-is a variant of
-.I dbzinit
-for creating a new database as a new generation of an old database.
-The database files for
-.I oldbase
-must exist.
-.I Dbzagain
-is equivalent to calling
-.I dbzfresh
-with a
-.I size
-equal to the result of applying
-.I dbzsize
-to the largest number of entries in the
-.I oldbase
-database and its previous 10 generations.
-.PP
-When many accesses are being done by the same program,
-.I dbz
-is massively faster if its first hash table is in memory.
-If the ``pag_incore'' flag is set to INCORE_MEM,
-an attempt is made to read the table in when
-the database is opened, and
-.I dbzclose
-writes it out to disk again (if it was read successfully and
-has been modified).
-.I Dbzsetoptions
-can be used to set the
-.B pag_incore
-and
-.B exists_incore
-flag to new value which should be ``INCORE_NO'', ``INCORE_MEM'', or
-\&``INCORE_MMAP'' for the
-.B .hash
-and
-.B .index
-files separately; this does not affect the status of a database that has
-already been opened. The default is ``INCORE_NO'' for the
-.B .index
-file and ``INCORE_MMAP'' for the
-.B .hash
-file. The attempt to read the table in may fail due to memory shortage;
-in this case
-.I dbz
-fails with an error.
-.IR Store s
-to an in-memory database are not (in general) written out to the file
-until
-.IR dbzclose
-or
-.IR dbzsync ,
-so if robustness in the presence of crashes
-or concurrent accesses is crucial, in-memory databases
-should probably be avoided or the
-.B writethrough
-option should be set to ``true'';
-.PP
-If the
-.B nonblock
-option is ``true'', then writes to the
-.B .hash
-and
-.B .index
-files will be done using non-blocking I/O. This can be significantly faster if
-your platform supports non-blocking I/O with files.
-.PP
-.I Dbzsync
-causes all buffers etc. to be flushed out to the files.
-It is typically used as a precaution against crashes or concurrent accesses
-when a
-.IR dbz -using
-process will be running for a long time.
-It is a somewhat expensive operation,
-especially
-for an in-memory database.
-.PP
-Concurrent reading of databases is fairly safe,
-but there is no (inter)locking,
-so concurrent updating is not.
-.PP
-An open database occupies three
-.I stdio
-streams and two file descriptors;
-Memory consumption is negligible (except for
-.I stdio
-buffers) except for in-memory databases.
-.SH SEE ALSO
-dbm(3), history(5), libinn(3)
-.SH DIAGNOSTICS
-Functions returning
-.I bool
-values return ``true'' for success, ``false'' for failure.
-Functions returning
-.I off_t
-values return a value with
-.I \-1
-for failure.
-.I Dbzinit
-attempts to have
-.I errno
-set plausibly on return, but otherwise this is not guaranteed.
-An
-.I errno
-of
-.B EDOM
-from
-.I dbzinit
-indicates that the database did not appear to be in
-.I dbz
-format.
-.PP
-If
-.SM DBZTEST
-is defined at compile-time then a
-.I main()
-function will be included. This will do performance tests and integrity test.
-.SH HISTORY
-The original
-.I dbz
-was written by
-Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us).
-Later contributions by David Butler and Mark Moraes.
-Extensive reworking,
-including this documentation,
-by Henry Spencer (henry@zoo.toronto.edu) as
-part of the C News project.
-MD5 code borrowed from RSA. Extensive reworking to remove backwards
-compatibility and to add hashes into dbz files by Clayton O'Neill (coneill@oneill.net)
-.SH BUGS
-.PP
-Unlike
-.IR dbm ,
-.I dbz
-will refuse
-to
-.I dbzstore
-with a key already in the database.
-The user is responsible for avoiding this.
-.PP
-The RFC822 case mapper implements only a first approximation to the
-hideously-complex RFC822 case rules.
-.PP
-.I Dbz
-no longer tries to be call-compatible with
-.I dbm
-in any way.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "DISTRIB.PATS 5"
-.TH DISTRIB.PATS 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-distrib.pats \- Default values for the Distribution header
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpathetc\fR/distrib.pats is used by \fBnnrpd\fR to determine the
-default value of the Distribution header. Blank lines and lines beginning
-with a number sign (\f(CW\*(C`#\*(C'\fR) are ignored. All other lines consist of three
-fields separated by a colon:
-.PP
-.Vb 1
-\& <weight>:<pattern>:<value>
-.Ve
-.PP
-The first field is the weight to assign to this match. If a newsgroup
-matches multiple lines, the line with the highest weight is used. This
-should be an arbitrary integer greater than zero. The order of lines in
-the file is only important if groups have equal weight (in which case, the
-first matching line will be used).
-.PP
-The second field is either the name of a newsgroup or a \fIuwildmat\fR\|(3)\-style
-pattern to specify a set of newsgroups.
-.PP
-The third field is the value that should be used for the Distribution
-header of a posted article, if this line was picked as the best match and
-no Distribution header was supplied by the user. It can be an empty
-string, specifying that no Distribution header should be added.
-.PP
-When a post is received by \fBnnrpd\fR that does not already contain a
-Distribution header, each newsgroup to which an article is posted will be
-checked against this file in turn, and the matching line with the highest
-weight will be used as the value of the Distribution header. If no lines
-match, or if the matching line has an empty string for its third field, no
-header will be added.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Converted to
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: distrib.pats.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fInnrpd\fR\|(8), \fIuwildmat\fR\|(3)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "DOMAIN 8"
-.TH DOMAIN 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-domain \- nnrpd domain resolver
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBdomain\fR \fBdomainname\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This program can be used in \fIreaders.conf\fR to grant access based on the
-subdomain part of the remote hostname. In particular, it only returns
-success if the remote hostname ends in \fBdomainname\fR. (A leading dot on
-\&\fBdomainname\fR is optional; even without it, the argument must match on
-dot-separated boundaries). The \*(L"username\*(R" returned is whatever initial
-part of the remote hostname remains after \fBdomainname\fR is removed. It
-is an error if there is no initial part (that is, if the remote hostname
-is \fIexactly\fR the specified \fBdomainname\fR).
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-The following \fIreaders.conf\fR\|(5) fragment grants access to hosts with
-internal domain names:
-.PP
-.Vb 4
-\& auth internal {
-\& res: "domain .internal"
-\& default\-domain: "example.com"
-\& }
-.Ve
-.PP
-.Vb 4
-\& access internal {
-\& users: "*@example.com"
-\& newsgroups: example.*
-\& }
-.Ve
-.PP
-Access is granted to the example.* groups for all connections from hosts
-that resolve to hostnames ending in \f(CW\*(C`.internal\*(C'\fR; a connection from
-\&\*(L"foo.internal\*(R" would match access groups as \*(L"foo@example.com\*(R".
-.SH "BUGS"
-.IX Header "BUGS"
-It seems the code does not confirm that the matching part is actually at
-the end of the remote hostname (e.g., \*(L"domain: example.com\*(R" would match
-the remote host \*(L"foo.example.com.org\*(R" by ignoring the trailing \*(L".org\*(R"
-part).
-.PP
-Does this resolver actually provide any useful functionality not
-available by using wildcards in the \fIreaders.conf\fR\|(5) \fIhosts\fR parameter?
-If so, the example above should reflect this functionality.
-.SH "HISTORY"
-.IX Header "HISTORY"
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-.PP
-$Id: domain.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH EXPIRE 8
-.SH NAME
-expire \- Usenet article and history expiration program
-.SH SYNOPSIS
-.B expire
-[
-.BI \-d " dir"
-]
-[
-.BI \-f " file"
-]
-[
-.BI \-g " file"
-]
-[
-.BI \-h " file"
-]
-[
-.B \-i
-]
-[
-.B \-N
-]
-[
-.B \-n
-]
-[
-.B \-p
-]
-[
-.BI \-r " reason"
-]
-[
-.BI \-s " size"
-]
-[
-.B \-t
-]
-[
-.BI \-v " level"
-]
-[
-.BI \-w " number"
-]
-[
-.B \-x
-]
-[
-.BI \-z " file"
-]
-[
-.I expire.ctl
-]
-.SH DESCRIPTION
-.I Expire
-scans the
-.IR history (5)-format
-text file
-.I <pathdb in inn.conf>/history
-and uses the information recorded in it to purge itself of old news articles.
-Articles stored using a storage method that has self-expire
-functionality are by default not affected by
-.IR expire 's
-primary behavior (but see the ``\fB\-N\fP'' flag to disable this). In
-this case,
-.I expire.ctl
-is ignored except ``/remember/'' line for that article;
-.I expire
-does still probe to see if the article still exists and purges the
-relevant history and overview entries if appropriate.
-However, if ``groupbaseexpiry'' in
-.I inn.conf
-is true,
-.I expire
-acts on all articles as specified by
-.I expire.ctl
-regardless of whether their storage methods have self-expire
-functionality. In this case, the ``\fB\-e\fP'', \&``\fB\-k\fP'',
-``\fB\-N\fP'', ``\fB\-p\fP'', ``\fB\-q\fP'', ``\fB\-w\fP'' and
-``\fB\-z\fP'' flags are ignored.
-.PP
-Note that
-.I expire
-never purges articles which do not match any entry in
-.IR expire.ctl .
-.SH OPTIONS
-.TP
-.B \-d dir
-If the ``\fB\-d\fP'' flag is used, then the new history file and database is
-created in the specified directory,
-.IR dir .
-This is useful when the filesystem does not have sufficient space to
-hold both the old and new history files.
-When this flag is used,
-.I expire
-leaves the server paused and creates a zero-length file named after the
-new history file, with an extension of ``.done'' to indicate that
-it has successfully completed the expiration.
-The calling script should install the new history file and un-pause the server.
-The ``\fB\-r\fP'' flag should be used with this flag.
-.TP
-.B \-f file
-To specify an alternate history file, use the ``\fB\-f\fP'' flag.
-This flag is valid when used with the ``\fB\-d\fP'', and the output will
-be written to the specified file.
-The default without ``\fB\-f\fP'' flag is ``history''.
-.TP
-.B \-g file
-If the ``\fB\-g\fP'' flag is given, then a one-line summary equivalent to the
-output of ``\fB\-v\fP 1'', except preceded by the current time, will be
-appended to the specified
-.IR file .
-.TP
-.B \-h file
-To specify an alternate input text history file, use the ``\fB\-h\fP'' flag.
-.I Expire
-uses the old
-.IR dbz (3)
-database to determine the size of the new one.
-(If ``\fB\-d\fP'' flag is not used, the output filename will be the same
-as the input filename with an extension of ``.n''.)
-The default without ``\fB\-h\fP'' flag is
-.IR <pathdb\ in\ inn.conf>/history .
-.TP
-.B \-i
-To ignore the old database, use the ``\fB\-i\fP'' flag.
-.TP
-.B \-N
-The control file is normally ignored for articles in storage methods
-which have self-expire functionality.
-If the ``\fB\-N\fP'' flag is used,
-.I expire
-still uses the control file for these articles.
-.TP
-.B \-n
-If
-.I innd
-is not running, use the ``\fB\-n\fP'' flag and
-.I expire
-will not send the ``pause'' or ``go'' commands.
-(For more details on the commands, see
-.IR ctlinnd (8)).
-Note that
-.I expire
-only needs exclusive access for a very short time \(em long enough to see
-if any new articles arrived since it first hit the end of the file, and to
-rename the new files to the working files.
-.TP
-.B \-p
-.I Expire
-makes its decisions on the time the article arrived, as found in the
-.I history
-file.
-This means articles are often kept a little longer than with other
-expiration programs that base their decisions on the article's posting
-date.
-To use the article's posting date, use the ``\fB\-p\fP'' flag.
-.TP
-.B \-r reason
-.I Expire
-normally sends a ``pause'' command to the local
-.IR innd (8)
-daemon when it needs exclusive access to the history file, using
-the string ``Expiring'' as the reason.
-To give a different reason, use the ``\fB\-r\fP'' flag.
-The process ID will be appended to the reason.
-When
-.I expire
-is finished and the new history file is ready, it sends a ``go'' command.
-See also the ``\fB\-n\fP'' flag.
-.TP
-.B \-s size
-Optimize the new history database for approximately
-.I size
-pairs (lines in
-.IR history ).
-Accurately specifying the size will create a more efficient database.
-(The size should be the estimated eventual size of the file, typically
-the size of the old file.)
-.TP
-.B \-t
-If the ``\fB\-t\fP'' flag is used, then
-.I expire
-will generate a list of the tokens that should be removed on its
-standard output, and the new history file will be left in
-.IR history.n ,
-.IR history.n.dir ,
-.I history.n.index
-and
-.IR history.n.hash .
-This flag be useful for debugging when used with the ``\fB\-n\fP''
-flags. Note that if the ``\fB\-f\fP'' flag is used, then the
-name specified with that flag will be used instead of
-.IR history .
-.TP
-.B \-v level
-The ``\fB\-v\fP'' flag is used to increase the verbosity of the program,
-generating messages to standard output.
-The
-.I level
-should be a number, where higher numbers result in more output.
-Level one will print totals of the various actions done (not valid if a
-new history file is not written), level two will print a report on each
-individual file, while level five results in multiple lines of output
-for every history line processed.
-.TP
-.B \-w number
-Use the ``\fB\-w\fP'' flag to ``warp'' time so that
-.I expire
-thinks it is running at some time other then the current time.
-The value should be a signed floating point number indicating the number
-of days to use as the offset.
-.TP
-.B \-x
-If the ``\fB\-x\fP'' flag is used, then
-.I expire
-will not create any new history files. This is most useful when combined
-with the ``\fB\-n\fP'' and `\fB`\-t\fP'' flags to see how
-different expiration policies would change the amount of disk space used.
-.TP
-.B \-z file
-If the ``\fB\-z\fP'' flag is used, then articles are not removed, but their
-names are appended to the specified
-.IR file .
-See the description of
-.I delayrm
-in
-.IR news.daily (8).
-.PP
-If a filename is specified, it is taken as the control file and parsed
-according to the rules in
-.IR expire.ctl .
-A single dash (``\-'') may be used to read the file from standard input.
-If no file is specified, the file
-.I <pathetc in inn.conf>/expire.ctl
-is read.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: expire.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-ctlinnd(8),
-dbz(3),
-expire.ctl(5),
-history(5),
-inn.conf(5),
-innd(8),
-inndcomm(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "EXPIRE.CTL 5"
-.TH EXPIRE.CTL 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-expire.ctl \- Configuration file for article expiration
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpathetc\fR/expire.ctl is the default configuration file for
-\&\fBexpire\fR and \fBexpireover\fR, which read it at start\-up. It serves two
-purposes: it defines how long history entries for expired or rejected
-articles are remembered, and it determines how long articles stored on the
-server are retained.
-.PP
-Normally, if all of the storage methods used by the server are
-self-expiring (such as \s-1CNFS\s0), all lines except the \f(CW\*(C`/remember/\*(C'\fR setting
-(described below) are ignored. This can be changed with the \fB\-N\fR option
-to \fBexpire\fR or \fBexpireover\fR.
-.PP
-Black lines and lines beginning with a number sign (\f(CW\*(C`#\*(C'\fR) are ignored.
-All other lines should be in one of two formats. The order of the file is
-significant, and the last matching entry will be used.
-.PP
-The first format specifies how long to keep history entries for articles
-that aren't present in the news spool. These are articles that have
-either already expired, or articles which the server rejected (when
-\&\fIremembertrash\fR is set to true in \fIinn.conf\fR). There should be one and
-only one line in this format, which looks like:
-.PP
-.Vb 1
-\& /remember/:<days>
-.Ve
-.PP
-where <days> is a decimal number that specifies the minimum number of days
-a history record for a given message \s-1ID\s0 is retained, regardless of whether
-the article is present in the spool. (History entries for articles still
-present in the spool are always retained.)
-.PP
-The primary reason to retain a record of old articles is in case a peer
-offers old articles that were previously accepted but have already
-expired. Without a history record for such articles, the server would
-accept the article again and readers would see duplicate articles.
-Articles older than a certain number of days won't be accepted by the
-server at all (see \fIartcutoff\fR in \fIinn.conf\fR\|(5) and the \fB\-c\fR flag in
-\&\fIinnd\fR\|(8)), and this setting should probably match that time period (10 days
-by default) to ensure that the server never accepts duplicates.
-.PP
-Most of the lines in this file will be in the second format, which
-consists of either four or five colon-separated fields:
-.PP
-.Vb 1
-\& <pattern>:<flag>:<min>:<default>:<max>
-.Ve
-.PP
-if \fIgroupbaseexpiry\fR is true in \fIinn.conf\fR (the default), and otherwise:
-.PP
-.Vb 1
-\& <classnum>:<min>:<default>:<max>
-.Ve
-.PP
-All lines must be in the correct format given the current setting of
-\&\fIgroupbaseexpiry\fR, and therefore the two formats cannot co-exist in the
-same file.
-.PP
-Normally, a rule matches a newsgroup through the combination of the
-<pattern> and <flag> fields. <pattern> is a \fIuwildmat\fR\|(3)\-style pattern,
-specifying the newsgroups to which the line is applied. Note that the
-last matching entry will be used, so general patterns (such as defaults
-for all groups where <pattern> is \f(CW\*(C`*\*(C'\fR) should appear at the beginning of
-the file before more specific settings.
-.PP
-The <flag> field can be used to further limit newsgroups to which the line
-applies, and should be chosen from the following set:
-.PP
-.Vb 4
-\& M Only moderated groups
-\& U Only unmoderated groups
-\& A All groups
-\& X Remove the article from all groups it appears in
-.Ve
-.PP
-One of M, U, or A must be specified. X should be used in combination with
-one of the other letters, not by itself.
-.PP
-An expiration policy is applied to every article in a newsgroup it
-matches. There is no way to set an expiration policy for articles
-crossposted to groups you don't carry that's different than other articles
-in the same group. Normally, articles are not completely deleted until
-they expire out of every group to which they were posted, but if an
-article is expired following a rule where <flag> contains X, it is deleted
-out of all newsgroups to which it was posted immediately.
-.PP
-If \fIgroupbaseexpiry\fR is instead set to false, there is no <pattern> and
-<flag> field and the above does not apply. Instead, there is a single
-<classnum> field, which is either a number matching the storage class
-number specified in \fIstorage.conf\fR or \f(CW\*(C`*\*(C'\fR to specify a default for all
-storage classes. All articles stored in a storage class will be expired
-following the instructions in the line with a matching <classnum>, and
-when articles are expired, they're always removed from all groups to which
-they were posted.
-.PP
-The remaining three fields are the same in either format, and are used to
-determine how long an article should be kept. Each field should be either
-a decimal number of days (fractions like \f(CW8.5\fR are allowed, but remember
-that articles are only removed when \fBexpire\fR or \fBexpireover\fR is run,
-normally once a day by \fBnews.daily\fR) or the word \f(CW\*(C`never\*(C'\fR.
-.PP
-The middle field, <default>, will be used as the expiration period for
-most articles. The other two fields, <min> and <max>, only come into
-play if the article requests a particular expiration date with an Expires
-header. Articles with an Expires header will be expired at the date given
-in that header, subject to the constraints that they will be retained at
-least <min> days and no longer than <max> days.
-.PP
-If <min> is set to \f(CW\*(C`never\*(C'\fR, no article matching that line will ever be
-expired. If <default> is set to \f(CW\*(C`never\*(C'\fR, no article matching that line
-without an explicit Expires header will ever be expired. If <max> is
-set to \f(CW\*(C`never\*(C'\fR, Expires headers will be honored no matter how far into
-the future they are.
-.PP
-One should think of the fields as a lower bound, the default, and an upper
-bound. Since most articles do not have an Expires header, the second
-field is the most important and most commonly applied.
-.PP
-Articles that do not match any expiration rule will not be expired, but
-this is considered an error and will result in a warning. There should
-always be a default line (a line with a <pattern> of \f(CW\*(C`*\*(C'\fR and <flag> of
-\&\f(CW\*(C`A\*(C'\fR, or a line with a <classnum> of \f(CW\*(C`*\*(C'\fR), which can explicitly state
-that articles should never expire by default if that's the desired
-configuration. The default line should generally be the first line of the
-file (except for \f(CW\*(C`/remember/\*(C'\fR) so that other expiration rules can
-override it.
-.PP
-It is often useful to honor the Expires header in articles, especially
-those in moderated groups. To do this, set <min> to zero, <default> to
-whatever normal expiration you wish, and <max> to \f(CW\*(C`never\*(C'\fR or some large
-number, like 365 days for a maximum article life of a year.
-.PP
-To ignore any Expires header, set all three fields to the same value.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-When \fIgroupbaseexpiry\fR is true (the default):
-.PP
-.Vb 2
-\& # Keep expired article history for 10 days, matching artcutoff.
-\& /remember/:10
-.Ve
-.PP
-.Vb 2
-\& # Most articles stay for two weeks, ignoring Expires.
-\& *:A:14:14:14
-.Ve
-.PP
-.Vb 3
-\& # Accept Expires headers in moderated groups for up to a year and
-\& # retain moderated groups for a bit longer.
-\& *:M:1:30:365
-.Ve
-.PP
-.Vb 3
-\& # Keep local groups for a long time and local project groups forever.
-\& example.*:A:90:90:90
-\& example.project.*:A:never:never:never
-.Ve
-.PP
-When \fIgroupbaseexpiry\fR is false, for class-based expiration:
-.PP
-.Vb 2
-\& # Keep expired article history for 10 days, matching artcutoff.
-\& /remember/:10
-.Ve
-.PP
-.Vb 2
-\& # Set a default expiration of seven days.
-\& *:7:7:7
-.Ve
-.PP
-.Vb 2
-\& # Class 0 is retained for two weeks.
-\& 0:14:14:14
-.Ve
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Converted to
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: expire.ctl.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIexpire\fR\|(8), \fIexpireover\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInews.daily\fR\|(8),
-\&\fIstorage.conf\fR\|(5), \fIuwildmat\fR\|(3)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "EXPIREOVER 8"
-.TH EXPIREOVER 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-expireover \- Expire entries from the news overview database
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBexpireover\fR [\fB\-ekNpqs\fR] [\fB\-f\fR \fIfile\fR] [\fB\-w\fR \fIoffset\fR]
-[\fB\-z\fR \fIrmfile\fR] [\fB\-Z\fR \fIlowmarkfile\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBexpireover\fR expires old entries from the news overview database. It
-reads in a list of newsgroups (by default from \fIpathdb\fR/active, but a
-different file can be specified with the \fB\-f\fR option) and then removes
-from the overview database mentions of any articles that no longer exist
-in the news spool.
-.PP
-If \fIgroupbaseexpiry\fR in \fIinn.conf\fR is true, \fBexpireover\fR also removes
-old articles from the news spool according to the expiration rules in
-\&\fIexpire.ctl\fR. Otherwise it only removes overview entries for articles
-that have already been removed by some other process, and \fB\-e\fR, \fB\-k\fR,
-\&\fB\-N\fR, \fB\-p\fR, \fB\-q\fR, \fB\-w\fR, and \fB\-z\fR are all ignored.
-.PP
-When \fIgroupbaseexpiry\fR is set, the default behavior of \fBexpireover\fR is
-to remove the article from the spool once it expires out of all of the
-newsgroups to which it was crossposted. The article is, however, removed
-from the overview database of each newsgroup as soon as it expires out of
-that individual newsgroup. The effect is that an article crossposted to
-several groups will be removed from the overview database from each group
-one-by-one as its age passes the expiration threshold for that group as
-set in \fIexpire.ctl\fR, and then when it expires out of the last newsgroup,
-it will be deleted from the news spool.
-.PP
-Articles that are stored in self-expiring storage backends such as \s-1CNFS\s0
-are normally treated differently and not expired until they expire out of
-the backend regardless of \fIexpire.ctl\fR. See \fB\-N\fR, however.
-.PP
-By default, \fBexpireover\fR purges all overview information for newsgroups
-that have been removed from the server; this behavior is suppressed if
-\&\fB\-f\fR is given.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-e\fR" 4
-.IX Item "-e"
-Remove articles from the news spool and all overview databases as soon as
-they expire out of any newsgroup to which they are posted, rather than
-retain them until they expire out of all newsgroups. \fB\-e\fR and \fB\-k\fR
-cannot be used at the same time. This flag is ignored if
-\&\fIgroupbaseexpiry\fR is false.
-.IP "\fB\-f\fR \fIfile\fR" 4
-.IX Item "-f file"
-Use \fIfile\fR as the newsgroup list instead of \fIpathdb\fR/active. \fIfile\fR
-can be \f(CW\*(C`\-\*(C'\fR to indicate standard input. Using this flag suppresses the
-normal purge of all overview information from newsgroups that have been
-removed from the server.
-.IP "\fB\-k\fR" 4
-.IX Item "-k"
-Retain all overview information for an article, as well as the article
-itself, until it expires out of all newsgroups to which it was posted.
-This can cause articles to stick around in a newsgroup for longer than the
-\&\fIexpire.ctl\fR rules indicate, when they're crossposted. \fB\-e\fR and \fB\-k\fR
-cannot be used at the same time. This flag is ignored if
-\&\fIgroupbaseexpiry\fR is false.
-.IP "\fB\-N\fR" 4
-.IX Item "-N"
-Apply \fIexpire.ctl\fR rules to expire articles even from storage methods
-that have self-expire functionality. This may remove articles from
-self-expiring storage methods before the articles \*(L"naturally\*(R" expire.
-This flag is ignored if \fIgroupbaseexpiry\fR is false.
-.IP "\fB\-p\fR" 4
-.IX Item "-p"
-By default, \fBexpireover\fR bases decisions on whether to remove an article
-on the arrival time on the server. This means that articles may be kept a
-little longer than if the decision were based on the article's posting
-date. If this option is given, expiration decisions are based on the
-article posting date instead. This flag is ignored if \fIgroupbaseexpiry\fR
-is false.
-.IP "\fB\-q\fR" 4
-.IX Item "-q"
-\&\fBexpireover\fR normally prints statistics at the end of the expiration
-process. \fB\-q\fR suppresses this report. This flag is ignored if
-\&\fIgroupbaseexpiry\fR is false.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-\&\fBexpireover\fR normally only checks the existence of articles in the news
-spool if querying the storage method for that article to see if it still
-exists is considered \*(L"inexpensive.\*(R" To always check the existence of all
-articles regardless of how resource-intensive this may be, use the \fB\-s\fR
-flag. See \fIstorage.conf\fR\|(5) for more information about this metric.
-.IP "\fB\-w\fR \fIoffset\fR" 4
-.IX Item "-w offset"
-\&\*(L"Warps\*(R" time so that \fBexpireover\fR thinks that it's running at some time
-other than the current time. This is occasionally useful to force groups
-to be expired or not expired without changing \fIexpire.ctl\fR for the expire
-run. \fIoffset\fR should be a signed floating point number specifying the
-number of days difference from the current time to use as \*(L"now.\*(R" This
-flag is ignored if \fIgroupbaseexpiry\fR is false.
-.IP "\fB\-z\fR \fIrmfile\fR" 4
-.IX Item "-z rmfile"
-Don't remove articles immediately but instead write the path to the
-article or the token of the article to \fIrmfile\fR, which is suitable input
-for \fIfastrm\fR\|(1). This can substantially speed up deletion of expired
-articles for those storage methods where each article is a single file
-(such as tradspool and timehash). See the description of \fIdelayrm\fR in
-\&\fInews.daily\fR\|(8) for more details. This flag is ignored if
-\&\fIgroupbaseexpiry\fR is false.
-.IP "\fB\-Z\fR \fIlowmarkfile\fR" 4
-.IX Item "-Z lowmarkfile"
-Write the lowest article numbers for each newsgroup as it's expired to the
-specified file. This file is then suitable for \f(CW\*(C`ctlinnd lowmark\*(C'\fR. See
-\&\fIctlinnd\fR\|(8) for more information.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Normally \fBexpireover\fR is invoked from \fInews.daily\fR\|(8), which handles such
-things as processing the \fIrmfile\fR and \fIlowmarkfile\fR if necessary.
-Sometimes it's convenient to manually expire a particular newsgroup,
-however. This can be done with a command like:
-.PP
-.Vb 2
-\& echo example.test | expireover \-f \- \-Z /usr/local/news/tmp/lowmark
-\& ctlinnd lowmark /usr/local/news/tmp/lowmark
-.Ve
-.PP
-This can be particularly useful if a lot of articles in a particular group
-have expired but the overview information is still present, causing some
-clients to see a lot of \*(L"this article may have been cancelled\*(R" messages
-when they first enter the newsgroup.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rob Robertson <rob@violet.berkeley.edu> and Rich \f(CW$alz\fR
-<rsalz@uunet.uu.net> (with help from Dave Lawrence <tale@uunet.uu.net>)
-for InterNetNews.
-.PP
-$Id: expireover.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive\fR\|(5), \fIctlinnd\fR\|(8), \fIexpire\fR\|(8), \fIexpire.ctl\fR\|(5), \fIinn.conf\fR\|(5),
-\&\fInews.daily\fR\|(8).
+++ /dev/null
-.TH EXPIRERM 8
-.SH NAME
-expirerm \- remove articles that have been expired.
-.SH SYNOPSIS
-.B expirerm
-.I file
-.SH DESCRIPTION
-.I Expirerm
-is a script that removes a list of files.
-The specified
-.I file
-lists the files.
-It is sorted, and then fed into a pipeline responsible for doing
-the removal, normally
-.IR fastrm (8).
-If there seemed to be a problem removing the files, then mail is sent to
-the news administrator.
-If there were no problems, then
-.I file
-is renamed to
-.I <pathlog in inn.conf>/expire.list
-where it is kept (for safety) until the next time expiration is done.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and
-Rich $alz <rsalz@uunet.uu.net>
-.SH "SEE ALSO"
-expire(8),
-fastrm(8),
-inn.conf(5).
-
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "FASTRM 1"
-.TH FASTRM 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-fastrm \- Quickly remove a list of files
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBfastrm\fR [\fB\-de\fR] [\fB\-u\fR|\fB\-u\fR\fIN\fR] [\fB\-s\fR|\fB\-s\fR\fIM\fR] [\fB\-c\fR|\fB\-c\fR\fII\fR]
-\&\fIbase-directory\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBfastrm\fR reads a list of either file names or storage \s-1API\s0 tokens, one per
-line, from its standard input and removes them. Storage \s-1API\s0 tokens are
-removed via the \fISMcancel()\fR interface. \fBfastrm\fR does not delete files
-safely or with an eye to security, but rather cuts every corner it can to
-delete files as fast as it can. It should therefore never be run on
-publically writable directories, or in any other environment where a
-hostile party may control the directory structure in which it is working.
-.PP
-If a file name is not an absolute path name, it is considered to be
-relative to \fIbase-directory\fR as given on the command line. The
-\&\fIbase-directory\fR parameter must be a simple absolute pathname (it must
-not contain multiple consecutive slashes or references to the special
-directories \f(CW\*(C`.\*(C'\fR or \f(CW\*(C`..\*(C'\fR).
-.PP
-\&\fBfastrm\fR is designed to be faster than the typical \f(CW\*(C`| xargs rm\*(C'\fR pipeline
-when given a sorted list of file names as input. For example, \fBfastrm\fR
-will usually \fIchdir\fR\|(2) into a directory before removing files from it,
-meaning that if its input is sorted, most names passed to \fIunlink\fR\|(2) will
-be simple names. This can substantially reduce the operating system
-overhead from directory lookups.
-.PP
-\&\fBfastrm\fR assumes that its input is valid and that it is safe to call
-\&\fIunlink\fR\|(2) on every file name it is given. As a safety measure, however,
-\&\fBfastrm\fR when running as root will check with \fIstat\fR\|(2) that a file name
-doesn't specify a directory before removing it. (In some operating
-systems, root is allowed to unlink directories, even directories which
-aren't empty, which can cause file system corruption.)
-.PP
-The input to \fBfastrm\fR should always be sorted \*(-- or even better be in the
-order file names are output by \fIfind\fR\|(1) \*(-- if speed is an issue and the
-input isn't solely storage \s-1API\s0 tokens. (It deals fine with unsorted
-input, but is unlikely to be any faster in that case than a simple \f(CW\*(C`xargs
-rm\*(C'\fR command.) Sorting may even slightly speed up the removal of storage
-\&\s-1API\s0 tokens due to caching effects, since sorting will tend to keep all of
-the tokens from a particular storage method together.
-.PP
-Various additional optimizations for removing files can be turned on
-and/or tuned with options (see below). Which options will be most
-effective depends heavily on the underlying structure of the file system,
-the way in which directories are stored and searched, and similar, often
-underdocumented, operating system implementation details. The more
-sophisticated the underlying operating system and file system, the more
-likely that it will already perform the equivalent of these optimizations
-internally.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-d\fR" 4
-.IX Item "-d"
-Don't remove any files. Instead, print a list of the files that would be
-removed to standard output. Each line contains either the current
-directory of \fBfastrm\fR at the time it would do the unlink and the relative
-path name it would pass to \fIunlink\fR\|(2) as two fields separated by whitespace
-and a \f(CW\*(C`/\*(C'\fR, the absolute path name (as a single field) that would be
-passed to \fIunlink\fR\|(2), or the string \f(CW\*(C`Token\*(C'\fR and the storage \s-1API\s0 token that
-would be removed.
-.IP "\fB\-e\fR" 4
-.IX Item "-e"
-Treat an empty input file as an error. This is most useful when \fBfastrm\fR
-is last in a pipeline after a preceding \fIsort\fR\|(1) command, ensuring that
-\&\fBfastrm\fR will fail if the sort fails.
-.IP "\fB\-c\fR\fII\fR" 4
-.IX Item "-cI"
-Controls when \fBfastrm\fR calls \fIchdir\fR\|(2). If the number of files to be
-unlinked from a given directory is at least \fII\fR, then \fBfastrm\fR will
-change to that directory before unlinking those files. Otherwise, it will
-use either the absolute path names or a path name relative to the current
-directory (whichever is likely more efficient). The \fII\fR parameter is
-optional; if just \fB\-c\fR is given, \fB\-c1\fR is assumed, which will cause
-\&\fBfastrm\fR to always chdir before calling \fIunlink\fR\|(2). The default is
-\&\fB\-c3\fR. Use \fB\-c0\fR to prevent \fBfastrm\fR from ever using \fIchdir\fR\|(2).
-.IP "\fB\-s\fR\fIM\fR" 4
-.IX Item "-sM"
-When \fB\-s\fR is given and the number of files to remove in a directory is
-greater than \fIM\fR, rather than remove files in the order given, \fBfastrm\fR
-will open the directory and read it, unlinking files in the order that
-they appear in the directory. On systems with a per-process directory
-cache or that use a linear search to find files in a directory, this
-should make directory lookups faster. The \fIM\fR parameter is optional; if
-just \fB\-s\fR is given, \fB\-s5\fR is assumed.
-.Sp
-When this option is in effect, \fBfastrm\fR won't attempt to remove files
-that it doesn't see in the directory, possibly significantly speeding it
-up if most of the files to be removed have already been deleted. However,
-using this option requires \fBfastrm\fR to do more internal work and it also
-assumes that the order of directory listings is stable in the presence of
-calls to \fIunlink\fR\|(2) between calls to \fIreaddir\fR\|(3). This may be a dangerous
-assumption with some sophisticated file systems (and in general this
-option is only useful with file systems that use unindexed linear searches
-to find files in directories or when most of the files to be removed have
-already been deleted).
-.Sp
-This optimization is off by default.
-.IP "\fB\-u\fR\fIN\fR" 4
-.IX Item "-uN"
-Specifying this option promises that there are no symbolic links in the
-directory tree from which files are being removed. This allows \fBfastrm\fR
-to make an additional optimization to its calls to \fIchdir\fR\|(2), constructing
-a relative path using \f(CW\*(C`../..\*(C'\fR and the like to pass to \fIchdir\fR\|(2) rather
-than always using absolute paths. Since this reduces the number of
-directory lookups needed with deeply nested directory structures (such as
-that typically created by traditional news spool storage), it can be a
-significant optimization, but it breaks horribly in the presence of
-symbolic links to directories.
-.Sp
-When \fB\-u\fR is given, \fBfastrm\fR will use at most \fIN\fR levels of \f(CW\*(C`..\*(C'\fR
-segments to construct paths. \fIN\fR is optional; if just \fB\-u\fR is given,
-\&\fB\-u1\fR is assumed.
-.Sp
-This optimization is off by default.
-.PP
-\&\fBfastrm\fR also accepts \fB\-a\fR and \fB\-r\fR options, which do nothing at all
-except allow you to say \f(CW\*(C`fastrm \-usa\*(C'\fR, \f(CW\*(C`fastrm \-ussr\*(C'\fR, or \f(CW\*(C`fastrm
-\&\-user\*(C'\fR. These happen to often be convenient sets of options to use.
-.SH "EXIT STATUS"
-.IX Header "EXIT STATUS"
-\&\fBfastrm\fR exits with a status of zero if there were no problems, and an
-exit status of 1 if something went wrong. Attempting to remove a file
-that does not exist is not considered a problem.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-\&\fBfastrm\fR is typically invoked by \s-1INN\s0 via \fIexpirerm\fR\|(8) using a command
-like:
-.PP
-.Vb 1
-\& fastrm \-e /usr/local/news/spool/articles < expire.list
-.Ve
-.PP
-To enable all optimizations and see the affect on the order of removal
-caused by \fB\-s\fR, use:
-.PP
-.Vb 1
-\& fastrm \-d \-s \-e \-u ~news/spool/articles < expire.list
-.Ve
-.PP
-If your file system has indexed directory lookups, but you have a deeply
-nested directory structure, you may want to use a set of flags like:
-.PP
-.Vb 1
-\& fastrm \-e \-u3 ~news/spool/articles < expire.list
-.Ve
-.PP
-to strongly prefer relative paths but not to use \fIreaddir\fR\|(2) to order the
-calls to \fIunlink\fR\|(2).
-.PP
-You may want to edit \fIexpirerm\fR\|(8) to change the flags passed to \fBfastrm\fR.
-.SH "WARNINGS"
-.IX Header "WARNINGS"
-\&\fBfastrm\fR cuts corners and does not worry about security, so it does not
-use \fIchdir\fR\|(2) safely and could be tricked into removing files other than
-those that were intended if run on a specially constructed file tree or a
-file tree that is being modified while it is running. It should therefore
-never be used with world-writable directories or any other directory that
-might be controlled or modified by an attacker.
-.SH "NOTES"
-.IX Header "NOTES"
-\&\fBfastrm\fR defers opening the storage subsystem or attempting to parse any
-\&\s-1INN\s0 configuration files until it encounters a token in the list of files
-to remove. It's therefore possible to use \fBfastrm\fR outside of \s-1INN\s0 as a
-general fast file removal program.
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBfastrm\fR was originally written by kre@munnari.oz.au. This manual page
-rewritten in \s-1POD\s0 by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: fastrm.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIexpirerm\fR\|(8)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH FILECHAN 8
-.SH NAME
-filechan \- file-writing backend for InterNetNews
-.SH SYNOPSIS
-.B filechan
-[
-.BI \-d " directory"
-]
-[
-.BI \-f " num_fields"
-]
-[
-.BI \-m " mapfile"
-]
-[
-.BI \-p " pidfile"
-]
-.SH DESCRIPTION
-.I Filechan
-reads lines from standard input and copies certain fields in
-each line into files named by other fields within the line.
-.I Filechan
-is intended to be called by
-.IR innd (8)
-as a channel feed.
-(It is not a full exploder and does not accept commands; see
-.IR newsfeeds (5)
-for a description of the difference, and
-.IR buffchan (8)
-for an exploder program.)
-.PP
-.I Filechan
-input is interpreted as a sequence of lines.
-Each line contains a fixed number of initial fields, followed by a
-variable number of filename fields.
-All fields in a line are separated by whitespace.
-The default number of initial fields is one.
-.PP
-For each line of input,
-.I filechan
-writes the initial fields, separated by whitespace and followed by a
-newline, to each of the files named in the filename fields.
-When writing to a file,
-.I filechan
-opens it in append mode and tries to lock it and change the
-ownership to the user and group who owns the directory where the file is
-being written.
-.PP
-Because the time window in which a file is open is very small, complicated
-flushing and locking protocols are not needed; a
-.IR mv (1)
-followed by a
-.IR sleep (1)
-for a couple of seconds is sufficient.
-.SH OPTIONS
-.TP
-.B \-f num_fields
-The ``\fB\-f\fP'' flag may be
-used to specify a different number of initial fields.
-.TP
-.B \-d directory
-By default,
-.I filechan
-writes its output into the directory
-.IR <pathoutgoing\ in\ inn.conf> .
-The ``\fB\-d\fP'' flag may be used to specify a directory the program should
-change to before starting.
-.TP
-.B \-p pidfile
-If the ``\fB\-p\fP'' flag is used, the program will write a line containing
-its process ID (in text) to the specified file.
-.TP
-.B \-m mapfile
-A map file may be specified by using the ``\fB\-m\fP'' flag.
-Blank lines and lines starting with a number sign (``#'') are ignored.
-All other lines should have two host names separated by a colon.
-The first field is the name that may appear in the input stream;
-the second field names the file to be used when the name in the first
-field appears.
-For example, the following map file may be used to map the short
-names used in the example below to the full domain names:
-.PP
-.RS
-.nf
-# This is a comment
-uunet:news.uu.net
-foo:foo.com
-munnari:munnari.oz.au
-.fi
-.RE
-.SH EXAMPLES
-If
-.I filechan
-is invoked with ``\fB\-f 2\fP'' and given the following input:
-.PP
-.RS
-.nf
-news/software/b/132 <1643@munnari.oz.au> foo uunet
-news/software/b/133 <102060@litchi.foo.com> uunet munnari
-comp/sources/unix/2002 <999@news.foo.com> foo uunet munnari
-.fi
-.RE
-.PP
-Then the file
-.I foo
-will have these lines:
-.PP
-.RS
-.nf
-news/software/b/132 <1643@munnari.oz.au>
-comp/sources/unix/2002 <999@news.foo.com>
-.fi
-.RE
-.sp
-the file
-.I munnari
-will have these lines:
-.PP
-.RS
-.nf
-news/software/b/133 <102060@litchi.foo.com>
-comp/sources/unix/2002 <999@news.foo.com>
-.fi
-.RE
-.sp
-and the file
-.I uunet
-will have these lines:
-.PP
-.RS
-.nf
-news/software/b/132 <1643@munnari.oz.au>
-news/software/b/133 <102060@litchi.foo.com>
-comp/sources/unix/2002 <999@news.foo.com>
-.fi
-.RE
-.SH HISTORY
-Written by Robert Elz <kre@munnari.oz.au>, flags added by Rich $alz
-<rsalz@uunet.uu.net>.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: filechan.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-buffchan(8),
-inn.conf(5),
-innd(8),
-newsfeeds(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH GETLIST 1
-.SH NAME
-getlist \- get a list from an NNTP server
-.SH SYNOPSIS
-.I getlist
-[
-.B \-A
-]
-[
-.BI \-h " host"
-]
-[
-.I list
-[
-.I pattern
-[
-.I types
-]
-]
-]
-.SH DESCRIPTION
-The
-.I getlist
-program obtains a list from an NNTP server and sends
-it to standard output.
-.PP
-The
-.B list
-may be one of
-.IR active ,
-.IR active.times ,
-.IR distributions ,
-or
-.IR newsgroups .
-These values request the
-.IR active ,
-.IR active.times ,
-.IR <pathetc\ in\ inn.conf>/distributions .
-or
-.I <pathdb in inn.conf>/newsgroups
-files, respectively.
-.SH OPTIONS
-.TP
-.B \-A
-If the ``\fB\-A\fP'' flag is used, then the program tries to authenticate
-as per
-.I passwd.nntp
-before issuing LIST command.
-.TP
-.B \-h
-If the ``\fB\-h\fP'' flag is used, then the program connects to the server
-on the specified host.
-The default is to connect to the server specified in the
-.I inn.conf
-file.
-.PP
-If the
-.I list
-parameter is
-.IR active ,
-then the
-.I pattern
-and
-.I types
-parameters may be used to limit the output.
-When
-.I pattern
-is used, only active lines with groups that match according to
-.IR uwildmat (3)
-are printed.
-When
-.I types
-is also given, only active lines that have a fourth field starting
-with a character found in
-.I types
-are printed.
-.PP
-For example, the following command will obtain the one-line descriptions
-of all newsgroups found on UUNET:
-.RS
-getlist -h news.uu.net newsgroups
-.RE
-.PP
-The following line lists all groups where local postings are permitted,
-are moderated or aliased:
-.RS
-getlist active '*' ym=
-.RE
-.PP
-Note that the listing files other than the active file is a common
-extension to the NNTP protocol and may not be available on all servers.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.SH "SEE ALSO"
-active(5), active.times(5), inn.conf(5), nnrpd(8), uwildmat(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "GREPHISTORY 1"
-.TH GREPHISTORY 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-grephistory \- Query the INN history database
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBgrephistory\fR [\fB\-eilnqsv\fR] [\fB\-f\fR \fIdb\fR] [\fImessage-id\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBgrephistory\fR queries the \s-1INN\s0 history database for information about the
-specified message \s-1ID\s0. If no flags are given, the program prints the
-storage \s-1API\s0 token of the corresponding article, or \f(CW\*(C`/dev/null\*(C'\fR if the
-article is listed in the history database but not stored on the server.
-If the message \s-1ID\s0 cannot be found in the database, \fBgrephistory\fR will
-print \f(CW\*(C`grephistory: not found\*(C'\fR and exit with a non-zero status.
-.PP
-Be sure to escape any special characters in the message \s-1ID\s0 from the shell.
-Single quotes are recommended for this purpose since many message IDs
-contain dollar signs.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-e\fR" 4
-.IX Item "-e"
-Only print the storage token if the article is stored on the system. (In
-other words, suppress the \f(CW\*(C`/dev/null\*(C'\fR or \f(CW\*(C`not found\*(C'\fR output for missing
-or remembered articles.)
-.IP "\fB\-f\fR \fIdb\fR" 4
-.IX Item "-f db"
-Query the history database \fIdb\fR rather than the default history database.
-.IP "\fB\-i\fR" 4
-.IX Item "-i"
-Rather than expecting a message \s-1ID\s0 on the command line, \fBgrephistory\fR
-will read a list of message IDs on standard input, one per line. Leading
-and trailing whitespace is ignored, as are any malformed lines. It will
-print out standard output those message IDs which are not found in the
-history database. This is used when processing \f(CW\*(C`ihave\*(C'\fR control messages.
-.IP "\fB\-l\fR" 4
-.IX Item "-l"
-Display the entire line from the history database, rather than just the
-storage \s-1API\s0 token.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-If the message \s-1ID\s0 is present in the history database but has no storage
-\&\s-1API\s0 token, print \f(CW\*(C`/dev/null\*(C'\fR and exit successfully. This can happen if
-an article has been cancelled or expired, but history information has
-still been retained. This is the default behavior.
-.IP "\fB\-q\fR" 4
-.IX Item "-q"
-Don't print any message, but still exit with the appropriate status.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-Rather than expecting a message \s-1ID\s0 on the command line, \fBgrephistory\fR
-will read a list of message IDs on standard input, one per line. Leading
-and trailing whitespace is ignored, as are any malformed lines. It will
-print on standard output the storage \s-1API\s0 tokens for any articles that are
-still available, one per line. This flag is used when processing
-\&\f(CW\*(C`sendme\*(C'\fR control messages.
-.IP "\fB\-v\fR" 4
-.IX Item "-v"
-Print out the hash of the message \s-1ID\s0 for diagnostic purposes, as well as
-any other requested information. This flag is not useful with \fB\-s\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.Sp
-$Id: grephistory.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIhistory\fR\|(5), \fIinn.conf\fR\|(5)
+++ /dev/null
-.\" $Revision: 3782 $
-.TH HISTORY 5
-.SH NAME
-history \- record of current and recently expired Usenet articles
-.SH DESCRIPTION
-The file
-.I <pathdb in inn.conf>/history
-keeps a record of all articles currently stored in the news system,
-as well as those that have been received but since expired.
-In a typical production environment, this file will be many megabytes.
-.PP
-The file consists of text lines.
-Each line corresponds to one article.
-The file is normally kept sorted in the order in which articles are
-received, although this is not a requirement.
-.IR Innd (8)
-appends a new line each time it files an article, and
-.IR expire (8)
-builds a new version of the file by removing old articles and purging
-old entries.
-.PP
-Each line consists of two or three fields separated by a tab, shown below
-as
-.IR \et :
-.RS
-.nf
-[Hash] \et date
-[Hash] \et date \et token
-.fi
-.RE
-.PP
-The
-.I Hash
-field is the ASCII representation of the hash of the Message-ID header.
-This is directly used for the key of the
-.IR dbz (3).
-.PP
-The
-.I date
-field consists of three sub-fields separated by a tilde.
-All sub-fields are the text representation of the number of seconds since
-the epoch \(em
-.IR i.e. ,
-a
-.IR time_t ;
-see
-.IR gettimeofday (2).
-The first sub-field is the article's arrival date.
-If copies of the article are still present then the second sub-field is
-either the value of the article's Expires header, or a hyphen if no
-expiration date was specified.
-If an article has been expired then the second sub-field will be a hyphen.
-The third sub-field is the value of the article's Date header, recording
-when the article was posted.
-.PP
-The
-.I token
-field is a token of the article.
-This field is empty if the article has been expired.
-.PP
-For example, an article whose Message-ID was
-<7q2saq$sal$1@isrv4.pa.vix.com>, posted on 26 Aug 1999 08:02:34 GMT and
-recieved at 26 Aug 1999 08:06:54 GMT, could have a
-history line (broken into three lines for display) like the
-following:
-.RS
-.nf
-[E6184A5BC2898A35A3140B149DE91D5C] \et
- 935678987~-~935678821 \et
- @030154574F00000000000007CE3B000004BA@
-.fi
-.RE
-.PP
-In addition to the text file, there is a
-.IR dbz (3)
-database associated with the file that uses the Message-ID field as a key
-to determine the offset in the text file where the associated line begins.
-For historical reasons, the key includes the trailing \e0 byte
-(which is not stored in the text file).
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: history.5 3782 2000-08-17 13:30:18Z kondou $
-.SH "SEE ALSO"
-dbz(3),
-expire(8),
-inn.conf(5),
-innd(8),
-makehistory(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "IDENT 8"
-.TH IDENT 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ident \- nnrpd ident resolver
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBident\fR [\fB\-p\fR \fIport\fR] [\fB\-t\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This program attempts to resolve usernames for \fBnnrpd\fR by using the
-ident protocol to query the remote host. It contacts the remote host
-using either IPv4 or IPv6 depending on which protocol was used for the
-incoming \s-1NNTP\s0 connection.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-p\fR \fIport\fR" 4
-.IX Item "-p port"
-If this option is given, attempt to contact identd on the specified
-remote port (which can be a numeric or symbolic specification).
-Non-numeric values will be looked up using \fIgetservbyname\fR\|(3). The
-default value is the result of \f(CW\*(C`getservbyname("ident")\*(C'\fR if available,
-or port 113 otherwise.
-.IP "\fB\-t\fR" 4
-.IX Item "-t"
-If this option is given, the identity returned will never have a domain
-part. That is, if the remote server returns a result containing an \f(CW\*(C`@\*(C'\fR
-character, \fBident\fR truncates the response at the \f(CW\*(C`@\*(C'\fR. This is useful
-to allow the \fIdefault-domain\fR parameter in \fIreaers.conf\fR to override
-the domain supplied by the remote host (particularly if the supplied
-domain part is an unqualified local machine name rather than a full
-domain name).
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-The following \fIreaders.conf\fR\|(5) fragment tells nnrpd to trust ident
-information for hosts on a local network, but to replace the domain
-returned from the ident query:
-.PP
-.Vb 5
-\& auth LAN {
-\& hosts: "192.168/16"
-\& res: "ident \-t"
-\& default\-domain: "internal.example.com"
-\& }
-.Ve
-.PP
-.Vb 4
-\& access LAN {
-\& users: "*@internal.example.com"
-\& newsgroups: example.*
-\& }
-.Ve
-.PP
-Access is granted to the example.* groups for all users on the local
-network whose machines respond to ident queries.
-.SH "HISTORY"
-.IX Header "HISTORY"
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-.PP
-$Id: ident.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5)
+++ /dev/null
-.\" $Revision: 6992 $
-.TH INCOMING.CONF 5
-.SH NAME
-incoming.conf \- names and addresses that feed us news
-.SH DESCRIPTION
-The file
-.I <pathetc in inn.conf>/incoming.conf
-consists of three types of entries: key/value, peer and group.
-Comments are from the hash character ``#'' to the end of the line.
-Blank lines are ignored. All key/value entries within each type
-must not be duplicated.
-.PP
-Key/value entries are a keyword immediately followed by a colon, at least
-one blank and a value. For example:
-.PP
-.RS
-.nf
- max-connections: 10
-.fi
-.RE
-.PP
-A legal key does not contains blanks, colons, nor ``#''.
-There are 3 different types of values: integers, booleans, and strings.
-Integers are as to be expected. A boolean value is either ``true'' or
-``false'' (case is significant). A string value is any other sequence of
-characters. If the string needs to contain whitespace, then it must be
-quoted with double quotes.
-.PP
-Peer entries look like:
-.PP
-.RS
-.nf
- peer <name> {
- # body
- }
-.fi
-.RE
-.PP
-The word ``peer'' is required. ``<name>''is a label for this peer.
-The ``<name>'' is any string valid as a key. The body of a peer entry
-contains some number of key/value entries.
-.PP
-Group entries look like:
-.PP
-.RS
-.nf
- group <name> {
- # body
- }
-.fi
-.RE
-.PP
-The word ``group'' is required. The ``<name>'' is any string valid as a
-key. The body of a group entry contains any number of the three types of
-entries. So key/value pairs can be defined inside a group, and peers can
-be nested inside a group, and other groups can be nested inside a group.
-.PP
-Key/value entries that are defined outside of all peer and group entries
-are said to be at ``global scope''. Global key/value entries act as
-defaults for peers. When
-.IR innd (8)
-looks for a specific value in a peer entry
-(for example, the maximum number of connections to allow), if the value
-is not defined in the peer entry, then the enclosing groups are examined
-for the entry (starting at the closest enclosing group). If there are no
-enclosing groups, or the enclosing groups don't define the key/value,
-then the value at global scope is used.
-.PP
-A small example could be:
-.PP
-.RS
-.nf
-# Global value applied to all peers that have
-# no value of their own.
-max-connections: 5
-
-# A peer definition.
-peer uunet {
- hostname: usenet1.uu.net
-}
-
-peer vixie {
- hostname: gw.home.vix.com
- max-connections: 10 # override global value.
-}
-
-# A group of two peers who can open more
-# connections than normal
-group fast-sites {
- max-connections: 15
-
- # Another peer. The ``max-connections'' value from the
- # ``fast-sites'' group scope is used. The ``hostname'' value
- # defaults to the peer's name.
- peer data.ramona.vix.com {
- }
-
- peer bb.home.vix.com {
- hostname: bb.home.vix.com
- max-connections: 20 # he can really cook.
- }
-}
-.fi
-.RE
-.PP
-Given the above configuration file, the defined peers would have the
-following values for the ``max-connections'' key.
-.PP
-.RS
-.nf
- uunet 5
- vixie 10
- data.ramona.vix.com 15
- bb.home.vix.com 20
-.fi
-.RE
-.PP
-Ten keys are allowed:
-.TP
-.BI hostname:
-This key requires a string value. It is a list of hostnames separated by a
-comma. A hostname is the host's FQDN, or the dotted quad ip-address of the
-peer. If this key is not present in a peer block, the hostname defaults to
-the label of the peer.
-.TP
-.BI streaming:
-This key requires a boolean value. It defines whether streaming commands
-are allowed from this peer. (default=true)
-.TP
-.BI max-connections:
-This key requires a positive integer value. It defines the maximum number
-of connections allowed. A value of zero specifies an unlimited number
-of maximum connections (``unlimited'' or ``none'' can be used as synonym).
-(default=0)
-.TP
-.BI hold-time:
-This key requires a positive integer value. It defines the hold time before
-closing, if the connection is over max-connections. A value of zero
-specifies immediate close. (default=0)
-.TP
-.BI password:
-This key requires a string value. It is used if you wish to require a peer
-to supply a password. (default=no password)
-.TP
-.BI identd:
-This key requires a string value. It is used if you wish to require a peer's
-user name retrieved through identd match the specified string. Note that
-currently
-.IR innd (8)
-does not implement any timeout in identd callbacks, so enabling this
-option may cause innd to hang if the remote peer does not respond to ident
-callbacks in a reasonable timeframe (default=no identd)
-.TP
-.BI patterns:
-This key requires a string value. It is a list of
-.IR newsfeeds (5)-style
-list of newsgroups which are to be accepted from this host. (default="*")
-.TP
-.BI email:
-This key requires a string value. Reserved for future use. (default=empty)
-.TP
-.BI comment:
-This key requires a string value. Reserved for future use. (default=empty)
-.TP
-.BI skip:
-This key requires a boolean value. Setting this entry causes this peer
-to be skipped. (default=false)
-.TP
-.BI noresendid:
-This key requires a boolean value. It defines whether
-.IR innd (8)
-should send
-``431 RESENDID'' responses if a message is offered that is being received
-from another peer. This can be useful for peers that resend messages
-right away, as innfeed does. (default=false)
-.TP
-.BI nolist:
-This key requires a boolean value. It defines whether a peer is allowed to
-issue list command. (default=false)
-.SH HISTORY
-Written by Fabien Tassin <fta@sofaraway.org> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: incoming.conf.5 6992 2004-10-01 05:30:17Z rra $
-.SH "SEE ALSO"
-inn.conf(5),
-innd(8),
-newsfeeds(5),
-uwildmat(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INEWS 1"
-.TH INEWS 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-inews \- Post a Usenet article to the local news server
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinews\fR [\fB\-ADhNORSVW\fR] [\fB\-acdeFfnortwx\fR \fIvalue\fR] [\fB\-p\fR \fIport\fR] [\fIfile\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinews\fR reads a Usenet news article, perhaps with headers, from \fIfile\fR
-or standard input if no file is given. It adds some headers and performs
-some consistency checks. If the article does not meet those checks, the
-article is rejected. If it passes the checks, \fBinews\fR sends the article
-to the local news server as specified in \fIinn.conf\fR.
-.PP
-By default, if a file named \fI.signature\fR exists in the home directory of
-the posting user, it is appended to the post, preceeded by a line that
-contains only \f(CW\*(C`\-\- \*(C'\fR. Signatures are not allowed to be more than four
-lines long.
-.PP
-Cancel messages can only be posted with \fBinews\fR if the sender of the
-cancel message matches the sender of the original message being
-cancelled. The same check is also applied to Supersedes. Sender in this
-case means the contents of the Sender header if present, otherwise the
-From header.
-.PP
-Control messages other than cancel messages are only allowed if \fBinews\fR
-is being run by the news user or by a user in the news group and if the
-control message is recognized. If the article contains a Distribution
-header with a distribution that matches one of the bad distribution
-patterns in \fIinn/options.h\fR (anything containing a period by default),
-the message will be rejected. The message will also be rejected if
-\&\fIcheckincludedtext\fR is true in \fIinn.conf\fR, it contains more quoted text
-than original text, and it is over 40 lines long.
-.PP
-If not provided, the Path header of an article is constructed as follows:
-The basic Path header will be \*(L"not\-for\-mail\*(R". If \fIpathhost\fR is specified
-in \fIinn.conf\fR, it will be added to the beginning Path. Otherwise, if
-\&\fIserver\fR is specified, the full domain of the local host will be added to
-the beginning of the Path. Then, if \fB\-x\fR was given, its value will be
-added to the beginning of the Path.
-.PP
-If posting fails, a copy of the failed post will be saved in a file named
-\&\fIdead.article\fR in the home directory of the user running \fBinews\fR.
-\&\fBinews\fR exits with a non-zero status if posting failed or with a zero
-status if posting was successful.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-Most of the options to \fBinews\fR take a single value and set the
-corresponding header in the message that is posted. If the value is more
-than one word or contains any shell metacharacters, it must be quoted to
-protect it from the shell. Here are all the options that set header
-fields and the corresponding header:
-.PP
-.Vb 12
-\& \-a Approved
-\& \-c Control
-\& \-d Distribution
-\& \-e Expires
-\& \-F References
-\& \-f From
-\& \-n Newsgroups
-\& \-o Organization
-\& \-r Reply\-To
-\& \-t Subject
-\& \-w Followup\-To
-\& \-x Path prefix
-.Ve
-.PP
-The \fB\-x\fR argument will be added to the beginning of the normal Path
-header; it will not replace it.
-.IP "\fB\-A\fR, \fB\-V\fR, \fB\-W\fR" 4
-.IX Item "-A, -V, -W"
-Accepted for compatibility with C News. These options have no affect.
-.IP "\fB\-D\fR, \fB\-N\fR" 4
-.IX Item "-D, -N"
-Perform the consistency checks and add headers where appropriate, but then
-print the article to standard output rather than sending it to the server.
-\&\fB\-N\fR is accepted as as synonym for compatibility with C News.
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Normally, this flag should always be given. It indicates that the article
-consists of headers, a blank line, and then the message body. If it is
-omitted, the input is taken to be just the body of the message, and any
-desired headers have to be specified with command-line options as
-described above.
-.IP "\fB\-O\fR" 4
-.IX Item "-O"
-By default, an Organization header will be added if none is present in the
-article. To prevent adding the default (from \fIorganization\fR in
-\&\fIinn.conf\fR), use this flag.
-.IP "\fB\-p\fR \fIport\fR" 4
-.IX Item "-p port"
-Connect to the specified port on the server rather than to the default
-(port 119).
-.IP "\fB\-R\fR" 4
-.IX Item "-R"
-Reject all control messages.
-.IP "\fB\-S\fR" 4
-.IX Item "-S"
-Do not attempt to append \fI~/.signature\fR to the message, even if it
-exists.
-.SH "NOTES"
-.IX Header "NOTES"
-If the \s-1NNTP\s0 server requests authentication, \fBinews\fR will try to read
-\&\fIpasswd.nntp\fR to get the username and password to use and will therefore
-need read access to that file. This is typically done by making that file
-group-readable and adding all users who should be able to use \fBinews\fR to
-post to that server to the appropriate group.
-.PP
-\&\fBinews\fR used to do even more than it does now, and all of the remaining
-checks that are not dependent on the user running \fBinews\fR should probably
-be removed in favor of letting the news server handle them.
-.PP
-Since \s-1INN\s0's \fBinews\fR uses \fIinn.conf\fR and some other corners of an \s-1INN\s0
-installation, it's not very appropriate as a general stand-alone \fBinews\fR
-program for general use on a system that's not running a news server.
-Other, more suitable versions of \fBinews\fR are available as part of various
-Unix news clients or by themselves.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-\&\s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fIrnews\fR\|(1)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INN.CONF 5"
-.TH INN.CONF 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-inn.conf \- Configuration data for InterNetNews programs
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fIinn.conf\fR in \fIpathetc\fR is the primary general configuration file for
-all InterNetNews programs. Settings which control the general operation
-of various programs, as well as the paths to all portions of the news
-installation, are found here. The \s-1INNCONF\s0 environment variable, if set,
-specifies an alternate path to \fIinn.conf\fR.
-.PP
-This file is intended to be fairly static. Any changes made to it will
-generally not affect any running programs until they restart. Unlike
-nearly every other configuration file, \fIinn.conf\fR cannot be reloaded
-dynamically using \fIctlinnd\fR\|(8); \fIinnd\fR\|(8) must be stopped and restarted for
-relevant changes to \fIinn.conf\fR to take effect (\f(CW\*(C`ctlinnd xexec innd\*(C'\fR is
-the fastest way to do this.)
-.PP
-Blank lines and lines starting with a number sign (\f(CW\*(C`#\*(C'\fR) are ignored. All
-other lines specify parameters, and should be of the following form:
-.PP
-.Vb 1
-\& <name>: <value>
-.Ve
-.PP
-(Any amount of whitespace can be put after the colon and is optional.) If
-the value contains embedded whitespace or any of the characers \f(CW\*(C`[]<\*(C'\fR\*(L"\e:>,
-it must be enclosed in double quotes (\*(R""). A backslash (\f(CW\*(C`\e\*(C'\fR) can be used
-to escape quotes and backslashes inside double quotes. <name> is
-case\-sensitive; \f(CW\*(C`server\*(C'\fR is not the same as \f(CW\*(C`Server\*(C'\fR or \f(CW\*(C`SERVER\*(C'\fR.
-(\fIinn.conf\fR parameters are generally all in lowercase.)
-.PP
-If <name> occurs more than once in the file, the first value is used.
-Some parameters specified in the file may be overridden by environment
-variables. Most parameters have default values if not specified in
-\&\fIinn.conf\fR; those defaults are noted in the description of each
-parameter.
-.PP
-Many parameters take a boolean value. For all such parameters, the value
-may be specified as \f(CW\*(C`true\*(C'\fR, \f(CW\*(C`yes\*(C'\fR, or \f(CW\*(C`on\*(C'\fR to turn it on and may be any
-of \f(CW\*(C`false\*(C'\fR, \f(CW\*(C`no\*(C'\fR, or \f(CW\*(C`off\*(C'\fR to turn it off. The case of these values is
-significant.
-.PP
-This documentation is extremely long and organized as a reference manual
-rather than as a tutorial. If this is your first exposure to \s-1INN\s0 and
-these parameters, it would be better to start by reading other man pages
-and referring to this one only when an \fIinn.conf\fR parameter is explicitly
-mentioned. Those parameters which need to be changed when setting up a
-new server are discussed in \fI\s-1INSTALL\s0\fR.
-.SH "PARAMETERS"
-.IX Header "PARAMETERS"
-.Sh "General Settings"
-.IX Subsection "General Settings"
-These parameters are used by a wide variety of different components of
-\&\s-1INN\s0.
-.IP "\fIdomain\fR" 4
-.IX Item "domain"
-This should be the domain name of the local host. It should not have a
-leading period, and it should not be a full host address. It is used only
-if the \fIGetFQDN()\fR routine in \fIlibinn\fR\|(3) cannot get the fully-qualified
-domain name by using either the \fIgethostname\fR\|(3) or \fIgethostbyname\fR\|(3) calls.
-The check is very simple; if either routine returns a name with a period
-in it, then it is assumed to have the full domain name. As this parameter
-is rarely used, do not use it to affect the righthand side of
-autogenerated Message\-IDs; see instead \fIvirtualhost\fR and \fIdomain\fR in
-readers.conf. The default value is unset.
-.IP "\fIinnflags\fR" 4
-.IX Item "innflags"
-The flags to pass to innd on startup. See \fIinnd\fR\|(8) for details on the
-possible flags. The default value is unset.
-.IP "\fImailcmd\fR" 4
-.IX Item "mailcmd"
-The path to the program to be used for mailing reports and control
-messages. The default is \fIpathbin\fR/innmail. This should not normally
-need to be changed.
-.IP "\fImta\fR" 4
-.IX Item "mta"
-The command to use when mailing postings to moderators and for the use of
-\&\fIinnmail\fR\|(1). The message, with headers and an added To: header, will be
-piped into this program. The string \f(CW%s\fR, if present, will be replaced
-by the e\-mail address of the moderator. It's strongly recommended for
-this command to include \f(CW%s\fR on the command line rather than use the
-addresses in the To: and Cc: headers of the message, since the latter
-approach allows the news server to be abused as a mechanism to send mail
-to arbitrary addresses and will result in unexpected behavior. There is
-no default value for this parameter; it must be set in \fIinn.conf\fR or a
-fatal error message will be logged via syslog.
-.Sp
-For most systems, \f(CW\*(C`/usr/lib/sendmail \-oi \-oem %s\*(C'\fR (adjusted for the
-correct path to sendmail) is a good choice.
-.IP "\fIpathhost\fR" 4
-.IX Item "pathhost"
-What to put into the Path: header to represent the local site. This is
-added to the Path: header of all articles that pass through the system,
-including locally posted articles, and is also used when processing some
-control messages and when naming the server in status reports. There is
-no default value; this parameter must be set in \fIinn.conf\fR or \s-1INN\s0 will
-not start. A good value to use is the fully-qualified hostname of the
-system.
-.IP "\fIserver\fR" 4
-.IX Item "server"
-The name of the default \s-1NNTP\s0 server. If \fInnrpdposthost\fR is not set and
-\&\s-1UNIX\s0 domain sockets are not supported, \fInnrpd\fR\|(8) tries to hand off
-locally-posted articles through an \s-1INET\s0 domain socket to this server.
-\&\fIactsync\fR\|(8), \fInntpget\fR\|(8), and \fIgetlist\fR\|(8) also use this value as the default
-server to connect to. In the latter cases, the value of the \s-1NNTPSERVER\s0
-environment variable, if it exists, overrides this. The default value is
-unset.
-.Sh "Feed Configuration"
-.IX Subsection "Feed Configuration"
-These parameters govern incoming and outgoing feeds: what size of
-articles are accepted, what filtering and verification is performed on
-them, whether articles in groups not carried by the server are still
-stored and propagated, and other similar settings.
-.IP "\fIartcutoff\fR" 4
-.IX Item "artcutoff"
-Articles older than this number of days are dropped. This setting should
-probably match the setting on the \f(CW\*(C`/remember/\*(C'\fR line in \fIexpire.ctl\fR.
-The default value is \f(CW10\fR.
-.IP "\fIbindaddress\fR" 4
-.IX Item "bindaddress"
-Which \s-1IP\s0 address \fIinnd\fR\|(8) should bind itself to. This must be in
-dotted-quad format (nnn.nnn.nnn.nnn). If set to \f(CW\*(C`all\*(C'\fR or not set, innd
-defaults to listening on all interfaces. The value of the
-\&\s-1INND_BIND_ADDRESS\s0 environment variable, if set, overrides this setting.
-The default value is unset.
-.IP "\fIbindaddress6\fR" 4
-.IX Item "bindaddress6"
-Like \fIbindaddress\fR but for IPv6 sockets. If only one of the \fIbindaddress\fR
-and \fIbindaddress6\fR parameters is used, then only the socket for the
-corresponding address family is created. If both parameters are used
-then two sockets are created. If neither of them is used, the list of
-sockets to listen on will be determined by the system library
-\&\fI\fIgetaddrinfo\fI\|(3)\fR function. The value of the \s-1INND_BIND_ADDRESS6\s0, if set,
-overrides this setting. The default value is unset.
-.Sp
-Note that you will generally need to put double quotes ("") around this
-value if you set it, since IPv6 addresses contain colons.
-.IP "\fIhiscachesize\fR" 4
-.IX Item "hiscachesize"
-If set to a value other than \f(CW0\fR, a hash of recently received message IDs
-is kept in memory to speed history lookups. The value is the amount of
-memory to devote to the cache in kilobytes. The cache is only used for
-incoming feeds and a small cache can hold quite a few message IDs, so
-large values aren't necessarily useful unless you have incoming feeds that
-are badly delayed. A good value for a system with more than one incoming
-feed is \f(CW256\fR; systems with only one incoming feed should probably leave
-this at \f(CW0\fR. The default value is \f(CW0\fR.
-.IP "\fIignorenewsgroups\fR" 4
-.IX Item "ignorenewsgroups"
-Whether newsgroup creation control messages (newgroup and rmgroup) should
-be fed as if they were posted to the newsgroup they are creating or
-deleting rather than to the newsgroups listed in the Newsgroups: header.
-If this parameter is set, the newsgroup affected by the control message
-will be extracted from the Control: header and the article will be fed as
-if its Newsgroups: header contained solely that newsgroup. This is useful
-for routing control messages to peers when they are posted to irrelevant
-newsgroups that shouldn't be matched against the peer's desired newsgroups
-in \fInewsfeeds\fR. This is a boolean value and the default is false.
-.IP "\fIimmediatecancel\fR" 4
-.IX Item "immediatecancel"
-When using the timecaf storage method, article cancels are normally just
-cached to be cancelled, not cancelled immediately. If this is set to
-true, they will instead by cancelled as soon as the cancel is processed.
-This is a boolean value and the default is false.
-.Sp
-This setting is ignored unless the timecaf storage method is used.
-.IP "\fIlinecountfuzz\fR" 4
-.IX Item "linecountfuzz"
-If set to something other than \f(CW0\fR, the line count of the article is
-checked against the Lines: header of the article (if present) and the
-artice is rejected if the values differ by more than this amount. A
-reasonable setting is \f(CW5\fR, which is the standard maximum signature length
-plus one (some injection software calculates the Lines: header before
-adding the signature). The default value is \f(CW0\fR, which tells \s-1INN\s0 not to
-check the Lines: header of incoming articles.
-.IP "\fImaxartsize\fR" 4
-.IX Item "maxartsize"
-The maximum size of article (headers and body) that will be accepted by
-the server, in bytes. A value of \f(CW0\fR allows any size of article, but
-note that \fBinnd\fR will crash if system memory is exceeded. The default
-value is \f(CW1000000\fR (approximately 1 \s-1MB\s0). See also \fIlocalmaxartsize\fR.
-.IP "\fImaxconnections\fR" 4
-.IX Item "maxconnections"
-The maximum number of incoming \s-1NNTP\s0 connections \fIinnd\fR\|(8) will accept. The
-default value is \f(CW50\fR.
-.IP "\fIpathalias\fR" 4
-.IX Item "pathalias"
-If set, this value is prepended to the Path: header of accepted posts
-(before \fIpathhost\fR) if it doesn't already appear in the Path: header.
-The main purpose of this parameter is to configure all news servers within
-a particular organization to add a common identity string to the
-Path: header. The default value is unset.
-.IP "\fIpathcluster\fR" 4
-.IX Item "pathcluster"
-If set, this value is appended to the Path: header of accepted posts
-(after \fIpathhost\fR) if it isn't already present as the last element
-of the Path: header. The main purpose of this parameter is to make
-several news servers appear as one server. The default value is unset.
-.Sp
-Note that the Path: header reads right to left, so appended means inserted
-at the leftmost side of the Path: header.
-.IP "\fIpgpverify\fR" 4
-.IX Item "pgpverify"
-Whether to enable \s-1PGP\s0 verification of control messages other than cancel.
-This is a boolean value and the default is based on whether configure found
-pgp, pgpv, or gpgv.
-.IP "\fIport\fR" 4
-.IX Item "port"
-What \s-1TCP\s0 port \fIinnd\fR\|(8) should listen on. The default value is \f(CW119\fR, the
-standard \s-1NNTP\s0 port.
-.IP "\fIrefusecybercancels\fR" 4
-.IX Item "refusecybercancels"
-Whether to refuse all articles whose message IDs start with
-\&\f(CW\*(C`<cancel.\*(C'\fR. This message \s-1ID\s0 convention is widely followed by spam
-cancellers, so the vast majority of such articles will be cancels of spam.
-This check, if enabled, is done before the history check and the message
-\&\s-1ID\s0 is not written to the history file. This is a boolean value and the
-default is false.
-.Sp
-This is a somewhat messy, inefficient, and inexact way of refusing spam
-cancels. A much better way is to ask all of your upstream peers to not
-send to you any articles with \f(CW\*(C`cyberspam\*(C'\fR in the Path: header (usually
-accomplished by having them mark \f(CW\*(C`cyberspam\*(C'\fR as an alias for your machine
-in their feed configuration). The filtering enabled by this parameter is
-hard\-coded; general filtering of message IDs can be done via the embedded
-filtering support.
-.IP "\fIremembertrash\fR" 4
-.IX Item "remembertrash"
-By default, \fIinnd\fR\|(8) records rejected articles in history so that, if
-offered the same article again, it can be refused before it is sent. If
-you wish to disable this behavior, set this to false. This can cause a
-substantial increase in the amount of bandwidth consumed by incoming news
-if you have several peers and reject a lot of articles, so be careful with
-it. Even if this is set to true, \s-1INN\s0 won't log some rejected articles to
-history if there's reason to believe the article might be accepted if
-offered by a different peer, so there is usually no reason to set this to
-false (although doing so can decrease the size of the history file). This
-is a boolean value and the default is true.
-.IP "\fIsourceaddress\fR" 4
-.IX Item "sourceaddress"
-Which local \s-1IP\s0 address to bind to for outgoing \s-1NNTP\s0 sockets (used by
-\&\fIinnxmit\fR\|(8) among other programs, but \fInot\fR \fIinnfeed\fR\|(8) \*(-- see
-\&\fIbindaddress\fR in \fIinnfeed.conf\fR\|(5) for that). This must be in dotted-quad
-format (nnn.nnn.nnn.nnn). If set to \f(CW\*(C`all\*(C'\fR or not set, the operating
-system will choose the source \s-1IP\s0 address for outgoing connections. The
-default value is unset.
-.IP "\fIsourceaddress6\fR" 4
-.IX Item "sourceaddress6"
-Like \fIsourceaddress\fR but for IPv6 sockets.
-.IP "\fIverifycancels\fR" 4
-.IX Item "verifycancels"
-Set this to true to enable a simplistic check on all cancel messages,
-attempting to verify (by simple header comparison) that the cancel message
-is from the same person as the original post. This can't be done if the
-cancel arrives before the article does, and is extremely easy to spoof.
-While this check may once have served a purpose, it's now essentially
-security via obscurity, commonly avoided by abusers, and probably not
-useful. This is a boolean value, and the default is false.
-.IP "\fIwanttrash\fR" 4
-.IX Item "wanttrash"
-Set this to true if you want to file articles posted to unknown newsgroups
-(newsgroups not in the \fIactive\fR file) into the \f(CW\*(C`junk\*(C'\fR newsgroup rather
-than rejecting them. This is sometimes useful for a transit news server
-that needs to propagate articles in all newsgroups regardless if they're
-carried locally. This is a boolean value and the default is false.
-.IP "\fIwipcheck\fR" 4
-.IX Item "wipcheck"
-If \s-1INN\s0 is offered an article by a peer on one channel, it will return
-deferral responses (code 436) to all other offers of that article for this
-many seconds. (After this long, if the peer that offered the article
-still hasn't sent it, it will be accepted from other channels.) The
-default value is \f(CW5\fR and probably doesn't need to be changed.
-.IP "\fIwipexpire\fR" 4
-.IX Item "wipexpire"
-How long, in seconds, to keep track of message IDs offered on a channel
-before expiring articles that still haven't been sent. The default value
-is \f(CW10\fR and probably doesn't need to be changed.
-.IP "\fIdontrejectfiltered\fR" 4
-.IX Item "dontrejectfiltered"
-Normally \fIinnd\fR\|(8) rejects incoming articles when directed to do so by any
-enabled article filters (Perl, Python, and \s-1TCL\s0). However, this parameter
-causes such articles \fInot\fR to be rejected; instead filtering can be
-applied on outbound articles. If this parameter is set, all articles will
-be accepted on the local machine, but articles rejected by the filter will
-\&\fInot\fR be fed to any peers specified in \fInewsfeeds\fR with the \f(CW\*(C`Af\*(C'\fR flag.
-.Sh "Article Storage"
-.IX Subsection "Article Storage"
-These parameters affect how articles are stored on disk.
-.IP "\fIcnfscheckfudgesize\fR" 4
-.IX Item "cnfscheckfudgesize"
-If set to a value other than \f(CW0\fR, the claimed size of articles in \s-1CNFS\s0
-cycbuffs is checked against \fImaxartsize\fR plus this value, and if larger,
-the \s-1CNFS\s0 cycbuff is considered corrupt. This can be useful as a sanity
-check after a system crash, but be careful using this parameter if you
-have changed \fImaxartsize\fR recently. The default value is \f(CW0\fR.
-.IP "\fIenableoverview\fR" 4
-.IX Item "enableoverview"
-Whether to write out overview data for articles. If set to false, \s-1INN\s0
-will run much faster, but reading news from the system will be impossible
-(the server will be for news transit only). If this option is set to
-true, \fIovmethod\fR must also be set. This is a boolean value and the
-default is true.
-.IP "\fIgroupbaseexpiry\fR" 4
-.IX Item "groupbaseexpiry"
-Whether to enable newsgroup-based expiry. If set to false, article expiry
-is done based on storage class of storing method. If set to true (and
-overview information is available), expiry is done by newsgroup name.
-This affects the format of \fIexpire.ctl\fR. This is a boolean value and the
-default is true.
-.IP "\fImergetogroups\fR" 4
-.IX Item "mergetogroups"
-Whether to file all postings to \f(CW\*(C`to.*\*(C'\fR groups in the pseudonewsgroup
-\&\f(CW\*(C`to\*(C'\fR. If this is set to true, the newsgroup \f(CW\*(C`to\*(C'\fR must exist in the
-\&\fIactive\fR file or \s-1INN\s0 will not start. (See the discussion of \f(CW\*(C`to.\*(C'\fR
-groups in \fIinnd\fR\|(8) under \s-1CONTROL\s0 \s-1MESSAGES\s0.) This is a boolean value and
-the default is false.
-.IP "\fIovercachesize\fR" 4
-.IX Item "overcachesize"
-How many cache slots to reserve for open overview files. If \s-1INN\s0 is
-writing overview files (see \fIenableoverview\fR), \fIovmethod\fR is set to
-\&\f(CW\*(C`tradindexed\*(C'\fR, and this is set to a value other than \f(CW0\fR, \s-1INN\s0 will keep
-around and open that many recently written-to overview files in case more
-articles come in for those newsgroups. Every overview cache slot consumes
-two file descriptors, so be careful not to set this value too high. You
-may be able to use the \f(CW\*(C`limit\*(C'\fR command to see how many open file
-descriptors your operating system allows. \fIinnd\fR\|(8) also uses an open file
-descriptor for each incoming feed and outgoing channel or batch file, and
-if it runs out of open file descriptors it may throttle and stop accepting
-new news. The default value is \f(CW15\fR (which is probably way too low if
-you have a large number of file descriptors available).
-.Sp
-This setting is ignored unless \fIovmethod\fR is set to \f(CW\*(C`tradindexed\*(C'\fR.
-.IP "\fIovgrouppat\fR" 4
-.IX Item "ovgrouppat"
-If set, restricts the overview data stored by \s-1INN\s0 to only the newsgroups
-matching this comma-separated list of wildmat expressions. Newsgroups not
-matching this setting may not be readable, and if \fIgroupbaseexpiry\fR is
-set to true and the storage method for these newsgroups does not have
-self-expire functionality, storing overview data will fail.
-The default is unset.
-.IP "\fIovmethod\fR" 4
-.IX Item "ovmethod"
-Which overview storage method to use. Currently supported values are
-\&\f(CW\*(C`tradindexed\*(C'\fR, \f(CW\*(C`buffindexed\*(C'\fR, and \f(CW\*(C`ovdb\*(C'\fR. There is no default value;
-this parameter must be set if \fIenableoverview\fR is true (the default).
-.RS 4
-.ie n .IP """buffindexed""" 4
-.el .IP "\f(CWbuffindexed\fR" 4
-.IX Item "buffindexed"
-Stores overview data and index information into buffers, which are
-preconfigured files defined in \fIbuffindexed.conf\fR. \f(CW\*(C`buffindexed\*(C'\fR never
-consumes additional disk space beyond that allocated to these buffers.
-.ie n .IP """tradindexed""" 4
-.el .IP "\f(CWtradindexed\fR" 4
-.IX Item "tradindexed"
-Uses two files per newsgroup, one containing the overview data and one
-containing the index. Fast for readers, but slow to write to.
-.ie n .IP """ovdb""" 4
-.el .IP "\f(CWovdb\fR" 4
-.IX Item "ovdb"
-Stores data into a Berkeley \s-1DB\s0 database. See the \fIovdb\fR\|(5) man page.
-.RE
-.RS 4
-.RE
-.IP "\fIhismethod\fR" 4
-.IX Item "hismethod"
-Which history storage method to use. The only currently supported
-value is \f(CW\*(C`hisv6\*(C'\fR. There is no default value; this parameter must
-be set.
-.RS 4
-.ie n .IP """hisv6""" 4
-.el .IP "\f(CWhisv6\fR" 4
-.IX Item "hisv6"
-Stores history data in the \s-1INN\s0 history v6 format: \fIhistory\fR\|(5) text
-file and a number of \fIdbz\fR\|(3) database files; this may be in true history
-v6 format, or tagged hash format, depending on the build
-options. Separation of these two is a project which has not yet been
-undertaken.
-.RE
-.RS 4
-.RE
-.IP "\fIstoreonxref\fR" 4
-.IX Item "storeonxref"
-If set to true, articles will be stored based on the newsgroup names in
-the Xref: header rather than in the Newsgroups: header. This affects what
-the patterns in \fIstorage.conf\fR apply to. The primary interesting effect
-of setting this to true is to enable filing of all control messages
-according to what storage class the control pseudogroups are filed in
-rather than according to the newsgroups the control messages are posted
-to. This is a boolean value and the default is true.
-.IP "\fIuseoverchan\fR" 4
-.IX Item "useoverchan"
-Whether to \fIinnd\fR\|(8) should create overview data internally through
-\&\fIlibstorage\fR\|(3). If set to false, innd creates overview data by itself. If
-set to true, innd does not create; instead overview data must be created
-by \fIoverchan\fR\|(8) from an appropriate entry in \fInewsfeeds\fR. Setting to true
-may be useful, if innd cannot keep up with incoming feed and the
-bottleneck is creation of overview data within innd. This is a boolean
-value and the default is false.
-.IP "\fIwireformat\fR" 4
-.IX Item "wireformat"
-Only used with the tradspool storage method, this says whether to write
-articles in wire format. Wire format means storing articles with \f(CW\*(C`\er\en\*(C'\fR at
-the end of each line and with periods at the beginning of lines doubled,
-the article format required by the \s-1NNTP\s0 protocol. Articles stored in this
-format are suitable for sending directly to a network connection without
-requiring conversion, and therefore setting this to true can make the
-server more efficient. The primary reason not to set this is if you have
-old existing software that looks around in the spool and doesn't
-understand how to read wire format. Storage methods other than tradspool
-always store articles in wire format. This is a boolean value and the
-default is false.
-.IP "\fIxrefslave\fR" 4
-.IX Item "xrefslave"
-Whether to act as the slave of another server. If set, \s-1INN\s0 attempts to
-duplicate exactly the article numbering of the server feeding it by
-looking at the Xref: header of incoming articles and assigning the same
-article numbers to articles as was noted in the Xref: header from the
-upstream server. The result is that clients should be able to point at
-either server interchangeably (using some load balancing scheme, for
-example) and see the same internal article numbering. Servers with this
-parameter set should generally only have one upstream feed, and should
-always have \fInnrpdposthost\fR set to hand locally posted articles off to
-the master server. The upstream should be careful to always feed articles
-in order (\fIinnfeed\fR\|(8) can have problems with this in the event of a
-backlog). This is a boolean value and the default is false.
-.IP "\fInfswriter\fR" 4
-.IX Item "nfswriter"
-For servers writing articles, determine whether the article spool is
-on \s-1NFS\s0 storage. If set, \s-1INN\s0 attempts to flush articles to the spool
-in a more timely manner, rather than relying on the operating system
-to flush things such as the \s-1CNFS\s0 article bitmaps. You should only set
-this parameter if you are attempting to use a shared \s-1NFS\s0 spool on a
-machine acting as a single writer within a cluster. This is a boolean
-value and the default is false.
-.IP "\fInfsreader\fR" 4
-.IX Item "nfsreader"
-For servers reading articles, determine whether the article spool is
-on \s-1NFS\s0 storage. If set, \s-1INN\s0 will attempt to force articles and
-overviews to be read directly from the \s-1NFS\s0 spool rather than from
-cached copies. You should only set this parameter if you are
-attempting to use a shared \s-1NFS\s0 spool on a machine acting a reader a
-cluster. This is a boolean value and the default is false.
-.IP "\fInfsreaderdelay\fR" 4
-.IX Item "nfsreaderdelay"
-For servers reading articles, determine whether the article spool is
-on \s-1NFS\s0 storage. If \fInfsreader\fR is set, \s-1INN\s0 will use the value of
-\&\fInfsreaderdelay\fR to delay the apparent arrival time of articles to
-clients by this amount; this value should be tuned based on the \s-1NFS\s0
-cache timeouts locally. This default is 60 (1 minute).
-.IP "\fImsgidcachesize\fR" 4
-.IX Item "msgidcachesize"
-How many cache slots to reserve for Message \s-1ID\s0 to storage token
-translations. When serving overview data to clients (\s-1NEWNEWS\s0, \s-1XOVER\s0
-etc.), \fInnrpd\fR\|(8) can cache the storage token associated with a Message
-\&\s-1ID\s0 and save the cost of looking it up in the history file; for some
-configurations setting this parameter can save more than 90% of the
-wall clock time for a session. The default value is 10000.
-.IP "\fItradindexedmmap\fR" 4
-.IX Item "tradindexedmmap"
-Whether to attempt to \fImmap()\fR tradindexed overviews articles. Setting
-this to true will give better performance on most systems, but some
-systems have problems with \fImmap()\fR. If this is set to false, overviews
-will be read into memory before being sent to readers. This is a
-boolean value and the default is true.
-.Sh "Reading"
-.IX Subsection "Reading"
-These parameters affect the behavior of \s-1INN\s0 for readers. Most of them are
-used by \fInnrpd\fR\|(8). There are some special sets of settings that are broken
-out separately after the initial alphabetized list.
-.IP "\fIallownewnews\fR" 4
-.IX Item "allownewnews"
-Whether to allow use of the \s-1NEWNEWS\s0 command by clients. This command used
-to put a heavy load on the server in older versions of \s-1INN\s0, but is now
-reasonably efficient, at least if only one newsgroup is specified by the
-client. This is a boolean value and the default is true. If you use the
-\&\fIaccess\fR parameter in \fIreaders.conf\fR, be sure to read about the way it
-overrides \fIallownewnews\fR.
-.IP "\fIarticlemmap\fR" 4
-.IX Item "articlemmap"
-Whether to attempt to \fImmap()\fR articles. Setting this to true will give
-better performance on most systems, but some systems have problems with
-\&\fImmap()\fR. If this is set to false, articles will be read into memory before
-being sent to readers. This is a boolean value and the default is false.
-.IP "\fIclienttimeout\fR" 4
-.IX Item "clienttimeout"
-How long (in seconds) a client connection can be idle before it exits.
-When setting this parameter, be aware that some newsreaders use the same
-connection for reading and posting and don't deal well with the connection
-timing out while a post is being composed. If the system isn't having a
-problem with too many long-lived connections, it may be a good idea to
-increase this value to \f(CW3600\fR (an hour). The default value is \f(CW600\fR
-(ten minutes).
-.IP "\fIinitialtimeout\fR" 4
-.IX Item "initialtimeout"
-How long (in seconds) \fBnnrpd\fR will wait for the first command from a
-reader connection before dropping the connection. This is a defensive
-timeout intended to protect the news server from badly behaved reader
-clients that open and abandon a multitude of connections without every
-closing them. The default value is \f(CW10\fR (ten seconds), which may need to
-be increased if many clients connect via slow network links.
-.IP "\fInnrpdcheckart\fR" 4
-.IX Item "nnrpdcheckart"
-Whether \fBnnrpd\fR should check the existence of an article before listing
-it as present in response to an \s-1NNTP\s0 command. The primary use of this
-setting is to prevent nnrpd from returning information about articles
-which are no longer present on the server but which still have overview
-data available. Checking the existence of articles before returning
-overview information slows down the overview commands, but reduces the
-number of \*(L"article is missing\*(R" errors seen by the client. This is a
-boolean value and the default is true.
-.IP "\fInnrpperlauth\fR" 4
-.IX Item "nnrpperlauth"
-This parameter is now obsolete; see \*(L"Changes to Perl Authentication
-Support for nnrpd\*(R" in \fIdoc/hook\-perl\fR.
-.IP "\fInnrppythonauth\fR" 4
-.IX Item "nnrppythonauth"
-This parameter is now obsolete; see \*(L"Changes to Python Authentication and
-Access Control Support for nnrpd\*(R" in \fIdoc/hook\-python\fR.
-.IP "\fInoreader\fR" 4
-.IX Item "noreader"
-Normally, \fIinnd\fR\|(8) will fork a copy of \fInnrpd\fR\|(8) for all incoming
-connections from hosts not listed in \fIincoming.conf\fR. If this parameter
-is set to true, those connections will instead be rejected with a 502
-error code. This should be set to true for a transit-only server that
-doesn't support readers, or if nnrpd is running in daemon mode or being
-started out of inetd. This is a boolean value and the default is false.
-.IP "\fIreaderswhenstopped\fR" 4
-.IX Item "readerswhenstopped"
-Whether to allow readers to connect even if the server is paused or
-throttled. This is only applicable if \fInnrpd\fR\|(8) is spawned from \fIinnd\fR\|(8)
-rather than run out of inetd or in daemon mode. This is a boolean value
-and the default is false.
-.IP "\fIreadertrack\fR" 4
-.IX Item "readertrack"
-Whether to enable the tracking system for client behavior. Tracked
-information is recorded to \fIpathlog\fR/tracklogs/log\-ID, where \s-1ID\s0 is
-determined by nnrpd's \s-1PID\s0 and launch time.) Currently the information
-recorded includes initial connection and posting; only information about
-clients listed in \fInnrpd.track\fR is recorded. This is a boolean value and
-the default is false.
-.IP "\fInnrpdflags\fR" 4
-.IX Item "nnrpdflags"
-When \fInnrpd\fR\|(8) is spawned from \fIinnd\fR\|(8), these flags are passed as
-arguments to the nnrpd process. This setting does not affect instances
-of nnrpd that are started in daemon mode, or instances that are started
-via another listener process such as \fIinetd\fR\|(8) or \fIxinetd\fR\|(8). Shell
-quoting and metacharacters are not supported. This is a string value
-and the default is unset.
-.IP "\fInnrpdloadlimit\fR" 4
-.IX Item "nnrpdloadlimit"
-If set to a value other than \f(CW0\fR, connections to nnrpd will be refused
-if the system load average is higher than this value. The default value
-is \f(CW16\fR.
-.PP
-\&\s-1INN\s0 has optional support for generating keyword information automatically
-from article body text and putting that information in overview for the
-use of clients that know to look for it. The following parameters control
-that feature.
-.PP
-This may be too slow if you're taking a substantial feed, and probably
-will not be useful for the average news reader; enabling this is not
-recommended unless you have some specific intention to take advantage of
-it.
-.IP "\fIkeywords\fR" 4
-.IX Item "keywords"
-Whether the keyword generation support should be enabled. This is a
-boolean value and the default is false.
-.Sp
-\&\s-1FIXME:\s0 Currently, support for keyword generation is configured into \s-1INN\s0
-semi-randomly (based on whether configure found the regex library); it
-should be an option to configure and that option should be mentioned here.
-.IP "\fIkeyartlimit\fR" 4
-.IX Item "keyartlimit"
-Articles larger than this value in bytes will not have keywords generated
-for them (since it would take too long to do so). The default value is
-\&\f(CW100000\fR (approximately 100 \s-1KB\s0).
-.IP "\fIkeylimit\fR" 4
-.IX Item "keylimit"
-Maximum number of bytes allocated for keyword data. If there are more
-keywords than will fit into this many bytes when separated by commas, the
-rest are discarded. The default value is \f(CW512\fR.
-.IP "\fIkeymaxwords\fR" 4
-.IX Item "keymaxwords"
-Maximum number of keywords that will be generated for an article. (The
-keyword generation code will attempt to discard \*(L"noise\*(R" words, so the
-number of keywords actually writen into the overview will usually be
-smaller than this even if the maximum number of keywords is found.) The
-default value is \f(CW250\fR.
-.Sh "Posting"
-.IX Subsection "Posting"
-These parameters are only used by \fInnrpd\fR\|(8), \fIinews\fR\|(1), and other programs
-that accept or generate postings. There are some special sets of settings
-that are broken out separately after the initial alphabetized list.
-.IP "\fIaddnntppostingdate\fR" 4
-.IX Item "addnntppostingdate"
-Whether to add an NNTP\-Posting\-Date: header to all local posts. This is a
-boolean value and the default is true. Note that \s-1INN\s0 either does not add
-this header or adds the name or \s-1IP\s0 address of the client. There is no
-intrinsic support for obfuscating the name of the client. That has to be
-done with a user-written Perl filter, if desired.
-.IP "\fIaddnntppostinghost\fR" 4
-.IX Item "addnntppostinghost"
-Whether to add an NNTP\-Posting\-Host: header to all local posts giving the
-\&\s-1FQDN\s0 or \s-1IP\s0 address of the system from which the post was received. This
-is a boolean value and the default is true.
-.IP "\fIcheckincludedtext\fR" 4
-.IX Item "checkincludedtext"
-Whether to check local postings for the ratio of new to quoted text and
-reject them if that ratio is under 50%. Included text is recognized by
-looking for lines beginning with \f(CW\*(C`>\*(C'\fR, \f(CW\*(C`|\*(C'\fR, or \f(CW\*(C`:\*(C'\fR. This is a
-boolean value and the default is false.
-.IP "\fIcomplaints\fR" 4
-.IX Item "complaints"
-The value of the X\-Complaints\-To: header added to all local posts. The
-default is the newsmaster's e\-mail address. (If the newsmaster, selected
-at configure time and defaulting to \f(CW\*(C`usenet\*(C'\fR, doesn't contain \f(CW\*(C`@\*(C'\fR, the
-address will consist of the newsmaster, a \f(CW\*(C`@\*(C'\fR, and the value of
-\&\fIfromhost\fR.)
-.IP "\fIfromhost\fR" 4
-.IX Item "fromhost"
-Contains a domain used to construct e\-mail addresses. The address of the
-local news administrator will be given as <user>@\fIfromhost\fR, where <user>
-is the newsmaster user set at compile time (\f(CW\*(C`usenet\*(C'\fR by default). This
-setting will also be used by \fImailpost\fR\|(8) to fully qualify addresses and by
-\&\fIinews\fR\|(1) to generate the Sender: header (and From: header if missing).
-The value of the \s-1FROMHOST\s0 environment variable, if set, overrides this
-setting. The default is the fully-qualified domain name of the local
-host.
-.IP "\fIlocalmaxartsize\fR" 4
-.IX Item "localmaxartsize"
-The maximum article size (in bytes) for locally posted articles. Articles
-larger than this will be rejected. A value of \f(CW0\fR allows any size of
-article, but note that \fBnnrpd\fR and \fBinnd\fR will crash if system memory is
-exceeded. See also \fImaxartsize\fR, which applies to all articles including
-those posted locally. The default value is \f(CW1000000\fR (approximately 1
-\&\s-1MB\s0).
-.IP "\fImoderatormailer\fR" 4
-.IX Item "moderatormailer"
-The address to which to send submissions for moderated groups. It is only
-used if the \fImoderators\fR file doesn't exist, or if the moderated group to
-which an article is posted is not matched by any entry in that file, and
-takes the same form as an entry in the \fImoderators\fR file. In most cases,
-\&\f(CW\*(C`%s@moderators.isc.org\*(C'\fR is a good value for this parameter (\f(CW%s\fR is
-expanded into a form of the newsgroup name). See \fImoderators\fR\|(5) for more
-details about the syntax. The default is unset. If this parameter isn't
-set and an article is posted to a moderated group that does not have a
-matching entry in the \fImoderators\fR file, the posting will be rejected
-with an error.
-.IP "\fInnrpdauthsender\fR" 4
-.IX Item "nnrpdauthsender"
-Whether to generate a Sender: header based on reader authentication. If
-this parameter is set, a Sender: header will be added to local posts
-containing the identity assigned by \fIreaders.conf\fR. If the assigned
-identity does not include an \f(CW\*(C`@\*(C'\fR, the reader's hostname is used. If this
-parameter is set but no identity is be assigned, the Sender: header will
-be removed from all posts even if the poster includes one. This is a
-boolean value and the default is false.
-.IP "\fInnrpdposthost\fR" 4
-.IX Item "nnrpdposthost"
-If set, \fInnrpd\fR\|(8) and \fIrnews\fR\|(1) will pass all locally posted articles to the
-specified host rather than trying to inject them locally. See also
-\&\fInnrpdpostport\fR. This should always be set if \fIxrefslave\fR is true. The
-default value is unset.
-.IP "\fInnrpdpostport\fR" 4
-.IX Item "nnrpdpostport"
-The port on the remote server to connect to to post when \fInnrpdposthost\fR
-is used. The default value is \f(CW119\fR.
-.IP "\fIorganization\fR" 4
-.IX Item "organization"
-What to put in the Organization: header if it is left blank by the poster.
-The value of the \s-1ORGANIZATION\s0 environment variable, if set, overrides this
-setting. The default is unset, which tells \s-1INN\s0 not to insert an
-Organization: header.
-.IP "\fIspoolfirst\fR" 4
-.IX Item "spoolfirst"
-If true, \fInnrpd\fR\|(8) will spool new articles rather than attempting to send
-them to \fIinnd\fR\|(8). If false, nnrpd will spool articles only if it receives
-an error trying to send them to innd. Setting this to true can be useful
-if nnrpd must respond as fast as possible to the client; however, when
-set, articles will not appear to readers until they are given to innd.
-nnrpd won't do this; \f(CW\*(C`rnews \-U\*(C'\fR must be run periodically to take the
-spooled articles and post them. This is a boolean value and the default
-is false.
-.IP "\fIstrippostcc\fR" 4
-.IX Item "strippostcc"
-Whether to strip To:, Cc:, and Bcc: headers out of all local posts via
-\&\fInnrpd\fR\|(8). The primary purpose of this setting is to prevent abuse of the
-news server by posting to a moderated group and including To: or Cc:
-headers in the post so that the news server will send the article to
-arbitrary addresses. \s-1INN\s0 now protects against this abuse in other ways
-provided \fImta\fR is set to a command that includes \f(CW%s\fR and honors it, so
-this is generally no longer needed. This is a boolean value and the
-default is false.
-.PP
-\&\fInnrpd\fR\|(8) has support for controlling high-volume posters via an
-exponential backoff algorithm, as configured by the following parameters.
-.PP
-Exponential posting backoff works as follows: News clients are indexed by
-\&\s-1IP\s0 address (or username, see \fIbackoffauth\fR below). Each time a post is
-received from an \s-1IP\s0 address, the time of posting is stored (along with the
-previous sleep time, see below). After a configurable number of posts in
-a configurable period of time, \fInnrpd\fR\|(8) will activate posting backoff and
-begin to sleep for increasing periods of time before actually posting
-anything. Posts will still be accepted, but at an increasingly reduced
-rate.
-.PP
-After backoff has been activated, the length of time to sleep is computed
-based on the difference in time between the last posting and the current
-posting. If this difference is less than \fIbackoffpostfast\fR, the new
-sleep time will be 1 + (previous sleep time * \fIbackoffk\fR). If this
-difference is less than \fIbackoffpostslow\fR but greater than
-\&\fIbackoffpostfast\fR, then the new sleep time will equal the previous sleep
-time. If this difference is greater than \fIbackoffpostslow\fR, the new
-sleep time is zero and posting backoff is deactivated for this poster.
-.PP
-Exponential posting backoff will not be enabled unless \fIbackoffdb\fR is set
-and \fIbackoffpostfast\fR and \fIbackoffpostslow\fR are set to something other
-than their default values.
-.PP
-Here are the parameters that control exponential posting backoff:
-.IP "\fIbackoffauth\fR" 4
-.IX Item "backoffauth"
-Whether to index posting backoffs by user rather than by source \s-1IP\s0
-address. You must be using authentication in \fInnrpd\fR\|(8) for a value of true
-to have any meaning. This is a boolean value and the default is false.
-.IP "\fIbackoffdb\fR" 4
-.IX Item "backoffdb"
-The path to a directory, writeable by the news user, that will contain the
-backoff database. There is no default for this parameter; you must
-provide a path to a creatable or writeable directory to enable exponential
-backoff.
-.IP "\fIbackoffk\fR" 4
-.IX Item "backoffk"
-The amount to multiply the previous sleep time by if the user is still
-posting too quickly. A value of \f(CW2\fR will double the sleep time for each
-excessive post. The default value is \f(CW1\fR.
-.IP "\fIbackoffpostfast\fR" 4
-.IX Item "backoffpostfast"
-Postings from the same identity that arrive in less than this amount of
-time (in seconds) will trigger increasing sleep time in the backoff
-algorithm. The default value is \f(CW0\fR.
-.IP "\fIbackoffpostslow\fR" 4
-.IX Item "backoffpostslow"
-Postings from the same identity that arrive in greater than this amount of
-time (in seconds) will reset the backoff algorithm. Another way to look
-at this constant is to realize that posters will be allowed to generate at
-most 86400/\fIbackoffpostslow\fR posts per day. The default value is \f(CW1\fR.
-.IP "\fIbackofftrigger\fR" 4
-.IX Item "backofftrigger"
-This many postings are allowed before the backoff algorithm is triggered.
-The default value is \f(CW10000\fR.
-.Sh "Monitoring"
-.IX Subsection "Monitoring"
-These parameters control the behavior of \fIinnwatch\fR\|(8), the program that
-monitors \s-1INN\s0 and informs the news administrator if anything goes wrong
-with it.
-.IP "\fIdoinnwatch\fR" 4
-.IX Item "doinnwatch"
-Whether to start \fIinnwatch\fR\|(8) from rc.news. This is a boolean value, and
-the default is true.
-.IP "\fIinnwatchbatchspace\fR" 4
-.IX Item "innwatchbatchspace"
-Free space in \fIpathoutgoing\fR, in \fIinndf\fR\|(8) output units (normally
-kilobytes), at which \fIinnd\fR\|(8) will be throttled by \fIinnwatch\fR\|(8), assuming a
-default \fIinnwatch.ctl\fR. The default value is \f(CW800\fR.
-.IP "\fIinnwatchlibspace\fR" 4
-.IX Item "innwatchlibspace"
-Free space in \fIpathdb\fR, in \fIinndf\fR\|(8) output units (normally kilobytes), at
-which \fIinnd\fR\|(8) will be throttled by \fIinnwatch\fR\|(8), assuming a default
-\&\fIinnwatch.ctl\fR. The default value is \f(CW25000\fR.
-.IP "\fIinnwatchloload\fR" 4
-.IX Item "innwatchloload"
-Load average times 100 at which \fIinnd\fR\|(8) will be restarted by \fIinnwatch\fR\|(8)
-(undoing a previous pause or throttle), assuming a default
-\&\fIinnwatch.ctl\fR. The default value is \f(CW1000\fR (that is, a load average of
-10.00).
-.IP "\fIinnwatchhiload\fR" 4
-.IX Item "innwatchhiload"
-Load average times 100 at which \fIinnd\fR\|(8) will be throttled by \fIinnwatch\fR\|(8),
-assuming a default \fIinnwatch.ctl\fR. The default value is \f(CW2000\fR (that
-is, a load average of 20.00).
-.IP "\fIinnwatchpauseload\fR" 4
-.IX Item "innwatchpauseload"
-Load average times 100 at which \fIinnd\fR\|(8) will be paused by \fIinnwatch\fR\|(8),
-assuming a default \fIinnwatch.ctl\fR. The default value is \f(CW1500\fR (that
-is, a load average of 15.00).
-.IP "\fIinnwatchsleeptime\fR" 4
-.IX Item "innwatchsleeptime"
-How long (in seconds) \fIinnwatch\fR\|(8) will sleep between each check of \s-1INN\s0.
-The default value is \f(CW600\fR.
-.IP "\fIinnwatchspoolnodes\fR" 4
-.IX Item "innwatchspoolnodes"
-Free inodes in \fIpatharticles\fR at which \fIinnd\fR\|(8) will be throttled by
-\&\fIinnwatch\fR\|(8), assuming a default \fIinnwatch.ctl\fR. The default value is
-\&\f(CW200\fR.
-.IP "\fIinnwatchspoolspace\fR" 4
-.IX Item "innwatchspoolspace"
-Free space in \fIpatharticles\fR and \fIpathoverview\fR, in \fIinndf\fR\|(8) output
-units (normally kilobytes), at which \fIinnd\fR\|(8) will be throttled by
-\&\fIinnwatch\fR\|(8), assuming a default \fIinnwatch.ctl\fR. The default value is
-\&\f(CW8000\fR.
-.Sh "Logging"
-.IX Subsection "Logging"
-These parameters control what information \s-1INN\s0 logs.
-.IP "\fIdocnfsstat\fR" 4
-.IX Item "docnfsstat"
-Whether to start \fIcnfsstat\fR\|(8) when \fIinnd\fR\|(8) is started. cnfsstat will log
-the status of all \s-1CNFS\s0 cycbuffs to syslog on a periodic basis (frequency
-is the default for \f(CW\*(C`cnfsstat \-l\*(C'\fR, currently 600 seconds). This is a
-boolean value and the default is false.
-.IP "\fIlogartsize\fR" 4
-.IX Item "logartsize"
-Whether the size of accepted articles (in bytes) should be written to the
-article log file. This is useful for flow rate statistics and is
-recommended. This is a boolean value and the default is true.
-.IP "\fIlogcancelcomm\fR" 4
-.IX Item "logcancelcomm"
-Set this to true to log \f(CW\*(C`ctlinnd cancel\*(C'\fR commands to syslog. This is a
-boolean value and the default is false.
-.IP "\fIlogcycles\fR" 4
-.IX Item "logcycles"
-How many old logs \fIscanlogs\fR\|(8) keeps. \fIscanlogs\fR\|(8) is generally run by
-\&\fInews.daily\fR\|(8) and will archive compressed copies of this many days worth
-of old logs. The default value is \f(CW3\fR.
-.IP "\fIlogipaddr\fR" 4
-.IX Item "logipaddr"
-Whether the verified name of the remote feeding host should be logged to
-the article log for incoming articles rather than the last entry in the
-Path: header. The only reason to ever set this to false is due to some
-interactions with \fInewsfeeds\fR flags; see \fInewsfeeds\fR\|(5) for more
-information. This is a boolean value and the default is true.
-.IP "\fIlogsitename\fR" 4
-.IX Item "logsitename"
-Whether the names of the sites to which accepted articles will be sent
-should be put into the article log file. This is useful for debugging and
-statistics and can be used by \fInewsrequeue\fR\|(8). This is a boolean value and
-the default is true.
-.IP "\fInnrpdoverstats\fR" 4
-.IX Item "nnrpdoverstats"
-Whether nnrpd overview statistics should be logged via syslog. This can
-be useful for measuring overview performance. This is a boolean value and
-the default is false.
-.IP "\fInntpactsync\fR" 4
-.IX Item "nntpactsync"
-How many articles to process on an incoming channel before logging the
-activity. The default value is \f(CW200\fR.
-.Sp
-\&\s-1FIXME:\s0 This is a rather unintuitive name for this parameter.
-.IP "\fInntplinklog\fR" 4
-.IX Item "nntplinklog"
-Whether to put the storage \s-1API\s0 token for accepted articles (used by
-nntplink) in the article log. This is a boolean value and the default is
-false.
-.IP "\fIstathist\fR" 4
-.IX Item "stathist"
-Where to write history statistics for analysis with
-\&\fIcontrib/stathist.pl\fR; this can be modified with \fIctlinnd\fR\|(8) while innd is
-running. Logging does not occur unless a path is given, and there is no
-default value.
-.IP "\fIstatus\fR" 4
-.IX Item "status"
-How frequently (in seconds) \fIinnd\fR\|(8) should write out a status report. The
-report is written to \fIpathhttp\fR/inn_status.html. If this is set to \f(CW0\fR or
-\&\f(CW\*(C`false\*(C'\fR, status reporting is disabled. The default value is \f(CW0\fR.
-.IP "\fItimer\fR" 4
-.IX Item "timer"
-How frequently (in seconds) \fIinnd\fR\|(8) should report performance timings to
-syslog. If this is set to \f(CW0\fR, performance timing is disabled. Enabling
-this is highly recommended, and \fIinnreport\fR\|(8) can produce a nice summary of
-the timings. If set to \f(CW0\fR, performance timings in \fInnrpd\fR\|(8) are also
-disabled, although nnrpd always reports statistics on exit and therefore
-any non-zero value is equivalent for it. The default value is \f(CW0\fR.
-.Sh "System Tuning"
-.IX Subsection "System Tuning"
-The following parameters can be modified to tune the low-level operation
-of \s-1INN\s0. In general, you shouldn't need to modify any of them except
-possibly \fIrlimitnofile\fR unless the server is having difficulty.
-.IP "\fIbadiocount\fR" 4
-.IX Item "badiocount"
-How many read or write failures until a channel is put to sleep or
-closed. The default value is \f(CW5\fR.
-.IP "\fIblockbackoff\fR" 4
-.IX Item "blockbackoff"
-Each time an attempted write returns \s-1EAGAIN\s0 or \s-1EWOULDBLOCK\s0, \fIinnd\fR\|(8) will
-wait for an increasing number of seconds before trying it again. This is
-the multiplier for the sleep time. If you're having trouble with channel
-feeds not keeping up, it may be good to change this value to \f(CW2\fR or \f(CW3\fR,
-since then when the channel fills \s-1INN\s0 will try again in a couple of
-seconds rather than waiting two minutes. The default value is \f(CW120\fR.
-.IP "\fIchaninacttime\fR" 4
-.IX Item "chaninacttime"
-The time (in seconds) to wait between noticing inactive channels. The
-default value is \f(CW600\fR.
-.IP "\fIchanretrytime\fR" 4
-.IX Item "chanretrytime"
-How many seconds to wait before a channel restarts. The default value is
-\&\f(CW300\fR.
-.IP "\fIdatamovethreshold\fR" 4
-.IX Item "datamovethreshold"
-The threshold for deciding whether to move already-read data to the top of
-buffer or extend the buffer. The buffer described here is used for reading
-\&\s-1NNTP\s0 data. Increasing this value may improve performance, but it should
-not be increased on Systems with insufficient memory. Permitted values
-are between \f(CW0\fR and \f(CW1048576\fR (out of range values are treated as
-\&\f(CW1048576\fR) and the default value is \f(CW8192\fR.
-.IP "\fIicdsynccount\fR" 4
-.IX Item "icdsynccount"
-How many article writes between updating the active and history files.
-The default value is \f(CW10\fR.
-.IP "\fIkeepmmappedthreshold\fR" 4
-.IX Item "keepmmappedthreshold"
-When using buffindexed, retrieving overview data (that is, responding to
-\&\s-1XOVER\s0 or running expireover) causes mmapping of all overview data blocks
-which include requested overview data for newsgroup. But for high volume
-newsgroups like control.cancel, this may cause too much mmapping at once
-leading to system resource problems. To avoid this, if the amount to be
-mmapped exceeds \fIkeepmmappedthreshold\fR (in \s-1KB\s0), buffindexed mmap's just
-one overview block (8 \s-1KB\s0). This parameter is specific to buffindexed
-overview storage method. The default value is \f(CW1024\fR (1 \s-1MB\s0).
-.IP "\fImaxcmdreadsize\fR" 4
-.IX Item "maxcmdreadsize"
-If set to anything other than \f(CW0\fR, maximum buffer size (in bytes) for
-reading \s-1NNTP\s0 command will have this value. It should not be large on
-systems which are slow to process and store articles, as that would lead
-to \fIinnd\fR\|(8) spending a long time on each channel and keeping other channels
-waiting. The default value is \s-1BUFSIZ\s0 defined in stdio.h (\f(CW1024\fR in most
-environments, see \fIsetbuf\fR\|(3)).
-.IP "\fImaxforks\fR" 4
-.IX Item "maxforks"
-How many times to attempt a \fIfork\fR\|(2) before giving up. The default value
-is \f(CW10\fR.
-.IP "\fInicekids\fR" 4
-.IX Item "nicekids"
-If set to anything other than \f(CW0\fR, all child processes of \fIinnd\fR\|(8) will
-have this \fInice\fR\|(2) value. This is usually used to give all child processes
-of \fIinnd\fR\|(8) a lower priority (higher nice value) so that \fIinnd\fR\|(8) can get
-the lion's share of the \s-1CPU\s0 when it needs it. The default value is \f(CW4\fR.
-.IP "\fInicenewnews\fR" 4
-.IX Item "nicenewnews"
-If set to anything greater than \f(CW0\fR, all \fInnrpd\fR\|(8) processes that receive
-and process a \s-1NEWNEWS\s0 command will \fInice\fR\|(2) themselves to this value
-(giving other nnrpd processes a higher priority). The default value is
-\&\f(CW0\fR. Note that this value will be ignored if set to a lower value than
-\&\fInicennrpd\fR (or \fInicekids\fR if \fInnrpd\fR\|(8) is spawned from \fIinnd\fR\|(8)).
-.IP "\fInicennrpd\fR" 4
-.IX Item "nicennrpd"
-If set to anything greater than \f(CW0\fR, all \fInnrpd\fR\|(8) processes will \fInice\fR\|(1)
-themselves to this value. This gives other news processes a higher
-priority and can help \fIoverchan\fR\|(8) keep up with incoming news (if that's
-the object, be sure \fIoverchan\fR\|(8) isn't also set to a lower priority via
-\&\fInicekids\fR). The default value is \f(CW0\fR, which will cause \fInnrpd\fR\|(8)
-processes spawned from \fIinnd\fR\|(8) to use the value of \fInicekids\fR, while
-\&\fInnrpd\fR\|(8) run as a daemon will use the system default priority. Note that
-for \fInnrpd\fR\|(8) processes spawned from \fIinnd\fR\|(8), this value will be ignored if
-set to a value lower than \fInicekids\fR.
-.IP "\fIpauseretrytime\fR" 4
-.IX Item "pauseretrytime"
-Wait for this many seconds before noticing inactive channels.
-Wait for this many seconds before innd processes articles when it's paused
-or the number of channel write failures exceeds \fIbadiocount\fR. The
-default value is \f(CW300\fR.
-.IP "\fIpeertimeout\fR" 4
-.IX Item "peertimeout"
-How long (in seconds) an \fIinnd\fR\|(8) incoming channel may be inactive before
-innd closes it. The default value is \f(CW3600\fR (an hour).
-.IP "\fIrlimitnofile\fR" 4
-.IX Item "rlimitnofile"
-The maximum number of file descriptors that \fIinnd\fR\|(8) or \fIinnfeed\fR\|(8) can have
-open at once. If \fIinnd\fR\|(8) or \fIinnfeed\fR\|(8) attempts to open more file
-descriptors than this value, it is possible the program may throttle or
-otherwise suffer reduced functionality. The number of open file
-descriptors is roughly the maximum number of incoming feeds and outgoing
-batches for \fIinnd\fR\|(8) and the number of outgoing streams for \fIinnfeed\fR\|(8). If
-this parameter is set to a negative value, the default limit of the
-operating system will be used; this will normally be adequate on systems
-other than Solaris. Nearly all operating systems have some hard maximum
-limit beyond which this value cannot be raised, usually either 128, 256,
-or 1024. The default value of this parameter is \f(CW\*(C`\-1\*(C'\fR. Setting it to
-\&\f(CW256\fR on Solaris systems is highly recommended.
-.Sh "Paths and File Names"
-.IX Subsection "Paths and File Names"
-.IP "\fIpatharchive\fR" 4
-.IX Item "patharchive"
-Where to store archived news. The default value is \fIpathspool\fR/archive.
-.IP "\fIpatharticles\fR" 4
-.IX Item "patharticles"
-The path to where the news articles are stored (for storage methods other
-than \s-1CNFS\s0). The default value is \fIpathspool\fR/articles.
-.IP "\fIpathbin\fR" 4
-.IX Item "pathbin"
-The path to the news binaries. The default value is \fIpathnews\fR/bin.
-.IP "\fIpathcontrol\fR" 4
-.IX Item "pathcontrol"
-The path to the files that handle control messages. The code for handling
-each separate type of control message is located here. Be very careful
-what you put in this directory with a name ending in \f(CW\*(C`.pl\*(C'\fR, as it can
-potentially be a severe security risk. The default value is
-\&\fIpathbin\fR/control.
-.IP "\fIpathdb\fR" 4
-.IX Item "pathdb"
-The path to the database files used and updated by the server (currently,
-\&\fIactive\fR, \fIactive.times\fR, \fIhistory\fR and its indices, and
-\&\fInewsgroups\fR). The default value is \fIpathnews\fR/db.
-.IP "\fIpathetc\fR" 4
-.IX Item "pathetc"
-The path to the news configuration files. The default value is
-\&\fIpathnews\fR/etc.
-.IP "\fIpathfilter\fR" 4
-.IX Item "pathfilter"
-The path to the Perl, Tcl, and Python filters. The default value is
-\&\fIpathbin\fR/filter.
-.IP "\fIpathhttp\fR" 4
-.IX Item "pathhttp"
-Where any \s-1HTML\s0 files (such as periodic status reports) are placed. If the
-news reports should be available in real-time on the web, the files in
-this directory should be served by a web server. The default value is
-the value of \fIpathlog\fR.
-.IP "\fIpathincoming\fR" 4
-.IX Item "pathincoming"
-Location where incoming batched news is stored. The default value is
-\&\fIpathspool\fR/incoming.
-.IP "\fIpathlog\fR" 4
-.IX Item "pathlog"
-Where the news log files are written. The default value is
-\&\fIpathnews\fR/log.
-.IP "\fIpathnews\fR" 4
-.IX Item "pathnews"
-The home directory of the news user and usually the root of the news
-hierarchy. There is no default; this parameter must be set in \fIinn.conf\fR
-or \s-1INN\s0 will refuse to start.
-.IP "\fIpathoutgoing\fR" 4
-.IX Item "pathoutgoing"
-Default location for outgoing feed files. The default value is
-\&\fIpathspool\fR/outgoing.
-.IP "\fIpathoverview\fR" 4
-.IX Item "pathoverview"
-The path to news overview files. The default value is
-\&\fIpathspool\fR/overview.
-.IP "\fIpathrun\fR" 4
-.IX Item "pathrun"
-The path to files required while the server is running and run-time state
-information. This includes lock files and the sockets for communicating
-with \fIinnd\fR\|(8). This directory and the control sockets in it should be
-protected from unprivileged users other than the news user. The default
-value is \fIpathnews\fR/run.
-.IP "\fIpathspool\fR" 4
-.IX Item "pathspool"
-The root of the news spool hierarchy. This used mostly to set the
-defaults for other parameters, and to determine the path to the backlog
-directory for \fIinnfeed\fR\|(8). The default value is \fIpathnews\fR/spool.
-.IP "\fIpathtmp\fR" 4
-.IX Item "pathtmp"
-Where \s-1INN\s0 puts temporary files. For security reasons, this is not the
-same as the system temporary files directory (\s-1INN\s0 creates a lot of
-temporary files with predictable names and does not go to particularly
-great lengths to protect against symlink attacks and the like; this
-is safe provided that normal users can't write into its temporary
-directory). The default value is set at configure time and defaults to
-\&\fIpathnews\fR/tmp.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-Here is a very minimalist example that only sets those parameters that are
-required.
-.PP
-.Vb 5
-\& mta: /usr/lib/sendmail \-oi \-oem %s
-\& ovmethod: tradindexed
-\& pathhost: news.example.com
-\& pathnews: /usr/local/news
-\& hismethod: hisv6
-.Ve
-.PP
-For a more comprehensive example, see the sample \fIinn.conf\fR distributed
-with \s-1INN\s0 and installed as a starting point; it contains all of the default
-values for reference.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews and since
-modified, updated, and reorganized by innumerable other people.
-.PP
-$Id: inn.conf.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinews\fR\|(1), \fIinnd\fR\|(8), \fIinnwatch\fR\|(8), \fInnrpd\fR\|(8), \fIrnews\fR\|(1).
-.PP
-Nearly every program in \s-1INN\s0 uses this file to one degree or another. The
-above are just the major and most frequently mentioned ones.
+++ /dev/null
-.TH INNCHECK 8
-.SH NAME
-inncheck \- check inn configuration and database files.
-.SH SYNOPSIS
-.B inncheck
-[
-.B \-a
-]
-[
-.B \-v
-]
-[
-.B \-pedantic
-]
-[
-.B \-f
-]
-[
-.B \-perm
-]
-[
-.B \-noperm
-]
-[
-.B "file=value | file"
-]
-.SH DESCRIPTION
-.I Inncheck
-examines various configuration files and databases and verifies things
-about them. Things verified depend on the file being checked, but generally
-are things like permissions, ownership, syntax errors in config files, etc.
-.PP
-.I Inncheck
-does not make changes to any files \(em it just reports what it
-thinks may be wrong, and it is up to the operator to fix the problem.
-.PP
-The set of files checked may be restricted by using \fBfile\fP or
-\fBfile=value\fP arguments. For example, putting \fBincoming.conf\fP causes
-only the
-.I incoming.conf
-file to be checked. Using \fBincoming.conf=/tmp/incoming.conf\fP on the
-command line will cause
-.I inncheck
-to only verify the incoming.conf file, and it will perform the
-checks on the file
-/tmp/incoming.conf file instead of the default one.
-.PP
-Valid values for
-.I file
-are:
-.PP
-.RS
-.nf
- active
- control.ctl
- expire.ctl
- incoming.conf
- inn.conf
- moderators
- newsfeeds
- overview.fmt
- nntpsend.ctl
- passwd.nntp
- readers.conf
-.fi
-.RE
-.SH OPTIONS
-.TP
-.B \-a
-If any ``\fBfile\fP'' value or ``\fBfile=value\fP'' pairs (see below) are
-given, then normally only the files they refer to are checked. Use
-the ``\fB\-a\fP'' flag to specify that
-.I all
-files should be checked regardless. In this case the form \fBfile=value\fP
-will be the more useful.
-.TP
-.B \-v
-Use the ``\fB\-v\fP'' option to get more verbose output.
-.TP
-.B \-pedantic
-Use the ``\fB\-pedantic\fP'' option to get reports on things that are not
-necessarily wrong, but may indicate a bad configuration \(em such as
-\fIinn.conf\fP missing a key.
-.TP
-.B \-f
-Use the ``\fB\-f\fP'' flag to have inncheck print the appropriate
-chown/chgrp/chmod command necessary to fix a problem that it reports. Any
-other output lines will be prefixed with a ``#'' character to make the
-output be valid input for a shell. Note that the ``\fB\-perm\fP'' flag
-must be used as well when using this flag.
-.TP
-.B \-perm
-Inncheck checks all files for permission problems.
-If the ``\fB\-perm\fP'' flag is used, then
-.I only
-the files specified by the \fBfile\fP or \fBfile=value\fP command line
-arguments will be checked for problems other than permission problems.
-.TP
-.B \-noperm
-To avoid doing any checking of file permissions or ownership, use
-the ``\fB-noperm\fP'' option.
-.SH EXAMPLES
-.PP
-To have
-.I inncheck
-check all files for syntax and permission problems simply:
-.PP
-.RS
-.nf
-inncheck
-.fi
-.RE
-.PP
-To have
-.I inncheck
-check all files for permission problems and to verify the syntax of the
-active and incoming.conf files do:
-.PP
-.RS
-.nf
-inncheck -perm active incoming.conf
-.fi
-.RE
-.PP
-To fix the permissions problems noted in the output of the above
-command, modify it as follow:
-.PP
-.RS
-.nf
-inncheck -f -perm | sh
-.fi
-.RE
-.PP
-To have
-.I inncheck
-check the test newsfeeds file in /var/tmp/newsfeeds.testing, do:
-.PP
-.RS
-.nf
-inncheck newsfeeds=/var/tmp/newsfeeds.testing
-.fi
-.RE
-.PP
-To have
-.I inncheck
-check all the files as it normally does, but to specify a different
-location for the newsfeeds file, so:
-.PP
-.RS
-.nf
-inncheck -a newsfeeds=/var/tmp/newsfeeds.testing
-.fi
-.RE
-.SH BUGS
-If the ``\fB-f\fP'' and ``\fB-perm\fP'' options are used together, along with
-``\fB\-a\fP'' or some ``\fBfile\fP'' or ``\fBfile=value\fP'' arguments that
-refer to a file with a syntax problem, then the output will no longer be
-valid input for a shell.
-.SH HISTORY
-Written by Brendan Kehoe <brendan@cygnus.com> and
-Rich Salz <rsalz@uunet.uu.net>
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: inncheck.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-active(5),
-expire.ctl(5),
-history(5),
-incoming.conf(5),
-inn.conf(5),
-newsfeeds(5)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INNCONFVAL 1"
-.TH INNCONFVAL 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-innconfval \- Get configuration parameters from inn.conf
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinnconfval\fR [\fB\-pstv\fR] [\fB\-i\fR \fIfile\fR] [\fIparameter\fR ...]
-.PP
-\&\fBinnconfval\fR \fB\-C\fR [\fB\-i\fR \fIfile\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinnconfval\fR normally prints the values of the parameters specified on
-the command line. By default, it just prints the parameter values, but if
-\&\fB\-p\fR, \fB\-s\fR, or \fB\-t\fR are given, it instead prints the parameter and
-value in the form of a variable assignment in Perl, Bourne shell, or Tcl
-respectively. If no parameters are specifically requested, \fBinnconfval\fR
-prints out all parameter values (this isn't particularly useful unless one
-of \fB\-p\fR, \fB\-s\fR, or \fB\-t\fR were specified).
-.PP
-All parameters are taken from \fIinn.conf\fR except for \fIversion\fR, which is
-always the version string of \s-1INN\s0.
-.PP
-If given the \fB\-C\fR option, \fBinnconfval\fR instead checks \fIinn.conf\fR,
-reporting any problems found to standard error. \fBinnconfval\fR will exit
-with status 0 if no problems are found and with status 1 otherwise.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-C\fR" 4
-.IX Item "-C"
-Check \fIinn.conf\fR rather than printing out the values of parameters.
-.IP "\fB\-i\fR \fIfile\fR" 4
-.IX Item "-i file"
-Use \fIfile\fR as the source configuration file rather than \fIinn.conf\fR.
-\&\fIfile\fR must be a valid \fIinn.conf\fR file and will be parsed the same as
-\&\fIinn.conf\fR would be.
-.IP "\fB\-p\fR" 4
-.IX Item "-p"
-Print out parameters as Perl assignment statements. The variable name
-will be the same as the \fIinn.conf\fR parameter, and string values will be
-enclosed in single quotes with appropriate escaping. Boolean values will
-be mapped to \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`false\*(C'\fR, and string parameters that are set to
-\&\s-1NULL\s0 will be mapped to empty strings.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-Print out parameters as Bourne shell assignment statements. The variable
-name will be the \fIinn.conf\fR parameter name in all capitals, and all
-variables will be exported. String values will be enclosed in single
-quotes with appropriate escaping, and boolean values will be mapped to
-\&\f(CW\*(C`true\*(C'\fR or \f(CW\*(C`false\*(C'\fR. String parameters that are set to \s-1NULL\s0 will be
-mapped to empty strings.
-.IP "\fB\-t\fR" 4
-.IX Item "-t"
-Print out parameters as Tcl assignment statements. The variable name will
-be the same as the \fIinn.conf\fR parameter name but with \f(CW\*(C`inn_\*(C'\fR prepended,
-and string variables will be escaped appropriately. Boolean values will
-be mapped to \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`false\*(C'\fR and string parameters that are set to
-\&\s-1NULL\s0 will be mapped to empty strings.
-.IP "\fB\-v\fR" 4
-.IX Item "-v"
-Print \s-1INN\s0's version. This is equivalent to \f(CW\*(C`innconfval version\*(C'\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews.
-.PP
-$Id: innconfval.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INND 8"
-.TH INND 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-innd \- InterNetNews daemon
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinnd\fR [\fB\-aCdfNrsu\fR] [\fB\-c\fR \fIdays\fR] [\fB\-H\fR \fIcount\fR] [\fB\-i\fR \fIcount\fR]
-[\fB\-I\fR \fIaddress\fR] [\fB\-l\fR \fIsize\fR] [\fB\-m\fR \fImode\fR] [\fB\-n\fR \fIflag\fR]
-[\fB\-o\fR \fIcount\fR] [\fB\-p\fR \fIfd\fR] [\fB\-P\fR \fIport\fR] [\fB\-t\fR \fItimeout\fR]
-[\fB\-T\fR \fIcount\fR] [\fB\-X\fR \fIseconds\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinnd\fR, the InterNetNews daemon, handles all incoming \s-1NNTP\s0 feeds,
-coordinates the storage, retransmission, and overview generation for all
-accepted articles, and manages the \fIactive\fR\|(5) and \fIhistory\fR\|(5) databases. It
-handles incoming connections on the \s-1NNTP\s0 port, and also creates and
-listens to a local Unix-domain stream socket in order to receive articles
-from local processes such as \fInnrpd\fR\|(8) and \fIrnews\fR\|(1).
-.PP
-As the master daemon, \fBinnd\fR should generally be started at boot and be
-always running. It listens to a Unix-domain datagram socket for commands
-to control its activites, commands that can be sent using \fIctlinnd\fR\|(8). The
-current status of \fBinnd\fR can be obtained by running \f(CW\*(C`ctlinnd mode\*(C'\fR, or
-for more detailed output, \fIinnstat\fR\|(8).
-.PP
-\&\fBinnd\fR can be in one of three operating modes: running, paused, or
-throttled. Running is the normal mode; when the server is throttled, it
-closes connections and rejects new ones. Paused is like a temporary
-throttle, suspending \fBinnd\fR's activities but not causing the server to
-shut down existing connections. The mode is normally changed via
-\&\fIctlinnd\fR\|(8), either by various automated processes (such as nightly article
-expiration) or manually by the news administrator, but \fBinnd\fR will also
-throttle itself if it encounters \s-1ENOSPC\s0 errors in writing data or an
-excessive number of I/O errors (among other problems).
-.PP
-\&\fBinnd\fR normally takes care of spawning \fInnrpd\fR\|(8) to handle connections
-from news reading clients, but it can be run on a separate port from
-\&\fInnrpd\fR\|(8) so that feed connections and news reading connections are handled
-separately (this can often be faster). Normally, \fBinnd\fR listens on port
-119, the assigned port for \s-1NNTP\s0; if it is desireable to run \fBinnd\fR and
-\&\fInnrpd\fR\|(8) on separate ports, it's recommended that \fInnrpd\fR\|(8) be given port
-119 (since many news reading clients connect only to that port) and that
-port 433 be used for \fBinnd\fR.
-.PP
-The primary configuration files that control \fBinnd\fR's activities are
-\&\fIincoming.conf\fR, which specifies what remote sites \fBinnd\fR will accept
-connections from, \fInewsfeeds\fR, which specifies what is to be done with
-incoming articles besides storing them, and \fIinn.conf\fR, which sets a wide
-variety of configuration parameters. Some parameters in \fIinn.conf\fR\|(5) can
-also be set with command-line flags; for these, the command-line flags
-take precedence if used.
-.PP
-\&\fBinnd\fR should normally not run directly. It must run as the news user or
-all sorts of file ownership problems may result, and normally the port it
-listens on (119 or 433) is privileged and must be opened by root.
-Instead, \fBinnd\fR should normally be started via \fIinndstart\fR\|(8), a small
-setuid-root program that opens the appropriate port, cleans up the
-environment, changes to the news user, and then runs \fBinnd\fR, passing
-along any command-line arguments.
-.PP
-To use IPv6, \fBinnd\fR must be started by \fBinndstart\fR.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-For the options below that override \fIinn.conf\fR settings, see \fIinn.conf\fR\|(5)
-for the default values if neither the \fIinn.conf\fR setting nor the
-command-line option is given.
-.IP "\fB\-a\fR" 4
-.IX Item "-a"
-By default, if a host connects to \fBinnd\fR but is not listed in
-\&\fIincoming.conf\fR, the connection is handed off to \fBnnrpd\fR (or rejected if
-\&\fInoreader\fR is set in \fIinn.conf\fR). If \fB\-a\fR is given, \fIincoming.conf\fR
-is ignored and any host can connect and transfer articles. This flag
-should never be used with an accessible server connected to Usenet; it
-would open the server up for all sorts of abuse.
-.IP "\fB\-c\fR \fIdays\fR" 4
-.IX Item "-c days"
-\&\fBinnd\fR normally rejects any article that is older (in days) than the
-value of \fIartcutoff\fR in \fIinn.conf\fR. This option, if given, overrides
-the value of that setting. If \fIdays\fR is 0, this check is suppressed and
-\&\fBinnd\fR will accept articles regardless of how old they are.
-.IP "\fB\-C\fR" 4
-.IX Item "-C"
-This flag tells \fBinnd\fR to accept and propagate but not actually process
-cancel or supersede messages. This is intended for sites concerned about
-abuse of cancels, or that wish to use another cancel mechanism with
-stronger authentication.
-.IP "\fB\-d\fR, \fB\-f\fR" 4
-.IX Item "-d, -f"
-\&\fBinnd\fR normally puts itself into the background, points its standard
-output and error to log files, and disassociates itself from the
-terminal. Using \fB\-d\fR prevents all of this, resulting in log messages
-being written to standard output; this is generally useful only for
-debugging. Using \fB\-f\fR prevents the backgrounding and disassociation but
-still redirects output; it may be useful if you want to monitor \fBinnd\fR
-with a program that would be confused by forks.
-.IP "\fB\-H\fR \fIcount\fR, \fB\-T\fR \fIcount\fR, \fB\-X\fR \fIseconds\fR" 4
-.IX Item "-H count, -T count, -X seconds"
-These flags control the number of connections per minute that are allowed.
-This code is meant to protect your server from newsreader clients that
-make too many connections per minute (and therefore these flags are
-probably only useful when \fBinnd\fR is spawning \fBnnrpd\fR). You probably
-should not use these options unless you're having problems. The table
-used for this check is fixed at 128 entries and is used as a ring; the
-size was chosen to make calculating the index easy and to be fairly sure
-that it won't run out of space. In practice, it is unlikely that even
-half the table will be used at any given moment.
-.Sp
-The \fB\-H\fR flag limits the number of times a host is allowed to connect to
-the server per the time interval given by \fB\-X\fR. The default is \f(CW2\fR.
-.Sp
-The \fB\-T\fR flag limits the total number of incoming connections per the
-time interval given by \fB\-X\fR. The maximum value is \f(CW128\fR, and the
-default is \f(CW60\fR.
-.IP "\fB\-i\fR \fIcount\fR" 4
-.IX Item "-i count"
-\&\fBinnd\fR normally allows a maximum number of concurrent \s-1NNTP\s0 connections
-given by the value of \fImaxconnections\fR in \fIinn.conf\fR. This option, if
-given, overrides the value of that setting. If \fIcount\fR is \f(CW0\fR, this
-check is suppressed.
-.IP "\fB\-I\fR \fIaddress\fR" 4
-.IX Item "-I address"
-Normally if \fBinnd\fR itself binds to a port, it lets the operating system
-pick the source \s-1IP\s0 address (unless \fIbindaddress\fR is set in \fIinn.conf\fR).
-If this option is given, it specifies the \s-1IP\s0 address that \s-1INN\s0 should bind
-as. This is only relevant for servers with multiple local \s-1IP\s0 addresses.
-The \s-1IP\s0 address must be in dotted quad (\f(CW\*(C`nnn.nnn.nnn.nnn\*(C'\fR) format.
-.Sp
-This option is rarely useful since \fBinnd\fR should not be binding to a
-port itself. Instead, use \fIinndstart\fR\|(8) and its analgous \fB\-I\fR option.
-.IP "\fB\-l\fR \fIsize\fR" 4
-.IX Item "-l size"
-\&\fBinnd\fR normally rejects any article larger than the value of
-\&\fImaxartsize\fR in \fIinn.conf\fR. This option, if given, overrides the value
-of that setting and specifies a maximum article size of \fIsize\fR. If
-\&\fIsize\fR is \f(CW0\fR, this check is suppressed.
-.IP "\fB\-m\fR \fImode\fR" 4
-.IX Item "-m mode"
-Normally \fBinnd\fR starts in the \f(CW\*(C`running\*(C'\fR mode. If this option is given,
-it specifies what mode \fBinnd\fR should start in. \fImode\fR should begin with
-one of \f(CW\*(C`g\*(C'\fR, \f(CW\*(C`p\*(C'\fR, or \f(CW\*(C`t\*(C'\fR, and the starting mode will be set to
-\&\f(CW\*(C`running\*(C'\fR, \f(CW\*(C`paused\*(C'\fR, or \f(CW\*(C`throttled\*(C'\fR, respectively, based on that
-initial letter. (\f(CW\*(C`g\*(C'\fR is short for \f(CW\*(C`go\*(C'\fR.)
-.IP "\fB\-N\fR" 4
-.IX Item "-N"
-If this option is given, any filters (Perl, Tcl, or Python) are disabled
-before \fBinnd\fR starts (normally, filters default to being enabled). The
-filters can be enabled after \fBinnd\fR has started with \fIctlinnd\fR\|(8).
-.IP "\fB\-n\fR \fIflag\fR" 4
-.IX Item "-n flag"
-Whether \fBinnd\fR allows (and hands off to \fBnnrpd\fR) reader connections
-while paused or throttled is normally determined by the value of
-\&\fIreaderswhenstopped\fR in \fIinn.conf\fR). This option, if given, overrides
-that value. If \fIflag\fR is \f(CW\*(C`n\*(C'\fR, \fBinnd\fR will not allow readers if it is
-paused or throttled. If \fIflag\fR is \f(CW\*(C`y\*(C'\fR, readers will be allowed
-regardless of \fBinnd\fR's operating mode.
-.IP "\fB\-o\fR \fIcount\fR" 4
-.IX Item "-o count"
-This flag limits the number of file descriptors that are available for
-outgoing file feeds. The default is the number of available file
-descriptors minus some reserved for internal use (which could potentially
-starve \fBinnd\fR of descriptors to use for accepting new connections). If
-\&\fBinnd\fR has more file feeds than \fIcount\fR, some of them will be buffered
-and only written out periodically.
-.Sp
-Normally you never need to use this option, since the number of outgoing
-feeds is fixed, being the number of file feeds configured in \fInewsfeeds\fR,
-and is generally small (particularly given that \fIinnfeed\fR\|(8) is now used for
-most outgoing feeds at large sites).
-.IP "\fB\-p\fR \fIfd\fR" 4
-.IX Item "-p fd"
-If this flag is given, \fBinnd\fR expects the file descriptor given by \fIfd\fR
-to already be open and bound to the appropriate local port and to be
-suitable for listening to for incoming connections. This is how
-\&\fBinndstart\fR tells \fBinnd\fR which open file descriptor is the network
-connection. If this flag is not given, \fBinnd\fR will attempt to open its
-network socket itself. \fBinndstart\fR always passes this flag to \fBinnd\fR.
-.IP "\fB\-P\fR \fIport\fR" 4
-.IX Item "-P port"
-The port \fBinnd\fR should listen on is normally given by the value of
-\&\fIport\fR in \fIinn.conf\fR. This option, if given, overrides that value and
-specifies the port that \fBinnd\fR should bind to. This option is rarely
-useful since \fBinnd\fR normally does not bind itself; instead the analgous
-\&\fB\-P\fR option to \fIinndstart\fR\|(8) should be used. Since \fBinnd\fR should never
-be run as root, \fIport\fR has to be a non-privileged port (one larger than
-1024).
-.IP "\fB\-r\fR" 4
-.IX Item "-r"
-Instructs \fBinnd\fR to renumber the \fIactive\fR file after starting, just as
-if a \f(CW\*(C`ctlinnd renumber\*(C'\fR command were sent.
-.IP "\fB\-s\fR" 4
-.IX Item "-s"
-Just check the syntax of the \fInewsfeeds\fR file and exit. \fBinnd\fR will
-exit with a non-zero status if any errors are found; the actual errors
-will be reported via \fIsyslog\fR\|(3).
-.IP "\fB\-t\fR \fIseconds\fR" 4
-.IX Item "-t seconds"
-Normally, \fBinnd\fR will flush any changes to history and the active file
-after 300 seconds of inactivity. This option changes that timeout to
-\&\fIseconds\fR.
-.IP "\fB\-u\fR" 4
-.IX Item "-u"
-The news log (the trace information for every article accepted by \fBinnd\fR)
-is normally buffered. This option changes the log to be unbuffered.
-.SH "CONTROL MESSAGES"
-.IX Header "CONTROL MESSAGES"
-Arriving articles that have a Control: header are called \*(L"control
-messages\*(R". Except for cancel messages, these messages are handled by
-\&\fIcontrolchan\fR\|(8) via a feed set up in \fInewsfeeds\fR.
-.PP
-(Cancel messages update the history database, so they must be handled
-internally; the cost of syncing, locking, then unlocking would be too high
-given the number of cancel messages that are received. Note that if an
-article is cancelled before it is received by the news server, it will
-be rejected when it arrives since the history database has been updated;
-it is useful for rejecting spam before it arrives.)
-.PP
-The distribution of control messages is different than that of standard
-articles. Control messages are normally filed into the pseudo-newsgroup
-named \f(CW\*(C`control\*(C'\fR regardless of which newsgroup they were actually posted
-to. If, however, a \f(CW\*(C`control.\*(C'\fR\fIcommand\fR newsgroup exists that matches
-the control command, the control message will be filed into that group
-instead. For example, a newgroup control message will be filed in
-\&\f(CW\*(C`control.newgroup\*(C'\fR if that group exists; otherwise, it will be filed in
-\&\f(CW\*(C`control\*(C'\fR.
-.PP
-If you want to specifically feed all control messages to a given site
-regardless of whether the control messages would affect the newsgroups
-you're feeding that site, you can put the appropriate control newsgroup in
-the subscription list. For example, to feed all cancel messages to a
-given remote site (normally a bad idea), add \f(CW\*(C`control.cancel\*(C'\fR to its
-subscription list. Normally it's best to exclude the control newsgroups
-from feeds to keep from sending your peers more control messages than they
-care about. That's why the \fInewsfeeds\fR pattern \f(CW\*(C`!control,!control.*\*(C'\fR
-is as often as not specified (adding this pattern do not prevent control
-messages which affect the newsgroups fed to a site from being sent to it).
-.PP
-checkgroups, newgroup and rmgroup control messages receive additional special
-treatment. If one of these control messages is approved and posted to the
-newsgroup being created or removed (or to the admin group to which the
-checkgroups is posted), the message will be sent to all sites
-whose subscription patterns would cause them to receive articles posted to
-that group. For example, if a newgroup control message for a nonexistent
-newsgroup \f(CW\*(C`news.admin.meow\*(C'\fR is received, it will be sent to any site
-whose subscription pattern would cause it to receive \f(CW\*(C`news.admin.meow\*(C'\fR if
-that newsgroup existed (such as a pattern of \f(CW\*(C`news.admin.*\*(C'\fR). For this
-reason, it is correct to post newgroup messages to the newsgroup that the
-control message would create. It is \fInot\fR generally correct to crosspost
-newgroup messages to some \*(L"well\-propagated\*(R" newsgroup; not only will this
-not actually improve their propagation to sites that want such control
-messages, but it will also cause sites that do not want those control
-messages to receive them. Therefore, assuming that a newgroup control
-message is sent to the group \f(CW\*(C`news.admin.meow\*(C'\fR (specified in the
-Newsgroups: header) in order to create the group \f(CW\*(C`news.admin.meow\*(C'\fR,
-the sites with the following subscription patterns will receive it:
-.PP
-.Vb 4
-\& *,@news.*
-\& news.*
-\& news.*,!control,!control.*
-\& control,control.*
-.Ve
-.PP
-but the sites with the following subscription patterns will not receive it:
-.PP
-.Vb 2
-\& *,@news.*,!control,!control.*
-\& comp.*,@news.*
-.Ve
-.PP
-If a control message is posted to a group whose name ends with the four
-characters \f(CW\*(C`.ctl\*(C'\fR, this suffix is stripped off and the control message is
-propagated as if it were posted to the base group. For example, a cancel
-message posted to \f(CW\*(C`news.admin.ctl\*(C'\fR will be sent to all sites that
-subscribe to \f(CW\*(C`control.cancel\*(C'\fR (or \f(CW\*(C`control\*(C'\fR if that newsgroup doesn't
-exist) or \f(CW\*(C`news.admin\*(C'\fR. This behavior is present for historical
-compatibility reasons and should be considered obsolete; support for the
-\&\f(CW\*(C`.ctl\*(C'\fR suffix may be removed in a future version of \s-1INN\s0.
-.PP
-Finally, articles posted to newsgroups beginning with \f(CW\*(C`to.\*(C'\fR are treated
-specially. Provided that either that newsgroup exists in the \fIactive\fR file
-or \fImergetogroups\fR is set in \fIinn.conf\fR, the remainder of the newsgroup
-is taken to be a site name, as configured in \fInewsfeeds\fR, and the article
-is sent to that site. If \fImergetogroups\fR is set, the article will be
-filed in the group named \f(CW\*(C`to\*(C'\fR (which must exist in the \fIactive\fR file). For
-example, with \fImergetogroups\fR set, an article posted to \f(CW\*(C`to.uunet\*(C'\fR will
-be filed in \f(CW\*(C`to\*(C'\fR and sent to the site \f(CW\*(C`uunet\*(C'\fR.
-.SH "PROTOCOL DIFFERENCES"
-.IX Header "PROTOCOL DIFFERENCES"
-\&\fBinnd\fR implements the \s-1NNTP\s0 commands defined in \s-1RFC\s0 977, with the
-following differences:
-.IP "1." 4
-The \s-1LIST\s0 command may be followed by an optional \s-1ACTIVE\s0, \s-1ACTIVE\s0.TIMES, or
-\&\s-1NEWSGROUPS\s0. There is only basic support for \s-1LIST\s0 in \fBinnd\fR since feeding
-peers normally don't need it; see \fInnrpd\fR\|(8) for full support.
-.IP "2." 4
-The \s-1AUTHINFO\s0 \s-1USER\s0 and \s-1AUTHINFO\s0 \s-1PASS\s0 commands are implemented, although the
-authentication is currently limited to matching a password for a given
-peer specified in \fIincoming.conf\fR. These are based on the reference Unix
-implementation.
-.IP "3." 4
-A new command, \s-1MODE\s0 \s-1READER\s0, is implemented. This command will cause the
-server to pass the connection to \fBnnrpd\fR.
-.IP "4." 4
-The streaming extension (\s-1MODE\s0 \s-1STREAM\s0, \s-1CHECK\s0, and \s-1TAKETHIS\s0) is fully
-supported.
-.IP "5." 4
-A batch transfer command, \s-1XBATCH\s0 \fIbyte-count\fR, is provided. This command
-will read \fIbyte-count\fR bytes and store them for later processing by
-\&\fIrnews\fR\|(1) (which must be run separately, probably from cron). See
-\&\fIinnxbatch\fR\|(8) and \fIbackends/sendxbatches\fR for more details on this
-extension.
-.IP "6." 4
-\&\fBinnd\fR implements a limited subset of the protocol useful for
-transferring news. The only other commands implemented are \s-1HEAD\s0, \s-1HELP\s0,
-\&\s-1IHAVE\s0, \s-1STAT\s0, and \s-1QUIT\s0. The remaining commands are mostly only useful for
-readers and are implemented by \fInnrpd\fR\|(8).
-.SH "HEADER MODIFICATIONS"
-.IX Header "HEADER MODIFICATIONS"
-\&\fBinnd\fR modifies as few article headers as possible, although it could be
-better in this area.
-.PP
-Empty headers and headers that consist of nothing but whitespace are
-dropped.
-.PP
-The local site's name (as set with the \fIpathhost\fR parameter in
-\&\fIinn.conf\fR) and an exclamation point are prepended to the Path: header,
-provided the first site name in the Path: header is different from the
-local one. In addition, \fIpathalias\fR and \fIpathcluster\fR may be similarly
-respectively prepended and appended to the Path: header; see \fIinn.conf\fR\|(5)
-for the details.
-.PP
-The Xref: header is removed and a new one created.
-.PP
-A Lines: header will be added if the article was missing one.
-.PP
-\&\fBinnd\fR does not rewrite incorrect headers. For example, it will not
-replace an incorrect Lines header, though it may reject such an article
-depending on the value of \fIlinecountfuzz\fR in \fIinn.conf\fR.
-.SH "CANCEL FEEDS"
-.IX Header "CANCEL FEEDS"
-In order to efficiently apply a large number of local cancels (such as
-from processing NoCeMs or from some other external source), \s-1INN\s0 supports a
-special feed mode available only to connections to the local Unix domain
-socket (not to connections to any network sockets).
-.PP
-To enter this mode, connect to the Unix domain socket (\fIpathrun\fR/nntpin)
-and send the command \s-1MODE\s0 \s-1CANCEL\s0. The response will have code \f(CW284\fR.
-Every subsequent line sent on that connection should consist of a single
-message \s-1ID\s0. An attempt will be made to cancel that message \s-1ID\s0, and the
-server will reply \f(CW289\fR for success or \f(CW484\fR for failure. (Failure can
-occur, for example, if the server is paused or throttled, or the
-Message-ID is corrupt. Failure does \fInot\fR occur if the article to be
-cancelled does not exist.)
-.SH "LOGGING"
-.IX Header "LOGGING"
-\&\fBinnd\fR reports all incoming articles in its log file (\fIpathlog\fR/news).
-This is a text file with a variable number of space-separated fields in
-one of the following formats:
-.PP
-.Vb 5
-\& mon dd hh:mm:ss.mmm + feed <message\-id> site ...
-\& mon dd hh:mm:ss.mmm j feed <message\-id> site ...
-\& mon dd hh:mm:ss.mmm c feed <message\-id> Cancelling <message\-id>
-\& mon dd hh:mm:ss.mmm \- feed <message\-id> reason
-\& mon dd hh:mm:ss.mmm ? feed <message\-id> reason
-.Ve
-.PP
-There may also be hostname and/or size fields after the message \s-1ID\s0
-depending on the settings of \fInntplinklog\fR and \fIlogartsize\fR in
-\&\fIinn.conf\fR.
-.PP
-The first three fields are the date and time to millisecond resolution.
-The fifth field is the site that sent the article (based on the Path
-header) and the sixth field is the article's message \s-1ID\s0; they will be a
-question mark if the information is not available.
-.PP
-The fourth field indicates whether the article was accepted or not. If it
-is a plus sign, then the article was accepted. If it is the letter \f(CW\*(C`j\*(C'\fR
-then the article was accepted, but all of the newsgroups to which the
-article was posted were set to mode \f(CW\*(C`j\*(C'\fR in the active file (or not listed
-in the active file and \fIwanttrash\fR was set in \fIinn.conf\fR) so the article
-was filed into the \f(CW\*(C`junk\*(C'\fR newsgroup. In both of these cases, the article
-has been accepted and the \f(CW\*(C`site ...\*(C'\fR field contains the space-separated
-list of sites to which the article is being sent.
-.PP
-If the fourth field is the letter \f(CW\*(C`c\*(C'\fR, then a cancel message was accepted
-before the original article arrived, and a history entry for the cancelled
-message was created so that \fBinnd\fR will reject that message if it arrives
-later.
-.PP
-If the fourth field is a minus sign, then the article was rejected. The
-reasons for rejection generated by \fBinnd\fR include:
-.PP
-.Vb 20
-\& "%s" header too long
-\& "%s" wants to cancel <%s> by "%s"
-\& Article exceeds local limit of %s bytes
-\& Article posted in the future \-\- "%s"
-\& Bad "%s" header
-\& Can't write history
-\& Duplicate
-\& Duplicate "%s" header
-\& EOF in headers
-\& Linecount %s != %s +\- %s
-\& Missing %s header
-\& No body
-\& No colon\-space in "%s" header
-\& No space
-\& Space before colon in "%s" header
-\& Too old \-\- "%s"
-\& Unapproved for "%s"
-\& Unwanted newsgroup "%s"
-\& Unwanted distribution "%s"
-\& Whitespace in "Newsgroups" header \-\- "%s"
-.Ve
-.PP
-where \f(CW%s\fR, above, is replaced by more specific information. (The Perl,
-Python, andr Tcl filters, if used, may reject articles with other
-reasons.)
-.PP
-If the fourth field is the letter \f(CW\*(C`?\*(C'\fR, the article contains strange
-strings, such as \s-1CR\s0 without \s-1LF\s0 or \s-1LF\s0 without \s-1CR\s0. (These characters should
-never occur in isolation, only together as \s-1CRLF\s0 to indicate the end of a
-line.) This log message is just informational, to give an idea of how
-widespread such articles are; \fBinnd\fR does not reject such articles.
-.PP
-Note that when \fIwanttrash\fR is set to true in \fIinn.conf\fR and an article
-is received that isn't posted to any valid newsgroups, it will be accepted
-and logged with two lines, a \f(CW\*(C`j\*(C'\fR line and a minus sign line.
-.PP
-\&\fBinnd\fR also makes extensive reports through \fIsyslog\fR\|(3). The first word of
-the log message will be the name of the site if the entry is site-specific
-(such as a \*(L"connected\*(R" message). The first word will be \f(CW\*(C`SERVER\*(C'\fR if the
-message relates to the server itself, such as when a read error occurs.
-.PP
-If the second word is the four letters \f(CW\*(C`cant\*(C'\fR, then an error is being
-reported. (The absence of an apostrophe is intentional; it makes it
-easier to grep from the command line and easier to find error messages in
-FAQs using a search engine.) In this case, the next two words generally
-name the system call or library routine that failed and the object upon
-which the action was being performed. The rest of the line may contain
-other information.
-.PP
-In other cases, the second word attempts to summarize what change has been
-made, while the rest of the line gives more specific information. The
-word \f(CW\*(C`internal\*(C'\fR generally indicates an internal logic error.
-.SH "SIGNALS"
-.IX Header "SIGNALS"
-\&\fBinnd\fR will catch \s-1SIGTERM\s0 and \s-1SIGHUP\s0 and shut down. If \fB\-d\fR is used,
-\&\s-1SIGINT\s0 will also be caught and will result in an orderly shutdown.
-.PP
-\&\fBinnd\fR will catch the \s-1SIGUSR1\s0 signal and recreate the control channel
-used by \fIctlinnd\fR\|(8).
-.SH "BUGS"
-.IX Header "BUGS"
-\&\fBinnd\fR normally attempts to strip \s-1IP\s0 options from incoming connections,
-since it uses IP-based authentication and source routing can confuse that.
-However, this doesn't work on all systems, and it doesn't work at all in
-the presence of IPv6 support (and is disabled in that case). Hence, if
-using \fBinnd\fR with IPv6 support, make sure that your kernel or router
-disables source routing.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews.
-.PP
-$Id: innd.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive\fR\|(5), \fIctlinnd\fR\|(8), \fIdbz\fR\|(3), \fIhistory\fR\|(5), \fIincoming.conf\fR\|(5), \fIinn.conf\fR\|(5),
-\&\fInewsfeeds\fR\|(5), \fInnrpd\fR\|(8), \fIrnews\fR\|(1), \fIsyslog\fR\|(3).
+++ /dev/null
-.\" $Revision: 1586 $
-.TH INNDCOMM 3
-.SH NAME
-inndcomm \- INND communication part of InterNetNews library
-.SH SYNOPSIS
-.nf
-.ta \w' unsigned long 'u
-.B
-#include "inndcomm.h"
-
-.B "int"
-.B "ICCopen()"
-
-.B "int"
-.B "ICCclose()"
-
-.B "void"
-.B "ICCsettimeout(i)"
-.B " int i;"
-
-.B "int"
-.B "ICCcommand(cmd, argv, replyp)"
-.B " char cmd;"
-.B " char *argv[];"
-.B " char **replyp;"
-
-.B "int"
-.B "ICCcancel(mesgid)"
-.B " char *mesgid;"
-
-.B "int"
-.B "ICCreserve(why)"
-.B " char *why;"
-
-.B "int"
-.B "ICCpause(why)"
-.B " char *why;"
-
-.B "int"
-.B "ICCgo(why)"
-.B " char *why;"
-
-.B "extern char *ICCfailure;"
-.fi
-.SH DESCRIPTION
-The routines described in this manual page are part of the InterNetNews
-library,
-.IR libinn (3).
-They are used to send commands to a running
-.IR innd (8)
-daemon on the local host.
-The letters ``ICC'' stand for
-.IR I nnd
-.IR C ontrol
-.IR C ommand.
-.PP
-.I ICCopen
-creates a
-Unix-domain datagram socket and binds it to the server's control socket, if
-.I <HAVE_UNIX_DOMAIN_SOCKETS in include/config.h>
-is defined. Otherwise it creates
-a named pipe for communicating with the server.
-It returns \-1 on failure or zero on success.
-This routine must be called before any other routine.
-.PP
-.I ICCclose
-closes any descriptors that have been created by
-.IR ICCopen .
-It returns \-1 on failure or zero on success.
-.PP
-.I ICCsettimeout
-can be called before any of the following routines to determine how long
-the library should wait before giving up on getting the server's reply.
-This is done by setting and catching a SIGALRM
-.IR signal (2).
-If the timeout is less then zero then no reply will be waited for.
-The SC_SHUTDOWN, SC_XABORT, and SC_XEXEC commands do not get a reply either.
-The default, which can be obtained by setting the timeout to zero, is to
-wait until the server replies.
-.PP
-.I ICCcommand
-sends the command
-.I cmd
-with parameters
-.I argv
-to the server.
-It returns \-1 on error.
-If the server replies, and
-.I replyp
-is not NULL, it will be filled in with an allocated buffer that contains
-the full text of the server's reply.
-This buffer is a string in the form of ``<digits><space><text>''
-where ``digits'' is the text value of the recommended exit code;
-zero indicates success.
-Replies longer then 4000 bytes will be truncated.
-The possible values of
-.I cmd
-are defined in the ``inndcomm.h'' header file.
-The parameters for each command are described in
-.IR ctlinnd (8).
-This routine returns \-1 on communication failure, or the exit status
-sent by the server which will never be negative.
-.PP
-.I ICCcancel
-sends a ``cancel'' message to the server.
-.I Mesgid
-is the Message-ID of the article that should be canceled.
-The return value is the same as for
-.IR ICCcommand .
-.PP
-.IR ICCpause ,
-.IR ICCreserve ,
-and
-.I ICCgo
-send a ``pause,'' ``reserve,'' or ``go'' command to the server, respectively.
-If
-.I ICCreserve
-is used, then the
-.I why
-value used in the
-.I ICCpause
-invocation must match; the value used in the
-.I ICCgo
-invocation must always match that the one used in the
-.I ICCpause
-invocation.
-The return value for all three routines is the same as for
-.IR ICCcommand .
-.PP
-If any routine described above fails, the
-.I ICCfailure
-variable will identify the system call that failed.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: inndcomm.3 1586 1998-12-09 15:53:55Z kondou $
-.SH "SEE ALSO"
-ctlinnd(8),
-innd(8),
-libinn(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INNDF 8"
-.TH INNDF 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-inndf \- Report free disk, inodes, and overview information
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinndf\fR [\fB\-Fhi\fR] [\fB\-f\fR \fIfilename\fR] \fIdirectory\fR [\fIdirectory\fR ...]
-.PP
-\&\fBinndf\fR \fB\-n\fR
-.PP
-\&\fBinndf\fR \fB\-o\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinndf\fR was originally a replacement for \f(CW\*(C`df | awk\*(C'\fR in \fIinnwatch.ctl\fR\|(5)
-and \fIinnstat\fR\|(8), and now also reports various other usage information about
-\&\s-1INN\s0's storage that \fIdf\fR\|(1) doesn't understand. \fBinndf\fR doesn't sync, forks
-less, and is generally less complicated than \fIdf\fR\|(1).
-.PP
-Its default behavior is to report free kilobytes (not disk blocks), or
-free inodes if \fB\-i\fR is used, in the file systems holding the directories
-given on the command line. (A kilobyte in this case is 1024 bytes.) If
-only one directory is given, the output will be a simple number; if more
-than one directory is given, the output will be formatted for human
-readability.
-.PP
-If \fIenableoverview\fR is set to true in \fIinn.conf\fR, \fBinndf\fR can also be
-used to get information about the overview database. With the \fB\-n\fR
-option, it reports a count of the total number of overview records stored.
-With \fB\-o\fR, it reports the percentage of space used in the overview
-database (for those overview methods where this is meaningful data).
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-f\fR \fIfilename\fR" 4
-.IX Item "-f filename"
-\&\fIfilename\fR should contain a list of directories to use in addition to
-those given by the arguments, one per line. Blank lines and anything
-after \f(CW\*(C`#\*(C'\fR on any line are ignored.
-.IP "\fB\-F\fR" 4
-.IX Item "-F"
-Like \fB\-f\fR execpt that the filename is \fIpathetc\fR/filesystems and it is
-not an error if this file doesn't exist. (This option is used primarily
-by such things as \fIinnstat\fR\|(8), so that the news administrator can add
-additional file systems to check to \fIpathetc\fR/filesystems without having
-to modify the script.)
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Print a usage message and exit.
-.IP "\fB\-i\fR" 4
-.IX Item "-i"
-Report the number of free inodes rather than the amount of free disk
-space.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-Report the total number of records in the overview database. Note that
-crossposted articles will have one overview record for each newsgroup
-they're posted to.
-.IP "\fB\-o\fR" 4
-.IX Item "-o"
-Report the percentage usage of the overview database space. This is only
-meaningful for overview methods that pre-allocate a certain amount of
-space rather than grow to accomodate more records. Currently, this flag
-is only useful for the buffindexed overview method.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Print the free kilobytes in /news/spool as a simple number:
-.PP
-.Vb 1
-\& inndf /news/spool
-.Ve
-.PP
-Report the free inodes in /usr/local/news and /news/spool in a format
-designed for human readability:
-.PP
-.Vb 1
-\& inndf \-i /usr/local/news /news/spool
-.Ve
-.PP
-The same, but also add in all file systems in \fIpathetc\fR/filesystems:
-.PP
-.Vb 1
-\& inndf \-i \-F /usr/local/news /news/spool
-.Ve
-.PP
-Print out the number of overview records and the percentage space used by
-a buffindexed overview database:
-.PP
-.Vb 1
-\& inndf \-no
-.Ve
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBinndf\fR was written by Ian Dickinson <idickins@fore.com>. This manual
-page was written by Swa Frantzen <Swa.Frantzen@belgium.eu.net>. Thanks
-also to the following folks for ports, patches, and comments:
-.PP
-.Vb 7
-\& Mahesh Ramachandran <rr@eel.ufl.edu>
-\& Chuck Swiger <chuck@its.com>
-\& Sang\-yong Suh <sysuh@kigam.re.kr>
-\& Brad Dickey <bdickey@haverford.edu>
-\& Taso N. Devetzis <devetzis@snet.net>
-\& Wei\-Yeh Lee <weiyeh@columbia.edu>
-\& Jeff Garzik <jeff.garzik@spinne.com>
-.Ve
-.PP
-and to all the other folks I met and worked with during my 10 years as a
-newsadmin.
-.PP
-Katsuhiro Kondou added the \fB\-n\fR and \fB\-o\fR options. Russ Allbery added
-reporting of percentage free disk space. Support for \fB\-f\fR and \fB\-F\fR was
-added by Fabien Tassin <fta@sofaraway.org>.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIdf\fR\|(1), \fIinnwatch.ctl\fR\|(5), \fIinnstat\fR\|(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INNDSTART 8"
-.TH INNDSTART 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-inndstart \- Start innd
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinndstart\fR [\fB\-P\fR \fIport\fR] [\fB\-I\fR \fIaddress\fR] [\fIinnd-options\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The purpose of \fBinndstart\fR is to raise system file descriptor limits,
-open the privileged news transfer port, and then start \fIinnd\fR\|(8), passing it
-the open file descriptor for the news port. \fBinndstart\fR is used since
-only privileged programs can perform those two operations and since
-\&\fBinnd\fR should not run with elevated privileges. It is installed setuid
-root and drops privileges to the news user (as set at configure time)
-before running \fBinnd\fR.
-.PP
-Normally there is no need to run \fBinndstart\fR directly. Instead, run
-\&\fIrc.news\fR\|(8) as the news user, and it will handle running \fBinndstart\fR
-appropriately for you.
-.PP
-Since \fBinndstart\fR is setuid root, it is extremely restrictive about who
-can run it and what it is willing to do. See \*(L"\s-1SECURITY\s0\*(R" for the full
-details.
-.PP
-\&\fBinndstart\fR can only be run by the news user; if run by any other user,
-it will abort. It will also only bind to ports 119, 433, or a port number
-given at configure time with \fB\-\-with\-innd\-port\fR among those ports below
-1024, although it can bind to any port above 1024. This is to prevent
-various security exploits possible by binding to arbitrary privileged
-ports.
-.PP
-Before running \fBinnd\fR, \fBinndstart\fR cleans out the environment and sets
-only those environment variables listed in \*(L"\s-1ENVIRONMENT\s0\*(R".
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-P\fR \fIport\fR" 4
-.IX Item "-P port"
-Bind to \fIport\fR instead of whatever is specified by \fIport\fR in
-\&\fIinn.conf\fR. Note that this is subject to the constraints mentioned
-above.
-.IP "\fB\-I\fR \fIaddress\fR" 4
-.IX Item "-I address"
-Bind as \fIaddress\fR instead of whatever is specified by \fIbindaddress\fR in
-\&\fIinn.conf\fR. The default behavior is to bind to \s-1INADDR_ANY\s0, and that's
-what's desired almost all the time. This option, and the \fIinn.conf\fR
-parameter, may be useful if the machine has multiple interface cards and
-\&\fBinnd\fR should only be listening on a particular one.
-.PP
-All other options given on the command line are passed verbatim to
-\&\fBinnd\fR. In addition, \fBinndstart\fR will give the \fB\-p\fR option to \fBinnd\fR,
-specifying the file descriptor of the open network socket.
-.SH "SECURITY"
-.IX Header "SECURITY"
-\&\fBinndstart\fR is setuid root, and therefore an expected point of attack.
-It has therefore been carefully written with security in mind. In a
-normal \s-1INN\s0 installation, it is installed setuid root and executable only
-by users in the news group.
-.PP
-Ideally, everything about \fBinndstart\fR's operations would be hard-coded so
-that it could not be modified. Fighting against this desire, however, is
-the ideal that as much of \s-1INN\s0's operation as possible should be
-configurable at run-time using \fIinn.conf\fR, and the news system should be
-able to an alternate inn.conf by setting \s-1INNCONF\s0 to the path to that file
-before starting any programs. The configuration data therefore can't be
-trusted.
-.PP
-The security model used is:
-.IP "\(bu" 2
-\&\fBinndstart\fR can only be executed by the news user and news group, as
-determined at configure time and compiled into \fBinndstart\fR as constants.
-Similarly, \fBinndstart\fR will always \fIsetuid()\fR and \fIsetgid()\fR to those users
-before running \fBinnd\fR. This is to prevent a user other than news but in
-the news group from using \fBinndstart\fR to leverage that access into access
-to the news account.
-.IP "\(bu" 2
-As mentioned above, \fBinndstart\fR will only bind to a very limited subset
-of ports below 1024. There are various attacks that can be performed
-using random low-numbered ports, including exploits of the \fIrsh\fR\|(1) family
-of commands on some systems.
-.IP "\(bu" 2
-\&\fBinndstart\fR does as little as possible as root, dropping privileges
-before performing any operations that do not require elevated privileges.
-.PP
-This program therefore gives the news user the ability to revoke system
-file descriptor limits and bind to the news port, and nothing else.
-.SH "DIAGNOSTICS"
-.IX Header "DIAGNOSTICS"
-\&\fBinndstart\fR may log the following messages to syslog and print them to
-stderr.
-.ie n .IP "can't bind: %s" 4
-.el .IP "can't bind: \f(CW%s\fR" 4
-.IX Item "can't bind: %s"
-(Fatal) Unable to bind to the designated port. This usually means that
-something else is already running on the news port. Check with
-\&\fInetstat\fR\|(8) and make sure that \fIinetd\fR\|(8) doesn't think it's running a
-service on the same port you're trying to run \fBinnd\fR on.
-.ie n .IP "can't bind to restricted port %d" 4
-.el .IP "can't bind to restricted port \f(CW%d\fR" 4
-.IX Item "can't bind to restricted port %d"
-(Fatal) \fBinndstart\fR was told to bind to a low numbered port (under 1024)
-other than 119, 433, or a port number given at configure time. This is
-not allowed for security reasons. If you're running \fBinnd\fR on a port
-other than 119 or 433, you need to give the \-\-with\-innd\-port flag to
-\&\f(CW\*(C`configure\*(C'\fR when you compile \s-1INN\s0.
-.ie n .IP "can't exec %s:\fR \f(CW%s" 4
-.el .IP "can't exec \f(CW%s:\fR \f(CW%s\fR" 4
-.IX Item "can't exec %s: %s"
-(Fatal) \fBinndstart\fR was unable to execute \fBinnd\fR. Make sure that
-\&\fIpathbin\fR is set correctly in inn.conf and that \fBinnd\fR is located in
-that directory and is executable by the news user.
-.IP "can't getgrnam(%s)" 4
-.IX Item "can't getgrnam(%s)"
-(Fatal) Unable to determine the \s-1GID\s0 for the compiled-in news group.
-Perhaps the news group is not listed in \fI/etc/group\fR.
-.IP "can't getpwnam(%s)" 4
-.IX Item "can't getpwnam(%s)"
-(Fatal) Unable to determine the \s-1UID\s0 for the compiled-in news user.
-Perhaps the news user is not listed in \fI/etc/passwd\fR.
-.ie n .IP "can't open socket: %s" 4
-.el .IP "can't open socket: \f(CW%s\fR" 4
-.IX Item "can't open socket: %s"
-(Fatal) Something went wrong in creating the network socket. Chances are
-your system is out of resources of some kind.
-.ie n .IP "can't set file descriptor limit to %d:\fR \f(CW%s" 4
-.el .IP "can't set file descriptor limit to \f(CW%d:\fR \f(CW%s\fR" 4
-.IX Item "can't set file descriptor limit to %d: %s"
-(Warning) Unable to set the system file descriptor limit to the specified
-value; the limit was left unchanged. Perhaps that value is too high for
-your system. Try changing \fIrlimitnofile\fR in \fIinn.conf\fR to a smaller
-value.
-.ie n .IP "can't set \s-1SO_REUSEADDR:\s0 %s" 4
-.el .IP "can't set \s-1SO_REUSEADDR:\s0 \f(CW%s\fR" 4
-.IX Item "can't set SO_REUSEADDR: %s"
-(Warning) \fBinndstart\fR attempts to set \s-1SO_REUSEADDR\s0 using \fIsetsockopt\fR\|(2) so
-that if \fBinnd\fR exits, it can be restarted again immediately without
-waiting for the port to time out. For some reason, this failed, and that
-option was not set on the port.
-.ie n .IP "can't seteuid to %d:\fR \f(CW%s" 4
-.el .IP "can't seteuid to \f(CW%d:\fR \f(CW%s\fR" 4
-.IX Item "can't seteuid to %d: %s"
-(Fatal) Unable to change the effective \s-1UID\s0. If \fBinndstart\fR has the
-correct permissions (setuid root) and seteuid to root (\s-1UID\s0 0) is failing,
-this may mean that your system has \fIseteuid\fR\|(2) but doesn't have support for
-\&\s-1POSIX\s0 saved UIDs. If this is the case, please report this to the \s-1INN\s0
-maintainers.
-.ie n .IP "can't setgid to %d:\fR \f(CW%s" 4
-.el .IP "can't setgid to \f(CW%d:\fR \f(CW%s\fR" 4
-.IX Item "can't setgid to %d: %s"
-(Fatal) Dropping privileges to the news group failed for some reason.
-.ie n .IP "can't setgroups (is inndstart setuid root?): %s" 4
-.el .IP "can't setgroups (is inndstart setuid root?): \f(CW%s\fR" 4
-.IX Item "can't setgroups (is inndstart setuid root?): %s"
-(Warning) Dropping all supplemental groups except the news group failed
-for some reason, and the process group membership was left unchanged.
-This almost always indicates that \fBinndstart\fR isn't setuid root as it has
-to be to do what it does. Make sure that \fBinndstart\fR is setuid root,
-owned by group news, and mode 4710.
-.ie n .IP "can't setuid to %d:\fR \f(CW%s" 4
-.el .IP "can't setuid to \f(CW%d:\fR \f(CW%s\fR" 4
-.IX Item "can't setuid to %d: %s"
-(Fatal) Dropping privileges to the news user failed for some reason.
-.ie n .IP "invalid address %s" 4
-.el .IP "invalid address \f(CW%s\fR" 4
-.IX Item "invalid address %s"
-(Fatal) \fB\-I\fR was specified on the command line, but the argument wasn't a
-valid address. Addresses must be given as numeric \s-1IP\s0 addresses.
-.IP "invalid bindaddress in inn.conf (%s)" 4
-.IX Item "invalid bindaddress in inn.conf (%s)"
-(Fatal) The \fIbindaddress\fR specified in \fIinn.conf\fR could not be converted
-to an \s-1IP\s0 address. See \fIinn.conf\fR\|(5) for more information about valid
-values.
-.ie n .IP "invalid port %s (must be a number)" 4
-.el .IP "invalid port \f(CW%s\fR (must be a number)" 4
-.IX Item "invalid port %s (must be a number)"
-(Fatal) \fB\-P\fR was specified on the command line, but the argument wasn't a
-valid port. Ports must be port numbers; service names are not allowed.
-.IP "missing address after \-I" 4
-.IX Item "missing address after -I"
-(Fatal) \fB\-I\fR was given on the command line, but no address was given
-after the option.
-.IP "missing port after \-P" 4
-.IX Item "missing port after -P"
-(Fatal) \fB\-P\fR was given on the command line, but no port was given after
-the option.
-.ie n .IP "must be run by user %s\fR (%d), not \f(CW%d" 4
-.el .IP "must be run by user \f(CW%s\fR (%d), not \f(CW%d\fR" 4
-.IX Item "must be run by user %s (%d), not %d"
-(Fatal) Someone other than the news user attempted to run \fBinndstart\fR.
-\&\fBinndstart\fR may only be run by the news user for security reasons.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Normally, \fBinndstart\fR is never run directly. However, a simple way to
-just restart \fBinnd\fR (if it is not running) without running any other
-auxilliary programs or performing any of the other checks done by
-\&\fIrc.news\fR\|(8) is to just run:
-.PP
-.Vb 1
-\& inndstart
-.Ve
-.PP
-as the news user.
-.PP
-To start \fBinnd\fR on port 433, passing it the \f(CW\*(C`\-c21\*(C'\fR option, use:
-.PP
-.Vb 1
-\& inndstart \-P433 \-c21
-.Ve
-.SH "ENVIRONMENT"
-.IX Header "ENVIRONMENT"
-One environment variable affects the operation of \fBinndstart\fR itself:
-.IP "\s-1INNCONF\s0" 8
-.IX Item "INNCONF"
-The full path to the \fIinn.conf\fR\|(5) file to read, rather than the default.
-This can be used to run multiple copies of \s-1INN\s0 on the same machine with
-different settings.
-.PP
-When executing \fBinnd\fR, \fBinndstart\fR cleans out the entire environmnent
-and sets only the following variables:
-.IP "\s-1BIND_INADDR\s0" 8
-.IX Item "BIND_INADDR"
-Passed verbatim from \fBinndstart\fR's environment. This is used by various
-programs to override the \fIbindaddress\fR parameter in \fIinn.conf\fR and
-therefore must be in \fBinnd\fR's environment for programs like \fIinnfeed\fR\|(8).
-.IP "\s-1HOME\s0" 8
-.IX Item "HOME"
-Set to \fIpathnews\fR from \fIinn.conf\fR.
-.IP "\s-1LOGNAME\s0" 8
-.IX Item "LOGNAME"
-Set to the news master, as determined at configure time.
-.IP "\s-1PATH\s0" 8
-.IX Item "PATH"
-Set to \fIpathbin\fR from \fIinn.conf\fR, \fIpathetc\fR from \fIinn.conf\fR, and then
-\&\fI/bin\fR, \fI/usr/bin\fR, and \fI/usr/ucb\fR in that order.
-.IP "\s-1SHELL\s0" 8
-.IX Item "SHELL"
-Set to the path to the system Bourne shell as determined by configure
-(probably \fI/bin/sh\fR).
-.IP "\s-1TMPDIR\s0" 8
-.IX Item "TMPDIR"
-Set to \fIpathtmp\fR from inn.conf.
-.IP "\s-1TZ\s0" 8
-.IX Item "TZ"
-Passed verbatim from \fBinndstart\fR's environment.
-.IP "\s-1USER\s0" 8
-.IX Item "USER"
-Set to the news master, as determined at configure time.
-.SH "FILES"
-.IX Header "FILES"
-.IP "inn.conf" 4
-.IX Item "inn.conf"
-Read for \fIpathnews\fR, \fIpathbin\fR, \fIpathtmp\fR, \fIrlimitnofile\fR,
-\&\fIbindaddress\fR, and \fIport\fR.
-.IP "\fIpathbin\fR/innd" 4
-.IX Item "pathbin/innd"
-The binary that is executed as \fBinnd\fR and passed the open network socket.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: inndstart.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fIinnd\fR\|(8)
+++ /dev/null
-.\" -*- nroff -*-
-.\"
-.\" Author: James A. Brister <brister@vix.com> -- berkeley-unix --
-.\" Start Date: Sat, 20 Jan 1996 15:50:56 +1100
-.\" Project: INN -- innfeed
-.\" File: innfeed.1
-.\" RCSId: $Id: innfeed.1 7798 2008-04-26 08:47:01Z iulius $
-.\" Description: Man page for innfeed(1)
-.\"
-.TH INNFEED 1
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH NAME
-innfeed \- multi-host, multi-connection, streaming NNTP feeder.
-.SH SYNOPSIS
-.B innfeed
-[
-.B \-a spool-dir
-]
-[
-.BI \-b " directory"
-]
-[
-.B \-C
-]
-[
-.BI \-c " filename"
-]
-[
-.BI \-d " num"
-]
-[
-.BI \-e " bytes"
-]
-[
-.B \-h
-]
-[
-.BI \-l " filename"
-]
-[
-.B \-m
-]
-[
-.B \-M
-]
-[
-.B \-o bytes
-]
-[
-.B \-p file
-]
-[
-.B \-S file
-]
-[
-.B \-x
-]
-[
-.B \-y
-]
-[
-.B \-z
-]
-[
-.B \-v
-]
-[ file ]
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH DESCRIPTION
-.PP
-.I Innfeed
-implements the NNTP protocol for transferring news between computers. It
-handles the standard IHAVE protocol as well as the CHECK/TAKETHIS
-streaming extension. Innfeed can feed any number of remote hosts at once
-and will open multiple connections to each host if configured to do so. The
-only limitations are the process limits for open file descriptors and memory.
-.PP
-As an alternative to using NNTP, INN may also be fed to an IMAP
-server. This is done by using an executable called imapfeed, which is
-identical to innfeed except for the delivery process. The new version
-has two types of connections: an LMTP connection to deliver regular
-messages and an IMAP connection to handle control messages. The
-startinnfeed process can then be told to start imapfeed instead of innfeed.
-(See the INSTALL file for how to do this.)
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH MODES
-.PP
-.I Innfeed
-has three modes of operation: channel, funnel-file and batch.
-.PP
-Channel mode is used when no filename is given on the command line,
-the ``input-file'' keyword is \fInot\fP given in the config file, \fIand\fP
-the ``\fI\-x\fP'' option is \fInot\fP given.
-In channel mode innfeed runs with stdin connected via a pipe to
-innd. Whenever innd closes this pipe (and it has several reasons during
-normal processing to do so), innfeed will exit. It first will try to
-finish sending all articles it was in the middle of transmitting, before
-issuing a QUIT command. This means innfeed may take a while to exit
-depending on how slow your peers are. It never (well, almost never) just
-drops the connection.
-.PP
-The recommended way to restart innfeed when run in channel mode is
-therefore to tell innd to close the pipe and spawn a new innfeed process.
-This can be done with ``ctlinnd flush <feed>'' where <feed> is the name of
-the innfeed channel feed in ``\fInewsfeeds\fP''.
-.PP
-Funnel-file mode is used when a filename is given as an argument
-or the ``input-file'' keyword is given in the config file.
-In funnel file mode it reads the specified file for the same formatted
-information as innd would give in channel mode. It is expected that innd is
-continually writing to this file, so when innfeed reaches the end of the file
-it will check periodically for new information. To prevent the funnel file
-from growing without bounds, you will need to periodically move the file to
-the side (or simply remove it) and have innd flush the file. Then, after
-the file is flushed by innd, you can send innfeed a SIGALRM, and it too
-will close the file and open the new file created by innd. Something like:
-.PP
-.RS
-.nf
-innfeed -p /var/run/news/innfeed.pid my-funnel-file &
-while true; do
- sleep 43200
- rm -f my-funnel-file
- ctlinnd flush funnel-file-site
- kill -ALRM `cat /var/run/news/innfeed.pid`
-done
-.fi
-.RE
-.PP
-Batch mode is used when the ``\fI\-x\fP'' flag is used.
-In batch mode innfeed will ignore stdin, and will simply process any
-backlog created by a previously running innfeed. This mode is not normally
-needed as innfeed will take care of backlog processing.
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH CONFIGURATION
-Innfeed expects a couple of things to be able to run correctly: a directory
-where it can store backlog files and a configuration file to describe which
-peers it should handle.
-.PP
-The configuration file is described in
-.IR innfeed.conf (5).
-The ``\fI\-c\fP''
-option can be used to specify a different file.
-.PP
-For each peer (say, ``\fIfoo\fP''), innfeed manages up to 4 files in the
-backlog directory: a ``\fIfoo.lock\fP'' file, which prevents other
-instances of innfeed from interfering with this one; a ``\fIfoo.input\fP''
-file which has old article information innfeed is reading for
-re-processing; a ``\fIfoo.output\fP'' file where innfeed is writing
-information on articles that couldn't be processed (normally due to a slow
-or blocked peer); and a ``\fIfoo\fP'' file.
-.PP
-This last file (``\fIfoo\fP'') is never created by innfeed, but if innfeed
-notices it, it will rename it to ``\fIfoo.input\fP'' at the next
-opportunity and will start reading from it. This lets you create a batch
-file and put it in a place where innfeed will find it. You should never
-alter the .input or .output files of a running innfeed.
-.PP
-The format of these last three files is one of the following:
-.PP
-.RS
-.nf
-/path/to/article <message-id>
-@token@ <message-id>
-.fi
-.RE
-.PP
-This is the same as the first two fields of the lines innd feeds to
-innfeed, and the same as the first two fields of the lines of the batch
-file innd will write if innfeed is unavailable for some reason. When
-innfeed processes its own batch files it ignores everything after the first
-two whitespace separated fields, so moving the innd-created batch file to
-the appropriate spot will work, even though the lines have extra fields.
-.PP
-The first field can also be a storage API token. The two types of lines can
-be intermingled; innfeed will use the storage manager if appropriate and
-otherwise treat the first field as a filename to read directly.
-.PP
-Innfeed writes its current status to the file ``\fIinnfeed.status\fP'' (or
-the file given by the ``\fI-S\fP'' option). This file contains details on
-the process as a whole, and on each peer this instance of innfeed is
-managing.
-.PP
-If innfeed is told to send an article to a host it is not managing, then
-the article information will be put into a file matching the pattern
-``\fIinnfeed-dropped.*\fP'', with part of the file name matching the pid of
-the innfeed process that is writing to it. Innfeed will not process this
-file except to write to it. If nothing is written to the file then it will
-be removed if innfeed exits normally.
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH SIGNALS
-.PP
-Upon receipt of a SIGALRM innfeed will close the funnel-file specified on
-the command line, and will reopen it (see funnel file description above).
-.PP
-Innfeed with catch SIGINT and will write a large debugging snapshot of the
-state of the running system.
-.PP
-Innfeed will catch SIGHUP and will reload the config file.
-See
-.IR innfeed.conf (5)
-for more details.
-.PP
-Innfeed will catch SIGCHLD and will close and reopen all backlog files.
-.PP
-Innfeed will catch SIGTERM and will do an orderly shutdown.
-.PP
-Upon receipt of a SIGUSR1 innfeed will increment the debugging level by
-one; receipt of a SIGUSR2 will decrement it by one. The debugging level
-starts at zero (unless the ``-d'' option it used), in which case no debugging
-information is emitted. A larger value for the level means more debugging
-information. Numbers up to 5 are currently useful.
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH SYSLOG ENTRIES
-.PP
-There are 3 different categories of syslog entries for statistics: Host,
-Connection and Global.
-.PP
-The Host statistics are generated for a given peer at regular intervals
-after the first connection is made (or, if the remote is unreachable, after
-spooling starts). The Host statistics give totals over all Connections that
-have been active during the given time frame. For example (broken here to
-fit the page, with ``vixie'' being the peer):
-.PP
-.nf
- May 23 12:49:08 data innfeed[16015]: vixie checkpoint
- seconds 1381 offered 2744 accepted 1286
- refused 1021 rejected 437 missing 0 spooled 990
- on_close 0 unspooled 240 deferred 10 requeued 25
- queue 42.1/100:14,35,13,4,24,10
-.fi
-.PP
-These meanings of these fields are:
-.nr XX \w'unspooled '
-.TP \n(XXu
-seconds
-The time since innfeed connected to the host or since the statistics
-were reset by a ``final'' log entry.
-.TP
-offered
-The number of IHAVE commands sent to the host if it is not in streaming mode.
-The sum of the number of TAKETHIS commands sent when no-CHECK mode
-is in effect plus the number CHECK commands sent in streaming mode (when
-no-CHECK mode is not in effect).
-.TP
-accepted
-The number of articles which were sent to the remote host and accepted
-by it.
-.TP
-refused
-The number of articles offered to the host that it it indicated it
-didn't want because it had already seen the Message-ID. The remote
-host indicates this by sending a 435 response to an IHAVE command or
-a 438 response to a CHECK command.
-.TP
-rejected
-The number of articles transferred to the host that it did not accept
-because it determined either that it already had the article or it did
-not want it because of the article's Newsgroups: or Distribution: headers,
-etc. The remote host indicates that it is rejecting the article by
-sending a 437 or 439 response after innfeed sent the entire article.
-.TP
-missing
-The number of articles which innfeed was told to offer to the host but
-which were not present in the article spool. These articles were probably
-cancelled or expired before innfeed was able to offer them to the host.
-.TP
-spooled
-The number of article entries that were written to the .output backlog file
-because the articles could not either be sent to the host or be refused
-by it. Articles are generally spooled either because new articles are
-arriving more quickly than they can be offered to the host, or because
-innfeed closed all the connections to the host and pushed all the
-articles currently in progress to the .output backlog file.
-.TP
-on_close
-The number of articles that were spooled when innfeed closed all the
-connections to the host.
-.TP
-unspooled
-The number of article entries that were read from the .input backlog
-file.
-.TP
-deferred
-The number of articles that the host told innfeed to retry later by
-sending a 431 or 436 response. Innfeed immediately puts these articles
-back on the tail of the queue.
-.TP
-requeued
-The number of articles that were in progress on connections when innfeed
-dropped those connections and put the articles back on the queue. These
-connections may have been broken by a network problem or became unresponsive
-causing innfeed to time them out.
-.TP
-queue
-The first number is the average (mean) queue size during the previous logging
-interval. The second number is the maximum allowable queue size.
-The third number is the percentage of the time that the queue
-was empty. The fourth through seventh numbers are the percentages of the
-time that the queue was >0% to 25% full, 25% to 50% full, 50% to 75%
-full, and 75% to <100% full. The last number is the percentage of the
-time that the queue was totally full.
-.PP
-If the ``\fI\-z\fP'' option is used (see below), then when the peer stats are
-generated, each Connection will log its stats too. For example, for
-connection number zero (from a set of five):
-.PP
-.nf
- May 23 12:49:08 data innfeed[16015]: vixie:0 checkpoint
- seconds 1381 offered 596 accepted 274
- refused 225 rejected 97
-.fi
-.PP
-If you only open a maximum of one Connection to a remote, then there will
-be a close correlation between Connection numbers and Host numbers, but in
-general you can't tie the two sets of number together in any easy or very
-meaningful way. When a Connection closes it will always log its stats.
-.PP
-If all Connections for a Host get closed together, then the Host logs its
-stats as ``final'' and resets its counters. If the feed is so busy that
-there's always at least one Connection open and running, then after some
-amount of time (set via the config file), the Host stats are logged as
-final and reset. This is to make generating higher level stats from log
-files, by other programs, easier.
-.PP
-There is one log entry that is emitted for a Host just after its last
-Connection closes and innfeed is preparing to exit. This entry contains
-counts over the entire life of the process. The ``seconds'' field is from the
-first time a Connection was successfully built, or the first time spooling
-started. If a Host has been completely idle, it will have no such log entry.
-.PP
-.nf
- May 23 12:49:08 data innfeed[16015]: decwrl global
- seconds 1381 offered 34 accepted 22
- refused 3 rejected 7 missing 0
-.fi
-.PP
-The final log entry is emitted immediately before exiting. It contains a
-summary of the statistics over the entire life of the process.
-.PP
-.nf
- Feb 13 14:43:41 data innfeed-0.9.4[22344]: ME global
- seconds 15742 offered 273441 accepted 45750
- refused 222008 rejected 3334 missing 217
-.fi
-.PP
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH OPTIONS
-.TP
-.B \-a
-The ``\fI\-a\fP'' flag is used to specify the top of the article spool
-tree. Innfeed does a chdir(2) to this directory, so it should probably be
-an absolute path. The default is <patharticles\ in\ inn.conf>.
-.TP
-.B \-b
-The ``\fI\-b\fP'' flag may be used to specify a different directory for backlog
-file storage and retrieval. If the path is relative then it is relative
-to <pathspool\ in\ inn.conf>. The default is ``\fIinnfeed\fP''.
-.TP
-.B \-c
-The ``\fI\-c\fP'' flag may be used to specify a different config file from the
-default value. If the path is relative then it is relative to
-<pathetc\ in\ inn.conf>. The default is ``\fIinnfeed.conf\fP''.
-.TP
-.B \-C
-The ``\fI\-C\fP'' flag is used to have innfeed simply check the config
-file, report on any errors and then exit.
-.TP
-.B \-d
-The ``\fI\-d\fP'' flag may be used to specify the initial logging level. All
-debugging messages go to stderr (which may not be what you want, see the
-``\fI\-l\fP'' flag below).
-.TP
-.B \-e
-The ``\fI\-e\fP'' flag may be used to specify the size limit (in bytes) for the
-\fI\%.output\fP backlog files innfeed creates. If the output file gets bigger
-than 10% more than the given number, innfeed will replace the output file
-with the tail of the original version. The default value is 0, which means
-there is no limit.
-.TP
-.B \-h
-Use the ``\fI\-h\fP'' flag to print the usage message.
-.TP
-.B \-l
-The ``\fI\-l\fP'' flag may be used to specify a different log file from
-stderr. As innd starts innfeed with stderr attached to /dev/null, using this
-option can be useful in catching any abnormal error messages, or any
-debugging messages (all ``normal'' errors messages go to syslog).
-.TP
-.B \-M
-If innfeed has been built with mmap support, then the ``\fI\-M\fP'' flag
-turns OFF the use of mmap(); otherwise it has no effect.
-.TP
-.B \-m
-The ``\fI\-m\fP'' flag is used to turn on logging of all missing
-articles. Normally if an article is missing, innfeed keeps a count, but
-logs no further information. When this flag is used, details about
-message-id and expected pathname are logged.
-.TP
-.B \-o
-The ``\fI\-o\fP'' flag sets a value of the maximum number of bytes of article
-data innfeed is supposed to keep in memory. This doesn't work properly yet.
-.TP
-.B \-p
-The ``\fI\-p\fP'' flag is used to specify the filename to write the pid of the
-process into. A relative path is relative to <pathrun\ in\ inn.conf>. The
-default is ``\fIinnfeed.pid\fP''.
-.TP
-.B \-S
-The ``\fI\-S\fP'' flag specifies the name of the file to write the periodic
-staus to. If the path is relative it is considered relative to
-<pathlog\ in\ inn.conf>. The default is ``\fIinnfeed.status\fP''.
-.TP
-.B \-v
-When the ``\fI\-v\fP'' flag is given, version information is printed to stderr
-and then innfeed exits.
-.TP
-.B \-x
-The ``\fI\-x\fP'' flag is used to tell innfeed not to expect any article
-information from innd but just to process any backlog files that exist and
-then exit.
-.TP
-.B \-y
-The ``\fI\-y\fP'' flag is used to allow dynamic peer binding. If this flag is
-used and article information is received from innd that specifies an
-unknown peer, then the peer name is taken to be the IP name too, and an
-association with it is created. Using this it is possible to only
-have the global defaults in the
-.I innfeed.conf
-file, provided the peername as used by innd is the same as the ip name.
-Note that
-.I innfeed
-with ``\fI\-y\fP'' and no peer in
-.I innfeed.conf
-would cause a problem that
-.I innfeed
-drops the first article.
-.TP
-.B \-z
-The ``\fI\-z\fP'' flag is used to cause each connection, in a parallel feed
-configuration, to report statistics when the controller for the connections
-prints its statistics.
-.TP
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH BUGS
-.PP
-When using the ``-x'' option, the config file entry's
-``initial-connections'' field will be the total number of connections
-created and used, no matter how many big the batch file, and no
-matter how big the ``max-connectiond'' field specifies. Thus a value
-of 0 for ``initial-connections'' means nothing will happen in ``-x''
-mode.
-.PP
-Innfeed does not automatically grab the file out of out.going--this needs
-to be prepared for it by external means.
-.PP
-Probably too many other bugs to count.
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH FILES
-innfeed.conf config file.
-.br
-innfeed directory for backlog files.
-.\"
-.\"
-.\"
-.\"
-.\"
-.SH HISTORY
-Written by James Brister <brister@vix.com> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innfeed.1 7798 2008-04-26 08:47:01Z iulius $
-.SH SEE ALSO
-.IR innfeed.conf(5)
+++ /dev/null
-.\" -*- nroff -*-
-.\"
-.\" Author: James A. Brister <brister@vix.com> -- berkeley-unix --
-.\" Start Date: Sun, 21 Jan 1996 00:47:37 +1100
-.\" Project: INN -- innfeed
-.\" File: innfeed.conf.5
-.\" RCSId: $Id: innfeed.conf.5 7778 2008-04-17 21:27:22Z iulius $
-.\" Description: Man page for innfeed.conf(5)
-.\"
-.TH innfeed.conf 5
-.SH NAME
-innfeed.conf \- configuration file for innfeed
-.SH DESCRIPTION
-.PP
-This man page describes the configuration file for version 1.0 of
-innfeed. This format has changed dramatically since version 0.9.3.
-.PP
-The file
-.B innfeed.conf
-is used to control the innfeed(1) program. It is a fairly free-format file
-that consists of three types of entries: \fIkey/value\fP, \fIpeer\fP and
-\fIgroup\fP.
-Comments are from the hash character ``#'' to the end of the line.
-.PP
-\fIKey/value\fP entries are a keyword and a value separated by a colon
-(which can itself be surrounded by whitespace). For example:
-.PP
-.RS
-.nf
-max-connections: 10
-.fi
-.RE
-.PP
-A legal
-key starts with a letter and contains only letters, digits, and ``_'',
-``-''.
-.LP
-There are 5 different type of values: integers, floating-point numbers,
-characters, booleans, and strings. Integer and floating point numbers are
-as to be expected except that exponents in floating point numbers are not
-supported. A boolean value is either ``true'' or ``false'' (case is not
-significant). A character value is a single-quoted character as defined by
-the C-language. A string value is any other sequence of characters. If the
-string needs to contain whitespace, then it must be quoted with double
-quotes, and uses the same format for embedding non-printing characters as
-normal C-language string.
-.PP
-Peer entries look like:
-.PP
-.RS
-.nf
-peer <name> {
- # body ...
-}
-.fi
-.RE
-.PP
-The word ``peer'' is required. The ``<name>'' is the same as the site name
-in INN's newsfeeds file. The body of a peer entry contains some number
-(possibly zero) of key/value entries.
-.PP
-Group entries look like:
-.PP
-.RS
-.nf
-group <name> {
- # body
-}
-.fi
-.RE
-.PP
-The word ``group'' is required. The ``<name>'' is any string valid as a
-key. The body of a group entry contains any number of the three types of
-entries. So key/value pairs can be defined inside a group, and peers can be
-nested inside a group, and other groups can be nested inside a group.
-.PP
-Key/value entries that are defined outside of all peer and group entries
-are said to be at ``global scope''. There are global key/value entries that
-apply to the process as a whole (for example the location of the backlog
-file directory), and there are global key/value entries that act as
-defaults for peers. When innfeed looks for a specific value in a peer entry
-(for example, the maximum number of connections to set up), if the value is
-not defined in the peer entry, then the enclosing groups are examined for
-the entry (starting at the closest enclosing group). If there are no
-enclosing groups, or the enclosing groups don't define the key/value, then
-the value at global scope is used.
-.PP
-A small example could be:
-.PP
-.RS
-.nf
-# Global value applied to all peers that have
-# no value of their own.
-max-connections: 5
-
-# A peer definition. ``uunet'' is the name used by innd in
-# the newsfeeds file.
-peer uunet {
- ip-name: usenet1.uu.net
-}
-
-peer vixie {
- ip-name: gw.home.vix.com
- max-connections: 10 # override global value.
-}
-
-# A group of two peers who can handle more connections
-# than normal
-group fast-sites {
- max-connections: 15
-
- # Another peer. The ``max-connections'' value from the
- # ``fast-sites'' group scope is used. The ``ip-name'' value
- # defaults to the peer's name.
- peer data.ramona.vix.com {
- }
-
- peer bb.home.vix.com {
- max-connections: 20 # he can really cook.
- }
-}
-.fi
-.RE
-.PP
-Given the above configuration file, the defined peers would have the
-following values for the ``max-connections'' key.
-.PP
-.RS
-.nf
-uunet 5
-vixie 10
-data.ramona.vix.com 15
-bb.home.vix.com 20
-.fi
-.RE
-.PP
-Innfeed ignores key/value pairs it is not interested in. Some config file
-values can be set via a command line option, in which case that setting
-overrides the settings in the file.
-.PP
-Config files can be included in other config files via the syntax:
-.sp 1
-.nf
-.RS
-$INCLUDE filename
-.RE
-.fi
-.sp 1
-There is a maximum nesting depth of 10.
-.PP
-For a fuller example config file, see the supplied \fIinnfeed.conf\fP.
-.SH "GLOBAL VALUES"
-.PP
-The following listing show all the keys that apply to the process as
-whole. These are not required (compiled-in defaults are used where needed).
-.TP
-.B news-spool
-This key requires a pathname value. It specifies where the top of the
-article spool is. This corresponds to the ``\fI\-a\fP'' command-line
-option.
-.TP
-.B input-file
-This key requires a pathname value. It specifies the pathname (relative to
-the \fBbacklog-directory\fP) that should be read in funnel-file mode. This
-corresponds to giving a filename as an argument on the command-line (i.e.
-its presence also implies that funnel-file mode should be used).
-.TP
-.B pid-file
-This key requires a pathname value. It specifies the pathname (relative to
-the \fBbacklog-directory\fP) where the pid of the innfeed process should be
-stored. This corresponds to the ``\fI\-p\fP'' command-line option.
-.TP
-.B debug-level
-This key defines the debug level for the process. A non-zero number
-generates a lot of messages to stderr, or to the config-defined ``log-file''.
-This corresponds to the ``\fI\-d\fP'' command-line option.
-.TP
-.B use-mmap
-This key requires a boolean value. It specifies whether mmaping should be
-used if innfeed has been built with mmap support. If article data on disk
-is not in NNTP-ready format (CR/LF at the end of each line), then after
-mmaping the article is read into memory and fixed up, so mmaping has no
-positive effect (and possibly some negative effect depending on your
-system), and so in such a case this value should be \fIfalse\fP. This
-corresponds to the ``\fI\-M\fP'' command-line option.
-.TP
-.B log-file
-This key requires a pathname value. It specifies where any logging messages
-that couldn't be sent via syslog(3) should go (such as those generated when
-a positive value for ``\fBdebug-value\fP'', is used). This corresponds to
-the ``\fI\-l\fP'' command-line option. A relative pathname is relative to
-the ``\fBbacklog-directory\fP'' value.
-.\" .TP
-.\" .B initial-sleep
-.\" This key requires a positive integer value. It specifies how many seconds
-.\" innfeed should sleep at startup before attempting to take out its locks. On
-.\" fast machines and with innfeed handling many connections, it can take too
-.\" long for innfeed to recognise that its input has been closed, and that it
-.\" should release any locks it holds.
-.\"..................................................
-.TP
-.B backlog-directory
-This key requires a pathname value. It specifies where the current innfeed
-process should store backlog files. This corresponds to the ``\fI\-b\fP''
-command-line option.
-.TP
-.B backlog-highwater
-This key requires a positive integer value. It specifies how many articles
-should be kept on the backlog file queue before starting to write new
-entries to disk.
-.TP
-.B backlog-ckpt-period
-This key requires a positive integer value. It specifies how many seconds
-between checkpoints of the input backlog file. Too small a number will mean
-frequent disk accesses, too large a number will mean after a crash innfeed
-will re-offer more already-processed articles than necessary.
-.TP
-.B backlog-newfile-period
-This key requires a positive integer value. It specifies how many seconds
-before each checks for externally generated backlog files that are to be
-picked up and processed.
-.TP
-.B backlog-rotate-period
-This key requires a positive integer value. It specifies how many seconds
-elapse before
-.B innfeed
-checks for a manually created backlog file and moves the output backlog
-file to the input backlog file.
-.\"..................................................
-.TP
-.B dns-retry
-This key requires a positive integer value. It defines the number of seconds
-between attempts to re-lookup host information that previous failed to be
-resolved.
-.TP
-.B dns-expire
-This key requires a positive integer value. It defines the number of seconds
-between refreshes of name to address DNS translation. This is so long-running
-processes don't get stuck with stale data, should peer ip addresses change.
-.TP
-.B close-period
-This key requires a positive integer value. It is the maximum number of
-seconds a connection should be kept open. Some NNTP servers don't deal well
-with connections being held open for long periods.
-.TP
-.B gen-html
-This key requires a boolean value. It specifies whether the
-\fBstatus-file\fP should be HTML-ified.
-.TP
-.B status-file
-This key requires a pathname value. It specifies the pathname (relative to
-the \fBbacklog-directory\fP) where the periodic status of the innfeed
-process should be stored. This corresponds to the ``\fI\-S\fP''
-command-line option.
-.TP
-.B connection-stats
-This key requires a boolean value. If the value is true, then whenever the
-transmission statistics for a peer are logged, then each active connection
-logs its own statistics. This corresponds to the ``\fI\-z\fP''
-command-line option.
-.TP
-.B host-queue-highwater
-This key requires a positive integer value. It defines how many articles
-will be held internally for a peer before new arrivals cause article
-information to be spooled to the backlog file.
-.TP
-.B stats-period
-This key requires a positive integer value. It defines how many seconds
-innfeed waits between generating statistics on transfer rates.
-.TP
-.B stats-reset
-This key requires a positive integer value. It defines how many seconds
-innfeed waits before resetting all internal transfer counters back to zero
-(after logging one final time). This is so a innfeed-process running more
-than a day will generate ``final'' stats that will be picked up by logfile
-processing scripts.
-.\"..................................................
-.TP
-.B initial-reconnect-time
-This key requires a positive integer value. It defines how many seconds to
-first wait before retrying to reconnect after a connection failure. If the
-next attempt fails too, then the reconnect time is approximately doubled
-until the connection succeeds, or \fBmax-reconnection-time\fP is reached.
-.TP
-.B max-reconnect-time
-This key requires an integer value. It defines the maximum number of
-seconds to wait between attempt to reconnect to a peer. The initial value
-for reconnection attempts is defined by \fBinitial-reconnect-time\fP, and
-it is doubled after each failure, up to this value.
-.TP
-.B stdio-fdmax
-This key requires a non-negative integer value. If the value is greater
-than zero, then whenever a network socket file descriptor is created and
-it has a value \fIless than\fP this, the file descriptor will be dup'ed to
-bring the value up greater than this. This is to leave lower numbered file
-descriptors free for stdio. Certain systems, Sun's in particular, require
-this. SunOS 4.1.x usually requires a value of 128 and Solaris requires a
-value of 256. The default if this is not specified, is 0.
-.\"..................................................
-.SH "GLOBAL PEER DEFAULTS"
-.PP
-All the key/value pairs mentioned in this section must be specified at
-global scope. They may also be specified inside a group or peer
-definition. Note that when peers are added dynamically (i.e. when
-innfeed receives an article for an unspecified peer), it will add
-the peer site using the parameters specified at global scope.
-.TP
-.B article-timeout
-This key requires a non-negative integer value. If no articles need to be
-sent to the peer for this many seconds, then the peer is considered idle
-and all its active connections are torn down.
-.TP
-.B response-timeout
-This key requires a non-negative integer value. It defines the maximum
-amount of time to wait for a response from the peer after issuing a
-command.
-.TP
-.B initial-connections
-This key requires a non-negative integer value. It defines the number of
-connections to be opened immediately when setting up a peer binding. A
-value of 0 means no connections will be created until an article needs to
-be sent.
-.TP
-.B max-connections
-This key requires positive integer value. It defines the maximum number of
-connections to run in parallel to the peer. A value of zero specifies an
-unlimited number of maximum connections. In general use of an unlimited
-number of maximum connections is not recommended. Do not ever set
-\fBmax-connections\fP to zero with \fBdynamic-method\fP 0 set, as this will
-saturate peer hosts with connections. [ Note that in previous versions
-of innfeed, a value of 1 had a special meaning. This is no longer the case,
-1 means a maximum of 1 connection ].
-.TP
-.B dynamic-method
-This key requires an integer value between 0 and 3. It controls how connections
-(up to max-connections) are opened, up to the maximum specified by
-\fBmax-connections\fP. In general (and specifically, with \fBdynamic-method\fP
-0), a new connection is opened when the current number of connections is
-below \fBmax-connections\fP, and an article is to be sent while no current
-connections are idle. Without further restraint (i.e. using
-\fBdynamic-method\fP 0), in practice this means that \fBmax-connections\fP
-connections are established while articles are being sent. Use of other
-\fBdynamic-method\fP settings imposes a further limit on the amount of
-connections opened below that specified by \fBmax-connections\fP. This
-limit is calculated in different ways, depending of the value of
-\fBdynamic-method\fP.
-Users should note that adding additional connections is not always
-productive - just because opening twice as many connections results
-in a small percentage increase of articles accepted by the remote peer,
-this may be at considerable resource cost both locally and at the remote
-site, whereas the remote site might well have received the extra articles
-sent from another peer a fraction of a second later. Opening large
-numbers of connections is considered antisocial.
-The meanings of the various settings are:
-.RS
-.TP
-.B 0 no method
-Increase of connections up to \fBmax-connections\fP is unrestrained.
-.TP
-.B 1 maximize articles per second
-Connections are increased (up to \fBmax-connections\fP) and decreased so as
-to maximize the number of articles per second sent, while using the fewest
-connections to do this.
-.TP
-.B 2 set target queue length
-Connections are increased (up to \fBmax-connections\fP) and decreased so as
-to keep the queue of articles to be sent within the bounds set by
-\fBdynamic-backlog-low\fP and \fBdynamic-backlog-high\fP,
-while using the minimum resources possible.
-As the queue will tend to fill if the site is not keeping up, this method
-ensures that the maximum number of articles are offered to the peer
-while using the minimum number of connections to achieve this.
-.TP
-.B 3 combination
-This method uses a combination of methods 1 and 2 above. For sites
-accepting a large percentage of articles, method 2 will be used to
-ensure these sites are offered as complete a feed as possible. For sites
-accepting a small percentage of articles, method 1 is used, to minimize
-remote resource usage. For intermediate sites, an appropriate combination
-is used.
-.RE
-.TP
-.B dynamic-backlog-low
-This key requires an integer value between 0 and 100. It represents (as a
-percentage) the low water mark for the host queue. If the host queue falls
-below this level while using \fBdynamic-method\fP 2 or 3, and if 2 or more
-connections are open, innfeed will attempt to drop connections to the host.
-An IIR filter is applied to the value to prevent connection flap (see
-\fBdynamic-filter\fP). A value of 25.0 is recommended. This value
-must be smaller than \fBdynamic-backlog-high\fP.
-.TP
-.B dynamic-backlog-high
-This key requries an integer value between 0 and 100. It represents (as a
-percentage) the high water mark for the host queue. If the host queue rises
-above this level while using \fBdynamic-method\fP 2 or 3, and if less than
-\fBmax-connections\fP are open to the host, innfeed will attempt
-to open further connections to the host. An IIR filter is applied to the value
-to prevent connection flap (see \fBdynamic-filter\fP). A value of 50.0
-is recommended. This value must be larger than \fBdynamic-backlog-low\fP.
-.TP
-.B dynamic-backlog-filter
-This key requires a floating-point value between 0 and 1. It represents the
-filter coefficient used by the IIR filter used to implement
-\fBdynamic-method\fP 2 and 3.
-The recommended value of this filter is 0.7, giving a time
-constant of 1/(1-0.7) articles. Higher values will result in slower
-response to queue fullness changes, lower values in faster response.
-.TP
-.B max-queue-size
-This key requires a positive integer value. It defines the maximum number
-of articles to process at one time when using streaming to transmit to a
-peer. Larger numbers mean more memory consumed as articles usually get
-pulled into memory (see the description of \fBuse-mmap\fP).
-.TP
-.B streaming
-This key requires a boolean value. It defines whether streaming commands
-are used to transmit articles to the peers.
-.TP
-.B no-check-high
-This key requires a floating-point number which must be in the range [0.0,
-100.0]. When running transmitting with the streaming commands, innfeed
-attempts an optimization called ``no-CHECK'' mode. This involves \fInot\fP
-asking the peer if it wants the article, but just sending it. This
-optimization occurs when the percentage of the articles the peer has
-accepted gets larger than this number. If this value is set to 100.0, then
-this effectively turns off no-CHECK mode, as the percentage can never get
-above 100.0. If this value is too small, then the number of articles the
-peer rejects will get bigger (and your bandwidth will be wasted). A value
-of 95.0 usually works pretty well. NOTE: In innfeed 0.9.3 and earlier this
-value was in the range [0.0, 9.0].
-.TP
-.B no-check-low:
-This key requires a floating-point number which must be in the range [0.0,
-100.0), and it must be smaller that the value for \fBno-check-high\fP. When
-running in no-CHECK mode, as described above, if the percentage of articles
-the remote accepts drops below this number, then the no-CHECK optimization
-is turned off until the percentage gets above the \fBno-check-high\fP value
-again. If there is small difference between this and the
-\fBno-check-high\fP value (less than about 5.0), then innfeed may
-frequently go in and out of no-CHECK mode. If the difference is too big,
-then it will make it harder to get out of no-CHECK mode when necessary
-(wasting bandwidth). Keeping this to between 5.0 and 10.0 less than
-\fBno-check-high\fP usually works pretty well.
-.TP
-.B no-check-filter
-This is a floating point value representing the time constant, in articles,
-over which the CHECK / no-CHECK calculations are done. The recommended
-value is 50.0 which will implement an IIR filter of time constant 50. This
-roughly equates to making a decision about the mode over the previous
-50 articles. A higher number will result in a slower response to changing
-percentages of articles accepted; a lower number will result in a faster
-response.
-.TP
-.B bindaddress
-This key requires a string value. It specifies which outgoing IPv4 address
-innfeed should bind the local end of its connection to.
-Must be an IPv4 address in dotted-quad format (nnn.nnn.nnn.nnn), "any",
-or "none". If not set or set to "any", innfeed defaults
-to letting the kernel choose this address.
-If set to "none", innfeed will not use IPv4 for outgoing connections
-to peers in this scope (i.e. it forces IPv6).
-The default value is unset.
-.TP
-.B bindaddress6
-This key requires a string value. It behaves like \fBbindaddress\fP except
-for outgoing IPv6 connections. Must be in numeric IPv6 format, "any",
-or "none". If set to "none", innfeed will not use IPv6 for outgoing
-connections to peers in this scope. A value containing colons must be
-enclosed in double quotes.
-.TP
-.B port-number
-This key requires a positive integer value. It defines the tcp/ip port
-number to use when connecting to the remote.
-.TP
-.B force-ipv4
-This key requires a boolean value. By default it is set to false.
-Setting it to true is the same as setting "bindaddress6: none"
-and removing "bindaddress: none" if it was set.
-.TP
-.B drop-deferred
-This key requires a boolean value. By default it is set to false. When
-set to true, and a peer replies with code 431 or 436 (try again later) just
-drop the article and don't try to re-send it. This is useful for some
-peers that keep on deferring articles for a long time to prevent innfeed
-from trying to offer the same article over and over again.
-.TP
-.B min-queue-connection
-This key requires a boolean value. By default it is set to false. When
-set to true, innfeed will attempt to use a connection with the least queue
-size (or the first empty connection). If this key is set to true, it is
-recommended that \fBdynamic-method\fP be set to 0. This allows for article
-propagation with the least delay.
-.TP
-.B no-backlog
-This key requires a boolean value. It specifies whether spooling should
-be enabled (false, the default) or disabled (true). Note that when no-backlog
-is set, articles reported as "spooled" are actually silently discarded.
-.TP
-.B backlog-limit
-This key requires a non-negative integer value. If the number is 0 then
-backlog files are allowed to grown without bound when the peer is unable to
-keep up with the article flow. If this number is greater than 0 then it
-specifies the size (in bytes) the backlog file should get truncated to when
-the backlog file reaches a certain limit. The limit depends on whether
-\fBbacklog-factor\fP or \fBbacklog-limit-highwater\fP is used.
-.TP
-.B backlog-factor
-This key requires a floating point value, which must be larger than 1.0. It
-is used in conjunction with the peer key \fBbacklog-limit\fP. If
-\fBbacklog-limit\fP has a value greater than zero, then when the backlog
-file gets larger than the value \fBbacklog-limit * backlog-factor\fP, then
-the backlog file will be truncated to the size \fBbacklog-limit\fP. For
-example if \fBbacklog-limit\fP has a value of 1000000, and
-\fBbacklog-factor\fP has a value of 2.0, then when the backlogfile gets to
-be larger than 2000000 bytes in size, it will be truncated to 1000000 bytes.
-The front
-portion of the file is removed, and the trimming happens on line boundaries,
-so the final size may be a bit less than this number. If
-\fBbacklog-limit-highwater\fP is defined too, then \fBbacklog-factor\fP
-takes precedence.
-.TP
-.B backlog-limit-highwater
-This key requires a positive integer value that must be larger than the
-value for \fBbacklog-limit\fP. If the size of the backlog file gets larger
-than this value (in bytes), then the backlog file will be shrunk down to
-the size of \fBbacklog-limit\fP. If both \fBbacklog-factor\fP and
-\fBbacklog-limit-highwater\fP are defined, then the value of
-\fBbacklog-factor\fP is used.
-.TP
-.B backlog-feed-first
-This key requires a boolean value. By default it is set to false. When set
-to true, the backlog is fed before new files. This is intended to enforce
-in-order delivery, so setting this to true when initial-connections or
-max-connections is more than 1 is inconsistent.
-.TP
-.B username
-This key requires a string value. If the value is defined, then innfeed
-tries to authenticate by ``AUTHINFO USER'' and this value used for user name.
-\fBpassword\fP must also be defined, if this key is defined.
-.TP
-.B password
-This key requires a string value. The value is the password
-used for ``AUTHINFO PASS''.
-\fBusername\fP must also be defined, if this key is defined.
-.TP
-.B deliver
-This key is used with imapfeed to authenticate to a remote host. It is optional.
-There are several parameters that must be included with deliver:
-.RS
-.TP
-.B deliver-authname
-The authname is who you want to authenticate as.
-.TP
-.B deliver-password
-This is the appropriate password for authname.
-.TP
-.B deliver-username
-The username is who you want to "act" as, that is, who is actually
-going to be using the server.
-.TP
-.B deliver-realm
-In this case, the "realm" is the realm in which the specified authname
-is valid. Currently this is only needed by the DIGEST-MD5 SASL
-mechanism.
-.TP
-.B deliver-rcpt-to
-A printf-style format string for creating the envelope recipient address.
-The pattern MUST include a single string specifier which will be
-replaced with the newgroup (e.g "bb+%s"). The default is "+%s".
-.TP
-.B deliver-to-header
-An optional printf-style format string for creating a To: header to be
-prepended to the article. The pattern MUST include a single string
-specifier which will be replaced with the newgroup (e.g
-"post+%s@domain"). If not specified, the To: header will not be
-prepended.
-.RE
-.\"..................................................
-.SH "PEER VALUES"
-As previously explained, the peer definitions can contain redefinitions of
-any of the key/value pairs described in the \fBGLOBAL PEER DEFAULTS\fP
-section above. There is one key/value pair that is specific to a peer
-definition.
-.TP
-.B ip-name
-This key requires a word value. The word is the host's FQDN, or the dotted
-quad ip-address. If this value is not specified then the name of the peer
-is taken to also be its ip-name. See the entry for
-data.ramona.vix.com in the example below.
-.\"..................................................
-.SH RELOADING
-.PP
-If innfeed gets a SIGHUP signal, then it will reread the config file. All
-values at global scope except for ``\fBbacklog-directory\fP'' can be
-changed (although note that ``\fBbindaddress\fP'' and
-``\fBbindaddress6\fP'' changes will only affect new connections). Any new
-peers are added and any missing peers have their connections closed.
-.\"..................................................
-.SH EXAMPLE
-.PP
-Below is the sample innfeed.conf file.
-.RS
-.nf
-#
-# innfeed.conf file. See the comment block at the
-# end for a fuller description.
-#
-
-##
-## Global values. Not specific to any peer. These
-## are optional, but if used will override the
-## compiled in values. Command-line options used
-## will override these values.
-##
-
-pid-file: innfeed.pid
-debug-level: 0
-use-mmap: false
-log-file: innfeed.log
-stdio-fdmax: 0
-
-backlog-directory: innfeed
-backlog-rotate-period: 60
-backlog-ckpt-period: 30
-backlog-newfile-period: 600
-
-dns-retry: 900
-dns-expire: 86400
-close-period: 3600
-gen-html: false
-status-file: innfeed.status
-connection-stats: false
-host-queue-highwater: 200
-stats-period: 600
-stats-reset: 43200
-
-max-reconnect-time: 3600
-initial-reconnect-time: 30
-
-
-##
-## Defaults for all peers. These must all exist at
-## global scope. Any of them can be redefined
-## inside a peer or group definition.
-##
-
-article-timeout: 600
-response-timeout: 300
-initial-connections: 1
-max-connections: 5
-max-queue-size: 25
-streaming: true
-no-check-high: 95.0
-no-check-low: 90.0
-no-check-filter: 50.0
-port-number: 119
-backlog-limit: 0
-backlog-factor: 1.10
-backlog-limit-highwater:0
-dynamic-method: 3
-dynamic-backlog-filter: 0.7
-dynamic-backlog-low: 25.0
-dynamic-backlog-high: 50.0
-no-backlog: false
-
-##
-## Peers.
-##
-peer decwrl {
- ip-name: news1.pa.dec.com
-}
-
-peer uunet {
- ip-name: news.uunet.uu.net
- max-connections: 10
-}
-
-peer data.ramona.vix.com {
- # ip-name defaults to data.ramona.vix.com
- streaming: false
-}
-
-peer bb.home.vix.com {
- ip-name: 192.5.5.33
-}
-
-
-
-# Blank lines are ignored. Everything after a '#'
-# is ignored too.
-#
-# Format is:
-# key : value
-#
-# See innfeed.conf(5) for a description of
-# necessary & useful keys. Unknown keys and their
-# values are ignored.
-#
-# Values may be a integer, floating-point, c-style
-# single-quoted characters, boolean, and strings.
-#
-# If a string value contains whitespace, or
-# embedded quotes, or the comment character
-# (``#''), then the whole string must be quoted
-# with double quotes. Inside the quotes, you may
-# use the standard c-escape sequence
-# (\\t,\\n,\\r,\\f,\\v,\\",\\').
-#
-# Examples:
-# eg-string: "New\\tConfig\\tfile\\n"
-# eg-long-string: "A long string that goes
-# over multiple lines. The
-# newline is kept in the
-# string except when quoted
-# with a backslash \\
-# as here."
-# eg-simple-string: A-no-quote-string
-# eg-integer: 10
-# eg-boolean: true
-# eg-char: 'a'
-# eg-ctrl-g: '\\007'
-
-.fi
-.RE
-.SH HISTORY
-Written by James Brister <brister@vix.com> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innfeed.conf.5 7778 2008-04-17 21:27:22Z iulius $
-.SH SEE ALSO
-innfeed(1), newsfeeds(5)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INNMAIL 1"
-.TH INNMAIL 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-innmail \- Simple mail\-sending program
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinnmail\fR [\fB\-h\fR] [\fB\-s\fR \fIsubject\fR] \fIaddress\fR [\fIaddress\fR ...]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinnmail\fR is a Perl script intended to provide the non-interactive
-mail-sending functionality of \fImail\fR\|(1) while avoiding nasty security
-problems. It takes the body of a mail message on standard input and sends
-it to the specified addresses by invoking the value of \fImta\fR in
-\&\fIinn.conf\fR.
-.PP
-At least one address (formatted for the \s-1MTA\s0 specified in \fIinn.conf\fR, if it
-matters) is required. \fBinnmail\fR will sanitize the addresses so that they
-contain only alphanumerics and the symbols \f(CW\*(C`@\*(C'\fR, \f(CW\*(C`.\*(C'\fR, \f(CW\*(C`\-\*(C'\fR, \f(CW\*(C`+\*(C'\fR, \f(CW\*(C`_\*(C'\fR,
-and \f(CW\*(C`%\*(C'\fR.
-.PP
-\&\fBinnmail\fR was written to be suitable for the \fImailcmd\fR setting in
-\&\fIinn.conf\fR.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Gives usage information.
-.IP "\fB\-s\fR \fIsubject\fR" 4
-.IX Item "-s subject"
-Sets the Subject: header of the message. A warning is issued if this
-option is omitted.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-This sends a one-line message to the local user \f(CW\*(C`joe\*(C'\fR:
-.PP
-.Vb 1
-\& echo "A one\-line message." | innmail \-s "Simple message" joe
-.Ve
-.PP
-\&\fBinnmail\fR by default is used by \s-1INN\s0 for sending nightly reports and
-control message reports.
-.SH "BUGS"
-.IX Header "BUGS"
-\&\fBinnmail\fR fails on addresses that begin with \f(CW\*(C`\-\*(C'\fR, although one might
-hope that the news server will not need to contact any such addresses.
-.PP
-There are many \*(L"correct\*(R" addresses that will be silently modified by the
-sanitization process. A news administrator should be careful to use
-particularly sane addresses if they may be passed to \fBinnmail\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBinnmail\fR was written by James Brister <brister@vix.com> for
-InterNetNews. This manual page was originally written by Jeffrey
-M. Vinocur.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fImail\fR\|(1).
+++ /dev/null
-.TH innreport 8
-.SH NAME
-innreport \- summarize INN log files.
-.SH SYNOPSIS
-innreport -f innreport.conf [ -[no]options ] [ logfiles ]
-.SH DESCRIPTION
-.I Innreport
-is a
-.IR perl (1)
-script that summarizes INN log files. It is normally invoked by
-.IR scanlogs (8).
-Supported programs are
-.IR innd (8),
-.IR innfeed (1),
-.IR innxmit (8),
-.I nntplink,
-.IR nnrpd (8),
-.IR batcher (8),
-.IR rnews (1),
-.IR crosspost (8)
-and a few others.
-.SH OPTIONS
-There are lots of 'em. Run innreport with ``\-h'' or ``\-help'' to get full
-details.
-.SH HISTORY
-Written by Fabien Tassin <fta@sofaraway.org> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innreport.8 4320 2001-01-12 16:57:49Z kondou $
-
-.SH "SEE ALSO"
-innd(8),
-innfeed(8),
-innxmit(8),
-news.daily(8),
-newslog(5),
-nnrpd(8),
-scanlogs(8),
-writelog(8).
+++ /dev/null
-.TH INNSTAT 8
-.SH NAME
-innstat \- print snapshot of INN system
-.SH SYNOPSIS
-.B innstat
-.SH DESCRIPTION
-The
-.I innstat
-script prints a snapshot of the INN system.
-It displays the operating mode of the server,
-as well as disk usage and the status of all log and lock files.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innstat.8 584 1998-04-09 15:16:17Z mibsoft $
-.SH "SEE ALSO"
-innd(8),
-news.daily(8),
-newslog(5),
-nnrpd(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "INNUPGRADE 8"
-.TH INNUPGRADE 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-innupgrade \- Upgrade INN configuration files
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBinnupgrade\fR \fIdirectory\fR
-.PP
-\&\fBinnupgrade\fR [\fB\-t\fR \fItype\fR] \fB\-f\fR \fIfile\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBinnupgrade\fR is intended to be run during a major upgrade of \s-1INN\s0 to fix
-the configuration files with any required changes. If given a directory,
-it will scan that directory for any files that it has updates defined for,
-try to perform those updates, and replace the files with updated versions
-if applying the updates resulted in any changes. The old versions of the
-files will be saved with a \f(CW\*(C`.OLD\*(C'\fR extension.
-.PP
-If the \fB\-f\fR flag is used, only that file will be updated. If the file
-name doesn't match the standard file name of an \s-1INN\s0 configuration file,
-the optional \fB\-t\fR flag may be given to specify the type. See
-\&\*(L"\s-1EXAMPLES\s0\*(R" for an example of this.
-.PP
-Currently, \fBinnupgrade\fR knows how to apply the following updates:
-.IP "\(bu" 2
-\&\fIinn.conf\fR: Quote values with whitespace and comment out keys with no
-values, required for the change in configuration parsers introduced in \s-1INN\s0
-2.4. The new format is not backward compatible with the previous parser,
-since the previous parser will include the double-quotes in the value of
-the parameter.
-.PP
-Normally, \fBinnupgrade\fR should be run on the \fIpathetc\fR directory after
-any upgrade of \s-1INN\s0 other than a patch release (any upgrade that changes
-the first or second version numbers). This may occur automatically during
-the upgrade process.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-f\fR \fIfile\fR" 4
-.IX Item "-f file"
-Only act on \fIfile\fR rather than working on an entire directory.
-.IP "\fB\-t\fR \fItype\fR" 4
-.IX Item "-t type"
-For a file specified with \fB\-f\fR, parse it and upgrade it as if it were
-named \fItype\fR. Used for upgrading files with the same syntax as normal
-\&\s-1INN\s0 configuration files but with different names. Only makes sense in
-combination with \fB\-f\fR.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Upgrade any configuration files found in \fI/usr/local/news/etc\fR:
-.PP
-.Vb 1
-\& innupgrade /usr/local/news/etc
-.Ve
-.PP
-Upgrade only \fI/news/etc/inn.conf\fR:
-.PP
-.Vb 1
-\& innupgrade \-f /news/etc/inn.conf
-.Ve
-.PP
-Upgrade a file named \fIinn\-special.conf\fR that should have the same syntax
-as \fIinn.conf\fR:
-.PP
-.Vb 1
-\& innupgrade \-t inn.conf \-f inn\-special.conf
-.Ve
-.PP
-Any upgrade rules that apply to \fIinn.conf\fR will be applied to the
-alternate file.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: innupgrade.8 7880 2008-06-16 20:37:13Z iulius $
+++ /dev/null
-.TH INNWATCH 8
-.SH NAME
-innwatch \- monitor innd.
-.SH SYNOPSIS
-.B innwatch
-[
-.BI -l " logfile"
-]
-[
-.BI -t " seconds"
-]
-.SH DESCRIPTION
-.I Innwatch
-is normally started by
-.IR rc.news .
-It periodically \(em every
-.I <innwatchsleeptime in inn.conf>
-seconds \(em examines the load average, and the number of free blocks
-and inodes on the spool partition, as described by its
-control file,
-.IR innwatch.ctl .
-.PP
-If the load gets too high, or the disk gets too full, it throttles the server.
-When the condition restores, it unblocks the server.
-In addition, on each pass through the loop it will check the
-logfile
-.I <pathlog in inn.conf>/news.crit
-to see if it has been modified, and send mail to the news administrator
-if so.
-.PP
-Upon receipt of an interrupt signal (SIGINT),
-.IR innwatch
-will report its status in the file
-.IR <pathrun\ in\ inn.conf>/innwatch.status .
-.SH OPTIONS
-.TP
-.B \-l logfile
-To specify a log file to watch, other than the default of
-.IR news.crit ,
-use the ``\fB\-l\fP'' flag.
-.TP
-.B \-t seconds
-To change the period between checks from the default from
-.I inn.conf ,
-use the ``\fB\-t\fP''
-flag.
-.SH HISTORY
-Written by Mike Cooper <mcooper@usc.edu>, with modifications by
-<kre@munnari.oz.au>, Steve Groom <stevo@elroy.Jpl.Nasa.Gov> and
-Christophe Wolfhugel <wolf@pasteur.fr>.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innwatch.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-ctlinnd(8),
-inn.conf(5),
-innwatch.ctl(5),
-shlock(1).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH INNWATCH.CTL 5
-.SH NAME
-innwatch.ctl \- control Usenet supervision by innwatch
-.SH DESCRIPTION
-The file
-.I <pathetc in inn.conf>/innwatch.ctl
-is used to determine what actions are taken during the periodic
-supervisions by
-.IR innwatch .
-.PP
-The file consists of a series of lines; blank lines and lines beginning
-with a number sign (``#'') are ignored.
-All other lines consist of seven fields, each preceded by a delimiting
-character, for example:
-.sp 1
-.nf
-.RS
-:label:state:condition:test:limit:command:reason
-.RE
-or
-.RS
-@label@state@condition@test@limit@command@reason
-.RE
-.fi
-.PP
-The delimiter can be any one of several non-alphanumeric characters that does
-not appear elsewhere in the line; there is no way to quote it to
-include it in any of the fields.
-Any of ``!'', ``,'', ``:'', ``@'', ``;'', or ``?'' is a good choice.
-Each line can have a different delimiter; the first character on each line
-is the delimiter for that line.
-White space surrounding delimiters, except before the first, is ignored,
-and does not form part of the fields; white space within fields is
-permitted.
-All delimiters must be present.
-.PP
-The first field is a label for this control line.
-It is used as an internal state indicator and in
-.I ctlinnd
-messages to control the server.
-If this field is empty, the line number is used.
-.PP
-The second field specifies when this control line should be used.
-It consists of a list of labels
-and special indicators,
-separated by whitespace.
-If the current state matches against any of the labels in this field,
-this line will be used as described below.
-The values that may be used are:
-.IP "\-"
-This line matches if the current state is the same as the label on
-this line, or if the current state is ``run'', the initial state.
-This is also the default state if this field is empty.
-.IP "+"
-This line matches if the current state is ``run''.
-.IP "*"
-This line always matches.
-.IP "label"
-This line matches if the current state is the specified ``label''.
-.IP "\-label"
-This line matches if the current state is not the specified ``label''.
-.PP
-The third field specifies a shell command that is invoked if this line matches.
-Do not use any shell filename expansion characters such as ``*'', ``?'',
-or ``['' (even quoted, they're not likely to work as intended).
-If the command succeeds, as indicated by its exit status, it is expected
-to have printed a single integer to standard output.
-This gives the value of this control line, to be used below.
-If the command fails, the line is ignored.
-The command is executed with its current directory set to the news spool
-articles directory,
-.IR <patharticles\ in\ inn.conf> .
-.PP
-The fourth field specifies the operator to use to test the value returned above.
-It should be one of the two letter numeric test operators defined in
-.IR test (1)
-such as ``eq'', ``lt'' and the like.
-The leading dash (``\-'') should not be included.
-.PP
-The fifth field specifies a constant with which to compare the value using
-the operator just defined.
-This is done by invoking the command:
-.sp 1
-.RS
-test value -operator constant
-.RE
-.sp 1
-The line is said to ``succeed'' if it returns true.
-.PP
-The sixth field specifies what should be done if the line succeeds,
-and in some cases if it fails.
-Any of the following words may be used:
-.IP throttle
-Causes
-.I innwatch
-to throttle the server if this line succeeds.
-It also sets the state to the value of the line's label.
-If the line fails, and the state was previously equal to
-the label on this line (that is, this line had previously succeeded),
-then a
-.I go
-command will be sent to the server, and
-.I innwatch
-will return to the ``run'' state.
-The ``throttle'' is only performed if the current state is ``run'' or a
-state other than the label of this line, regardless of whether the command
-succeeds.
-.IP pause
-Is identical to ``throttle'' except that the server is paused.
-.IP shutdown
-Sends a ``shutdown'' command to the server.
-It is for emergency use only.
-.IP flush
-Sends a ``flush'' command to the server.
-.IP go
-Causes
-.I innwatch
-to send a ``go'' command to the server and to set the state to ``run''.
-.IP exit
-Causes
-.I innwatch
-to exit.
-.PP
-.IP skip
-The remainder of the control file is skipped for the current pass.
-.PP
-The last field specifies the reason that is used in those
-.I ctlinnd
-commands that require one.
-More strictly, it is part of the reason \(em
-.I innwatch
-appends some information to it.
-In order to enable other sites to recognize the state of the local
-.I innd
-server, this field should usually be set to one of several standard
-values.
-Use ``No\ space'' if the server is rejecting articles because of a lack
-of filesystem resources.
-Use ``loadav'' if the server is rejecting articles because of a lack
-of CPU resources.
-.PP
-Once
-.I innwatch
-has taken some action as a consequence of its control line, it skips the
-rest of the control file for this pass.
-If the action was to restart the server (that is, issue a ``go'' command),
-then the next pass will commence almost immediately, so that
-.I innwatch
-can discover any other condition that may mean that the server should
-be suspended again.
-.SH EXAMPLES
-.RS
-.nf
-@@@inndf .@lt@10000@throttle@No space
-@@@inndf -i .@lt@1000@throttle@No space (inodes)
-.fi
-.RE
-.PP
-The first line causes the server to be throttled if the free space drops
-below 10000 units
-(using whatever units
-.IR inndf (8)
-uses), and restarted again when free space increases above the threshold.
-.PP
-The second line does the same for inodes.
-.PP
-The next three lines act as a group and should
-appear in the following order.
-It is easier to explain them, however, if they are described from the last up.
-.PP
-.RS
-.nf
-!load!load hiload!loadavg!lt!5!go!
-:hiload:+ load:loadavg:gt:8:throttle:loadav
-/load/+/loadavg/ge/6/pause/loadav
-.fi
-.RE
-.PP
-The final line causes the server to be paused if
-.I innwatch
-is in the ``run'' state and the load average rises to, or above, six.
-The state is set to ``load'' when this happens.
-The previous line causes the server to be throttled when
-.I innwatch
-is in the ``run'' or ``load'' state, and the load average rises above eight.
-The state is set to ``hiload'' when this happens.
-Note that
-.I innwatch
-can switch the server from ``paused'' to ``throttled'' if the load average
-rises from below six to between six and seven, and then to above eight.
-The first line causes the server to be sent a ``go'' command if
-.I innwatch
-is in the ``load'' or ``hiload'' state, and the load average drops below five.
-.PP
-Note that all three lines assume a mythical command
-.I loadavg
-that is assumed to print the current load average as an integer.
-In more practical circumstances, a pipe of
-.I uptime
-into
-.I awk
-is more likely to be useful.
-.SH BUGS
-This file must be tailored for each individual site, the sample supplied
-is truly no more than a sample.
-The file should be ordered so that the more common problems are tested first.
-.PP
-The ``run'' state is not actually identified by the label with that three
-letter name, and using it will not work as expected.
-.PP
-Using an ``unusual'' character for the delimiter such as ``('', ``*'',
-``&'', ``\(ga'', ``\(aa'', and the like, is likely to lead to obscure and
-hard to locate bugs.
-.SH HISTORY
-Written by <kre@munnari.oz.au> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innwatch.ctl.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5),
-innd(8),
-inndf(8),
-ctlinnd(8),
-news.daily(8).
+++ /dev/null
-.TH INNXBATCH 8
-.SH NAME
-innxbatch \- send xbatched Usenet articles to a remote NNTP server
-.SH SYNOPSIS
-.I innxbatch
-[
-.B \-D
-]
-[
-.BI \-t " timeout"
-]
-[
-.BI \-T " timeout"
-]
-[
-.B \-v
-]
-.I host
-.I file ...
-.SH DESCRIPTION
-.I Innxbatch
-connects to the NNTP server at the specified
-.I host
-and sends it the specified xbatch files, using the XBATCH extension to
-the NNTP protocol. It is normally invoked by a script run out of
-.IR cron (8)
-that uses
-.IR shlock (1)
-to lock the host name, followed by a
-.IR ctlinnd (8)
-command to flush the batchfile.
-.PP
-Each file is removed after it has been successfully transferred.
-.PP
-If a communication error such as a
-.IR write (2)
-failure, or an unexpected reply from the remote server occurs,
-.I innxbatch
-will stop sending and leave all remaining files untouched for later retry.
-
-
-.SH OPTIONS
-.TP
-.B \-t seconds
-.I Innxbatch
-normally blocks until the connection is made.
-To specify a timeout on how long to try to make the connection, use
-the ``\-t'' flag.
-.TP
-.B \-T seconds
-To specify the total amount of time that should be allowed for article
-transfers, use the ``\-T'' flag.
-.br
-The default is to wait until an I/O error occurs, or all the articles have
-been transferred. If the ``\-T'' flag is used, the time is checked
-just before each article is started; it will not abort a transfer that
-is in progress.
-.TP
-.B \-v
-Upon exit,
-.I innxbatch
-reports transfer and CPU usage statistics via
-.IR syslog (3).
-If the ``\-v'' flag is used, they will also be printed on the standard
-output.
-.TP
-.B \-D
-Use the ``\-D'' flag to print debugging information on standard error.
-This will show the protocol transactions between
-.I innxbatch
-and the NNTP server on the remote host.
-.SH EXAMPLES
-A sample
-.I newsfeeds(5)
-entry to produce appropriate xbatch files (thanks to Karsten Leipold
-<poldi@dfn.de>):
-.sp 1
-.nf
- nase\e
- :*\e
- :Tc,Wnb\e
-.ds R$ <pathbin in inn.conf>
- :\*(R$/batcher \e
-.ds R$ <$ac_cv_path_COMPRESS in config.cache>
-.ds P$ <pathoutgoing in inn.conf>
- -p "(\*(R$ >\e
- \*(P$/nase.\e$\e$)" \e
- nase.do.main
-.fi
-.sp 1
-A sample script to invoke
-.I innxbatch(8)
-is:
-.sp 1
-.nf
- #!/bin/sh
- ## SH script to send xbatches for a site, wrapped around innxbatch
- ## Invocation:
- ## sendxbatches.sh <sitename> <hostname> <xbatch file name> ...
-
- if [ $# -le 3 ]
- then
- echo "usage: $0 <sitename> <hostname> <xbatch file name>"
- exit 1
- fi
-
- . <pathbin in inn.conf>/innshellvars
-
- site="$1"; host="$2"; shift; shift
-
- ctlinnd flush "$site" \e
- && sleep 5 \e
- && exec $NEWSBIN/innxbatch -v -D "$host" $*
-.fi
-.SH HISTORY
-Written by Stefan Petri <petri@ibr.cs.tu-bs.de>, modelled after
-.IR innxmit (8)
-and the XBATCH patch for the nntp reference implementation.
-.SH "SEE ALSO"
-ctlinnd(8),
-inn.conf(5),
-innd(8),
-innxmit(8),
-newsfeeds(5),
-nntpsend(8),
-shlock(1).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH INNXMIT 8
-.SH NAME
-innxmit \- send Usenet articles to a remote NNTP server
-.SH SYNOPSIS
-.I innxmit
-[
-.B \-a
-]
-[
-.B \-c
-]
-[
-.B \-d
-]
-[
-.B \-H
-]
-[
-.B \-l
-]
-[
-.BI \-P " portnum"
-]
-[
-.B \-p
-]
-[
-.B \-r
-]
-[
-.B \-s
-]
-[
-.BI \-T " timeout"
-]
-[
-.BI \-t " timeout"
-]
-.I host
-.I file
-.SH DESCRIPTION
-.I Innxmit
-connects to the NNTP server at the specified
-.I host
-(validating itself via
-.IR passwd.nntp
-if possible)
-and sends it the articles specified in the batchfile named
-.IR file .
-It is normally invoked by a script run out of
-.IR cron (8)
-that uses
-.IR shlock (1)
-to lock the host name, followed by a
-.IR ctlinnd (8)
-command to flush the batchfile.
-.PP
-If the
-.I file
-is not an absolute pathname, it is taken relative to the
-.I <pathoutgoing in inn.conf>
-directory.
-It is normally written by specifying the ``Wnm'' flags in the
-.I newsfeeds
-file.
-Each line in the batchfile should be in one of the following formats:
-.PP
-.RS
-.nf
-token Message-ID
-token
-.fi
-.RE
-.PP
-The
-.I token
-field names the article to be sent.
-If the
-.I Message-ID
-field is not specified, it will be obtained by scanning the article.
-The
-.I token
-and
-.I Message-Id
-fields are separated by a space.
-.PP
-If a communication error such as a
-.IR write (2)
-failure occurs,
-.I innxmit
-will stop sending and rewrite the batchfile to contain the current
-article and any other unsent articles.
-.SH OPTIONS
-.TP
-.B \-a
-If all articles were sent successfully,
-.I innxmit
-will remove the batchfile; otherwise it will rewrite it to contain the
-list of unsent articles.
-If no articles were sent or rejected, the file is left untouched.
-This can cause the batchfile to grow excessively large if many articles
-have been expired and there are communication problems.
-To always rewrite the batchfile, use the ``\fB\-a\fP'' flag.
-.TP
-.B \-c
-In streaming mode, a check of each message ID is still made to avoid sending
-articles already on the server.
-The ``\fB\-c\fP'' flag will, if streaming mode is supported,
-result in sending articles without checking.
-This results in slightly greater throughput and may be appropriate when
-it is known that the site could not already have the articles such as in
-the case of a "leaf" site.
-.TP
-.B \-d
-Use the ``\fB\-d\fP'' flag to print debugging information on standard error.
-This will show the protocol transactions between
-.I innxmit
-and the NNTP server on the remote host.
-.TP
-.B \-H
-If the ``\fB\-H\fP'' flag is given, then only headers are sent to
-.I host
-for all articles except control messages.
-And Bytes: header is also included even if it does not exist in the original
-article. ``\fB\-H\fP'' flag is useful for diablo reader.
-.TP
-.B \-l
-The ``\fB\-l\fP'' flag is used to turn on logging of reasons the remote gives
-for rejecting an article.
-.TP
-.B \-P portnum
-To specify a port number other than the default, use the ``\fB\-P\fP'' flag.
-.TP
-.B \-p
-If the ``\fB\-p\fP'' flag is given, then no connection is made and the batchfile
-is purged of entries that refer to files that no longer exist.
-This implies the ``\fB\-a\fP'' flag.
-.TP
-.B \-r
-If the remote server sends an unexpected reply code,
-.I innxmit
-will requeue the article and proceed.
-Use the ``\fB\-r\fP'' flag if the article should not be requeued.
-.TP
-.B \-s
-.I Innxmit
-will attempt to negotiate a streaming mode extension of the NNTP
-protocol with the server at connect time.
-If successful it will use a slightly different protocol that enhances
-throughput.
-If the server does not recognize the streaming mode negotiation
-.I innxmit
-will revert to normal NNTP transfer mode.
-Use the ``\fB\-s\fP'' flag to disable the attempt to negotiate the streaming
-mode extension.
-.TP
-.B \-T seconds
-To specify the total amount of time that should be allowed for article
-transfers, use the ``\fB\-T\fP'' flag.
-The default is to wait until an I/O error occurs, or all the articles have
-been transferred.
-If the ``\fB\-T\fP'' flag is used, the time is checked just before each
-article is started; it will not abort a transfer that is in progress.
-.TP
-.B \-t seconds
-.I Innxmit
-normally blocks until the connection is made.
-To specify a timeout on how long to try to make the connection, use
-the ``\fB\-t\fP''
-flag.
-.TP
-.B \-v
-Upon exit,
-.I innxmit
-reports transfer and CPU usage statistics via
-.IR syslog (3).
-If the ``\fB\-v\fP'' flag is used, they will also be printed on the standard
-output.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: innxmit.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-ctlinnd(8),
-inn.conf(5),
-innd(8),
-newsfeeds(5),
-shlock(1).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "libauth 3"
-.TH libauth 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-libauth \- routines for writing nnrpd resolvers and authenticators
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-.Vb 1
-\& #include "libauth.h"
-.Ve
-.PP
-.Vb 5
-\& struct res_info {
-\& struct sockaddr *client;
-\& struct sockaddr *local;
-\& char *clienthostname;
-\& };
-.Ve
-.PP
-.Vb 4
-\& struct auth_info {
-\& char *username;
-\& char *password;
-\& };
-.Ve
-.PP
-.Vb 2
-\& struct auth_info *get_auth_info(FILE *);
-\& struct res_info *get_res_info (FILE *);
-.Ve
-.PP
-.Vb 2
-\& void free_auth_info(struct auth_info*);
-\& void free_res_info (struct res_info*);
-.Ve
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-These functions provide a convenient C frontend to the nnrpd external
-authentication interface documented in \fIdoc/external\-auth\fR. Use of
-this library is \fBnot\fR required; in particular, external resolvers and
-authenticators written in languages other than C will need to implement
-the necessary functionality themselves.
-.PP
-The \fIget_auth_info()\fR and \fIget_res_info()\fR functions allocate sufficient
-memory for a \fBstruct auth_info\fR or \fBstruct res_info\fR and any necessary
-fields, and return a pointer to the struct with the fields filled in
-from information supplied by nnrpd (the \fBFILE*\fR parameter generally
-should be \f(CW\*(C`stdin\*(C'\fR). Both functions return \s-1NULL\s0 on error. The caller
-is responsible for deallocating the memory by using the functions below.
-.PP
-The string fields of both structs are straightforward. The \fBclient\fR
-and \fBlocal\fR fields of \fBstruct res_info\fR actually point to instances of
-\&\fBstruct sockaddr_in\fR (or \fBstruct sockaddr_in6\fR if IPv6 support is
-compiled in).
-.PP
-The \fIfree_auth_info()\fR and \fIfree_res_info()\fR functions free the struct
-passed in as argument and all necessary fields.
-.SH "BUGS"
-.IX Header "BUGS"
-In many cases, nnrpd provides more information than is normally useful
-(for example, even when calling an authenticator, the resolver
-information is often provided.) On the other hand, in certain cases it
-provides less information than might be expected (for example, if nnrpd
-is reading from stdin rather than a socket). The implementation is
-capable of handling at least the first of these issues, but that
-functionality is not exposed in the interface.
-.PP
-At present, \fIlibauth.h\fR and its implementation are located in
-\&\fIauthprogs/\fR; perhaps they should be moved to \fIinclude/\fR and \fIlib/\fR,
-respectively?
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Jeffrey M. Vinocur <jeff@litech.org> for InterNetNews.
-.PP
-$Id: libauth.3 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5), \fIdoc/external\-auth\fR
+++ /dev/null
-.\" $Revision: 6124 $
-.TH LIBINN 3
-.SH NAME
-libinn \- InterNetNews library routines
-.SH SYNOPSIS
-.nf
-.ta \w' unsigned long 'u
-.B
-#include "libinn.h"
-
-.B "typedef struct _TIMEINFO {"
-.B " time_t time;"
-.B " long usec;"
-.B " long tzone;
-.B "} TIMEINFO;"
-
-.B "char *"
-.B "GenerateMessageID(domain)"
-.B " char *domain;"
-
-.B "void"
-.B "HeaderCleanFrom(from)"
-.B " char *from;"
-
-.B "char *"
-.B "HeaderFind(Article, Header, size)"
-.B " char *Article;"
-.B " char *Header;"
-.B " int size;"
-
-.B "FILE *"
-.B "CAopen(FromServer, ToServer)"
-.B " FILE *FromServer;"
-.B " FILE *ToServer;"
-
-.B "FILE *"
-.B "CAlistopen(FromServer, ToServer, request)"
-.B " FILE *FromServer;"
-.B " FILE *ToServer;"
-.B " char *request;"
-
-.B "void"
-.B "CAclose()"
-
-.B "struct _DDHANDLE *"
-.B "DDstart(FromServer, ToServer)"
-.B " FILE *FromServer;"
-.B " FILE *ToServer;"
-
-.B "void"
-.B "DDcheck(h, group)"
-.B " DDHANDLE *h;"
-.B " char *group;"
-
-.B "char *"
-.B "DDend(h)"
-.B " DDHANDLE *h;"
-
-.B "void"
-.B "close_on_exec(fd, flag)"
-.B " int fd;"
-.B " bool flag;"
-
-.B "int"
-.B "nonblocking(fd, flag)"
-.B " int fd;"
-.B " bool flag;"
-
-.B "bool"
-.B "inn_lock_file(fd, type, flag)"
-.B " int fd;"
-.B " LOCKTYPE type;"
-.B " bool block;"
-
-.B "char *"
-.B "GetFQDN(domain)"
-.B " char *domain;"
-
-.B "char *"
-.B "GetModeratorAddress(FromServer, ToServer, group, moderatormailer)"
-.B " FILE *FromServer;"
-.B " FILE *ToServer;"
-.B " char *group;"
-.B " char *moderatormailer;"
-
-.B "int"
-.B "GetResourceUsage(usertime, systime)"
-.B " double *usertime;"
-.B " double *systime;"
-
-.B "int"
-.B "GetTimeInfo(now)"
-.B " TIMEINFO *now;"
-
-.B "int"
-.B "NNTPlocalopen(FromServerp, ToServerp, errbuff)"
-.B " FILE **FromServerp;"
-.B " FILE **ToServerp;"
-.B " char *errbuff;"
-
-.B "int"
-.B "NNTPremoteopen(port, FromServerp, ToServerp, errbuff)"
-.B " int port;"
-.B " FILE **FromServerp;"
-.B " FILE **ToServerp;"
-.B " char *errbuff;"
-
-.B "int"
-.B "NNTPconnect(host, port, FromServerp, ToServerp, errbuff)"
-.B " char *host;"
-.B " int port;"
-.B " FILE **FromServerp;"
-.B " FILE **ToServerp;"
-.B " char *errbuff;"
-
-.B "int"
-.B "NNTPsendarticle(text, ToServer, Terminate)"
-.B " char *text;"
-.B " FILE *ToServer;"
-.B " int Terminate;"
-
-.B "int"
-.B "NNTPsendpassword(server, FromServer, ToServer)"
-.B " char *server;"
-.B " FILE *FromServer;"
-.B " FILE *ToServer;"
-
-.B "void"
-.B "Radix32(value, p)
-.B " unsigned long value;"
-.B " char *p;"
-
-.B "char *"
-.B "ReadInFile(name, Sbp)"
-.B " char *name;"
-.B " struct stat *Sbp;"
-
-.B "char *"
-.B "ReadInDescriptor(fd, Sbp)"
-.B " int fd;"
-.B " struct stat *Sbp;"
-
-.B "HASH"
-.B "HashMessageID(MessageID)"
-.B " const char *MessageID;"
-.fi
-.SH DESCRIPTION
-.I Libinn
-is a library of utility routines for manipulating Usenet articles and
-related data.
-It is not necessary to use the header file
-.IR libinn.h ;
-if it is not available, it is only necessary to properly declare the
-.I TIMEINFO
-datatype, as given above.
-.PP
-.I GenerateMessageID
-uses the current time, process-ID, and fully-qualified domain name, which is
-passed as an argument and used if local host can not be resolved or it is
-different from ``domain'' set in
-.IR inn.conf ,
-to create a Message-ID header that is highly likely to be unique.
-The returned value points to static space that is reused on subsequent calls.
-.PP
-.I HeaderCleanFrom
-removes the extraneous information from the value of a ``From'' or ``Reply-To''
-header and leaves just the official mailing address.
-In particular, the following transformations are made to the
-.I from
-parameter:
-.RS
-.nf
-.ta \w'stuff <address> 'u
-address --> address
-address (stuff) --> address
-stuff <address> --> address
-.fi
-.RE
-The transformations are simple, based on RFC\ 1036 which limits the format
-of the header.
-.PP
-.I HeaderFind
-searches through
-.I Article
-looking for the specified
-.IR Header .
-.I Size
-should be the length of the header name.
-It returns a pointer to the value of the header, skipping leading whitespace,
-or NULL if the header cannot be found.
-.I Article
-should be a standard C string containing the text of the article; the end
-of the headers is indicated by a blank line \(em two consecutive \en
-characters.
-.PP
-.I CAopen
-and
-.I CAclose
-provide news clients with access to the active file; the ``CA'' stands for
-.IR C lient
-.IR A ctive.
-.I CAopen
-opens the
-.I active
-file for reading.
-It returns a pointer to an open FILE, or NULL on error.
-If a local or NFS-mounted copy exists,
-.I CAopen
-will use that file.
-The
-.I FromServer
-and
-.I ToServer
-parameters should be FILE's connected to the NNTP server for input and
-output, respectively.
-See
-.I NNTPremoteopen
-or
-.IR NNTPlocalopen ,
-below.
-If either parameter is NULL, then
-.I CAopen
-will just return NULL if the file is not locally available.
-If they are not NULL,
-.I CAopen
-will use them to query the NNTP server using
-the ``list'' command to make a local temporary copy.
-.PP
-The
-.I CAlistopen
-sends a ``list'' command to the server and returns a temporary file
-containing the results.
-The
-.I request
-parameter, if not NULL, will be sent as an argument to the command.
-Unlike
-.IR CAopen ,
-this routine will never use a locally-available copy of the active file.
-.PP
-.I CAclose
-closes the active file and removes any temporary file that might have
-been created by
-.I CAopen
-or
-.IR CAlistopen .
-.PP
-.I CloseOnExec
-can make a descriptor ``close-on-exec'' so that it is not shared
-with any child processes.
-If the flag is non-zero, the file is so marked; if zero, the ``close-on-exec''
-mode is cleared.
-.PP
-.IR DDstart ,
-.IR DDcheck ,
-and
-.I DDend
-are used to set the Distribution header; the ``DD'' stands for
-.IR D efault
-.IR D istribution.
-The
-.I distrib.pats
-file is consulted to determine the proper value for the Distribution
-header after all newsgroups have been checked.
-.I DDstart
-begins the parsing.
-It returns a pointer to an opaque handle that should be used on subsequent
-calls.
-The
-.I FromServer
-and
-.I ToServer
-parameters should be FILE's connected to the NNTP server for input and
-output, respectively.
-If either parameter is NULL, then an empty default will ultimately be returned
-if the file is not locally available.
-.PP
-.I DDcheck
-should be called
-with the handle,
-.IR h ,
-returned by
-.I DDstart
-and a newgroups,
-.IR group ,
-to check.
-It can be called as often as necessary.
-.PP
-.I DDend
-releases any state maintained in the handle and returns an allocated copy
-of the text that should be used for the Distribution header.
-.PP
-.I SetNonBlocking
-enables (if
-.I flag
-is non-zero) or disables (if
-.I flag
-is zero) non-blocking I/O on the indicated descriptor.
-It returns \-1 on failure or zero on success.
-.PP
-.I inn_lock_file
-tries to lock the file descriptor
-.IR fd .
-If
-.I block
-is true it will block until the lock can be made, otherwise
-it will return false if the file cannot be locked.
-.I type
-is one of: INN_LOCK_READ, INN_LOCK_WRITE, or INN_LOCK_UNLOCK.
-It returns false on failure or true on success.
-.PP
-.I GetFQDN
-returns the fully-qualified domain name of the local host.
-.I Domain
-is used if local host can not be resolved.
-The returned value points to static space that is reused on subsequent calls,
-or NULL on error.
-.PP
-.I GetModeratorAddress
-returns the mailing address of the moderator for specified
-.I group
-or NULL on error.
-.I Moderatormailer
-is used as its address, if there is no matched moderator.
-See
-.IR moderators (5)
-for details on how the address is determined.
-.I GetModeratorAddress
-does no checking to see if the specified group is actually moderated.
-The returned value points to static space that is reused on subsequent
-calls.
-The
-.I FromServer
-and
-.I ToServer
-parameters should be FILE's connected to the NNTP server for input and
-output, respectively. If either of these parameters is NULL, then an
-attempt to get the list from a local copy is made.
-.PP
-.I GetResourceUsage
-fills in the
-.I usertime
-and
-.I systime
-parameters with the total user and system time used by the current
-process and any children it may have spawned.
-If
-.I <HAVE_GETRUSAGE in include/config.h>
-is defined, it gets the values by doing a
-.IR getrusage (2)
-system call; otherwise it calls
-.IR times (2).
-It returns \-1 on failure, or zero on success.
-.PP
-.I GetTimeInfo
-fills in the
-.I now
-parameter with information about the current time and tzone.
-The ``time'' and ``usec'' fields will be filled in by a call to
-.IR gettimeofday (2)
-if
-.I <$ac_cv_func_gettimeofday in config.cache>
-is ``yes''. Otherwise, the ``time'' field will be filled in by a call to
-.IR time (2),
-and the ``usec'' field will be set to zero.
-The ``tzone'' field will be filled in with the current offset from GMT.
-If
-.I <HAVE_TM_GMTOFF in include/config.h>
-is defined, this is done by calling
-.IR localtime (3)
-and taking the value of the ``tm_gmtoff'' field, negating it, and dividing
-it by 60.
-Otherwise, this is done by calling
-.IR localtime (3)
-and comparing the value with that returned by a call to
-.IR gmtime (3).
-
-For efficiency, the ``tzone'' field is only recalculated if more than an
-hour pass passed since the last time
-.I GetTimeInfo
-has been called.
-This routine returns \-1 on failure, or zero on success.
-.PP
-.I NNTPlocalopen
-opens a connection to the private port of an InterNetNews server running on
-the local host, if
-.I <HAVE_UNIX_DOMAIN_SOCKETS in include/config.h>
-is defined.
-It returns \-1 on failure, or zero on success.
-.I FromServerp
-and
-.I ToServerp
-will be filled in with FILE's which can be used to communicate
-with the server.
-.I Errbuff
-can either be NULL or a pointer to a buffer at least 512 bytes long.
-If not NULL, and the server refuses the connection, then it will be
-filled in with the text of the server's reply.
-This routine is not for general use.
-If
-.I <HAVE_UNIX_DOMAIN_SOCKETS in include/config.h>
-is not defined, this
-is a stub routine, for compatibility with systems that have Unix-domain
-stream sockets.
-It always returns \-1.
-.PP
-.I NNTPremoteopen
-does the same except that it uses ``innconf->server''
-as the local server, and opens a connection to the
-.IR port .
-Any client program can use this routine.
-It returns \-1 on failure, or zero on success.
-.PP
-.I NNTPconnect
-is the same as
-.I NNTPremoteopen
-except that the desired host is given as the
-.I host
-parameter.
-.PP
-.I NNTPsendarticle
-writes
-.I text
-on
-.I ToServer
-using NNTP conventions for line termination.
-The text should consist of one or more lines ending with a newline.
-If
-.I Terminate
-is non-zero, then the routine will also write the NNTP data-termination
-marker on the stream.
-It returns \-1 on failure, or zero on success.
-.PP
-.I NNTPsendpassword
-sends authentication information to an NNTP server by finding the appropriate
-entry in the
-.I passwd.nntp
-file.
-.I Server
-contains the name of the host; ``innconf->server'' will be used if
-.I server
-is NULL.
-.I FromServer
-and
-.I ToServer
-should be FILE's that are connected to the server.
-No action is taken if the specified host is not listed in the password file.
-.PP
-.I Radix32
-converts the number in
-.I value
-into a radix-32 string into the buffer pointed to by
-.IR p .
-The number is split into five-bit pieces and each pieces is converted
-into a character using the alphabet
-.I "0..9a..v"
-to represent the numbers 0..32.
-Only the lowest 32 bits of
-.I value
-are used, so
-.I p
-need only point to a buffer of eight bytes (seven characters and the
-trailing \e0).
-.PP
-.I ReadInFile
-reads the file named
-.I name
-into allocated memory, appending a terminating \e0 byte.
-It returns a pointer to the space, or NULL on error.
-If
-.I Sbp
-is not NULL, it is taken as the address of a place to store the results
-of a
-.IR stat (2)
-call.
-.PP
-.I ReadInDescriptor
-performs the same function as
-.I ReadInFile
-except that
-.I fd
-refers to an already-open file.
-.PP
-.I HashMessageID
-returns hashed message-id using MD5.
-.SH EXAMPLES
-.RS
-.nf
-char *p;
-char *Article;
-char buff[256], errbuff[256];
-FILE *F;
-FILE *ToServer;
-FILE *FromServer;
-int port = 119;
-
-if ((p = HeaderFind(Article, "From", 4)) == NULL)
- Fatal("Can't find From line");
-(void)strcpy(buff, p);
-HeaderCleanFrom(buff);
-
-if ((F = CAopen(FromServer, ToServer)) == NULL)
- Fatal("Can't open active file");
-
-/* Don't pass the file on to our children. */
-CloseOnExec(fileno(F), 1);
-
-/* Make a local copy. */
-p = ReadInDescriptor(fileno(F), (struct stat *)NULL);
-
-/* Close the file. */
-CAclose();
-
-if (NNTPremoteopen(port, &FromServer, &ToServer, errbuff) < 0)
- Fatal("Can't connect to server");
-
-if ((p = GetModeratorAddress("comp.sources.unix")) == NULL)
- Fatal("Can't find moderator's address");
-.fi
-.RE
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: libinn.3 6124 2003-01-14 06:03:29Z rra $
-.SH "SEE ALSO"
-active(5),
-dbz(3z),
-parsedate(3),
-inn.conf(5),
-inndcomm(3),
-moderators(5),
-passwd.nntp(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "libinnhist 3"
-.TH libinnhist 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-his \- routines for managing INN history
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fB#include <inn/history.h>\fR
-.PP
-\&\fBstruct history;\fR
-.PP
-\&\fBstruct histstats {\fR
-\&\fB int hitpos;\fR
-\&\fB int hitneg;\fR
-\&\fB int misses;\fR
-\&\fB int dne;\fR
-\&\fB};\fR
-.PP
-\&\fB#define \s-1HIS_RDONLY\s0 ...\fR
-\&\fB#define \s-1HIS_RDWR\s0 ...\fR
-\&\fB#define \s-1HIS_CREAT\s0 ...\fR
-\&\fB#define \s-1HIS_ONDISK\s0 ...\fR
-\&\fB#define \s-1HIS_INCORE\s0 ...\fR
-\&\fB#define \s-1HIS_MMAP\s0 ...\fR
-.PP
-\&\fBenum {\fR
-\&\fB \s-1HISCTLG_PATH\s0,\fR
-\&\fB \s-1HISCTLS_PATH\s0,\fR
-\&\fB \s-1HISCTLS_SYNCCOUNT\s0,\fR
-\&\fB \s-1HISCTLS_NPAIRS\s0,\fR
-\&\fB \s-1HISCTLS_IGNOREOLD\s0,\fR
-\&\fB \s-1HISCTLS_STATINTERVAL\s0\fR
-\&\fB};\fR
-.PP
-\&\fBstruct history *HISopen(const char *\fR\fIpath\fR\fB, const char *\fR\fImethod\fR\fB, int \fR\fIflags\fR\fB);\fR
-.PP
-\&\fBbool HISclose(struct history *\fR\fIhistory\fR\fB);\fR
-.PP
-\&\fBbool HISsync(struct history *\fR\fIhistory\fR\fB);\fR
-.PP
-\&\fBvoid HISsetcache(struct history *\fR\fIhistory\fR\fB, size_t \fR\fIsize\fR\fB);\fR
-.PP
-\&\fBbool HISlookup(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIkey\fR\fB, time_t *\fR\fIarrived\fR\fB, time_t *\fR\fIposted\fR\fB, time_t *\fR\fIexpires\fR\fB, \s-1TOKEN\s0 *\fR\fItoken\fR\fB);\fR
-.PP
-\&\fBbool HIScheck(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIkey\fR\fB);\fR
-.PP
-\&\fBbool HISwrite(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIkey\fR\fB, time_t \fR\fIarrived\fR\fB, time_t \fR\fIposted\fR\fB, time_t \fR\fIexpires\fR\fB, const \s-1TOKEN\s0 *\fR\fItoken\fR\fB);\fR
-.PP
-\&\fBbool HISremember(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIkey\fR\fB, time_t \fR\fIarrived\fR\fB);\fR
-.PP
-\&\fBbool HISreplace(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIkey\fR\fB, time_t \fR\fIarrived\fR\fB, time_t \fR\fIposted\fR\fB, time_t \fR\fIexpires\fR\fB, const \s-1TOKEN\s0 *\fR\fItoken\fR\fB);\fR
-.PP
-\&\fBbool HISexpire(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIpath\fR\fB, const char *\fR\fIreason\fR\fB, bool \fR\fIwriting\fR\fB, void *\fR\fIcookie\fR\fB, time_t \fR\fIthreshold\fR\fB, bool (*\fR\fIexists\fR\fB)(void *cookie, time_t arrived, time_t posted, time_t expires, const \s-1TOKEN\s0 *token));\fR
-.PP
-\&\fBbool HISwalk(struct history *\fR\fIhistory\fR\fB, const char *\fR\fIreason\fR\fB, void *\fR\fIcookie\fR\fB, bool (*\fR\fIcallback\fR\fB)(void *cookie, time_t arrived, time_t posted, time_t expires, const \s-1TOKEN\s0 *token));\fR
-.PP
-\&\fBstruct histstats HISstats(struct history *\fR\fIhistory\fR\fB);\fR
-.PP
-\&\fBconst char *HISerror(struct history *\fR\fIhistory\fR\fB);\fR
-.PP
-\&\fBbool HISctl(struct history *\fR\fIhistory\fR\fB, int \fR\fIrequest\fR\fB, void *\fR\fIval\fR\fB);\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-These functions provide provide access to the \s-1INN\s0 history
-database. They maintain key/value pairs in an opaque database whilst
-providing for expiry of outdated information.
-.PP
-The history structure is an opaque handle returned from HISopen.
-.PP
-The \fBHISopen\fR function opens the history file designated by \fIpath\fR
-using the mode \fIflags\fR using the specified \fImethod\fR. \fIflags\fR may be
-\&\fB\s-1HIS_RDONLY\s0\fR to indicate that read-only access to the history
-database is desired, or \fB\s-1HIS_RDWR\s0\fR for read/write access. History
-methods are defined at build time; the history method currently
-available is \*(L"hisv6\*(R". On success a newly initialised history handle is
-returned, or \fB\s-1NULL\s0\fR on failure.
-.PP
-\&\fB\s-1HIS_ONDISK\s0\fR, \fB\s-1HIS_INCORE\s0\fR and \fB\s-1HIS_MMAP\s0\fR may be logically ORed
-into \fIflags\fR to provide a hint to the underlying history manager as
-to how it should handle its data files; \fB\s-1HIS_ONDISK\s0\fR indicates that
-the caller would like as much of the data to be kept on disk (and out
-of memory), \fB\s-1HIS_INCORE\s0\fR indicates that the data files should be kept
-in main memory where possible and \fB\s-1HIS_MMAP\s0\fR that the files should be
-\&\fImmap()\fRed into the processes address space. \fB\s-1HIS_INCORE\s0\fR is typically
-used where a mass rebuild of the history database is being performed;
-the underlying history manager may assume that the caller will call
-\&\fBHISsync\fR() to sync the data files to disk.
-.PP
-The \fB\s-1HIS_CREAT\s0\fR flag indicates that the history database should be
-initialised as new; if any options which affect creation of the
-database need to be set an anonymous history handle should be created
-by calling \fBHISopen\fR with \fIpath\fR set to \fB\s-1NULL\s0\fR, any options set
-using \fBHISctl\fR, then the database opened by calling \fBHISctl\fR with
-\&\fB\s-1HISCTLS_PATH\s0\fR.
-.PP
-The \fBHISclose\fR function closes the handle \fIhistory\fR and deallocates
-any resources associated with it. It returns \fBfalse\fR on failure or
-\&\fBtrue\fR on success.
-.PP
-The \fBHISsync\fR function synchronises any outstanding transactions
-associated with \fIhistory\fR to disk.
-.PP
-\&\fBHISsetcache\fR associates a cache used for speeding up HIScheck with
-\&\fIhistory\fR. The cache will occupy approximately \fIsize\fR bytes.
-.PP
-\&\fBHISlookup\fR retrieves a token from \fIhistory\fR based on the passed
-\&\fIkey\fR (normally the Message\-ID). If no entry with an associated token
-can be found, \fBHISlookup\fR will return \fBfalse\fR. If a token is found
-\&\fIarrived\fR, \fIexpires\fR, and \fIposted\fR are filled in with the message
-arrival, expiry, and posting times respectively (or zero, if the time
-component is not available), in addition to \fItoken\fR being set to the
-retrieved token and a function return value of \fBtrue\fR. Any of
-arrived, expires, posted, or token may be \fB\s-1NULL\s0\fR in which case that
-component is not returned to the caller, without affecting the return
-value.
-.PP
-\&\fBHIScheck\fR checks the database \fIhistory\fR for \fIkey\fR (normally the
-Message\-ID); if \fIkey\fR has previously been set via \fBHISwrite\fR,
-\&\fBHIScheck\fR returns \fBtrue\fR, else \fBfalse\fR.
-.PP
-\&\fBHISwrite\fR writes a new entry to the database \fIhistory\fR associated
-with \fIkey\fR. \fIarrived\fR, \fIposted\fR, and \fIexpired\fR specify the arrival,
-posting, and expiry time respectively; \fIposted\fR and \fIexpired\fR may be
-specifed as <= 0 in which case that component shall be treated as
-absent in the database. \fItoken\fR is associated with the specified
-\&\fIkey\fR. \fBHISwrite\fR returns \fBtrue\fR on success, or \fBfalse\fR on
-failure. The behaviour when \fIkey\fR is not unique with respect to the
-existing entries in \fIhistory\fR is unspecified.
-.PP
-\&\fBHISremember\fR writes a new entry to the database \fIhistory\fR
-associated with \fIkey\fR, merely remembering that this \fIkey\fR has been
-seen, together with its arrival time \fIarrived\fR. \fBHISremember\fR
-returns \fBtrue\fR on success, or \fBfalse\fR on failure. The behaviour when
-\&\fIkey\fR is not unique with respect to the existing entries in
-\&\fIhistory\fR is unspecified.
-.PP
-\&\fBHISreplace\fR replaces an existing entry in the database \fIhistory\fR,
-associated with \fIkey\fR. \fIarrived\fR, \fIposted\fR, \fIexpired\fR specify the
-arrival, posting and expiry time respectively; \fIposted\fR and
-\&\fIexpired\fR may be specifed as <= 0 in which case that component shall
-be treated as absent in the database. \fItoken\fR is associated with the
-specified \fIkey\fR; if \fB\s-1NULL\s0\fR then the history database merely
-remembers that this \fIkey\fR has been seen, together with its arrival
-time. \fBHISreplace\fR returns \fBtrue\fR on success, or \fBfalse\fR on
-failure.
-.PP
-\&\fBHISexpire\fR expires the history database associated with \fIhistory\fR,
-creating a new, replacement, database in the same location if \fIpath\fR
-is \fB\s-1NULL\s0\fR, or in \fIpath\fR if not \fB\s-1NULL\s0\fR; if \fIpath\fR is not \fB\s-1NULL\s0\fR
-then the replacement of the old history database with the new one is
-assumed to be performed out of band by the caller. The \fIwriting\fR flag
-is normally passed as \fBtrue\fR, if you wish to inhibit writing of the
-new database (and so merely see the callbacks), \fIwriting\fR may be set
-\&\fBfalse\fR.
-.PP
-If the underlying history mechanism needs to pause the server, the
-\&\fIreason\fR string is used as the argument to the `ctlinnd pause'
-command, and as such the server should be reserved by the caller prior
-to calling \fBHISexpire\fR; if the caller wishes to inhibit pausing of
-the server, passing \fB\s-1NULL\s0\fR will achieve this. If \fIreason\fR is not
-\&\fB\s-1NULL\s0\fR, then on successful return from \fBHISexpire\fR the server will
-be left paused and the caller should unpause it.
-.PP
-The history database is scanned and entries with an associated storage
-token are passed to the discrimination function \fIexists\fR.
-.PP
-If \fIexists\fR() returns \fBfalse\fR it indicates that stored entity
-associated with token is no longer available (or no longer required),
-and therefore the associated history entry may be expired once it
-meets the \fIthreshold\fR constraint. If \fIexists\fR() returns \fBtrue\fR the
-entry is kept as-is in the newly expired history database.
-.PP
-The \fIexists\fR function is passed the arrival, posting and expiry
-times, in addition to the token associated with the entry. Note that
-posting and/or expiry may be zero, but that the token will never be
-\&\fB\s-1NULL\s0\fR (such entries are handled solely via the threshold
-mechanism). The storage token passed to the discrimination function
-may updated if required (for example, as might be needed by a
-hierachical storage management implementation).
-.PP
-Entries in the database with an arrival time less than \fIthreshold\fR
-with no token associated with them are deleted from the database.
-.PP
-The parameter \fIcookie\fR is passed to the discrimination function, and
-may be used for any purpose required by the caller.
-.PP
-If the discrimination function attempts to access the underlying
-database (for read or write) during the callback, the behaviour is
-unspecified.
-.PP
-\&\fBHISwalk\fR provides an iteration function for the specified \fIhistory\fR
-database. For every entry in the history database, \fIcallback\fR is
-invoked, passing the \fIcookie\fR, arrival, posting, and expiry times, in
-addition to the token associated with the entry. If the \fIcallback\fR()
-returns \fBfalse\fR the iteration is aborted and \fBHISwalk\fR returns
-\&\fBfalse\fR to the caller.
-.PP
-To process the entire database in the presence of a running server,
-\&\fIreason\fR may be passed; if this argument is not \fB\s-1NULL\s0\fR, it is used
-as an an argument to the `ctlinnd (reserve|pause|go)' commands. If
-\&\fIreason\fR is \fB\s-1NULL\s0\fR and the server is running, the behaviour of
-\&\fBHISwalk\fR is undefined.
-.PP
-If the callback function attempts to access the underlying database
-during the callback, the behaviour is unspecified.
-.PP
-\&\fBHISstats\fR returns statistics on the history cache mechanism; given a
-handle \fIhistory\fR, the return value is a \fIstruct histstats\fR
-detailing:
-.ie n .IP """hitpos""" 4
-.el .IP "\f(CWhitpos\fR" 4
-.IX Item "hitpos"
-The number of times an item was found directly in the cache and known
-to exist in the underlying history manager.
-.ie n .IP """hitneg""" 4
-.el .IP "\f(CWhitneg\fR" 4
-.IX Item "hitneg"
-The number of times an item was found directly in the cache and known
-not to exist in the underlying history manager.
-.ie n .IP """misses""" 4
-.el .IP "\f(CWmisses\fR" 4
-.IX Item "misses"
-The number of times an item was not found directly in the cache, but
-on retrieval from the underlying history manager was found to exist.
-.ie n .IP """dne""" 4
-.el .IP "\f(CWdne\fR" 4
-.IX Item "dne"
-The number of times an item was not found directly in the cache, but
-on retrieval from the underlying history manager was found not to exist.
-.PP
-Note that the history cache is only checked by \fBHIScheck\fR and only
-affected by \fBHIScheck\fR, \fBHISwrite\fR, \fBHISremember\fR and
-\&\fBHISreplace\fR. Following a call to \fBHISstats\fR the history statistics
-associated with \fIhistory\fR are cleared.
-.PP
-\&\fBHISerror\fR returns a string describing the most recent error
-associated with \fIhistory\fR; the format and content of these strings is
-history manager dependent. Note that on setting an error, the history
-\&\s-1API\s0 will call the \fBwarn\fR function from \fIlibinn\fR\|(3).
-.PP
-\&\fBHISctl\fR provides a control interface to the underlying history
-manager. The \fIrequest\fR argument determines the type of the request
-and the meaning of the \fIval\fR argument. The values for \fIrequest\fR are:
-.ie n .IP """HISCTLG_PATH"" (const char **)" 4
-.el .IP "\f(CWHISCTLG_PATH\fR (const char **)" 4
-.IX Item "HISCTLG_PATH (const char **)"
-Get the base file path which the history handle represents. \fIval\fR
-should be a pointer to a location of type \fBconst char *\fR. The
-result must not later be passed to \fIfree\fR\|(3).
-.ie n .IP """HISCTLS_PATH"" (const char *)" 4
-.el .IP "\f(CWHISCTLS_PATH\fR (const char *)" 4
-.IX Item "HISCTLS_PATH (const char *)"
-Set the base file path which this history handle should use; typically
-this is used after an anonymous handle has been created using
-\&\fBHISopen(\s-1NULL\s0, ...)\fR. \fIval\fR should be a value of type \fBconst char
-*\fR and will be copied before being stored internally.
-.ie n .IP """HISCTLS_SYNCCOUNT"" (size_t *)" 4
-.el .IP "\f(CWHISCTLS_SYNCCOUNT\fR (size_t *)" 4
-.IX Item "HISCTLS_SYNCCOUNT (size_t *)"
-Set an upper bound on how many history operations may be pending in
-core before being synced to permanent storage; \fB0\fR indicates
-unlimited. \fIval\fR should be a pointer to a value of type \fBsize_t\fR and
-will not be modified by the call.
-.ie n .IP """HISCTLS_NPAIRS"" (size_t *)" 4
-.el .IP "\f(CWHISCTLS_NPAIRS\fR (size_t *)" 4
-.IX Item "HISCTLS_NPAIRS (size_t *)"
-Set a hint to the to the underlying history manager as to how many
-entries there are expected to be in the history database; \fB0\fR
-indicates that an automatic or default sizing should be made. \fIval\fR
-should be a pointer to a value of type \fBsize_t\fR and will not be
-modified by the call.
-.ie n .IP """HISCTLS_IGNOREOLD"" (bool *)" 4
-.el .IP "\f(CWHISCTLS_IGNOREOLD\fR (bool *)" 4
-.IX Item "HISCTLS_IGNOREOLD (bool *)"
-Instruct the underlying history manager to ignore existing database
-when creating new ones; typically this option may be set to \fBtrue\fR if
-the administrator believes that the existing history database is
-corrupt and that ignoring it may help. \fIval\fR should be a pointer to a
-value of type \fBbool\fR and will not be modified by the call.
-.ie n .IP """HISCTLS_STATINTERVAL"" (time_t *)" 4
-.el .IP "\f(CWHISCTLS_STATINTERVAL\fR (time_t *)" 4
-.IX Item "HISCTLS_STATINTERVAL (time_t *)"
-For the history v6 and tagged hash managers, set the interval, in
-seconds, between \fIstat\fR\|(2)s of the history files checking for replaced
-files (as happens during expire); this option is typically used by
-\&\fInnrpd\fR\|(8) like applications. \fIval\fR should be a pointer to a value of
-type \fBtime_t\fR and will not be modified by the call.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Alex Kiernan <alexk@demon.net> for InterNetNews 2.4.0.
-.Sp
-$Id: libinnhist.3 7880 2008-06-16 20:37:13Z iulius $
+++ /dev/null
-.\" $Revision: 6124 $
-.TH LIBSTORAGE 3
-.SH NAME
-libstorage \- InterNetNews Storage API library routines
-.SH SYNOPSIS
-.nf
-.ta \w' unsigned long 'u
-
-#include "storage.h"
-
-.B "bool IsToken(const char *text);"
-
-.B "char *TokenToText(const TOKEN token);"
-
-.B "TOKEN TextToToken(const char *text);"
-
-.B "bool SMsetup(SMSETUP type, void *value);"
-
-.B "bool SMinit(void);"
-
-.B "TOKEN SMstore(const ARTHANDLE article);"
-
-.B "ARTHANDLE *SMretrieve(const TOKEN token, const RETRTYPE amount);"
-
-.B "ARTHANDLE *SMnext(const ARTHANDLE *article, const RETRTYPE amount);"
-
-.B "void SMfreearticle(ARTHANDLE *article);"
-
-.B "bool SMcancel(TOKEN token);"
-
-.B "bool SMprobe(PROBETYPE type, TOKEN *token, void *value);"
-
-.B "void SMprintfiles(FILE *file, TOKEN token, char **xref, int ngroups)"
-
-.B "bool SMflushcacheddata(FLUSHTYPE type);"
-
-.B "void SMshutdown(void);"
-
-.B "int SMerrno;"
-.B "char *SMerrorstr;"
-
-#include "ov.h"
-
-.B "bool OVopen(int mode);"
-
-.B "bool OVctl(OVCTLTYPE type, void *val);"
-
-.B "bool OVgroupstats(char *group, int *lo, int *hi, int *count, int *flag);"
-
-.B "bool OVgroupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag);"
-
-.B "bool OVgroupdel(char *group);"
-
-.B "OVADDRESULT OVadd(TOKEN token, char *data, int len, time_t arrived);"
-
-.B "bool OVcancel(TOKEN token);"
-
-.B "void *OVopensearch(char *group, int low, int high);"
-
-.B "bool OVsearch(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived);"
-
-.B "void OVclosesearch(void *handle);"
-
-.B "bool OVgetartinfo(char *group, ARTNUM artnum, char **data, int *len, TOKEN *token);"
-
-.B "bool OVexpiregroup(char *group, int *lo);"
-
-.B "typedef struct _OVGE {"
-.B " bool delayrm;"
-.B " bool usepost;"
-.B " bool quiet;"
-.B " bool keep;"
-.B " bool earliest;"
-.B " bool ignoreselfexpire;"
-.B " char *filename;"
-.B " time_t now;"
-.B " float timewarp;"
-.B "} OVGE;"
-
-.B "void OVclose(void);"
-
-.fi
-.SH DESCRIPTION
-.I Libstorage
-is a library of common utility (the storage manager) routines for accessing
-Usenet articles and related data independent of particular storage method;
-this is known as the storage API.
-The storage manager's function is to isolate the applications from the
-individual methods and make the policy decisions as to which storage method
-should be called to store an article.
-.PP
-One of the core concepts in the storage API is that articles are not
-manipulated using the message-id or article number, but rather a token that
-uniquely identifies the article to the method that stored it. This may seem
-to be redundant since the message-id already is a unique identifier for the
-article, however, since the storage method generates the token, it can
-encode all the information it needs to locate the article in the token.
-.PP
-\&``OV'' is a common utility routines for accessing newsgroups and overview
-data independent of particular overview method.
-The ``OV'' function is to isolate the applications from the
-individual methods.
-.PP
-All articles passed through the storage API are assumed to be in wire
-format. Wire format means ``\\CR\\LF'' at the end of lines, ``.'' at the
-beginning of lines, and ``.\\CR\\LF'' at the end of article on NNTP stream
-are not stripped. This has a performance win when transferring articles.
-For the ``tradspool'' method, wire format can be disabled. This is just
-for compatibility which is needed by some old tools written for
-traditional spool.
-.PP
-.I IsToken
-checks to see if the text is formatted as a text token string.
-It returns true if formatted correctly or returns false if not.
-.PP
-.I TokenToText
-converts token into text string for output.
-.PP
-.I TextToToken
-converts text into token.
-.PP
-.I SMsetup
-configures some parameters for use by storage manager.
-.I Type
-is one of following.
-.sp 1
-.in +0.5i
-.nf
-SM_RDWR allow read/write open for storage
- files (default is false)
-SM_PREOPEN open all storage files at startup
- time and keep them (default is false)
-.fi
-.in -0.5i
-.sp 1
-The
-.I value
-is the pointer which tells each type's value.
-It returns true if setup is successful, or false if not.
-.PP
-.I SMinit
-calls the setup function for all of the configured methods based on
-.IR SMsetup .
-This function should be called prior to all other storage API functions which
-begin with ``SM'' except
-.IR SMsetup .
-It returns true if initialization is successful or returns false if not.
-.I SMinit
-returns true, unless all storage methods fail initialization.
-.PP
-.I SMstore
-stores an article specified with
-.IR article .
-If
-.I arrived
-is specified,
-.I SMstore
-uses its value as article's arrival time; otherwise
-.I SMstore
-uses the current time for it.
-.I SMstore
-returns token type as
-.IR type ,
-or returns
-.I TOKEN_EMPTY
-if article is not stored because some error occurs or simply does not
-match any
-.IR uwildmat (3)
-in
-.IR storage.conf .
-.I SMstore
-fails if
-.I SM_RDWR
-has not been set to true with
-.IR SMsetup .
-.PP
-.I SMretrieve
-retrieves an article specified with
-.IR token .
-.I Amount
-is the one of following which specifies retrieving type.
-.sp 1
-.in +0.5i
-.nf
-RETR_ALL retrieve whole article
-RETR_HEAD retrieve headers of article
-RETR_BODY retrieve body of article
-RETR_STAT just check to see if article exists
-.fi
-.in -0.5i
-.sp 1
-.PP
-The data area indicated by
-.I ARTHANDLE
-should not be modified.
-.PP
-.I SMnext
-is similar in function to
-.I SMretrieve
-except that it is intended for traversing the method's article store
-sequentially.
-To start a query,
-.I SMnext
-should be called with a NULL pointer
-.IR ARTHANDLE .
-Then
-.I SMnext
-returns
-.I ARTHANDLE
-which should be used for the next query.
-If a NULL pointer
-.I ARTHANDLE
-is returned, no articles are left to be queried.
-If
-.I data
-of
-.I ARTHANDLE
-is NULL pointer or
-.I len
-of
-.I ARTHANDLE
-is 0, it indicates the article may be corrupted and should be cancelled by
-.IR SMcancel .
-The data area indicated by
-.I ARTHANDLE
-should not be modified.
-.PP
-.I SMfreearticle
-frees all allocated memory used by
-.I SMretrieve
-and
-.IR SMnext .
-If
-.I SMnext
-will be called with previously returned
-.IR ARTHANDLE ,
-.I SMfreearticle
-should not be called as
-.I SMnext
-frees allocated memory internally.
-.PP
-.I SMcancel
-removes the article specified with
-.IR token .
-It returns true if cancellation is successful or returns false if not.
-.I SMcancel
-fails if
-.I SM_RDWR
-has not been set to true with
-.IR SMsetup .
-.PP
-.I SMprobe
-checks the token on
-.IR PROBETYPE .
-.I Type
-is one of following.
-.sp 1
-.in +0.5i
-.nf
-SELFEXPIRE checks to see if the method of the token
- has self expire functionality
-SMARTNGNUM gets newsgroup name and article number
- of the token.
-.fi
-.in -0.5i
-.sp 1
-.PP
-.I SMprintfiles
-shows file name or token usable by
-.IR fastrm (8).
-.PP
-.I SMflushcacheddata
-flushes cached data on each storage method.
-.I Type
-is one of following.
-.sp 1
-.in +0.5i
-.nf
-SM_HEAD flushes cached header
-SM_CANCELEDART flushes articles which should be canceled
-SM_ALL flushes all cached data
-.fi
-.in -0.5i
-.sp 1
-.PP
-.I SMshutdown
-calls the shutdown for each configured storage method and
-then frees any resources it has allocated for itself.
-.PP
-.I SMerrno
-and
-.I SMerrorstr
-indicate the reason of the last error concerning storage manager.
-.PP
-.I OVopen
-calls the setup function for configured method which is specified as
-\&``ovmethod'' in
-.IR inn.conf .
-.I Mode
-is constructed from following.
-.sp 1
-.in +0.5i
-.nf
-OV_READ allow read open for overview
- method
-OV_WRITE allow write open for overview
- method
-.fi
-.in -0.5i
-.sp 1
-This function should be called prior to all other OV functions which
-begin with ``OV''.
-.PP
-.I OVctl
-probes or sets some parameters for overview method.
-.I Type
-is one of following.
-.sp 1
-.in +0.5i
-.nf
-OVGROUPBASEDEXPIRE setup how group-based expiry is
- done
-OVCUTOFFLOW do not add overview data, if the
- data is under lowest article
-OVSORT probe which key is suitable for
- overview method
-OVSPACE probe overview space usage
-OVSTATALL stat all articles when
- OVexpiregroup is called
-.fi
-.in -0.5i
-.sp 1
-.PP
-.I OVgroupstats
-retrieves specified newsgroup information from overview method.
-.PP
-.I OVgroupadd
-informs overview method that specified newsgroup is being added.
-.PP
-.I OVgroupdel
-informs overview method that specified newsgroup is being removed.
-.PP
-.I OVadd
-stores an overview data.
-.PP
-.I OVcancel
-requests the overview method delete overview data specified with token.
-.PP
-.I OVopensearch
-requests the overview method prepare overview data retrieval.
-The request range is determined by
-.I low
-and
-.IR high .
-.PP
-.I OVsearch
-retrieves information; article number, overview data, or arrival time.
-.I OVsearch
-should be called with NULL handle when it is the first time;
-subsequent
-.I OVsearch
-calls should use the handle returned by the previous call to
-.IR OVsearch .
-.I OVsearch
-returns true, unless it reaches high which is specified by
-.IR OVopensearch .
-Retrieved overview data are sorted by article number, and
-.I len
-is ``0'' if there is no overview data for article. Note that the
-retrieved data is not neccessarily null-terminated; you should only rely
-on
-.I len
-octets of overview data being present.
-.PP
-.I OVclosesearch
-frees all resources which have been allocated by
-.IR OVopensearch .
-.PP
-.I OVgetartinfo
-retrieves overview data and token specified with
-.IR artnum .
-.PP
-.I OVexpiregroup
-expires overview data for the newsgroup.
-.I OVexpiregroup
-checks the existense of the article and purges overview data if the
-article no longer exists.
-If ``groupbaseexpiry'' in
-.I inn.conf
-is true,
-.I OVexpiregroup
-also expires articles.
-.PP
-.I OVclose
-frees all resources which are used by the overview method.
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: libstorage.3 6124 2003-01-14 06:03:29Z rra $
-.SH "SEE ALSO"
-expire(8),
-inn.conf(5),
-storage.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "list 3"
-.TH list 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-list \- list routines
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fB#include <inn/list.h>\fR
-.PP
-struct node {
- struct node *succ;
- struct node *pred;
-};
-.PP
-struct list {
- struct node *head;
- struct node *tail;
- struct node *tailpred;
-};
-.PP
-\&\fBvoid list_new(struct list *\fR\fIlist\fR\fB);\fR
-.PP
-\&\fBstruct node *list_addhead(struct list *\fR\fIlist\fR\fB, struct node *\fR\fInode\fR\fB);\fR
-.PP
-\&\fBstruct node *list_addtail(struct list *\fR\fIlist\fR\fB, struct node *\fR\fInode\fR\fB);\fR
-.PP
-\&\fBstruct node *list_head(struct list *\fR\fIlist\fR\fB);\fR
-.PP
-\&\fBstruct node *list_tail(struct list *\fR\fIlist\fR\fB);\fR
-.PP
-\&\fBstruct node *list_succ(struct node *\fR\fInode\fR\fB);\fR
-.PP
-\&\fBstruct node *list_pred(struct node *\fR\fInode\fR\fB);\fR
-.PP
-\&\fBstruct node *list_remhead(struct list *\fR\fIlist\fR\fB);\fR
-.PP
-\&\fBstruct node *list_remtail(struct list *\fR\fIlist\fR\fB);\fR
-.PP
-\&\fBstruct node *list_remove(struct node *\fR\fInode\fR\fB);\fR
-.PP
-\&\fBstruct node *list_insert(struct list *\fR\fIlist\fR\fB, struct node *\fR\fInode\fR\fB, struct node *\fR\fIpred\fR\fB);\fR
-.PP
-\&\fBbool list_isempty(struct list *\fR\fIlist\fR\fB);\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBlist_new\fR initialises the list header \fIlist\fR so as to create an
-empty list.
-.PP
-\&\fBlist_addhead\fR adds \fInode\fR to the head of \fIlist\fR, returning the node
-just added.
-.PP
-\&\fBlist_addtail\fR adds \fInode\fR to the tail of \fIlist\fR, returning the node
-just added.
-.PP
-\&\fBlist_head\fR returns a pointer to the the node at the head of \fIlist\fR
-or \fB\s-1NULL\s0\fR if the list is empty.
-.PP
-\&\fBlist_tail\fR returns a pointer to the the node at the tail of \fIlist\fR
-or \fB\s-1NULL\s0\fR if the list is empty.
-.PP
-\&\fBlist_succ\fR returns the next (successor) node on the list after
-\&\fInode\fR or \fB\s-1NULL\s0\fR if \fInode\fR was the final node.
-.PP
-\&\fBlist_pred\fR returns the previous (predecessor) node on the list before
-\&\fInode\fR or \fB\s-1NULL\s0\fR if \fInode\fR was the first node.
-.PP
-\&\fBlist_remhead\fR removes the first node from \fIlist\fR and returns it to
-the caller. If the list is empty \fB\s-1NULL\s0\fR is returned.
-.PP
-\&\fBlist_remtail\fR removes the last node from \fIlist\fR and returns it to
-the caller. If the list is empty \fB\s-1NULL\s0\fR is returned.
-.PP
-\&\fBlist_remove\fR removes \fInode\fR from the list it is on and returns it
-to the caller.
-.PP
-\&\fBlist_insert\fR inserts \fInode\fR onto \fIlist\fR after the node \fIpred\fR. If
-\&\fIpred\fR is \fB\s-1NULL\s0\fR then \fInode\fR is added to the head of \fIlist\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Alex Kiernan <alex.kiernan@thus.net> for InterNetNews 2.4.0.
-.PP
-$Id: list.3 7880 2008-06-16 20:37:13Z iulius $
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "MAILPOST 8"
-.TH MAILPOST 8 "2008-04-26" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-mailpost \- Feed an e\-mail message into a newsgroup
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBmailpost\fR [\fB\-hn\fR] [\fB\-a\fR \fIaddr\fR] [\fB\-b\fR \fIdatabase\fR] [\fB\-c\fR \fIwait-time\fR]
-[\fB\-d\fR \fIdistribution\fR] [\fB\-f\fR \fIaddr\fR] [\fB\-m\fR \fImailing-list\fR]
-[\fB\-o\fR \fIoutput-command\fR] [\fB\-p\fR \fIport\fR] [\fB\-r\fR \fIaddr\fR]
-[\fB\-x\fR \fIheader\fR[\fB:\fR\fIheader\fR...]] \fInewsgroups\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The \fBmailpost\fR program reads a properly formatted e\-mail message from stdin
-and feeds it to \fBinews\fR for posting to a news server. \fInewsgroups\fR is a
-whitespace-separated list of group names to which to post the article
-(at least one newsgroup must be specified).
-.PP
-Before feeding the article to \fBinews\fR, it checks that the article has not
-been seen before, and it changes some headers (cleans up some address
-headers, removes X\-Trace: and X\-Complaints\-To:, and puts \f(CW\*(C`X\-\*(C'\fR in front
-of unknown headers).
-.PP
-If the article has been seen before (\fBmailpost\fR records the Message-ID of
-each article it handles), then the article will be silently dropped. Other
-errors will cause the article to be mailed to the newsmaster (selected
-at configure time and defaulting to \f(CW\*(C`usenet\*(C'\fR).
-.PP
-Normally, \fBmailpost\fR is run by \fIsendmail\fR\|(8) via an alias entry:
-.PP
-.Vb 2
-\& local\-mail\-wreck\-bikes: "|<pathbin in inn.conf>/mailpost
-\& \-b /var/tmp \-d local local.mail.rec.bicycles.racing"
-.Ve
-.PP
-Instead of \fI/var/tmp\fR, the mail spool directory can be specified,
-or any other directory where the \fBmailpost\fR process has write access.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-a\fR \fIaddr\fR" 4
-.IX Item "-a addr"
-If the \fB\-a\fR flag is used, the value given is added to the article
-as an Approved: header.
-.IP "\fB\-b\fR \fIdatabase\fR" 4
-.IX Item "-b database"
-If the \fB\-b\fR flag is used, then it defines the location of the database
-used to store the Message-IDs of articles sent on. This is to prevent articles
-looping around if a news-to-mail gateway sends them back here. This option may
-be required if the \fBmailpost\fR process does not have write access to the news
-temporary directory. The default value is \fIpathtmp\fR as set in \fIinn.conf\fR.
-.IP "\fB\-c\fR \fIwait-time\fR" 4
-.IX Item "-c wait-time"
-The \fB\-c\fR flag indicates a length of time to sleep before posting. If
-duplicate messages are received in this interval (by any instance of
-\&\fBmailpost\fR using the same database), the article is only posted once, but
-with Newsgroups: header modified to crosspost the article to all indicated
-groups. The units for \fIwait-time\fR are seconds; a reasonable value may be
-anywhere from tens to hundreds of seconds, or even higher, depending on how
-long mail can be delayed on its way to your system.
-.IP "\fB\-d\fR \fIdistribution\fR" 4
-.IX Item "-d distribution"
-If the \fB\-d\fR flag is used, the value given is added to the article as a
-Distribution: header.
-.IP "\fB\-f\fR \fIaddr\fR" 4
-.IX Item "-f addr"
-The \fB\-f\fR flag is a synonym for the \fB\-r\fR flag.
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Print usage information and exit.
-.IP "\fB\-m\fR \fImailing-list\fR" 4
-.IX Item "-m mailing-list"
-If the \fB\-m\fR flag is used, the value given is added to the article in a
-Mailing\-List: header, if such a header doesn't already exist.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-If the \fB\-n\fR flag is used, neither an article is posted nor a mail is sent
-in case an error occurs. Everything is written to the standard output.
-.IP "\fB\-o\fR \fIoutput-command\fR" 4
-.IX Item "-o output-command"
-Specifies the program to which the resulting article processed by \fBmailpost\fR
-should be sent. For debugging purpose, \f(CW\*(C`\-o cat\*(C'\fR can be used. The default
-value is \f(CW\*(C`inews \-S \-h\*(C'\fR.
-.IP "\fB\-p\fR \fIport\fR" 4
-.IX Item "-p port"
-Specifies the port on which \fBnnrpd\fR is listening, used for article posting.
-If given, \fB\-p\fR is passed along to \fBinews\fR.
-.IP "\fB\-r\fR \fIaddr\fR" 4
-.IX Item "-r addr"
-A heuristic is used to determine a reasonable value for the Path: header.
-The \fB\-r\fR flag indicates what to use if no other value can be determined.
-.IP "\fB\-x\fR \fIheader\fR[\fB:\fR\fIheader\fR...]" 4
-.IX Item "-x header[:header...]"
-A colon-separated list of additional headers which should be treated as
-known headers; these headers will be passed through to \fBinews\fR without
-having \f(CW\*(C`X\-\*(C'\fR prepended.
-.Sp
-Known headers are:
-.Sp
-.Vb 12
-\& Approved
-\& Content\-*
-\& Date
-\& Distribution
-\& From
-\& Mailing\-List
-\& Message\-ID
-\& MIME\-*
-\& References
-\& Return\-Path
-\& Sender
-\& Subject
-.Ve
-.SH "FILES"
-.IX Header "FILES"
-.IP "\fIpathbin\fR/mailpost" 4
-.IX Item "pathbin/mailpost"
-The Perl script itself used to feed an e\-mail message to a newsgroup.
-.IP "\fIpathtmp\fR/mailpost\-msgid.dir and \fIpathtmp\fR/mailpost\-msgid.pag" 4
-.IX Item "pathtmp/mailpost-msgid.dir and pathtmp/mailpost-msgid.pag"
-The default database files which record previously seen Message\-IDs.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Paul Vixie long ago and then hacked up by James Brister for \s-1INN\s0
-integration.
-.PP
-$Id: mailpost.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive\fR\|(5), \fIinews\fR\|(1), \fIinn.conf\fR\|(5), \fInnrpd\fR\|(8), \fIuwildmat\fR\|(3).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH MAKEACTIVE 8
-.SH NAME
-makeactive \- tool to recover Usenet active file.
-.SH SYNOPSIS
-.IR makeactive (8)
-is obsolete.
-.SH "SEE ALSO"
-active(5)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH MAKEDBZ 8
-.SH NAME
-makedbz \- rebuild dbz files
-.SH SYNOPSIS
-.B makedbz
-[
-.BI \-f " filename"
-]
-[
-.B \-i
-]
-[
-.B \-o
-]
-[
-.BI \-s " size"
-]
-.SH DESCRIPTION
-.PP
-.I Makedbz
-rebuilds
-.IR dbz (3)
-database.
-The default name of the text file is
-.IR <pathdb\ in\ inn.conf>/history ;
-to specify a different name, use the ``\fB\-f\fP'' flag.
-.SH OPTIONS
-.TP
-.B \-f file
-If the ``\fB\-f\fP'' flag is used, then the database files are named
-.IR file.dir ,
-.IR file.index ,
-and
-.IR file.hash .
-If the ``\fB\-f\fP'' flag is not used, then a temporary link to the name
-.I history.n
-is made and the database files are written as
-.I history.n.index
-,
-.I history.n.hash
-and
-.IR history.n.dir .
-.TP
-.B \-i
-To ignore the old database use the ``\fB\-i\fP'' flag.
-Using the ``\fB\-o\fP'' or ``\fB\-s\fP'' flags implies the ``\fB\-i\fP'' flag.
-.TP
-.B \-o
-If the ``\fB\-o\fP'' flag is used, then the link is not made and any existing
-history files are overwritten.
-If the old database exists,
-.I makedbz
-will use it to determine the size of the new database.
-.TP
-.B \-s size
-The program will also ignore any old database if the ``\fB\-s\fP'' flag is used
-to specify the approximate number of entries in the new database.
-Accurately specifying the size is an optimization that will create a more
-efficient database. Size is measured in key-value pairs (i.e., lines).
-(The size should be the estimated eventual size of the file, typically
-the size of the old file.)
-For more information, see the discussion of
-.I dbzfresh
-and
-.I dbzsize
-in
-.IR dbz (3).
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: makedbz.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-dbz(3),
-history(5),
-inn.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "MAKEHISTORY 8"
-.TH MAKEHISTORY 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-makehistory \- Initialize or rebuild INN history database
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBmakehistory\fR [\fB\-abeFIOx\fR] [\fB\-f\fR \fIfilename\fR] [\fB\-l\fR \fIcount\fR]
-[\fB\-T\fR \fItmpdir\fR] [\fB\-s\fR \fIsize\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBmakehistory\fR rebuilds the \fIhistory\fR\|(5) text file, which contains a list of
-Message-IDs of articles already seen by the server. It can also be used
-to rebuild the overview database. Note that the \fIdbz\fR\|(3) indexes for the
-history file are rebuilt by \fImakedbz\fR\|(8), not by \fBmakehistory\fR as in
-earlier versions of \s-1INN\s0.
-.PP
-The default location of the history text file is \fIpathdb\fR/history; to
-specify an alternate location, use the \fB\-f\fR flag.
-.PP
-By default, \fBmakehistory\fR will scan the entire spool, using the storage
-manager, and write a history line for every article. To also generate
-overview information, use the \fB\-O\fR flag.
-.PP
-\&\s-1WARNING:\s0 If you're trying to rebuild the overview database, be sure to
-stop \fIinnd\fR\|(8) and delete or zero out the existing database before you start
-for the best results. An overview rebuild should not be done while the
-server is running. Unless the existing overview is deleted, you may end
-up with problems like out-of-order overview entries, excessively large
-overview buffers, and the like.
-.PP
-If \fIovmethod\fR in \fIinn.conf\fR is \f(CW\*(C`ovdb\*(C'\fR, you must have the ovdb processes
-running while rebuilding overview. ovdb needs them available while
-writing overview entries. You can start them by hand separate from the
-rest of the server by running \fBovdb_init\fR; see \fIovdb_init\fR\|(8) for more
-details.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-a\fR" 4
-.IX Item "-a"
-Append to the history file rather than generating a new one. If you
-append to the main history file, make sure \fIinnd\fR\|(8) is throttled or not
-running, or you can corrupt the history.
-.IP "\fB\-b\fR" 4
-.IX Item "-b"
-Delete any messages found in the spool that do not have valid Message-ID
-headers in them.
-.IP "\fB\-e\fR" 4
-.IX Item "-e"
-Compute Bytes headers which is used for overview data. This option is valid
-only if \fB\-O\fR flag is specified and \fIoverview.fmt\fR includes \f(CW\*(C`Bytes:\*(C'\fR.
-.IP "\fB\-f\fR \fIfilename\fR" 4
-.IX Item "-f filename"
-Rather than writing directly to \fIpathdb\fR/history, instead write to
-\&\fIfilename\fR.
-.IP "\fB\-F\fR" 4
-.IX Item "-F"
-Fork a separate process to flush overview data to disk rather than doing
-it directly. The advantage of this is that it allows \fBmakehistory\fR to
-continue to collect more data from the spool while the first batch of data
-is being written to the overview database. The disadvantage is that up to
-twice as much temporary disk space will be used for the generated overview
-data. This option only makes sense in combination with \fB\-O\fR. With
-\&\f(CW\*(C`buffindexed\*(C'\fR, the \f(CW\*(C`overchan\*(C'\fR program is invoked to write overview.
-.IP "\fB\-I\fR" 4
-.IX Item "-I"
-Don't store overview data for articles numbered lower than the lowest
-article number in \fIactive\fR. This is useful if there are for whatever
-reason old articles on disk that shouldn't be available to readers or put
-into the overview database.
-.IP "\fB\-l\fR \fIcount\fR" 4
-.IX Item "-l count"
-This option specifies how many articles to process before writing the
-accumulated overview information out to the overview database. The
-default is \f(CW10000\fR. Since overview write performance is faster with
-sorted data, each \*(L"batch\*(R" gets sorted. Increasing the batch size
-with this option may further improve write performance, at the cost
-of longer sort times. Also, temporary space will be needed to store
-the overview batches. At a rough estimate, about 300 * \fIcount\fR bytes
-of temporary space will be required (not counting temp files created
-by \fIsort\fR\|(1)). See the description of the \fB\-T\fR option for how to
-specify the temporary storage location. This option has no effect
-with \f(CW\*(C`buffindexed\*(C'\fR, because \f(CW\*(C`buffindexed\*(C'\fR does not need sorted
-overview and no batching is done.
-.IP "\fB\-s\fR \fIsize\fR" 4
-.IX Item "-s size"
-Size the history database for approximately \fIsize\fR pairs. Accurately
-specifying the size is an optimization that will create a more
-efficient database. (The size should be the estimated eventual size
-of the \fIhistory\fR file, typically the size of the old file, in lines.)
-.IP "\fB\-O\fR" 4
-.IX Item "-O"
-Create the overview database as well as the history file. Overview
-information is only required if the server supports readers; it is not
-needed for a transit-only server (see \fIenableoverview\fR in \fIinn.conf\fR\|(5)).
-If you are using the \f(CW\*(C`buffindexed\*(C'\fR overview storage method, erase all of
-your overview buffers before running \fBmakehistory\fR with \fB\-O\fR.
-.IP "\fB\-T\fR \fItmpdir\fR" 4
-.IX Item "-T tmpdir"
-If \fB\-O\fR is given, \fBmakehistory\fR needs a location to write temporary
-overview data. By default, it uses \fIpathtmp\fR, set in \fIinn.conf\fR, but if
-this option is given, the provided \fItmpdir\fR is used instead. This is
-also used for temporary files created by \fIsort\fR\|(1) (which is invoked in the
-process of writing overview information since sorted overview information
-writes faster). By default, sort usually uses your system temporary
-directory; see the \fIsort\fR\|(1) man page on your system to be sure.
-.IP "\fB\-x\fR" 4
-.IX Item "-x"
-If this option is given, \fBmakehistory\fR won't write out history file
-entries. This is useful mostly for building overview without generating
-a new history file.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Here's a typical example of rebuilding the entire history and overview
-database, removing broken articles in the news spool. This uses the
-default temporary file locations and should be done while innd isn't
-running (or is throttled).
-.PP
-.Vb 1
-\& makehistory \-b \-f history.n \-O \-l 30000 \-I
-.Ve
-.PP
-This will rebuild the overview (if using \f(CW\*(C`buffindexed\*(C'\fR, erase the
-existing overview buffers before running this command) and leave a new
-history file as \f(CW\*(C`history.n\*(C'\fR in \fIpathdb\fR. To preserve all of the history
-entries from the old history file that correspond to rejected articles or
-expired articles, follow the above command with:
-.PP
-.Vb 2
-\& cd /usr/local/news/db
-\& awk 'NF == 2 { print }' < history >> history.n
-.Ve
-.PP
-(replacing the path with your \fIpathdb\fR, if it isn't the default). Then
-look over the new history file for problems and run:
-.PP
-.Vb 1
-\& makedbz \-s `wc \-l < history` \-f history.n
-.Ve
-.PP
-Then rename all of the files matching \f(CW\*(C`history.n.*\*(C'\fR to \f(CW\*(C`history.*\*(C'\fR,
-replacing the current history database and indexes. After that, it's safe
-to unthrottle innd.
-.PP
-For a simpler example:
-.PP
-.Vb 1
-\& makehistory \-b \-f history.n \-I \-O
-.Ve
-.PP
-will scan the spool, removing broken articles and generating history and
-overview entries for articles missing from history.
-.PP
-To just rebuild overview:
-.PP
-.Vb 1
-\& makehistory \-O \-x \-F
-.Ve
-.SH "FILES"
-.IX Header "FILES"
-.IP "inn.conf" 4
-.IX Item "inn.conf"
-Read for \fIpathdb\fR, \fIpathtmp\fR, and other settings.
-.IP "\fIpathdb\fR/history" 4
-.IX Item "pathdb/history"
-This is the default output file for \fBmakehistory\fR.
-.IP "\fIpathtmp\fR" 4
-.IX Item "pathtmp"
-Where temporary files are written unless \fB\-T\fR is given.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Originally written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews and
-updated by various other people since.
-.PP
-$Id: makehistory.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIdbz\fR\|(3), \fIactive\fR\|(5), \fIhistory\fR\|(5), \fIinn.conf\fR\|(5), \fIctlinnd\fR\|(8), \fIinnd\fR\|(8),
-\&\fImakedbz\fR\|(8), \fIovdb_init\fR\|(8), \fIoverview.fmt\fR\|(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH MOD-ACTIVE 8
-.SH NAME
-mod-active \- batch processing of ctlinnd newgroup/rmgroup/changegroup
-.SH SYNOPSIS
-.B mod-active
-[
-.I ctlinnd_command_file
-]
-.SH DESCRIPTION
-.B mod-active
-is a
-.B perl
-script that updates the
-.I active
-file based on its input lines of ctlinnd newgroup, rmgroup and
-changegroup commands. It pauses the server briefly while the existing
-active file is read and rewritten, which not only keeps
-.B innd
-from updating the active file but also locks against other instances
-of
-.BR mod-active .
-.PP
-The input to
-.B mod-active
-can come either from one or more files named on the command line, or
-from the standard input. Typically its input is the output from the
-.B docheckgroups
-or
-.B actsync
-commands. Every line which contains the string "ctlinnd newgroup",
-"ctlinnd rmgroup", or "ctlinnd changegroup", optionally preceded by
-whitespace and/or the path to
-.BR ctlinnd ,
-is noted for the update. Redundant commands, such as a newgroup
-directive for a group that already exists, are silently ignored. All
-other lines in the input are also silently ignored.
-.PP
-After the new
-.I active
-file has been generated, the existing one is renamed to
-.I active.old
-and the new one is moved into place. The script then displays the
-differences between the two files.
-.PP
-Any groups that were added to the
-.I active
-file are also added to the
-.I active.times
-file with the string "checkgroups-update".
-.SH BUGS
-Though
-.B innd
-is paused while
-.B mod-active
-works, it is not inconceivable that there could be a conflict if
-something else tries to update the active file during the relatively
-short time that mod-active is working. The two most realistic ways I
-can think of for this to happen are either by an administrator
-concurrently doing a manual ctlinnd command, or by
-.B innd
-receiving a control message, then
-.B mod-active
-pausing the server, then the control message handler script that
-.B innd
-forked running its own
-.B ctlinnd
-command while
-.B mod-active
-is working.
-I've been using
-.B mod-active
-regularly for several years, though, and never had either problem.
-.SH HISTORY
-Written by David C Lawrence <tale@isc.org>.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.SH "SEE ALSO"
-.IR active (5),
-.IR active.times (5),
-.IR actsync (8),
-.IR ctlinnd (8),
-.IR innd (8).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH MODERATORS 5
-.SH NAME
-moderators \- submission addresses for moderated newsgroups
-.SH DESCRIPTION
-When an unapproved article is posted locally to a moderated newsgroup,
-it is not passed off to
-.IR innd (8)
-for normal handling; instead it's instead sent via e-mail to the submission
-address for that newsgroup. The file
-.I <pathetc in inn.conf>/moderators
-lists the submission addresses for moderated newsgroups.
-This file is used by
-.IR nnrpd "(8), " inews (1),
-and any other program that uses the GetModeratorAddress() routine (see
-.IR libinn (3)).
-.PP
-The moderators file is a list of associations between
-.IR uwildmat(3)
-patterns matching newsgroups and the submission address for those
-newsgroups.
-Blank lines and lines starting with a number sign (``#'') are ignored.
-All other lines should consist of two fields separated by a colon.
-.PP
-The first field specifies the group or groups to match using
-.IR uwildmat(3).
-The first matching line is used, so more specific patterns should occur
-earlier than general patterns.
-.PP
-The second field, the submission address, may have at most one
-.I %s
-anywhere in it; if present, this will be replaced by the name of the
-newsgroup with periods replaced by dashes. If there is a literal ``%'' in
-the submission address, it must be written as ``%%'' (even if not followed
-by an ``s'').
-.PP
-Here is a sample file:
-.RS
-.nf
-
-example.important:announce-request@example.com
-example.*:%s@smtp.example.com
-gnu.*:%s@prep.ai.mit.edu
-*:%s@moderators.isc.org
-
-.fi
-.RE
-Using the above file, postings to the moderated newsgroup in the left
-column will be sent to the address shown in the right column:
-.RS
-.nf
-
-.ta \w'example.x.announce 'u
-example.important announce-request@example.com
-example.x.announce example-x-announce@smtp.example.com
-gnu.emacs.sources gnu-emacs-sources@prep.ai.mit.edu
-comp.sources.unix comp-sources-unix@moderators.isc.org
-
-.fi
-.RE
-Periods are converted to dashes for historical reasons, from back in the
-days when periods in the local part of addresses were not always handled
-correctly. It's probably no longer necessary, but so much now depends on
-it that it can't be easily changed.
-.PP
-It's intended that the sample moderators file included in the INN
-distribution always be sufficient for all world-wide newsgroups. The
-hosts behind moderators.isc.org have graciously volunteered to handle
-forwarding tasks for all world-wide newsgroups so that individual sites
-don't have to keep track of the submission addresses for moderated groups.
-The forwarding database used by moderators.isc.org is coordinated by
-moderators-request@isc.org; if you know of a world-wide newsgroup
-hierarchy that is not correctly handled by moderators.isc.org, please send
-the details to that address.
-.PP
-Given that, the only thing you should have to add to the sample file under
-normal circumstances are the forwarding addresses for local or
-limited-distribution moderated groups.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: moderators.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inews(1), inn.conf(5), libinn(3), uwildmat(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "MOTD.NEWS 5"
-.TH MOTD.NEWS 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-motd.news \- Message of the day information for readers
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This file, found in \fIpathetc\fR/motd.news, contains local information for
-news readers in a free-form format. The entire file is returned verbatim
-to any client that issues the \s-1LIST\s0 \s-1MOTD\s0 command. This might be used for
-new information, notification of upcoming downtime, or similar purposes.
-.PP
-Be aware that use of the \s-1LIST\s0 \s-1MOTD\s0 command is not widespread and most news
-clients will never ask for this file.
-.PP
-If this file is missing, it is not an error. The server will just send
-the client an empty response.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Rewritten in \s-1POD\s0 by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: motd.news.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5)
+++ /dev/null
-.TH NEWS.DAILY 8
-.SH NAME
-news.daily \- do regular Usenet system administration
-.SH SYNOPSIS
-.B news.daily
-[
-.B keyword...
-]
-
-.SH DESCRIPTION
-.I News.daily
-performs a number of important Usenet administrative functions.
-This includes producing a status report, removing old news articles,
-processing log files, rotating the archived log files, renumbering the
-active file,
-removing any old socket files found in the
-.I <pathrun in inn.conf>
-directory, and collecting the output.
-.I "This program should be run under the news administrator's id, not as root."
-.PP
-By default,
-.I news.daily
-performs all of its functions and mails the output to the news administrator,
-.IR <USER\ specified\ with\ \-\-with\-news\-master\ at\ configure> .
-By specifying ``keywords'' on the command line, it is possible to
-modify the functions performed, as well as change the arguments given to
-.IR expire (8)
-and
-.IR expireover (8).
-.PP
-.I News.daily
-should be run once a day, typically out of
-.IR cron (8).
-It may be run more often, but such invocations should at least use the
-\&``norotate'' keyword (or perhaps the \&``notdaily'' keyword) to
-prevent the log files from being processed and rotated too fast.
-.PP
-The
-.IR shlock (1)
-program is used to prevent simultaneous executions.
-.SH "KEYWORDS"
-.PP
-The following keywords may be used:
-.TP
-.I delayrm
-This uses the ``\fB\-z\fP'' flag when invoking
-.I expire
-and
-.IR expireover .
-The names of articles to be removed are written to a temporary file, and
-then renamed after expiration by calling
-.IR expirerm (8).
-.TP
-.IR expctl= path
-Specify the file to use as the
-.IR expire.ctl (5)
-file for
-.IR expire .
-.TP
-.IR expdir= path
-By default,
-.I expire
-builds the new
-.IR history (5)
-file and database in the same directory as the current files.
-Using this keyword specifies a different local to build the new files
-(by passing the ``\fB\-d\fP'' flag to
-.IR expire ),
-which will then be moved to the right location when finished.
-.TP
-.I nostat
-This keyword disables the status report generated by
-.I innstat
-(see
-.IR innstat (8)).
-Without this keyword, the status report is the first function performed,
-just prior to obtaining the
-.I news.daily
-lock.
-.TP
-.I notdaily
-By default
-.I news.daily
-expects to be run only once a day, and it does
-various things (like rotating logs) that normally should only be done on
-daily basis. Use this keyword any extra times
-.I news.daily
-is run in the
-day and the normal logfile processing (and rotation) will not be done.
-.TP
-.I noexpire
-By default,
-.I expire
-is invoked to remove old news articles.
-Using this keyword disables this function.
-.TP
-.I noexpireover
-By default,
-.I expireover
-is invoked to remove old overview database, if
-.I enableoverview
-is set in
-.IR inn.conf .
-Using this keyword disables this function.
-.TP
-.I noexplog
-.I Expire
-normally appends information to
-.I <pathlog in inn.conf>/expire.log
-(see
-.IR newslog (5)).
-Using this keyword causes the
-.I expire
-output to be handled as part of
-.IR news.daily 's
-output.
-It has no effect if the ``noexpire'' keyword is used.
-.TP
-.IR flags= "'args\ for\ expire'"
-By default,
-.I expire
-is invoked with argument ``\-v1''.
-Using this keyword changes the arguments to those specified.
-Be careful to use quotes if multiple arguments are needed.
-This keyword has no effect if the ``noexpire'' keyword is used.
-.TP
-.I nologs
-After expiration,
-.IR scanlogs (8)
-is invoked to process the log files.
-Using this keyword disables all log processing functions.
-.TP
-.I norotate
-By default, log processing includes rotating and cleaning out log files.
-Using this keyword disables the rotating and cleaning aspect of the log
-processing: the logs files are only scanned for information and no contents
-are altered.
-.IP
-This keyword has no effect if the ``nologs'' keyword is used.
-The ``norotate'' keyword is passed on to
-.I scanlogs
-if it is invoked.
-.TP
-.I norenumber
-This keyword disables the
-.IR ctlinnd (8)
-renumber operation.
-Normally, the low-water marks for all newsgroups (see
-.IR active (5))
-are reset.
-.TP
-.I norm
-By default, any socket
-.I ctlinnd
-socket that has not been modified for two days will be removed.
-Using this keyword disables this function.
-.TP
-.I nomail
-.I News.daily
-normally sends a mail message containing the results to the administrator.
-Using this keyword causes this message to be sent to stdout and stderr instead.
-Normally, all utilities invoked by the script have their stdout and stderr
-redirected into a file.
-If the file is empty, no message is sent.
-.TP
-.I expireover
-The
-.I expireover
-program is called after expiration to purge the overview databases.
-If no overview data is created, the ``expireover''
-keyword is not needed. This is the case that the server runs only for
-feeder(no reader).
-.TP
-.IR expireoverflags= "'args\ for\ expireover'"
-If the ``expireover'' keyword is used, this keyword may be used to specify
-the flags to be passed to
-.IR expireover .
-If the ``delayrm'' keyword is used, then the default value is ``\-z''
-and the list of deleted files; otherwise, the default value is ``\-s''.
-.TP
-.I /full/path
-The program specified by the given path is executed just before any
-expiration is done.
-A typical use is to specify an alternate expiration program and use the
-\&``noexpire'' keyword.
-Multiple programs may be specified; they will be invoked in order.
-.TP
-.IR postexec= "'post executed program'"
-The program specified by the given path is executed just after all
-expiration is done.
-Multiple programs may be specified; they will be invoked in order.
-.TP
-.I lowmark
-If the ``lowmark'' keyword is used,
-.IR ctlinnd (8)
-lowmark is used for renumbering
-.IR active .
-Normal
-.IR ctlinnd (8)
-renumber operation will take long time. With ``lowmark'' keyword this will
-take less time.
-If the ``lowmark'' keyword is used,
-\&``norenumber'' keyword is not needed, since
-.I news.daily
-specifies it implicitly.
-.TP
-.IR tmpdir= path
-Sets the environment variable TMPDIR to the specified path.
-Various parts of the expire process, such as sort, will then use this
-path as the directory for temporary files.
-.SH HISTORY
-.I News.daily
-and this manual page written by Landon Curt Noll <chongo@toad.com> and
-Rich $alz <rsalz@uunet.uu.net>.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: news.daily.8 6398 2003-07-12 19:15:50Z rra $
-.SH "SEE ALSO"
-active(5),
-ctlinnd(8),
-expire(8),
-fastrm(8),
-inn.conf(5),
-newslog(5),
-innwatch.ctl(5),
-shlock(1).
+++ /dev/null
-.\" -*- nroff -*-
-.\" $Revision: 5909 $
-.TH NEWS2MAIL 8
-.SH NAME
-news2mail \- a channel script to gateway news into email.
-.SH SYNOPSIS
-.I news2mail
-.SH DESCRIPTION
-.I news2mail
-runs as a channel process underneath innd. It is set up as channel feed in
-newsfeeds, with different mailing lists as funnel entries pointing to it (see
-below).
-.PP
-.I news2mail
-uses a config file
-.PP
-.RS
-.I <pathetc\ in\ inn.conf>/news2mail.cf
-.RE
-.PP
-to map mailing list names to email addresses.
-.PP
-.I news2mail
-causes sendmail to queue the messages for later delivery (to avoid DOS attacks
-by mass postings). You must run 'sendmail -q' periodically to get the queue
-processed.
-.SH CONFIG FILE
-The config file format is simple: comments (start with ``#'') and blank lines
-are ignored. All other lines have two fields on them. The first is the list
-name and is what innd uses (i.e. the site field of the entry in the newsfeeds
-file). The second field is the actual email address to send the article to. In
-the email message, the ``To'' header will have the mailing list name (i.e. the
-first field).
-.PP
-.RS
-.nf
-# list-name address
-big-red-ants@ucsd.edu big-red-ants-digest@ucsd.edu
-news-software@ucsd.edu news-software-digest@ucsd.edu
-.fi
-.RE
-.PP
-a set of newsfeeds entries for these lists would be:
-.PP
-.RS
-.nf
-.ds R$ <pathbin in inn.conf>
-n2m!:!*:Tc,Ac,Wn*:\*(R$/news2mail
-
-big-red-ants@ucsd.edu:rec.pets.redants.*:Tm:n2m!
-
-news-software@ucsd.edu:news.software.nntp:Tm:n2m!
-.fi
-.RE
-.PP
-.I news2mail
-strips most article headers from the article before mailing. It leaves: From, Subject
-Date, Organization and Message-ID in there. It add a To header with the mailing
-list name in it.
-.SH HISTORY
-news2mail was written by Brian Kantor. This man page was written by James
-Brister.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: news2mail.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-ctlinnd(8),
-inn.conf(5),
-innd(8),
-newsfeeds(5),
-shlock(1).
-
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "NEWSFEEDS 5"
-.TH NEWSFEEDS 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-newsfeeds \- Determine where Usenet articles are sent
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpathetc\fR/newsfeeds specifies how incoming articles should be
-distributed to other programs and files on the server. It is parsed by
-the InterNetNews server \fIinnd\fR\|(8) when it starts up, or when directed to by
-\&\fIctlinnd\fR\|(8). \fBinnd\fR doesn't send articles to remote sites itself, so
-\&\fInewsfeeds\fR doesn't directly determine which remote news servers articles
-are sent to. Instead, it specifies what batch files should be created or
-which programs should be run (and what information should be sent to
-them), and then this information is used by programs like \fIinnxmit\fR\|(8) and
-\&\fIinnfeed\fR\|(8) to feed articles to remote sites.
-.PP
-The \fInewsfeeds\fR file isn't used solely to set up feeding accepted
-articles to remote sites but also to pass them (or bits of information
-about them) to any local programs or files that want that data. For
-example, \fIcontrolchan\fR\|(8), a daemon that processes incoming control
-messages, runs out of \fInewsfeeds\fR, as could a news to mail gateway.
-.PP
-The file is interpreted as a set of lines, parsed according to the
-following rules: If a line ends with a backslash, the backslash, the
-newline, and any whitespace at the start of the next line is deleted.
-This is repeated until the entire \*(L"logical\*(R" line is collected. If the
-logical line is blank or starts with a number sign (\f(CW\*(C`#\*(C'\fR), it is ignored.
-.PP
-All other lines are interpreted as feed entries. An entry should consist
-of four colon-separated fields; two of the fields may have optional
-sub\-fields, marked off by a slash. Fields or sub-fields that take
-multiple parameters should be separated by a comma. Extra whitespace can
-cause problems and should be avoided. Except for the site names, case is
-significant. The format of an entry is:
-.PP
-.Vb 4
-\& sitename[/exclude,exclude,...]\e
-\& :pattern,pattern...[/distribution,distribution...]\e
-\& :flag,flag...\e
-\& :parameter
-.Ve
-.PP
-Each field is described below.
-.PP
-The \fIsitename\fR is the name of the site to which a news article can be
-sent. It is used for writing log entries and for determining if an
-article should be forwarded to a site. (A \*(L"site\*(R" is the generic term for
-some destination of newsfeed data; it often corresponds to a remote news
-peer, but doesn't have to. For example, a local archiving program run
-from \fInewsfeeds\fR is also a \*(L"site.\*(R") If \fIsitename\fR already appears in
-the article's Path: header, then the article will not be sent to the site.
-The name is usually whatever the remote site uses to identify itself in
-the Path: header, but can be almost any word.
-.PP
-Be careful, though, to avoid having the \fIsitename\fR accidentally match a
-Path: header entry unintentionally. For this reason, special local
-entries (such as archivers or gateways) should probably end with an
-exclamation point to make sure that they do not have the same name as any
-real site. For example, \f(CW\*(C`gateway\*(C'\fR is an obvious name for the local entry
-that forwards articles out to a mailing list. If a site with the name
-\&\f(CW\*(C`gateway\*(C'\fR posts an article, when the local site receives the article it
-will see the name in the Path and not send the article to its own
-\&\f(CW\*(C`gateway\*(C'\fR entry. Since \f(CW\*(C`gateway!\*(C'\fR can't appear as an individual Path:
-entry since \f(CW\*(C`!\*(C'\fR is a delimiter in the Path: header, that would be a
-better thing to use for \fIsitename\fR.
-.PP
-(Another way to avoid this problem is with the \f(CW\*(C`Ap\*(C'\fR flag; see the
-description below.)
-.PP
-If an entry has an exclusion sub\-field, the article will not be sent to
-that site if any of \fIexclude\fR appear in the Path: header. (It's
-sometimes convenient to have the \fIsitename\fR be an abbreviated form of the
-name of the remote site, since all the \fIsitename\fRs to which an article
-is sent are written to the log and using shorter \fIsitename\fRs can
-therefore improve performance for large servers. In this case, the Path:
-header entries of those sites should be given as \fIexclude\fR entries and
-the \f(CW\*(C`Ap\*(C'\fR flag used so that the abbreviated \fIsitename\fR doesn't
-accidentally match some other Path: header entry.)
-.PP
-The same \fIsitename\fR can be used more than once and the appropriate action
-will be taken for each entry that should receive the article, but this is
-recommended only for program feeds to avoid confusion. Case is not
-significant in site names.
-.PP
-The comma-separated \fIpattern\fR specifies which groups to send to the site;
-it is interpreted to build a \*(L"subscription list\*(R" for the site. The
-default subscription is to get all groups carried by the server. It is a
-\&\fIuwildmat\fR\|(3) pattern supporting poison (\f(CW\*(C`@\*(C'\fR) wildcards; see the \fIuwildmat\fR\|(3)
-man page for full details on the pattern matching language. \fIpattern\fR
-will be matched against every newsgroup carried by the server and all
-newsgroups that match will be added to the subscription list for the site.
-.PP
-Normally, a given article (or information about it) is sent to a site if
-any of the newsgroups to which the article was posted are in that site's
-subscription list. If a newsgroup matches a \f(CW\*(C`@\*(C'\fR pattern in \fIpattern\fR,
-then not only is it not added to the subscription list, but any articles
-crossposted to that newsgroup also will not be sent to that site even if
-other newsgroups to which it was crossposted are in that site's
-subscription list. This is called a poison pattern (because matching
-groups are \*(L"poisoned\*(R").
-.PP
-For example, to receive all comp.* groups, but only comp.sources.unix
-within the sources newsgroups, the following \fIpattern\fR can be used:
-.PP
-.Vb 1
-\& comp.*,!comp.sources.*,comp.sources.unix
-.Ve
-.PP
-Note that the trailing \f(CW\*(C`.*\*(C'\fR is required; the pattern has to match the
-whole newsgroup name. \f(CW\*(C`comp.sources.*\*(C'\fR could be written \f(CW\*(C`comp.sources*\*(C'\fR
-and would exclude the newsgroup comp.sources (if it exists) as well as the
-groups in the comp.sources.* hierarchy, but note that this would also
-exclude a newsgroup named comp.sources\-only (whereas the above pattern
-would add that group to the site subscription list since it matches
-\&\f(CW\*(C`comp.*\*(C'\fR and none of the other patterns.
-.PP
-For another example, to feed alt.* and misc.* to a given site but not any
-articles posted to alt.binaries.warez (even if they're also crossposted to
-other alt.* or misc.* groups), the following pattern can be used:
-.PP
-.Vb 1
-\& alt.*,@alt.binaries.warez,misc.*
-.Ve
-.PP
-Note, however, that if you reversed the \f(CW\*(C`alt.*\*(C'\fR and <@alt.binaries.warez>
-entries, this pattern would be equivalent to \f(CW\*(C`alt.*,misc.*\*(C'\fR, since the
-last matching pattern determines whether a given newsgroup matches and the
-poison logic only applies if the poison entry is the last matching entry.
-.PP
-Control messages follow slightly different propagation rules than normal
-articles; see \fIinnd\fR\|(8) for the details. Note that most subscriptions
-should have \f(CW\*(C`!junk,!control,!control.*\*(C'\fR in their pattern list due to those
-propagation rules (and since junk is a special internal newsgroup; see
-\&\fIwanttrash\fR in \fIinn.conf\fR\|(5) for more details on what it's used for) and
-that the best way to keep control messages local to a site is with a
-distribution.
-.PP
-A subscription can be further modified by specifying distributions that
-the site should or should not receive. The default is to send all
-articles to all sites that subscribe to any of the groups where it has
-been posted, but if an article has a Distribution: header and any
-\&\fIdistribution\fRs are specified, then they are checked according to the
-following rules:
-.IP "1." 4
-If the Distribution: header matches any of the values in the sub\-field,
-the article is sent.
-.IP "2." 4
-If a \fIdistribution\fR starts with an exclamation point, and it matches the
-Distribution: header, the article is not sent.
-.IP "3." 4
-If the Distribution: header does not match any \fIdistribution\fR in the
-site's entry and no negations were used, the article is not sent.
-.IP "4." 4
-If the Distribution: header does not match any \fIdistribution\fR in the
-site's entry and any \fIdistribution\fR started with an exclamation point,
-the article is sent.
-.PP
-If an article has more than one distribution specified, then each one is
-handled according according to the above rules. If any of the specified
-distributions indicate that the article should be sent, it is; if none do,
-it is not sent. In other words, the rules are used as a logical or.
-.PP
-It is almost definitely a mistake to have a single feed that specifies
-distributions that start with an exclamation point along with some that
-don't.
-.PP
-Distributions are text words, not patterns; entries like \f(CW\*(C`*\*(C'\fR or \f(CW\*(C`all\*(C'\fR
-have no special meaning.
-.PP
-The \fIflag\fR field is described in \*(L"\s-1FLAG\s0 \s-1VALUES\s0\*(R". The interpretation of
-the \fIparameter\fR field depends on the type of feed and is explained in
-more detail in \*(L"\s-1FEED\s0 \s-1TYPES\s0\*(R". It can be omitted for some types of
-feeds.
-.PP
-The site named \f(CW\*(C`ME\*(C'\fR is special. There must be exactly one such entry,
-and it should be the first entry in the file. If the \f(CW\*(C`ME\*(C'\fR entry has an
-exclusion sub\-field, incoming articles are rejected completely if any of
-the names specified in that exclusion sub-field appear in their Path:
-headers. If the \f(CW\*(C`ME\*(C'\fR entry has a subscription list, that list is
-prepended to the subscription list of all other entries. For example,
-\&\f(CW\*(C`*,!control,!control.*,!junk,!foo.*\*(C'\fR could be used to set the default subscription
-list for all other feeds so that local postings are not propagated unless
-\&\f(CW\*(C`foo.*\*(C'\fR explicitly appears in the site's subscription list. This feature
-tends to be somewhat confusing since the default subscription is prepended
-and can be overridden by other patterns.
-.PP
-If the \f(CW\*(C`ME\*(C'\fR entry has a distribution sub\-field, only articles that match
-that distribution list are accepted and all other articles are rejected.
-A common use for this is to put something like \f(CW\*(C`/!local\*(C'\fR in the \f(CW\*(C`ME\*(C'\fR
-entry to reject local postings from other misconfigured sites.
-.PP
-Finally, it is also possible to set variables in \fInewsfeeds\fR and use them
-later in the file. A line starting with \f(CW\*(C`$\*(C'\fR sets a variable. For
-example:
-.PP
-.Vb 1
-\& $LOCALGROUPS=local.*,example.*
-.Ve
-.PP
-This sets the variable \f(CW\*(C`LOCALGROUPS\*(C'\fR to \f(CW\*(C`local.*,example.*\*(C'\fR. This
-variable can later be used elsewhere in the file, such as in a site entry
-like:
-.PP
-.Vb 1
-\& news.example.com:$LOCALGROUPS:Tf,Wnm:
-.Ve
-.PP
-which is then completely equivalent to:
-.PP
-.Vb 1
-\& news.example.com:local.*,example.*:Tf,Wnm:
-.Ve
-.PP
-Variables aren't solely simple substitution. If either \f(CW\*(C`!\*(C'\fR or \f(CW\*(C`@\*(C'\fR
-immediately preceeds the variable and the value of the variable contains
-commas, that character will be duplicated before each comma. This
-somewhat odd-sounding behavior is designed to make it easier to use
-variables to construct feed patterns. The utility becomes more obvious
-when you observe that the line:
-.PP
-.Vb 1
-\& news.example.net:*,@$LOCALGROUPS:Tf,Wnm:
-.Ve
-.PP
-is therefore equivalent to:
-.PP
-.Vb 1
-\& news.example.net:*,@local.*,@example.*:Tf,Wnm:
-.Ve
-.PP
-which (as explained below) excludes all of the groups in \f(CW$LOCALGROUPS\fR from
-the feed to that site.
-.SH "FLAG VALUES"
-.IX Header "FLAG VALUES"
-The \fIflags\fR parameter specifies miscellaneous parameters, including the
-type of feed, what information should be sent to it, and various
-limitations on what articles should be sent to a site. They may be
-specified in any order and should be separated by commas. Flags that take
-values should have the value immediately after the flag letter with no
-whitespace. The valid flags are:
-.IP "\fB<\fR \fIsize\fR" 4
-.IX Item "< size"
-An article will only be sent to this site if it is less than \fIsize\fR bytes
-long. The default is no limit.
-.IP "\fB>\fR \fIsize\fR" 4
-.IX Item "> size"
-An article will only be sent to this site if it is greater than \fIsize\fR
-bytes long. The default is no limit.
-.IP "\fBA\fR \fIchecks\fR" 4
-.IX Item "A checks"
-An article will only be sent to this site if it meets the requirements
-specified in \fIchecks\fR, which should be chosen from the following set.
-\&\fIchecks\fR can be multiple letters if appropriate.
-.RS 4
-.IP "c" 3
-.IX Item "c"
-Exclude all kinds of control messages.
-.IP "C" 3
-.IX Item "C"
-Only send control messages, not regular articles.
-.IP "d" 3
-.IX Item "d"
-Only send articles with a Distribution header. Combined with a particular
-distribution value in the \fIdistribution\fR part of the site entry, this can
-be used to limit articles sent to a site to just those with a particuliar
-distribution.
-.IP "e" 3
-.IX Item "e"
-Only send articles where every newsgroup listed in the Newsgroups: header
-exists in the active file.
-.IP "f" 3
-.IX Item "f"
-Don't send articles rejected by filters. This is only useful when
-\&\fIdontrejectfiltered\fR is set in \fIinn.conf\fR. With that variable set, this
-lets one accept all articles but not propagate filtered ones to some
-sites.
-.IP "o" 3
-Only send articles for which overview data was stored.
-.IP "O" 3
-.IX Item "O"
-Send articles to this site that don't have an X\-Trace: header, even if the
-\&\f(CW\*(C`O\*(C'\fR flag is also given.
-.IP "p" 3
-.IX Item "p"
-Only check the exclusions against the Path: header of articles; don't
-check the site name. This is useful if your site names aren't the same as
-the Path: entries added by those remote sites, or for program feeds where
-the site name is arbitrary and unrelated to the Path: header.
-.RE
-.RS 4
-.Sp
-If both \f(CW\*(C`c\*(C'\fR and \f(CW\*(C`C\*(C'\fR are given, the last specified one takes precedence.
-.RE
-.IP "\fBB\fR \fIhigh\fR/\fIlow\fR" 4
-.IX Item "B high/low"
-If a site is being fed by a file, channel, or exploder (see below), the
-server will normally start trying to write the information as soon as
-possible. Providing a buffer may give better system performance and help
-smooth out overall load if a large batch of news comes in. The value of
-the this flag should be two numbers separated by a slash. \fIhigh\fR
-specifies the point at which the server can start draining the feed's I/O
-buffer, and \fIlow\fR specifies when to stop writing and begin buffering
-again; the units are bytes. The default is to do no buffering, sending
-output as soon as it is possible to do so.
-.IP "\fBC\fR \fIcount\fR" 4
-.IX Item "C count"
-If this flag is specified, an article will only be sent to this site if
-the number of groups it is posted to, plus the square of the number of
-groups followups would appear in, is no more than \fIcount\fR. \f(CW30\fR is a
-good value for this flag, allowing crossposts to up to 29 groups when
-followups are set to a single group or poster and only allowing crossposts
-to 5 groups when followups aren't set.
-.IP "\fBF\fR \fIname\fR" 4
-.IX Item "F name"
-Specifies the name of the file that should be used if it's necessary to
-begin spooling for the site (see below). If \fIname\fR is not an absolute
-path, it is taken to be relative to \fIpathoutgoing\fR in \fIinn.conf\fR. If
-\&\fIname\fR is a directory, the file \fItogo\fR in that directory will be used as
-the file name.
-.IP "\fBG\fR \fIcount\fR" 4
-.IX Item "G count"
-If this flag is specified, an article will only be sent to this site if it
-is posted to no more than \fIcount\fR newsgroups. This has the problem of
-filtering out many FAQs, as well as newsgroup creation postings and
-similar administrative announcements. Either the \fBC\fR flag or the \fBU\fR
-flag is a better solution.
-.IP "\fBH\fR \fIcount\fR" 4
-.IX Item "H count"
-If this flag is specified, an article will only be sent to this site if it
-has \fIcount\fR or fewer sites in its Path: line. This flag should only be
-used as a rough guide because of the loose interpretation of the Path:
-header; some sites put the poster's name in the header, and some sites
-that might logically be considered to be one hop become two because they
-put the posting workstation's name in the header. The default value for
-\&\fIcount\fR if not specified is one. (Also see the \fBO\fR flag, which is
-sometimes more appropriate for some uses of this flag.)
-.IP "\fBI\fR \fIsize\fR" 4
-.IX Item "I size"
-The flag specifies the size of the internal buffer for a file feed. If
-there are more file feeds than allowed by the system, they will be
-buffered internally in least-recently-used order. If the internal buffer
-grows bigger then \fIsize\fR bytes, however, the data will be written out to
-the appropriate file. The default value is 16 \s-1KB\s0.
-.IP "\fBN\fR \fIstatus\fR" 4
-.IX Item "N status"
-Restricts the articles sent to this site to those in newsgroups with the
-moderation status given by \fIstatus\fR. If \fIstatus\fR is \f(CW\*(C`m\*(C'\fR, only articles
-in moderated groups are sent; if \fIstatus\fR is \f(CW\*(C`u\*(C'\fR, only articles in
-unmoderated groups are sent.
-.IP "\fBO\fR \fIoriginator\fR" 4
-.IX Item "O originator"
-If this flag is specified, an article will only be sent to this site if it
-contains an X\-Trace: header and the first field of this header matches
-\&\fIoriginator\fR. \fIoriginator\fR is a \fIuwildmat\fR\|(3) expression without commas or
-a list of such expressions, separated by \f(CW\*(C`/\*(C'\fR. The article is never sent
-if the first character of the pattern begins with \f(CW\*(C`@\*(C'\fR and the rest of the
-pattern matches. One use of this flag is to restrict the feed to locally
-generated posts by using an \fIoriginator\fR pattern that matches the
-X\-Trace: header added by the local server.
-.IP "\fBP\fR \fIpriority\fR" 4
-.IX Item "P priority"
-The nice priority that this channel or program feed should receive. This
-should be a positive number between 0 and 20 and is the priority that the
-new process will run with. This flag can be used to raise the priority to
-normal if you're using the \fInicekids\fR parameter in \fIinn.conf\fR.
-.IP "\fBQ\fR \fIhashfeed\fR" 4
-.IX Item "Q hashfeed"
-Specifies the \fIhashfeed\fR match expression for this site. It must be in
-the form \f(CW\*(C`value/mod\*(C'\fR or \f(CW\*(C`start\-end/mod\*(C'\fR. The Message-ID of the article
-is hashed using \s-1MD5\s0, which results in a 128\-bit hash. The lowest
-32\ bits are then taken by default as the hashfeed value (which is an
-integer). If the hashfeed value modulus \f(CW\*(C`mod\*(C'\fR plus one equals \f(CW\*(C`value\*(C'\fR or
-is between \f(CW\*(C`start\*(C'\fR and \f(CW\*(C`end\*(C'\fR, the article will be fed to this site. All
-these numbers must be integers.
-.Sp
-It is a deterministic way to control the flow of articles and to split a feed.
-For instance:
-.Sp
-.Vb 2
-\& Q1/2 Feeds about 50% of all articles to this site.
-\& Q2/2 Feeds the other 50% of all articles.
-.Ve
-.Sp
-Another example with three sites:
-.Sp
-.Vb 3
-\& Q1\-3/10 Feeds about 30% of all articles.
-\& Q4\-5/10 Feeds about 20% of all articles.
-\& Q6\-10/10 Feeds about 50% of all articles.
-.Ve
-.Sp
-If this flag is specified multiple times, the contents will be
-logically \f(CW\*(C`OR\*(C'\fRed together (just one match is needed).
-.Sp
-You can use an extended syntax of the form \f(CW\*(C`value/mod_offset\*(C'\fR or
-\&\f(CW\*(C`start\-end/mod_offset\*(C'\fR. As \s-1MD5\s0 generates a 128\-bit return value,
-it is possible to specify from which byte-offset the 32\-bit integer
-used by hashfeed starts. The default value for \f(CW\*(C`offset\*(C'\fR is \f(CW\*(C`_0\*(C'\fR
-and thirteen overlapping values from \f(CW\*(C`_0\*(C'\fR to \f(CW\*(C`_12\*(C'\fR can be used.
-Only up to four totally independent values exist: \f(CW\*(C`_0\*(C'\fR, \f(CW\*(C`_4\*(C'\fR,
-\&\f(CW\*(C`_8\*(C'\fR and \f(CW\*(C`_12\*(C'\fR.
-.Sp
-Therefore, it allows to a generate a second level of deterministic
-distribution. Indeed, if a news server is fed \f(CW\*(C`Q1/2\*(C'\fR, it can go on
-splitting thanks to \f(CW\*(C`Q1\-3/9_4\*(C'\fR for instance.
-.Sp
-The algorithm is compatible with the one used by Diablo\ 5.1 and up.
-If you want to use the legacy quickhashing method used by Diablo
-before 5.1, you can put an \f(CW\*(C`@\*(C'\fR sign just after the \fBQ\fR flag (for
-instance \f(CW\*(C`Q@1\-3/10\*(C'\fR, but the distribution of the messages is not
-perfect with this legacy method whose use is discouraged and for
-which offsets cannot be used).
-.IP "\fBS\fR \fIsize\fR" 4
-.IX Item "S size"
-If the amount of data queued for the site gets to be larger than \fIsize\fR
-bytes, the server will switch to spooling, appending to a file specified
-by the \fBF\fR flag, or \fIpathoutgoing\fR/\fIsitename\fR if \fBF\fR is not specified.
-Spooling usually happens only for channel or exploder feeds, when the
-spawned program isn't keeping up with its input.
-.IP "\fBT\fR \fItype\fR" 4
-.IX Item "T type"
-This flag specifies the type of feed for this site. \fItype\fR should be a
-letter chosen from the following set:
-.Sp
-.Vb 6
-\& c Channel
-\& f File
-\& l Log entry only
-\& m Funnel (multiple entries feed into one)
-\& p Program
-\& x Exploder
-.Ve
-.Sp
-Each feed is described below in \*(L"\s-1FEED\s0 \s-1TYPES\s0\*(R". The default is \fBTf\fR,
-for a file feed.
-.IP "\fBU\fR \fIcount\fR" 4
-.IX Item "U count"
-If this flag is specified, an article will only be sent to this site if
-followups to this article would be posted to no more than \fIcount\fR
-newsgroups. (Also see \fBC\fR for a more complex way of handling this.)
-.IP "\fBW\fR \fIitems\fR" 4
-.IX Item "W items"
-For a file, channel, or exploder feed, this flag controls what information
-will be sent to this site. For a program feed, only the asterisk (\f(CW\*(C`*\*(C'\fR)
-has any effect. \fIitems\fR should be chosen from the following set:
-.RS 4
-.IP "b" 3
-.IX Item "b"
-Size of the article (in wire format, meaning with \s-1CRLF\s0 at the end of each
-line, periods doubled at the beginning of lines, and ending in a line with
-a single period) in bytes.
-.IP "e" 3
-.IX Item "e"
-The time the article will expire as seconds since epoch if it has an
-Expires: header, \f(CW0\fR otherwise.
-.IP "f" 3
-.IX Item "f"
-The storage \s-1API\s0 token of the article (the same as \f(CW\*(C`n\*(C'\fR). The article can
-be retrieved given the storage \s-1API\s0 token by using \fIsm\fR\|(8).
-.IP "g" 3
-.IX Item "g"
-The newsgroup the article is in; if cross\-posted, then the first of the
-groups to which the article was posted that this site gets. (The
-difference from \f(CW\*(C`G\*(C'\fR is that this sends the newsgroup to which the article
-was posted even if it is a control message.)
-.IP "h" 3
-.IX Item "h"
-The history hash key of the article (derived from the message \s-1ID\s0).
-.IP "m" 3
-.IX Item "m"
-The message \s-1ID\s0 of the article.
-.IP "n" 3
-.IX Item "n"
-The storage \s-1API\s0 token of the article. The article can be retrieved given
-the storage \s-1API\s0 token by using \fIsm\fR\|(8).
-.IP "p" 3
-.IX Item "p"
-The time the article was posted a seconds since epoch.
-.IP "s" 3
-.IX Item "s"
-The site that fed the article to the server. This is taken from either
-the Path: header or the \s-1IP\s0 address of the sending site depending on the
-value of \fIlogipaddr\fR in \fIinn.conf\fR. If \fIlogipaddr\fR is true and the \s-1IP\s0
-address is \f(CW0.0.0.0\fR (meaning that the article was fed from localhost by
-a program like \fIrnews\fR\|(8)), the Path: header value will be sent instead.
-.IP "t" 3
-.IX Item "t"
-The time the article was received as seconds since epoch.
-.IP "\&*" 3
-The names of the appropriate funnel entries, or all sites that get the
-article (see below for more details).
-.IP "D" 3
-.IX Item "D"
-The value of the Distribution: header of the article, or \f(CW\*(C`?\*(C'\fR if there is
-no such header in the article.
-.IP "G" 3
-.IX Item "G"
-Where the article is stored. If the newsgroup is crossposted, this is
-generally the first of the groups to which it was posted that this site
-receives; however, control messages are filed in control or control.*
-(which is the difference between this item and \f(CW\*(C`g\*(C'\fR).
-.IP "H" 3
-.IX Item "H"
-All of the headers, followed by a blank line. The Xref header will
-already be present, and a Bytes header containing the article's size in
-bytes as in the \f(CW\*(C`b\*(C'\fR item will be added to the headers. If used, this
-should be the only item in the list.
-.IP "N" 3
-.IX Item "N"
-The value of the Newsgroups: header.
-.IP "P" 3
-.IX Item "P"
-The value of the Path: header.
-.IP "O" 3
-.IX Item "O"
-Overview data for the article.
-.IP "R" 3
-.IX Item "R"
-Information needed for replication (the Xref header without the site
-name).
-.RE
-.RS 4
-.Sp
-More than one letter can be given. If multiple items are specified, they
-will be written in the order specified separated by spaces. (\f(CW\*(C`H\*(C'\fR should
-be the only item if given, but if it's not a newline will be sent before
-the beginning of the headers.) The default is \fBWn\fR.
-.Sp
-The \f(CW\*(C`H\*(C'\fR and \f(CW\*(C`O\*(C'\fR items are intended for use by programs that create news
-overview databases or require similar information. \fBWnteO\fR is the flag
-to generate input needed by the \fIoverchan\fR\|(8) program.
-.Sp
-The asterisk (\f(CW\*(C`*\*(C'\fR) has special meaning. Normally it expands to a
-space-separated list of all sites that received the current article. If,
-however, this site is a target of a funnel feed (in other words, if it is
-named by other sites which have the \fBTm\fR flag), then the asterisk expands
-to the names of the funnel feeds that received the article. Similarly, if
-the site is a program feed, an asterisk in the \fIparameter\fR field will be
-expanded into the list of funnel feeds that received the article. A
-program feed cannot get the site list unless it is the target of other
-\&\fBTm\fR feeds.
-.RE
-.SH "FEED TYPES"
-.IX Header "FEED TYPES"
-\&\fBinnd\fR provides four basic types of feeds: log, file, program, and
-channel. An exploder is a special type of channel. In addition, several
-entries can feed into the same feed; these are funnel feeds, which refer
-to an entry that is one of the other types. Funnel feeds are partially
-described above with the description of the \fBW*\fR flag. A funnel feed
-gets every article that would be sent to any of the feeds that funnel into
-it and normally include the \fBW*\fR flag in their flags so that the program
-processing that feed knows which sites received which articles. The most
-common funnel feed is \fIinnfeed\fR\|(8).
-.PP
-Note that the term \*(L"feed\*(R" is technically a misnomer, since the server
-doesn't transfer articles itself and only writes data to a file, program,
-or log telling another program to transfer the articles.
-.PP
-The simplest feed is a log feed (\fBTl\fR). Other than a mention in the news
-log file, \fIpathlog\fR/news, no data is written out. This is equivalent to
-a \fBTf\fR entry writing to \fI/dev/null\fR, except that no file is ever opened.
-Flushing a log feed does nothing.
-.PP
-A file feed (\fBTf\fR) is the next simplest type of feed. When the site
-should receive an article, the specified data is written out to the file
-named by the \fIparameter\fR field. If \fIparameter\fR is not an absolute path,
-it is taken to be relative to \fIpathoutgoing\fR in \fIinn.conf\fR. If
-\&\fIparameter\fR is not given, it defaults to \fIpathoutgoing\fR/\fIsitename\fR.
-The file name should be unique (two file feeds should not ever point to
-the same file).
-.PP
-File feeds are designed for use by external programs that periodically
-process the written data. To cooperate with \fBinnd\fR properly, such
-external programs should first rename the batch file and then send a flush
-command for that site to \fBinnd\fR using \fIctlinnd\fR\|(8). \fBinnd\fR will then
-write out any buffered data, close the file, and reopen it (under the
-original name), and the program can process the data in the renamed file
-at its leisure. File feeds are most frequently used in combination with
-\&\fInntpsend\fR\|(8).
-.PP
-A program feed (\fBTp\fR) spawns a given program for every article that the
-site receives. The \fIparamter\fR field must be the command line to execute,
-and should contain one instance of \f(CW%s\fR, which will be replaced by the
-storage \s-1API\s0 token of the article (the actual article can be retrieved by
-the program using \fIsm\fR\|(8)). The program will not receive anything on
-standard input (unlike earlier versions of \s-1INN\s0, where the article is sent
-to the program on stdin), and standard output and error from the program
-will be set to the error log (\fIpathlog\fR/errlog). \fBinnd\fR will try to
-avoid spawning a shell if the command has no shell meta\-characters; this
-feature can be defeated if necessary for some reason by appending a
-semi-colon to the end of the command. The full path name of the program
-to be run must be specified unless the command will be run by the shell
-(and it is strongly recommended that the full path name always be
-specified regardless).
-.PP
-If a program feed is the target of a funnel, and if \fBW*\fR appears in the
-flags of the site, a single asterisk may be present in the \fIparameter\fR
-and will be replaced by a space-separated list of names of the sites
-feeding into the funnel which received the relevant article. If the site
-is not the target of a funnel, or if the \fBW*\fR flag is not used, the
-asterisk has no special meaning.
-.PP
-Flushing a program feed does nothing.
-.PP
-For a channel (\fBTc\fR) or exploder (\fBTx\fR) feed, the \fIparameter\fR field
-again names the process to start. As with program feeds, the full path to
-the program must be specified. However, rather than spawning the program
-for every article, it is spawned once and then whenever the site receives
-an article, the data specified by the site flags is written to the
-standard input of the spawned program. Standard output and error are set
-as with program feeds. If the process exits, it will be restarted
-automatically. If the process cannot be started, the server will spool
-input to a file named \fIpathoutgoing\fR/\fIsitename\fR and will try to start
-the process again later.
-.PP
-When a channel or exploder feed is flushed, the server closes its end of
-the pipe to the program's standard input. Any pending data that has not
-been written will be spooled; see the description of the \fBS\fR flag above.
-The server will then spawn a new instance of the program. No signal is
-sent to the program; it is up to the program handling a channel or
-exploder feed to notice end of file on its standard input and exit
-appropriately.
-.PP
-Exploders are a special type of channel feed. In addition to the channel
-feed behavior described above, exploders can also be sent command lines.
-These lines start with an exclamation point and their interpretation is up
-to the exploder. The following commands are generated automatically by
-the server:
-.PP
-.Vb 4
-\& !newgroup group
-\& !rmgroup group
-\& !flush
-\& !flush site
-.Ve
-.PP
-These commands are sent whenever the \fIctlinnd\fR\|(8) command of the same name
-is received by the server. In addition, the \fIctlinnd\fR\|(8) \f(CW\*(C`send\*(C'\fR command
-can be used to send an arbitrary command line to an exploder. The primary
-exploder is \fIbuffchan\fR\|(8).
-.PP
-Finally, \fBTm\fR feeds are the input to a funnel. The \fIparameter\fR field of
-the site should name the site handling articles for all of the funnel
-inputs.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-All of the following examples assume that \s-1INN\s0 was installed with a prefix
-of \fI/usr/local/news\fR; if you installed it somewhere else, modify the
-paths as appropriate.
-.PP
-The syntax of the \fInewsfeeds\fR file is so complex because you can specify
-a staggering variety of feeds. \s-1INN\s0 is capable of interacting with a wide
-variety of programs that do various things with news articles. Far and
-away the most common two entries in \fInewsfeeds\fR, however, are file feeds
-for \fInntpsend\fR\|(8) and funnel feeds for \fIinnfeed\fR\|(8).
-.PP
-The former look like this:
-.PP
-.Vb 1
-\& feed.example.com:*,!control,!control.*,!junk:Tf,Wnm:
-.Ve
-.PP
-which generates a file named \fIpathoutgoing\fR/feed.example.com containing
-one line per article consisting of the storage \s-1API\s0 token, a space, and the
-message \s-1ID\s0.
-.PP
-The latter look like this:
-.PP
-.Vb 1
-\& feed.example.com:*,!control,!control.*,!junk:Tm:innfeed!
-.Ve
-.PP
-Very similar, except that this is the input to a funnel feed named
-\&\f(CW\*(C`innfeed!\*(C'\fR. One could also write this as:
-.PP
-.Vb 1
-\& example/feed.example.com:*,!control,!control.*,!junk:Ap,Tm:innfeed!
-.Ve
-.PP
-(note the \fBAp\fR so that articles that contain just \f(CW\*(C`example\*(C'\fR in the Path:
-header will still be sent), which is completely equivalent except that
-this will be logged in \fIpathlog\fR/news as going to the site \f(CW\*(C`example\*(C'\fR
-rather than \f(CW\*(C`feed.example.com\*(C'\fR.
-.PP
-The typical feed entry for \fIinnfeed\fR\|(8) is a good example of a channel feed
-that's the target of various funnel feeds:
-.PP
-.Vb 1
-\& innfeed!:!*:Tc,Wnm*:/usr/local/news/bin/startinnfeed \-y
-.Ve
-.PP
-Note that the \fIpattern\fR for this feed is just \f(CW\*(C`!*\*(C'\fR so that it won't
-receive any articles directly. The feed should only receive those
-articles that would go to one of the funnel feeds that are feeding into
-it. \fIinnfeed\fR\|(8) (spawned by \fBstartinnfeed\fR) will receive one line per
-article on its standard input containing the storage \s-1API\s0 token, the
-message \s-1ID\s0, and a space-separated list of sites that should receive that
-article.
-.PP
-Here's a more esoteric example of a channel feed:
-.PP
-.Vb 2
-\& watcher!:*:Tc,Wbnm\e
-\& :exec awk '$1 > 1000000 { print "BIG", $2, $3 }' > /dev/console
-.Ve
-.PP
-This receives the byte size of each article along with the storage \s-1API\s0
-token and message \s-1ID\s0, and prints to the console a line for every article
-that's over a million bytes. This is actually rather a strange way to
-write this since \s-1INN\s0 can do the size check itself; the following is
-equivalent:
-.PP
-.Vb 2
-\& watcher!:*:Tc,>1000000,Wbnm\e
-\& :exec awk '{ print "BIG", $2, $3}' > /dev/console
-.Ve
-.PP
-Here's a cute, really simple news to mail gateway that also serves as an
-example of a fairly fancy program feed:
-.PP
-.Vb 2
-\& mailer!:!*:W*,Tp\e
-\& :sm %s | innmail \-s "News article" *
-.Ve
-.PP
-Remember that \f(CW%s\fR is replaced by the storage \s-1API\s0 token, so this
-retrieves the article and pipes it into \fBinnmail\fR (which is safer than
-programs like \fIMail\fR\|(1) because it doesn't parse the body for tilde
-commands) with a given subject line. Note the use of \f(CW\*(C`*\*(C'\fR in the command
-line and \fBW*\fR in the flags; this entry is designed to be used as the
-target of funnel feeds such as:
-.PP
-.Vb 2
-\& peter@example.com:news.software.nntp:Tm:mailer!
-\& sue@example.com:news.admin.misc:Tm:mailer!
-.Ve
-.PP
-Suppose that the server receives an article crossposted between
-news.admin.misc and news.software.nntp. The server will notice that the
-article should be sent to the site \f(CW\*(C`peter@example.com\*(C'\fR and the site
-\&\f(CW\*(C`bob@example.com\*(C'\fR, both of which funnel into \f(CW\*(C`mailer!\*(C'\fR, so it will look
-at the \f(CW\*(C`mailer!\*(C'\fR site and end up executing the command line:
-.PP
-.Vb 1
-\& sm @...@ | innmail \-s "News article" peter@example.com sue@example.com
-.Ve
-.PP
-which will mail the article to both Peter and Sue.
-.PP
-Finally, another very useful example of a channel feed: the standard
-entry for \fIcontrolchan\fR\|(8).
-.PP
-.Vb 3
-\& controlchan!\e
-\& :!*,control,control.*,!control.cancel/!collabra\-internal\e
-\& :Tc,Wnsm:/usr/local/news/bin/controlchan
-.Ve
-.PP
-This program only wants information about articles posted to a control
-newsgroup other than control.cancel, which due to the sorting of control
-messages described in \fIinnd\fR\|(8) will send it all control messages except for
-cancel messages. In this case, we also exclude any article with a
-distribution of \f(CW\*(C`collabra\-internal\*(C'\fR. \fBcontrolchan\fR gets the storage
-\&\s-1API\s0 token, the name of the sending site (for processing old-style ihave
-and sendme control messages, be sure to read about \fIlogipaddr\fR in
-\&\fIcontrolchan\fR\|(8)), and the message \s-1ID\s0 for each article.
-.PP
-For many other examples, including examples of the special \f(CW\*(C`ME\*(C'\fR site
-entry, see the example \fInewsfeeds\fR file distributed with \s-1INN\s0. Also see the
-install documentation that comes with \s-1INN\s0 for information about setting up
-the standard newsfeeds entries used by most sites.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Reformatted
-and rewritten in \s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: newsfeeds.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactive\fR\|(5), \fIbuffchan\fR\|(8), \fIcontrolchan\fR\|(8), \fIctlinnd\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8),
-\&\fIinnfeed\fR\|(8), \fIinnxmit\fR\|(8), \fInntpsend\fR\|(8), \fIuwildmat\fR\|(3).
+++ /dev/null
-.TH NEWSLOG 5
-.SH NAME
-newslog \- description of Usenet log files
-.SH DESCRIPTION
-Most log files created by Usenet programs reside in the
-.I <pathlog in inn.conf>
-directory and have a ``.log'' extension.
-Several versions are usually kept with an additional extension such as ``.1'',
-``.2'', etc. \(em the higher the number, the older the log.
-The older versions may be compressed and thus may have a ``.1.gz'',
-``.2.gz'', etc. extension.
-.PP
-The
-.I scanlogs
-script and related utilities (see
-.IR scanlogs (8))
-are responsible for rotating and compressing these files.
-.PP
-Some log files always have data, others only have data if there is a
-problem, and others are only created if a particular program is used
-or configuration parameter is set.
-The
-.I innstat
-script (see
-.IR innstat (8))
-monitors the size of all log files.
-.PP
-The following files will only accumulate data under the direction of
-.IR control.ctl (5):
-.sp 1
-.RS
-control.log
-miscctl.log
-newgroup.log
-rmgroup.log
-unwanted.log
-.RE
-.sp 1
-In order to create these files, the ``message'' and ``action'' fields of
-.I control.ctl
-should be chosen from the following table:
-.sp 1
-.RS
-.nf
-.ta \w'newgroup 'u +\w'doit=newgroup 'u
-Message Action Meaning
-all log=miscctl Log all messages by default
-default log=miscctl Log unknown messages
-newgroup doit=newgroup Create group and log message
-newgroup log=newgroup Log message
-rmgroup doit=rmgroup Remove group and log message
-rmgroup log=rmgroup Log message
-``other'' doit=miscctl log and process the message
-``other'' log=miscctl Log message
-.fi
-.RE
-.sp 1
-Here, ``other'' refers to any other control message such as:
-.sp 1
-.RS
-.nf
-checkgroups
-ihave
-sendme
-sendsys
-senduuname
-version
-.fi
-.RE
-.PP
-The following is a list of log files:
-.TP
-.I control.log
-This file maintains a count of the number of newgroup and rmgroup control
-messages seen for each newsgroup.
-The count is of the number of control messages with the indicated
-arguments, regardless if they were actually processed.
-All control arguments, including invalid ones, are counted.
-This file is updated by
-.IR tally.control ,
-which is invoked by
-.I scanlogs
-if either the newgroup or rmgroup logs exist.
-This file is not rotated.
-.TP
-.I errlog
-This file contains the standard output and standard error of any program
-spawned by
-.IR innd (8),
-such as channel feeds configured in
-.IR newsfeeds .
-This file should normally be empty.
-.I Scanlogs
-will print the entire contents of this log file if it is non-empty.
-.TP
-.I expire.log
-By default, when
-.I news.daily
-is going to expire old news articles, it writes the date to this file,
-followed by any output from
-.IR expire (8)
-and the ending date.
-All lines but the first are indented four spaces.
-.TP
-.I miscctl.log
-When
-.I control.ctl
-is configured as described above, all control messages except newgroup
-and rmgroup are appended to this file by
-.IR writelog .
-There will be a summary line describing the message and the action
-taken, followed by the article indented by four spaces, and a blank line.
-.TP
-.I newgroup.log
-When
-.I control.ctl
-is configured as described above, all newgroup messages are appended
-to this file using the same format as for
-.IR miscctl.log .
-.TP
-.I news
-This file logs articles received by
-.IR innd .
-.I Scanlogs
-summarizes the rejected articles reported in this file.
-.TP
-.I news.crit
-All critical error messages issued by
-.I innd
-are appended to this file via
-.IR syslog (3).
-This log file should be empty.
-.I Scanlogs
-will print the entire contents of this log file if it is non-empty.
-You should have the following line in your system
-.I syslog.conf
-file, using a tab character for the delimiter:
-.sp 1
-.RS
-.RS
-news.crit <pathlog in inn.conf>/news.crit
-.RE
-.RE
-.sp 1
-(A typical entry is shown; it should agree with
-.I <pathlog in inn.conf>.)
-.TP
-.I news.err
-All major error messages issued by
-.I innd
-are appended to this file via
-.IR syslog (3).
-This log file should be empty.
-.I Scanlogs
-will print the entire contents of this log file if it is non-empty.
-You should have the following line in your system
-.I syslog.conf
-file, using a tab character for the delimiter:
-.sp 1
-.RS
-.RS
-news.err <pathlog in inn.conf>/news.err
-.RE
-.RE
-.sp 1
-(A typical entry is shown; it should agree with
-.I <pathlog in inn.conf>.)
-.TP
-.I news.notice
-All standard error messages and status messages issued by
-.I innd
-are appended to this file via
-.IR syslog (3).
-.I Scanlogs
-uses the
-.IR perl (1)
-script
-.IR innreport (8)
-to summarize this file.
-You should have the following line in your system
-.I syslog.conf
-file, using a tab character for the delimiter:
-.sp 1
-.RS
-.RS
-news.notice <pathlog in inn.conf>/news.notice
-.RE
-.RE
-(A typical entry is shown; it should agree with
-.I <pathlog in inn.conf>.)
-.TP
-.I nntpsend.log
-The
-.IR nntpsend (8)
-programs appends all status messages to this file.
-.TP
-.I rmgroup.log
-When
-.I control.ctl
-is configured as described above, all rmgroup messages are appended to this
-file using the same format as for
-.IR miscctl.log .
-.TP
-.I unwanted.log
-This log maintains a count of the number of articles that were rejected
-because they were posted to newsgroups that do not exist at the local site.
-This file is updated by
-.I tally.unwanted
-and maintained in reverse numeric order (the most popular rejected group
-first).
-This file is not rotated.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: newslog.5 6398 2003-07-12 19:15:50Z rra $
-.SH "SEE ALSO"
-control.ctl(5),
-ctlinnd(8),
-expire(8),
-inn.conf(5),
-innd(8),
-news.daily(8),
-nntpsend(8),
-syslog.conf(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "NINPATHS 8"
-.TH NINPATHS 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ninpaths \- Report Usenet Path statistics (new inpaths)
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBninpaths\fR \fB\-p\fR \fB\-d\fR \fIdumpfile\fR
-.PP
-\&\fBninpaths\fR \fB\-r\fR \fIsite\fR \fB\-u\fR \fIdumpfile\fR [\fB\-u\fR \fIdumpfile\fR ...] \fB\-v\fR
-\&\fIlevel\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This is an efficient and space-saving inpaths reporting program. It works
-as follows: you feed it the Path lines via an \s-1INN\s0 channel feed or some
-other similar method, and from time to time the program writes all its
-internal counters accumulated so far to a dump file. Another instance of
-the program picks up all the dump files, adds them up and formats them
-into the report. The purpose of the final report is to summarize the
-frequency of occurrence of sites in the Path headers of articles.
-.PP
-Some central sites accumulate the Path data from many news servers running
-this program or one like it, and then report statistics on the most
-frequently seen news servers in Usenet article Path lines. The
-\&\fBsendinpaths\fR shell script can be run once a month to mail the
-accumulated statistics to such a site and remove the old dump files.
-.PP
-You can get a working setup by doing the following:
-.IP "1." 4
-Create a directory at \fIpathlog\fR/path (replacing \fIpathlog\fR here and in
-all steps that follow with the full path to your \s-1INN\s0 log directory).
-.IP "2." 4
-Set up a channel feed using an entry like:
-.Sp
-.Vb 1
-\& inpaths!:*:Tc,WP:ninpaths \-p \-d <pathlog>/path/inpaths.%d
-.Ve
-.Sp
-if your version of \s-1INN\s0 supports \s-1WP\s0 (2.0 and later all do). Replace
-<pathlog> with the full path to your \s-1INN\s0 log directory.
-.IP "3." 4
-Enter into your news user crontab something like:
-.Sp
-.Vb 1
-\& 6 6 * * * ctlinnd flush inpaths!
-.Ve
-.Sp
-(the actual time doesn't matter). This will force \fBninpaths\fR to generate
-a dump file once a day.
-.IP "4." 4
-Once per month, run the \fBsendinpaths\fR script, which collects the dumps,
-makes a report, and then deletes the old dumps. (You can generate a
-report without mailing it and without deleting it with \f(CW\*(C`sendinpaths \-n\*(C'\fR.)
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-d\fR \fIdumpfile\fR" 4
-.IX Item "-d dumpfile"
-Save dumps in \fIdumpfile\fR. Any \f(CW%d\fR in \fIdumpfile\fR will be replaced with
-the current system time when the dump is made. This option should be used
-with \fB\-p\fR.
-.IP "\fB\-p\fR" 4
-.IX Item "-p"
-Read Path lines from standard input.
-.IP "\fB\-r\fR \fIsite\fR" 4
-.IX Item "-r site"
-Generate a report for \fIsite\fR. Generally \fIsite\fR should be the value of
-\&\fIpathhost\fR from \fIinn.conf\fR.
-.IP "\fB\-u\fR \fIdumpfile\fR" 4
-.IX Item "-u dumpfile"
-Read data from \fIdumpfile\fR. This option can be repeated to read data from
-multiple dump files.
-.IP "\fB\-v\fR \fIlevel\fR" 4
-.IX Item "-v level"
-Set the verbosity level of the report. Valid values for \fIlevel\fR are 0,
-1, and 2, with 2 being the default.
-.SH "NOTES"
-.IX Header "NOTES"
-If your \s-1INN\s0 doesn't have the \s-1WP\s0 feed flag (1.5 does not, 1.6 does, 1.7 I
-don't know, 2.0 and later all do), use the following newsfeeds entry:
-.PP
-.Vb 1
-\& inpaths!:*:Tc,WH:ginpaths
-.Ve
-.PP
-where \fBginpaths\fR is the following script:
-.PP
-.Vb 2
-\& #!/bin/sh
-\& exec egrep '^Path: ' | ninpaths \-p \-d <pathlog>/path/inpaths.%d
-.Ve
-.PP
-replacing <pathlog> as above.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInewsfeeds\fR\|(5), \fIsendinpaths\fR\|(8)
-.PP
-This is a slightly modified version of Olaf Titz's original ninpaths
-program, which is posted to alt.sources and kept on his \s-1WWW\s0 archive under
-<http://sites.inka.de/~bigred/sw/>.
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBninpaths\fR was written by Olaf Titz <olaf@bigred.inka.de>.
-.PP
-The idea and some implementation details for ninpaths come from the
-original inpaths program, but most of the code has been rewritten for
-clarity. This program is in the public domain.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "NNRPD 8"
-.TH NNRPD 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-nnrpd \- NNTP server for reader clients
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBnnrpd\fR [\fB\-DfnoSt\fR] [\fB\-b\fR \fIaddress\fR] [\fB\-c\fR \fIconfigfile\fR]
-[\fB\-g\fR \fIshadowgroup\fR>] [\fB\-i\fR \fIinitial\fR] [\fB\-I\fR \fIinstance\fR] [\fB\-p\fR \fIport\fR]
-[\fB\-P\fR \fIprefork\fR] [\fB\-r\fR \fIreason\fR] [\fB\-s\fR \fIpadding\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBnnrpd\fR is an \s-1NNTP\s0 server for newsreaders. It accepts commands on its
-standard input and responds on its standard output. It is normally
-invoked by \fIinnd\fR\|(8) with those descriptors attached to a remote client
-connection. \fBnnrpd\fR also supports running as a standalone daemon.
-.PP
-Unlike \fIinnd\fR\|(8) \fBnnrpd\fR supports all \s-1NNTP\s0 commands for user-oriented
-reading and posting. \fBnnrpd\fR uses the \fIreaders.conf\fR file to control
-who is authorized to access the Usenet database.
-.PP
-On exit, \fBnnrpd\fR will report usage statistics through \fIsyslog\fR\|(3).
-.PP
-\&\fBnnrpd\fR only reads config files (both \fIreaders.conf\fR and \fIinn.conf\fR)
-when it is spawned. You can therefore never change the behavior of a
-client that's already connected. If \fBnnrpd\fR is run from \fBinnd\fR (the
-default) or from \fIinetd\fR\|(8), \fIxinetd\fR\|(8), or some equivalent, a new \fBnnrpd\fR
-process is spawned for every connection and therefore any changes to
-configuration files will be immediately effective for all new
-connections. If you are instead running \fBnnrpd\fR with the \fB\-D\fR option,
-any configuration changes won't take effect until \fBnnrpd\fR is restarted.
-.PP
-The \fIinn.conf\fR setting \fInnrpdflags\fR can be used to pass any of the
-options below to instances of \fBnnrpd\fR that are spawned directly from
-\&\fBinnd\fR. Many options only make sense when \fB\-D\fR is used, so these
-options should not be used with \fInnrpdflags\fR. See also the discussion
-of \fInnrpdflags\fR in \fIinn.conf\fR\|(5).
-.PP
-When \fInnrpdloadlimit\fR in \fIinn.conf\fR is not 0, it will also reject
-connections if the load average is greater than that value (typically 16).
-\&\fBnnrpd\fR can also prevent high-volume posters from abusing your
-resources. See the discussion of exponential backoff in \fIinn.conf\fR\|(5).
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-b\fR \fIaddress\fR" 4
-.IX Item "-b address"
-The \fB\-b\fR parameter instructs \fBnnrpd\fR to bind to the specified \s-1IP\s0
-address when started as a standalone daemon using the \fB\-D\fR flag. This
-has to be a valid IPv4 or IPv6 address belonging to an interface of
-the local host. It can also be ::0 (although the default is 0.0.0.0
-if unspecified).
-.IP "\fB\-c\fR \fIconfigfile\fR" 4
-.IX Item "-c configfile"
-By default, \fBnnrpd\fR reads the \fIreaders.conf\fR to determine how to
-authenticate connections. The \fB\-c\fR flag specifies an alternate file
-for this purpose. If the file name isn't fully qualified, it is taken
-to be relative to \fIpathetc\fR in \fIinn.conf\fR (this is useful to have
-several instances of \fBnnrpd\fR running on different ports or \s-1IP\s0
-addresses with different settings.)
-.IP "\fB\-D\fR" 4
-.IX Item "-D"
-If specified, this parameter causes \fBnnrpd\fR to operate as a
-daemon. That is, it detaches itself and runs in the background,
-forking a process for every connection. By default \fBnnrpd\fR listens on
-the \s-1NNTP\s0 port (119), so either \fIinnd\fR\|(8) has to be started on another
-port or \fBnnrpd\fR \fB\-p\fR parameter. Note that with this parameter,
-\&\fBnnrpd\fR continues running until killed. This means that it reads
-\&\fIinn.conf\fR once on startup and never again until restarted. \fBnnrpd\fR
-should therefore be restarted if inn.conf is changed.
-.Sp
-When started in daemon mode, \fBnnrpd\fR will write its \s-1PID\s0 into a file in
-the \fIpathrun\fR directory. The file will be named \fInnrpd\-%d.pid\fR, where
-\&\f(CW%d\fR is replaced with the port that \fBnnrpd\fR is configured to listen on
-(119 unless the \fB\-p\fR option is given).
-.IP "\fB\-f\fR" 4
-.IX Item "-f"
-If specified, \fBnnrpd\fR does not detach itself and runs in the
-foreground when started as a standalone daemon using the \fB\-D\fR flag.
-.IP "\fB\-g\fR \fIshadowgroup\fR" 4
-.IX Item "-g shadowgroup"
-On systems that have a shadow password file, \fBnnrpd\fR tries to add the
-group \fIshadow\fR as a supplementary group if it is running in
-standalone mode. On many systems, members of that group have read
-permission for the shadow password file. The \fB\-g\fR parameter instructs
-\&\fBnnrpd\fR to try to add the named group as a supplementary group on
-shadow systems instead of \fIshadow\fR. This only works if
-\&\f(CW\*(C`HAVE_GETSPNAM\*(C'\fR in \fIinclude/config.h\fR is defined and \fBnnrpd\fR is
-running in standalone mode since this call only works when \fBnnrpd\fR is
-started as root.
-.IP "\fB\-i\fR \fIinitial\fR" 4
-.IX Item "-i initial"
-Specify an initial command to \fBnnrpd\fR. When used, \fIinitial\fR is taken
-as if it were the first command received by \fBnnrpd\fR.
-.IP "\fB\-I\fR \fIinstance\fR" 4
-.IX Item "-I instance"
-If specified \fIinstance\fR is used as an additional static portion
-within MessageIDs generated by \fBnnrpd\fR; typically this option would
-be used where a cluster of machines exist with the same virtual
-hostname and must be disambiguated during posts.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-The \fB\-n\fR flag turns off resolution of \s-1IP\s0 addresses to names. If you
-only use IP-based restrictions in \fIreaders.conf\fR and can handle \s-1IP\s0
-addresses in your logs, using this flag may result in some additional
-speed.
-.IP "\fB\-o\fR" 4
-.IX Item "-o"
-The \fB\-o\fR flag causes all articles to be spooled instead of sending
-them to \fIinnd\fR\|(8). \fBrnews\fR with the \fB\-U\fR flag should be invoked from
-cron on a regular basis to take care of these articles. This flag is
-useful if \fIinnd\fR\|(8) in accepting articles and \fBnnrpd\fR is started
-standalone or using \fIinetd\fR\|(8).
-.IP "\fB\-p\fR \fIport\fR" 4
-.IX Item "-p port"
-The \fB\-p\fR parameter instructs \fBnnrpd\fR to listen on \fIport\fR when
-started as a standalone daemon using the \fB\-D\fR flag.
-.IP "\fB\-P\fR \fIprefork\fR" 4
-.IX Item "-P prefork"
-The \fB\-P\fR parameter instructs \fBnnrpd\fR to prefork \fIprefork\fR children
-awaiting connections when started as a standalone daemon using the
-\&\fB\-D\fR flag.
-.IP "\fB\-r\fR \fIreason\fR" 4
-.IX Item "-r reason"
-If the \fB\-r\fR flag is used, then \fBnnrpd\fR will reject the incoming
-connection giving \fIreason\fR as the text. This flag is used by \fIinnd\fR\|(8)
-when it is paused or throttled.
-.IP "\fB\-s\fR \fIpadding\fR" 4
-.IX Item "-s padding"
-As each command is received, \fBnnrpd\fR tries to change its \f(CW\*(C`argv\*(C'\fR
-array so that \fIps\fR\|(1) will print out the command being executed. To get
-a full display, the \fB\-s\fR flag may be used with a long string as its
-argument, which will be overwritten when the program changes its
-title.
-.IP "\fB\-S\fR" 4
-.IX Item "-S"
-If specified, \fBnnrpd\fR will start a negotiation for \s-1SSL\s0 session as
-soon as connected. To use this flag, \f(CW\*(C`\-\-with\-openssl\*(C'\fR must have been
-specified at \f(CW\*(C`configure\*(C'\fR time.
-.IP "\fB\-t\fR" 4
-.IX Item "-t"
-If the \fB\-t\fR flag is used then all client commands and initial
-responses will be traced by reporting them in syslog. This flag is set
-by \fIinnd\fR\|(8) under the control of the \fIctlinnd\fR\|(8) \f(CW\*(C`trace\*(C'\fR command, and
-is toggled upon receipt of a \f(CW\*(C`SIGHUP\*(C'\fR; see \fIsignal\fR\|(2).
-.SH "SSL SUPPORT"
-.IX Header "SSL SUPPORT"
-If \s-1INN\s0 is built with \f(CW\*(C`\-\-with\-openssl\*(C'\fR, \fBnnrpd\fR will support news reading
-over \s-1TLS\s0 (also known as \s-1SSL\s0). For clients that use the \s-1STARTTLS\s0 command,
-no special configuration is needed beyond creating a \s-1TLS/SSL\s0 certificate
-for the server. You should do this in exactly the same way that you would
-generate a certificate for a web server.
-.PP
-If you're happy with a self-signed certificate (which will generate
-warnings with some news reader clients), you can create and install one in
-the default path by running \f(CW\*(C`make cert\*(C'\fR after \f(CW\*(C`make install\*(C'\fR when
-installing \s-1INN\s0, or by running the following commands:
-.PP
-.Vb 6
-\& openssl req \-new \-x509 \-nodes \-out /usr/local/news/lib/cert.pem \e
-\& \-days 366 \-keyout /usr/local/news/lib/key.pem
-\& chown news:news /usr/local/news/lib/cert.pem
-\& chmod 640 /usr/local/news/lib/cert.pem
-\& chown news:news /usr/local/news/lib/key.pem
-\& chmod 600 /usr/local/news/lib/key.pem
-.Ve
-.PP
-Replace the paths with something appropriate to your \s-1INN\s0 installation.
-This will create a self-signed certificate that will expire in a year.
-The \fBopenssl\fR program will ask you a variety of questions about your
-organization. Enter the fully qualified domain name of the server as the
-name the certificate is for.
-.PP
-Most news clients currently do not use the \s-1STARTTLS\s0 command, however, and
-instead expect to connect to a separate port (563) and start an \s-1SSL\s0
-negotiation immediately. \fBinnd\fR does not, however, know how to listen
-for connections to that port and then spawn \fBnnrpd\fR the way that it does
-for regular reader connections. You will therefore need to arrange for
-\&\fBnnrpd\fR to listen on that port through some other means. This can be
-done with the \fB\-D\fR flag (and \f(CW\*(C`\-P 563\*(C'\fR), but the easiest way is probably
-to add a line like:
-.PP
-.Vb 1
-\& nntps stream tcp nowait news /usr/lib/news/bin/nnrpd nnrpd \-S
-.Ve
-.PP
-to \fI/etc/inetd.conf\fR or the equivalent on your system and let \fBinetd\fR
-run \fBnnrpd\fR. (Change the path to \fBnnrpd\fR to match your installation if
-needed.) You may need to replace \f(CW\*(C`nntps\*(C'\fR with \f(CW563\fR if \f(CW\*(C`nntps\*(C'\fR isn't
-defined in \fI/etc/services\fR on your system.
-.SH "PROTOCOL DIFFERENCES"
-.IX Header "PROTOCOL DIFFERENCES"
-\&\fBnnrpd\fR implements the \s-1NNTP\s0 commands defined in \s-1RFC\s0 977, with the
-following differences:
-.IP "1." 4
-The \f(CW\*(C`slave\*(C'\fR command is not implemented. This command has never been
-fully defined.
-.IP "2." 4
-The \f(CW\*(C`list\*(C'\fR command may be followed by the optional word \f(CW\*(C`active.times\*(C'\fR,
-\&\f(CW\*(C`distributions\*(C'\fR, \f(CW\*(C`distrib.pats\*(C'\fR, \f(CW\*(C`moderators\*(C'\fR, \f(CW\*(C`newsgroups\*(C'\fR,
-\&\f(CW\*(C`subscriptions\*(C'\fR, or \f(CW\*(C`Ioverview.fmt\*(C'\fR to get a list of when newsgroups
-where created, a list of valid distributions, a file specifying default
-distribution patterns, moderators list, a one-per-line description of the
-current set of newsgroups, a list of the automatic group subscriptions, or
-a listing of the \fIoverview.fmt\fR file.
-.Sp
-The command \f(CW\*(C`list active\*(C'\fR is equivalent to the \f(CW\*(C`list\*(C'\fR command. This
-is a common extension.
-.IP "3." 4
-The \f(CW\*(C`xhdr\*(C'\fR, \f(CW\*(C`authinfo user\*(C'\fR and \f(CW\*(C`authinfo pass\*(C'\fR commands are
-implemented. These are based on the reference Unix implementation. See
-\&\s-1RFC\s0 2980.
-.IP "4." 4
-A new command, \f(CW\*(C`xpat header range|MessageID pat [morepat...]\*(C'\fR, is
-provided. The first argument is the case-insensitive name of the header
-to be searched. The second argument is either an article range or a
-single Message\-ID, as specified in \s-1RFC\s0 977. The third argument is a
-\&\f(CW\*(C`uwildmat\*(C'\fR(3)\-style pattern; if there are additional arguments they are
-joined together separated by a single space to form the complete pattern.
-This command is similar to the \f(CW\*(C`xhdr\*(C'\fR command. It returns a \f(CW221\fR
-response code, followed by the text response of all article numbers that
-match the pattern.
-.IP "5." 4
-The \f(CW\*(C`listgroup group\*(C'\fR command is provided. This is a comment extension.
-It is equivalent to the \f(CW\*(C`group\*(C'\fR command, except that the reply is a
-multi-line response containing the list of all article numbers in the
-group.
-.IP "6." 4
-The \f(CW\*(C`xgtitle [group]\*(C'\fR command is provided. This extension is used by
-ANU\-News. It returns a \f(CW282\fR reply code, followed by a one-line
-description of all newsgroups thatmatch the pattern. The default is the
-current group.
-.IP "7." 4
-The \f(CW\*(C`xover [range]\*(C'\fR command is provided. It returns a \f(CW224\fR reply code,
-followed by the overview data for the specified range; the default is to
-return the data for the current article.
-.IP "8." 4
-The \f(CW\*(C`xpath MessageID\*(C'\fR command is provided; see \fIinnd\fR\|(8).
-.IP "9." 4
-The \f(CW\*(C`date\*(C'\fR command is provided; this is based on the draft \s-1NNTP\s0 protocol
-revision (draft\-ietf\-nntpext\-imp\-04.txt). It returns a one-line response
-code of \f(CW111\fR followed by the \s-1GMT\s0 date and time on the server in the form
-\&\f(CW\*(C`YYYYMMDDhhmmss\*(C'\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Overview
-support added by Rob Robertston <rob@violet.berkeley.edu> and Rich in
-January, 1993. Exponential backoff (for posting) added by Dave Hayes in
-Febuary 1998.
-.PP
-$Id: nnrpd.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIctlinnd\fR\|(8), \fIinnd\fR\|(8), \fIinn.conf\fR\|(5), \fIsignal\fR\|(2), \fIuwildmat\fR\|(3).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH NNRPD.TRACK 5
-.SH NAME
-nnrpd.track \- file to specify hosts to be tracked by nnrpd.
-.SH DESCRIPTION
-This file, which is located in
-.I <pathetc in inn.conf>,
-specifies which hosts are to have their activities recorded during an
-.I nnrpd
-session.
-The
-.I nnrpd
-server reads it when first spawned by
-.IR innd ,
-provided
-.I readertrack
-in
-.I inn.conf
-is true; otherwise this file is not used.
-.PP
-Entries consist of one host specification per line, each line having two
-fields, separated by a colon:
-.RS
-.nf
-
-host:identity
-.fi
-.RE
-.PP
-The first field is either the FQDN of a host, or a domain name (in
-the form *.domain.com).
-.PP
-The second field is simply a segment of text which may be used to
-more easily identify the client, typically an e-mail address or other
-identifying mark.
-.PP
-For example:
-.RS
-.nf
-
-nasty.foo.com:nasty@foo.com
-*.bar.com:VeryNastyClient
-.fi
-.RE
-.PP
-Written by Steve Carrie <stephenc@uk.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: nnrpd.track.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5),
-innd(8),
-newsfeeds(5),
-nnrpd(8),
+++ /dev/null
-.\" $Revision: 5909 $
-.TH NNTPGET 1
-.SH NAME
-nntpget \- get Usenet articles from a remote NNTP server
-.SH SYNOPSIS
-.I nntpget
-[
-.BI \-d " dist"
-]
-[
-.BI \-f " file"
-]
-[
-.BI \-n " newsgroups"
-]
-[
-.BI \-t " timestring"
-]
-[
-.B \-o
-]
-[
-.BI \-u " file"
-]
-[
-.B \-v
-]
-.I host
-.SH DESCRIPTION
-.I Nntpget
-connects to the NNTP server at the specified
-.I host
-and retrieves articles from it. The Message-ID's of the desired articles
-are read from standard input. The articles are sent to standard output.
-.SH OPTIONS
-.TP
-.B \-o
-The ``\-o'' option may be used only if the command is executed on the
-host where the
-.IR innd (8)
-server is running.
-If this option is used,
-.I nntpget
-connects to the specified remote
-.I host
-to retrieve articles.
-Any article not present in the local
-.I history
-database is then fetched from the remote site and offered to the local server.
-.TP
-.B \-v
-If the ``\fB\-v\fP'' option is used with the ``\fB\-o\fP'' option then the
-Message-ID
-of each article will be sent to standard output as it is processed.
-.TP
-.B \-f
-The list of article Message-ID's is normally read from standard input.
-If the ``\fB\-f\fP'' option is used, then a ``newnews'' command is used
-to retrieve
-all articles newer then the modification date of the specified
-.IR file .
-.TP
-.B \-u
-The ``\fB\-u\fP'' option is like ``\fB\-f\fP'' except that if the transfer
-succeedes, the file will be updated with a statistics line, modifying its
-timestamp so that it can be used in later invocations.
-.TP
-.B \-t
-If the ``\-t'' option is used, then the specified
-.I timestring
-is used as the time and date parameter to the ``newnews'' command.
-.TP
-.B \-n
-If either the ``\fB\-u\fP'' or ``\fB\-f\fP'' options are used, then
-the ``\fB\-n\fP'' option
-may be used to specify a newsgroup list. The default is ``*''.
-.TP
-.B \-d
-The ``\fB\-d\fP'' option may be
-used to specify a distribution list when using the ``\fB\-u\fP''
-or ``\fB\-f\fP'' options.
-The default is no distribution list.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: nntpget.1 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-innd(8).
+++ /dev/null
-.TH NNTPSEND 8
-.SH NAME
-nntpsend \- send Usenet articles to remote site
-.SH SYNOPSIS
-.B nntpsend
-[
-.B \-a
-]
-[
-.B \-c
-]
-[
-.B \-D
-]
-[
-.B \-d
-]
-[
-.B \-l
-]
-[
-.B \-N
-]
-[
-.B \-n
-]
-[
-.BI \-P " portnum"
-]
-[
-.B \-p
-]
-[
-.B \-r
-]
-[
-.B \-S
-]
-[
-.BI \-s " size"
-]
-[
-.BI \-T " timelimit"
-]
-[
-.BI \-t " timeout"
-]
-[
-.BI \-w " delay"
-]
-[
-.I sitename
-.I fqdn
-] ...
-.SH DESCRIPTION
-.I Nntpsend
-is a front-end that invokes
-.IR innxmit (1)
-to send Usenet articles to a remote NNTP site.
-.PP
-The sites to be fed may be specified by giving
-.I sitename
-.I fqdn
-pairs on the command line.
-If no such pairs are given,
-.I nntpsend
-defaults to the information given in the
-.I nntpsend.ctl
-config file.
-.PP
-The
-.I sitename
-should be the name of the site as specified in the
-.IR newsfeeds (5)
-file.
-The
-.I fqdn
-should be the hostname or IP address of the remote site.
-.PP
-An
-.I innxmit
-is launched for sites with queued news.
-All
-.I innxmit
-processes are spawned in the background and the script waits for
-them all to finish before returning.
-Output is sent to the file
-.IR <pathlog\ in\ inn.conf>/nntpsend.log .
-In order to keep from overwhelming the local system,
-.I nntpsend
-waits five seconds before spawning each child.
-.PP
-.I Nntpsend
-expects that the batchfile for a site is named
-.IR <pathoutgoing\ in\ inn.conf>/sitename .
-To prevent batchfile corruption,
-.IR shlock (1)
-is used to ``lock'' these files.
-.PP
-When
-.I sitename
-.I fqdn
-pairs are given on the command line,
-any flags given on the command completely describe how
-.I innxmit
-and
-.I shrinkfile
-operate.
-When no such pairs are given on the command line, then
-the information found in
-.I nntpsend.ctl
-becomes the default flags for that site.
-Any flags given on the command line override the default flags
-for the site.
-.SH OPTIONS
-.TP
-.B "\-d \-D"
-The ``\-d'' flag causes
-.I nntpsend
-to send output to stdout rather than the log file
-.IR <pathlog\ in\ inn.conf>/nntpsend.log .
-The ``\-D'' flag does the same
-and it passes ``\-d'' to all
-.I innxmit
-invocations, which in turn causes
-.I innxmit
-to go into debug mode.
-.TP
-.B -n
-If the ``\-n'' flag is used, then
-.I nntpsend
-does not use
-.IR shlock (1)
-and does not lock batch files.
-.TP
-.B \-s size
-If the ``\-s'' flag is used, then
-.IR shrinkfile (1)
-will be invoked to perform a head truncation on the batchfile and the flag
-will be passed to it.
-.TP
-.B \-w delay
-If the ``\-w'' flag is used, then
-.I nntpsend
-waits for
-.I delay
-seconds after flushing the site before launching
-.IR innxmit .
-.TP
-.B "\-a \-c \-l \-N \-P \-p \-r \-S \-T \-t"
-The ``\fB\-a\fP'', ``\fB\-c\fP'', ``\fB\-l\fP'', ``\fB\-P\fP'', ``\fB\-p\fP'',
-``\fB\-r\fP'', \``\fB\-S\fP'', ``\fB\-T\fP'' and ``\fB\-t\fP''
-flags are passed on to the child
-.I innxmit
-program. The ``\-N'' flag is passed as ``\fB\-s\fP'' flag to the child
-.I innxmit
-program.
-See
-.IR innxmit (8)
-for more details.
-Note that if the ``\-p'' flag is used then no connection is made and
-no articles are fed to the remote site.
-It is useful to have
-.IR cron (8)
-invoke
-.I nntpsend
-with this flag in case a site cannot be reached for an extended period of time.
-.SH EXAMPLES
-With the following
-.IR nntpsend.ctl (5)
-control file:
-.PP
-.RS
-.nf
-nsavax:erehwon.nsavax.gov::-S -t60
-group70:group70.org::
-walldrug:walldrug.com:4m-1m:-T1800 -t300
-kremvax:kremvax.cis:2m:
-.fi
-.RE
-.PP
-The command:
-.PP
-.RS
-nntpsend
-.PP
-.RE
-will result in the following:
-.PP
-.RS
-.nf
-Sitename Truncation Innxmit flags
-nsavax (none) \-a \-S \-t60
-group70 (none) \-a \-t180
-walldrug 1m if >4m \-a \-T1800 \-t300
-kremvax 2m \-a \-t180
-.fi
-.RE
-.PP
-The command:
-.PP
-.RS
-nntpsend \-d \-T1200
-.RE
-.PP
-will result in the following:
-.PP
-.RS
-.nf
-Sitename Truncation Innxmit flags
-nsavax (none) \-a \-d \-S \-T1200 \-t60
-group70 (none) \-a \-d \-T1200 \-t180
-walldrug 1m if >4m \-a \-d \-T1200 \-t300
-kremvax 2m \-a \-d \-T1200 \-t180
-.fi
-.RE
-.PP
-The command:
-.PP
-.RS
-nntpsend \-s 5m \-T1200 nsavax erehwon.nsavax.gov group70 group70.org
-.PP
-.RE
-will result in the following:
-.PP
-.RS
-.nf
-Sitename Truncation Innxmit flags
-nsavax 5m \-a \-T1200 \-t180
-group70 5m \-a \-T1200 \-t180
-.fi
-.RE
-.PP
-Remember that ``\-a'' is always given, and ``\-t'' defaults to 180.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com>
-and Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: nntpsend.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5),
-innxmit(1),
-newsfeeds(5),
-nntpsend.ctl(5),
-shrinkfile(1).
+++ /dev/null
-.TH NNTPSEND.CTL 5
-.SH NAME
-nntpsend.ctl \- list of sites to feed via nntpsend
-.SH DESCRIPTION
-The file
-.I <pathetc in inn.conf>/nntpsend.ctl
-specifies the default list of sites to be fed by
-.IR nntpsend (8).
-.PP
-Comments begin with a number sign (``#'') and continue through the end
-of the line.
-Blank lines and comments are ignored.
-All other lines should consist of four fields separated by a colon.
-.PP
-The first field is the name of the site as specified in the
-.I newsfeeds
-file.
-.PP
-The second field should be the hostname or IP address of the remote site.
-.PP
-The third field, if non-empty, specifies the default head truncation size of
-site's batchfile.
-If this field is empty, no truncation is performed.
-This field may be of the form ``\fRmaxsize-truncsize\fP'', in which case it
-is passed to
-.I shrinkfile
-as ``\fR\-m maxsize \-s truncsize\fP''; otherwise it is of the form
-``\fRtruncsize\fP'', in which case it is passed as ``\fR\-s truncsize\fP''.
-.PP
-The fourth field specifies some default flags passed to
-.IR innxmit (8).
-The flag ``\-a'' is always given to
-.I innxmit
-and need not appear here.
-If no ``\-t timeout'' flag is given in this field or on the
-.I nntpsend
-command line, ``\-t\ 180'' will be given to
-.IR innxmit .
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: nntpsend.ctl.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-innxmit(8), newsfeeds(5), nntpsend(8), trunc(1).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "OVDB 5"
-.TH OVDB 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ovdb \- Overview storage method for INN
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-Ovdb is a storage method that uses the BerkeleyDB library to store
-overview data. It requires version 2.6.x or later of the BerkeleyDB
-library, but has mostly been tested with version 3 and 4.
-.PP
-Ovdb makes use of the full transaction/logging/locking functionality of
-the BerkeleyDB environment. BerkeleyDB may be downloaded from
-<http://www.sleepycat.com> and is needed to build the ovdb backend.
-.SH "UPGRADING"
-.IX Header "UPGRADING"
-This is version 2 of ovdb. If you have a database created with a previous
-version of ovdb (such as the one shipped with \s-1INN\s0 2.3.0) your database
-will need to be upgraded using \fIovdb_init\fR\|(8). See the man page
-\&\fIovdb_init\fR\|(8) for upgrade instructions.
-.SH "INSTALLATION"
-.IX Header "INSTALLATION"
-To build ovdb support into \s-1INN\s0, specify the option \f(CW\*(C`\-\-with\-berkeleydb\*(C'\fR
-when running the configure script. By default, configure will search for
-a BerkeleyDB tree in several likely locations, and choose the highest
-version (based on the name of the directory, e.g., \fIBerkeleyDB.3.0\fR) that
-it finds. There will be a message in the configure output indicating the
-chosen pathname.
-.PP
-You can override this pathname by adding a path to the option, e.g.,
-\&\f(CW\*(C`\-\-with\-berkeleydb=/usr/BerkeleyDB.3.1\*(C'\fR. This directory is expected to
-have subdirectories \fIinclude\fR and \fIlib\fR, containing \fIdb.h\fR, and the
-library itself, respectively.
-.PP
-The ovdb database will take up more disk space for a given spool than the
-other overview methods. Plan on needing at least 1.1 \s-1KB\s0 for every article
-in your spool (not counting crossposts). So, if you have 5 million
-articles, you'll need at least 5.5 \s-1GB\s0 of disk space for ovdb. With
-BerkeleyDB 2.x, the db files are 'grow only'; the library will not shrink
-them, even if data is removed. So, reserving extra space above the
-estimate is a good idea. Plus, you'll need additional space for
-transaction logs: at least 100 \s-1MB\s0. By default the transaction logs go in
-the same directory as the database. To improve performance, they can be
-placed on a different disk \*(-- see the \s-1DB_CONFIG\s0 section.
-.SH "CONFIGURATION"
-.IX Header "CONFIGURATION"
-To enable ovdb, set the \fIovmethod\fR parameter in \fIinn.conf\fR to \f(CW\*(C`ovdb\*(C'\fR.
-The ovdb database is stored in the directory specified by the
-\&\fIpathoverview\fR paramter in \fIinn.conf\fR. This is the \*(L"\s-1DB_HOME\s0\*(R" directory.
-To start out, this directory should be empty (other than an optional
-\&\fI\s-1DB_CONFIG\s0\fR file; see \s-1DB_CONFIG\s0 for details) and \fBinnd\fR (or
-\&\fBmakehistory\fR) will create the files as necessary in that directory.
-Make sure the directory is owned by the news user.
-.PP
-Other parameters for configuring ovdb are in the \fIovdb.conf\fR\|(5)
-configuration file. See also the sample \fIovdb.conf\fR.
-.IP "cachesize" 4
-.IX Item "cachesize"
-Size of the memory pool cache, in kilobytes. The cache will have a
-backing store file in the \s-1DB\s0 directory which will be at least as big. In
-general, the bigger the cache, the better. Use \f(CW\*(C`ovdb_stat \-m\*(C'\fR to see
-cache hit percentages. To make a change of this parameter take effect,
-shut down and restart \s-1INN\s0 (be sure to kill all of the nnrpds when shutting
-down). Default is 8000, which is adequate for small to medium sized
-servers. Large servers will probably need at least 20000.
-.IP "numdbfiles" 4
-.IX Item "numdbfiles"
-Overview data is split between this many files. Currently, \fBinnd\fR will
-keep all of the files open, so don't set this too high or \fBinnd\fR may run
-out of file descriptors. \fBnnrpd\fR only opens one at a time, regardless.
-May be set to one, or just a few, but only do that if your \s-1OS\s0 supports
-large (>2G) files. Changing this parameter has no effect on an
-already-established database. Default is 32.
-.IP "txn_nosync" 4
-.IX Item "txn_nosync"
-If txn_nosync is set to false, BerkeleyDB flushes the log after every
-transaction. This minimizes the number of transactions that may be lost
-in the event of a crash, but results in significantly degraded
-performance. Default is true.
-.IP "useshm" 4
-.IX Item "useshm"
-If useshm is set to true, BerkeleyDB will use shared memory instead of
-mmap for its environment regions (cache, lock, etc). With some platforms,
-this may improve performance. Default is false. This parameter is
-ignored if you have BerkeleyDB 2.x
-.IP "shmkey" 4
-.IX Item "shmkey"
-Sets the shared memory key used by BerkeleyDB when 'useshm' is true.
-BerkeleyDB will create several (usually 5) shared memory segments, using
-sequentially numbered keys starting with 'shmkey'. Choose a key that does
-not conflict with any existing shared memory segments on your system.
-Default is 6400. This parameter is only used with BerkeleyDB 3.1 or
-newer.
-.IP "pagesize" 4
-.IX Item "pagesize"
-Sets the page size for the \s-1DB\s0 files (in bytes). Must be a power of 2.
-Best choices are 4096 or 8192. The default is 8192. Changing this
-parameter has no effect on an already-established database.
-.IP "minkey" 4
-.IX Item "minkey"
-Sets the minimum number of keys per page. See the BerkeleyDB
-documentation for more info. Default is based on page size:
-.Sp
-.Vb 1
-\& default_minkey = MAX(2, pagesize / 2048 \- 1)
-.Ve
-.Sp
-The lowest allowed minkey is 2. Setting minkey higher than the default is
-not recommended, as it will cause the databases to have a lot of overflow
-pages. Changing this parameter has no effect on an already-established
-database.
-.IP "maxlocks" 4
-.IX Item "maxlocks"
-Sets the BerkeleyDB \*(L"lk_max\*(R" parameter, which is the maxmium number of
-locks that can exist in the database at the same time. Default is 4000.
-.IP "nocompact" 4
-.IX Item "nocompact"
-The nocompact parameter affects expireover's behavior. The expireover
-function in ovdb can do its job in one of two ways: by simply deleting
-expired records from the database, or by re-writing the overview records
-into a different location leaving out the expired records. The first
-method is faster, but it leaves 'holes' that result in space that can not
-immediately be reused. The second method 'compacts' the records by
-rewriting them.
-.Sp
-If this parameter is set to 0, expireover will compact all newsgroups; if
-set to 1, expireover will not compact any newsgroups; and if set to a
-value greater than one, expireover will only compact groups that have less
-than that number of articles.
-.Sp
-Experience has shown that compacting has minimal effect (other than
-making expireover take longer) so the default is now 1. This parameter
-will probably be removed in the future.
-.IP "readserver" 4
-.IX Item "readserver"
-Normally, each nnrpd process directly accesses the BerkeleyDB environment.
-The process of attaching to the database (and detaching when finished) is
-fairly expensive, and can result in high loads in situations when there
-are lots of reader connections of relatively short duration.
-.Sp
-When the readserver parameter is \*(L"true\*(R", the nnrpds will access overview
-via a helper server (\fBovdb_server\fR \*(-- which is started by \fBovdb_init\fR).
-This can also result in cleaner shutdowns for the database, improving
-stability and avoiding deadlocks and corrupted databases. If you are
-experiencing any instability in ovdb, try setting this parameter to true.
-Default is false.
-.IP "numrsprocs" 4
-.IX Item "numrsprocs"
-This parameter is only used when \fIreadserver\fR is true. It sets the
-number of ovdb_server processes. As each ovdb_server can process only one
-transaction at a time, running more servers can improve reader response
-times. Default is 5.
-.IP "maxrsconn" 4
-.IX Item "maxrsconn"
-This parameter is only used when \fIreadserver\fR is true. It sets a maximum
-number of readers that a given ovdb_server process will serve at one time.
-This means the maximum number of readers for all of the ovdb_server
-processes is (numrsprocs * maxrsconn). Default is 0, which means an
-umlimited number of connections is allowed.
-.SH "DB_CONFIG"
-.IX Header "DB_CONFIG"
-A file called \fI\s-1DB_CONFIG\s0\fR may be placed in the database directory to
-customize where the various database files and transaction logs are
-written. By default, all of the files are written in the \*(L"\s-1DB_HOME\s0\*(R"
-directory. One way to improve performance is to put the transaction logs
-on a different disk. To do this, put:
-.PP
-.Vb 1
-\& DB_LOG_DIR /path/to/logs
-.Ve
-.PP
-in the \fI\s-1DB_CONFIG\s0\fR file. If the pathname you give starts with a /, it is
-treated as an absolute path; otherwise, it is relative to the \*(L"\s-1DB_HOME\s0\*(R"
-directory. Make sure that any directories you specify exist and have
-proper ownership/mode before starting \s-1INN\s0, because they won't be created
-automatically. Also, don't change the \s-1DB_CONFIG\s0 file while anything that
-uses ovdb is running.
-.PP
-Another thing that you can do with this file is to split the overview
-database across multiple disks. In the \fI\s-1DB_CONFIG\s0\fR file, you can list
-directories that BerkeleyDB will search when it goes to open a database.
-.PP
-For example, let's say that you have \fIpathoverview\fR set to
-\&\fI/mnt/overview\fR and you have four additional file systems created on
-\&\fI/mnt/ov?\fR. You would create a file \*(L"/mnt/overview/DB_CONFIG\*(R" containing
-the following lines:
-.PP
-.Vb 5
-\& set_data_dir /mnt/overview
-\& set_data_dir /mnt/ov1
-\& set_data_dir /mnt/ov2
-\& set_data_dir /mnt/ov3
-\& set_data_dir /mnt/ov4
-.Ve
-.PP
-(For BerkeleyDB 2.x, replace \f(CW\*(C`set_data_dir\*(C'\fR with \f(CW\*(C`DB_DATA_DIR\*(C'\fR.)
-.PP
-Distribute your ovNNNNN files into the four filesystems. (say, 8 each).
-When called upon to open a database file, the db library will look for it
-in each of the specified directories (in order). If said file is not
-found, one will be created in the first of those directories.
-.PP
-Whenever you change \s-1DB_CONFIG\s0 or move database files around, make sure all
-news processes that use the database are shut down first (including
-nnrpds).
-.PP
-The \s-1DB_CONFIG\s0 functionality is part of BerkeleyDB itself, rather than
-something provided by ovdb. See the BerkeleyDB documentation for complete
-details for the version of BerkeleyDB that you're running.
-.SH "RUNNING"
-.IX Header "RUNNING"
-When starting the news system, \fBrc.news\fR will invoke \fBovdb_init\fR.
-\&\fBovdb_init\fR must be run before using the database. It performs the
-following tasks:
-.IP "\(bu" 4
-Creates the database environment, if necessary.
-.IP "\(bu" 4
-If the database is idle, it performs a normal recovery. The recovery will
-remove stale locks, recreate the memory pool cache, and repair any damage
-caused by a system crash or improper shutdown.
-.IP "\(bu" 4
-Starts the \s-1DB\s0 housekeeping processes (\fBovdb_monitor\fR) if they're not
-already running.
-.PP
-And when stopping \s-1INN\s0, \fBrc.news\fR kills the ovdb_monitor processes after
-the other \s-1INN\s0 processes have been shut down.
-.SH "DIAGNOSTICS"
-.IX Header "DIAGNOSTICS"
-Problems relating to ovdb are logged to news.err with \*(L"\s-1OVDB\s0\*(R" in the error
-message.
-.PP
-\&\s-1INN\s0 programs that use overview will fail to start up if the ovdb_monitor
-processes aren't running. Be sure to run \fBovdb_init\fR before running
-anything that accesses overview.
-.PP
-Also, \s-1INN\s0 programs that use overview will fail to start up if the user
-running them is not the \*(L"news\*(R" user.
-.PP
-If a program accessing the database crashes, or otherwise exits uncleanly,
-it might leave a stale lock in the database. This lock could cause other
-processes to deadlock on that stale lock. To fix this, shut down all news
-processes (using \f(CW\*(C`kill \-9\*(C'\fR if necessary) and then restart. \fBovdb_init\fR
-should perform a recovery operation which will remove the locks and repair
-damage caused by killing the deadlocked processes.
-.SH "FILES"
-.IX Header "FILES"
-.IP "inn.conf" 4
-.IX Item "inn.conf"
-The \fIovmethod\fR and \fIpathoverview\fR parameters are relevant to ovdb.
-.IP "ovdb.conf" 4
-.IX Item "ovdb.conf"
-Optional configuration file for tuning. See \s-1CONFIGURATION\s0 above.
-.IP "\fIpathoverview\fR" 4
-.IX Item "pathoverview"
-Directory where the database goes. BerkeleyDB calls it the '\s-1DB_HOME\s0'
-directory.
-.IP "\fIpathoverview\fR/DB_CONFIG" 4
-.IX Item "pathoverview/DB_CONFIG"
-Optional file to configure the layout of the database files.
-.IP "\fIpathrun\fR/ovdb.sem" 4
-.IX Item "pathrun/ovdb.sem"
-A file that gets locked by every process that is accessing the database.
-This is used by \fBovdb_init\fR to determine whether the database is active
-or quiescent.
-.IP "\fIpathrun\fR/ovdb_monitor.pid" 4
-.IX Item "pathrun/ovdb_monitor.pid"
-Contains the process \s-1ID\s0 of \fBovdb_monitor\fR.
-.SH "TO DO"
-.IX Header "TO DO"
-Implement a way to limit how many databases can be open at once (to reduce
-file descriptor usage); maybe using something similar to the cache code in
-ov3.c
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInnrpd\fR\|(8), \fIovdb_init\fR\|(8), \fIovdb_monitor\fR\|(8),
-\&\fIovdb_stat\fR\|(8)
-.PP
-BerkeleyDB documentation: in the \fIdocs\fR directory of the BerkeleyDB
-source distribution, or on the Sleepycat web page:
-<http://www.sleepycat.com/>.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "OVDB_INIT 8"
-.TH OVDB_INIT 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ovdb_init \- Prepare ovdb database for use
-.SH "SYNOPSYS"
-.IX Header "SYNOPSYS"
-ovdb_init [\f(CW\*(C`\-u\*(C'\fR|\f(CW\*(C`\-r\*(C'\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This command must be run before any other process can access the
-overview database. It performs the following steps:
-.IP "1" 4
-.IX Item "1"
-Creates the database environment, if necessary
-.IP "2" 4
-.IX Item "2"
-If the database is idle (and if the \f(CW\*(C`\-u\*(C'\fR option is not specified),
-it performs a normal recovery. The recovery will remove stale locks,
-recreate the memory pool cache, and repair any damage caused by a system
-crash or improper shutdown.
-.IP "3" 4
-.IX Item "3"
-If the \f(CW\*(C`\-u\*(C'\fR option is specified, it performs any necessary upgrades
-to the database. See the \s-1UPGRADING\s0 section below.
-.IP "4" 4
-.IX Item "4"
-Starts the \s-1DB\s0 housekeeping processes (ovdb_monitor) if they're not
-already running. (Unless the \f(CW\*(C`\-r\*(C'\fR option is specified).
-.IP "5" 4
-.IX Item "5"
-Starts the ovdb readserver (ovdb_server) processes if \f(CW\*(C`readserver\*(C'\fR
-in \fIovdb.conf\fR is \f(CW\*(C`true\*(C'\fR, and if they're not
-already running. (Unless the \f(CW\*(C`\-r\*(C'\fR option is specified).
-.PP
-Returns exit status of 0 if all steps were completed successfully.
-In the event of an error, messages are written to syslog and/or stderr.
-.PP
-If a recovery was attempted but it failed, the database may be
-damaged beyond repair, requiring a rebuild with \fImakehistory\fR\|(8).
-.PP
-This command is normally invoked automatically by \fIrc.news\fR\|(8).
-.PP
-It is \s-1OK\s0 to run this command multiple times.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.ie n .IP """\-r""" 4
-.el .IP "\f(CW\-r\fR" 4
-.IX Item "-r"
-Perform recovery only. \f(CW\*(C`ovdb_monitor\*(C'\fR is not started.
-.ie n .IP """\-u""" 4
-.el .IP "\f(CW\-u\fR" 4
-.IX Item "-u"
-Perform any needed upgrades. Recovery is not attempted.
-\&\f(CW\*(C`ovdb_monitor\*(C'\fR is started if the upgrade succeeded.
-.SH "UPGRADING"
-.IX Header "UPGRADING"
-There are two situations in which the database will need to be
-upgraded:
-.IP "\(bu" 4
-You upgrade the BerkeleyDB library to a newer version, for example
-from 2.7.7 to 3.1.17. In this case, the BerkeleyDB db\->\fIupgrade()\fR
-method is used.
-.IP "\(bu" 4
-You upgrade ovdb to a newer major version; i.e., ovdb\-1.0 to ovdb\-2.0.
-.PP
-In both of these cases, the database is upgraded in\-place; and the
-upgrade can not be undone. Do not interrupt the upgrade process once
-it has started, because there is a risk of irrepairable corruption.
-The upgrade may take several minutes to complete.
-If an upgrade does get interrupted, try running the upgrade again.
-.PP
-Here's an example procedure to upgrade a database created with BerkeleyDB
-2.7.7 to use BerkeleyDB 3.1.17:
-.IP "1" 4
-.IX Item "1"
-Build and install the BerkeleyDB 3.1.17
-.IP "2" 4
-.IX Item "2"
-Run configure in the \s-1INN\s0 source tree and make sure it picks up the
-right BerkeleyDB directory (e.g., /usr/local/BerkeleyDB.3.1)
-.IP "3" 4
-.IX Item "3"
-Do a \f(CW\*(C`make\*(C'\fR
-.IP "4" 4
-.IX Item "4"
-Shut down \s-1INN\s0 (e.g., with \f(CW\*(C`rc.news stop\*(C'\fR). Be sure to kill all nnrpds as
-well.
-.IP "5" 4
-.IX Item "5"
-Do a \f(CW\*(C`make update\*(C'\fR to install the new binaries.
-.IP "6" 4
-.IX Item "6"
-Run \f(CW\*(C`ovdb_init \-u\*(C'\fR as the news user.
-.IP "7" 4
-.IX Item "7"
-Start \s-1INN\s0 with \f(CW\*(C`rc.news\*(C'\fR
-.PP
-It is \s-1OK\s0 to specify \f(CW\*(C`\-u\*(C'\fR even if no upgrades are needed.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIovdb\fR\|(5), \fImakehistory\fR\|(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "OVDB_MONITOR 8"
-.TH OVDB_MONITOR 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ovdb_monitor \- Database maintenance
-.SH "SYNOPSYS"
-.IX Header "SYNOPSYS"
-Use \f(CW\*(C`ovdb_init\*(C'\fR to start ovdb_monitor
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-When started (by \f(CW\*(C`ovdb_init\*(C'\fR), \f(CW\*(C`ovdb_monitor\*(C'\fR forks three processes
-that perform routine database maintenance tasks. These are:
-transaction checkpointing, deadlock detection, and transaction log
-removal. The process \s-1ID\s0 of the parent is written to
-\&\fI\fIpathrun\fI/ovdb_monitor.pid\fR. This \s-1PID\s0 is used by other \s-1INN\s0
-commands to verify that ovdb_monitor is running.
-.PP
-To shut down ovdb_monitor, send a \s-1TERM\s0 signal to the process \s-1ID\s0
-in \fI\fIpathrun\fI/ovdb_monitor.pid\fR . The parent process will shut
-down the three children and wait for their exit before exiting itself.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIovdb\fR\|(5), \fIovdb_init\fR\|(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "OVDB_SERVER 8"
-.TH OVDB_SERVER 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ovdb_server \- overview 'helper' server
-.SH "SYNOPSYS"
-.IX Header "SYNOPSYS"
-Use \f(CW\*(C`ovdb_init\*(C'\fR to start ovdb_server
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-If the \f(CW\*(C`readserver\*(C'\fR parameter in \fIovdb.conf\fR is true,
-\&\f(CW\*(C`ovdb_init\*(C'\fR will start \f(CW\*(C`ovdb_server\*(C'\fR.
-.PP
-\&\f(CW\*(C`ovdb_server\*(C'\fR opens the overview database, and accesses it
-on behalf of the nnrpd reader processes.
-.PP
-To shut down ovdb_server, send a \s-1TERM\s0 signal to the process \s-1ID\s0
-in \fI\fIpathrun\fI/ovdb_server.pid\fR . The parent process will shut
-down its children and wait for their exit before exiting itself.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIovdb\fR\|(5), \fIovdb_init\fR\|(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "OVDB_STAT 8"
-.TH OVDB_STAT 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-ovdb_stat \- Display information from the ovdb database
-.SH "SYNOPSYS"
-.IX Header "SYNOPSYS"
-\&\fBovdb_stat\fR \fB\-Hgci\fR [\fB\-r\fR \fIartnumrange\fR] newsgroup [newsgroup ...]
-.PP
-\&\fBovdb_stat\fR \fB\-Hklmtv\fR [\fB\-d\fR \fIdatabase\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBovdb_stat\fR displays information from the ovdb database: BerkeleyDB
-statistics, newsgroup data, and overview records; and optionally
-outputs in \s-1HTML\s0 format.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-g\fR" 4
-.IX Item "-g"
-Newsgroup himark, lowmark, article count, and flag for the given newsgroups
-(as stored in the ovdb \*(L"groupinfo\*(R" database) are displayed.
-.IP "\fB\-c\fR" 4
-.IX Item "-c"
-Similar to \fB\-g\fR, except the himark, lowmark, and count are calculated
-by actually scanning the overview records and counting them.
-This can be a lengthy operation on groups with lots of articles.
-.IP "\fB\-i\fR" 4
-.IX Item "-i"
-Internal data regarding the given newsgroups are displayed.
-.IP "\fB\-r\fR \fIartnumrange\fR" 4
-.IX Item "-r artnumrange"
-Overview records are retrieved. The \fIartnumrange\fR parameter may be
-a single article number, or a range of articles in the format \f(CW\*(C`low\-hi\*(C'\fR.
-.IP "\fB\-H\fR" 4
-.IX Item "-H"
-Output is presented in \s-1HTML\s0 format.
-.IP "\fB\-k\fR" 4
-.IX Item "-k"
-Displays lock region statistics, as returned by the BerkeleyDB \fIlock_stat()\fR
-call.
-.IP "\fB\-l\fR" 4
-.IX Item "-l"
-Displays log region statistics, as returned by the BerkeleyDB \fIlog_stat()\fR
-call.
-.IP "\fB\-m\fR" 4
-.IX Item "-m"
-Displays global memory pool statistics, as returned by the
-BerkeleyDB \fImemp_stat()\fR call.
-.IP "\fB\-M\fR" 4
-.IX Item "-M"
-Same as \fB\-m\fR, and also displays memory pool statistics for each
-database file.
-.IP "\fB\-t\fR" 4
-.IX Item "-t"
-Displays log region statistics, as returned by the BerkeleyDB \fItxn_stat()\fR
-call.
-.IP "\fB\-v\fR" 4
-.IX Item "-v"
-Displays ovdb version, and BerkeleyDB version.
-.IP "\fB\-d\fR \fIdatabase\fR" 4
-.IX Item "-d database"
-Displays information about the given database, as returned by the
-BerkeleyDB db\->\fIstat()\fR call. This operation may take a long time
-on busy systems (several minutes or more).
-.SH "WARNINGS"
-.IX Header "WARNINGS"
-ovdb_stat may be safely killed with the \s-1INT\s0, \s-1TERM\s0, or \s-1HUP\s0 signals.
-It catches those signals and exits cleanly.
-Do not kill ovdb_stat with other signals, unless absolutely necessary,
-because it may leave stale locks in the \s-1DB\s0 environment.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIovdb\fR\|(5)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH OVERCHAN 8
-.SH NAME
-overchan \- update the news overview database
-.SH SYNOPSIS
-.B overchan
-[
-.BR file \ ...
-]
-.SH DESCRIPTION
-.I Overchan
-reads article data from
-.I files
-or standard input if none are specified.
-(A single dash in the file list means to read standard input.)
-It uses this information to update the news overview database.
-.I Overchan
-was originally designed to be used by InterNetNews or the C News ``mkov'' packages
-to update the database as the articles come in.
-For current INN, the database is stored in a selected overview method.
-This can be done within
-.IR innd (8)
-itself, but
-.IR overchan (8)
-can be used instead, if
-.I <useoverchan in inn.conf>
-is ``true'' and appropriate setup is done in
-.IR newsfeeds ,
-for example:
-.PP
-.RS
-overview!:*:Tc,WnteO:<pathbin in inn.conf>/overchan
-.RE
-.PP
-.I Overchan
-input data consists of a line of text, separated into four parts by a space.
-The first part is a token for the article.
-The second part is time when the article was received.
-The third part is time when the article will be expired (which represents
-the Expires header).
-The fourth part is the data to be stored.
-.PP
-The data in the overview files should be expired by running
-.IR expireover (8).
-This is normally done by adding the ``expireover'' flag to the
-.IR news.daily (8)
-invocation.
-.PP
-.SH HISTORY
-Written by Rob Robertson <rob@violet.berkeley.edu>
-and Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: overchan.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-expireover(8),
-inn.conf(5),
-news.daily(8),
-newsfeeds(5).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH OVERVIEW.FMT 5
-.SH NAME
-overview.fmt \- format of news overview database
-.SH DESCRIPTION
-The file
-.I <pathetc in inn.conf>/overview.fmt
-specifies the organization of the news overview database.
-Blank lines and lines beginning with a number sign (``#'') are ignored.
-The order of lines in this file is important; it determines the order
-in which the fields will appear in the database.
-.PP
-Most lines will consist of an article header name, optionally
-followed by a colon.
-A trailing set of lines can have the word ``full'' appear after the
-colon; this indicates that the header should appear as well as its value.
-.PP
-If this file is changed, new overview records will be constructed with
-the modified format. If it is desired that existing records be updated to
-the new format, it is necessary to rebuild the overview database using
-.IR makehistory (8)
-after removing all existing overview files.
-.PP
-\&``Xref:full'' must be included, or
-.IR innd (8)
-and other programs which utilize overview method cannot start.
-.PP
-The default file, show below, is compatible with Geoff Collyer's ``nov''
-package:
-.PP
-.RS
-.nf
-Subject:
-From:
-Date:
-Message-ID:
-References:
-Bytes:
-Lines:
-Xref:full
-.fi
-.RE
-.PP
-Usually the only modifications which should be made to the default file
-are additions of new fields to the end of the file; all such fields
-should have ``full'' after the colon. The first eight fields should
-remain in the same order as above.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-Intended to be compatible with the
-.I nov
-package written by Geoff Collyer <geoff@world.std.com>.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: overview.fmt.5 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5)
+++ /dev/null
-.\" $Revision: 6312 $
-.TH PARSEDATE 3
-.SH NAME
-parsedate \- convert time and date string to number
-.SH SYNOPSIS
-.nf
-.ta \w' unsigned long 'u
-.B "#include <sys/types.h>"
-
-.B "typedef struct _TIMEINFO {"
-.B " time_t time;"
-.B " long usec;"
-.B " long tzone;
-.B "} TIMEINFO;"
-
-.B "time_t"
-.B "parsedate(text, now)"
-.B " char *text;"
-.B " TIMEINFO *now;"
-.fi
-.SH DESCRIPTION
-.I Parsedate
-converts many common time specifications into the number of seconds
-since the epoch \(em
-.IR i.e. ,
-a
-.IR time_t ;
-see
-.IR time (2).
-.PP
-.I Parsedate
-returns the time, or \-1 on error.
-.I Text
-is a character string containing the time and date.
-.I Now
-is a pointer to the time that should be used for calculating relative dates.
-If
-.I now
-is NULL, then
-.I GetTimeInfo in
-.IR libinn (3)
-is used to obtain the current time and timezone.
-.PP
-The character string consists of zero or more specifications of the following
-form:
-.TP
-.I time
-A time of day, which is of the form
-.IR hh [ :mm [ :ss ]]
-.RI [ meridian ]
-.RI [ zone ]
-or
-.IR hhmm
-.RI [ meridian ]
-.RI [ zone ].
-If no meridian is specified,
-.I hh
-is interpreted on a 24-hour clock.
-.TP
-.I date
-A specific month and day with optional year.
-The acceptable formats are
-.IR mm/dd [ /yy ],
-.IR yyyy/mm/dd ,
-.IR "monthname dd" "[, " yy ],
-.IR "dd monthname" " [" yy "],
-and
-.IR "day, dd monthname yy" .
-The default year is the current year.
-If the year is less then 100, then 1900 is added to it; if it is
-less then 21, then 2000 is added to it.
-.TP
-.I "relative time"
-A specification relative to the current time.
-The format is
-.IR "number unit" ;
-acceptable units are
-.IR year ,
-.IR month ,
-.IR week ,
-.IR day ,
-.IR hour ,
-.I minute
-(or
-.IR min ),
-and
-.I second
-(or
-.IR sec ).
-The unit can be specified as a singular or plural, as in
-.IR "3 weeks" .
-.PP
-The actual date is calculated according to the following steps.
-First, any absolute date and/or time is processed and converted.
-Using that time as the base, day-of-week specifications are added.
-Next, relative specifications are used.
-If a date or day is specified, and no absolute or relative time is given,
-midnight is used.
-Finally, a correction is applied so that the correct hour of the day is
-produced after allowing for daylight savings time differences.
-.PP
-.I Parsedate
-ignores case when parsing all words; unknown words are taken to be unknown
-timezones, which are treated as GMT.
-The names of the months and days of the week can be abbreviated to their
-first three letters, with optional trailing period.
-Periods are ignored in any timezone or meridian values.
-.SH BUGS
-.I Parsedate
-does not accept all desirable and unambiguous constructions.
-Semantically incorrect dates such as ``February 31'' are accepted.
-.PP
-Daylight savings time is always taken as a one-hour change which is wrong
-for some places.
-The daylight savings time correction can get confused if parsing a
-time within an hour of when the reckoning changes, or if given a
-partial date.
-.SH HISTORY
-Originally written by Steven M. Bellovin <smb@research.att.com> while
-at the University of North Carolina at Chapel Hill and distributed
-under the name
-.IR getdate .
-.PP
-A major overhaul was done by Rich $alz <rsalz@bbn.com> and Jim Berets
-<jberets@bbn.com> in August, 1990.
-.PP
-It was further revised (primarily to remove obsolete constructs and timezone
-names) a year later by Rich (now <rsalz@osf.org>) for InterNetNews,
-and the name was changed.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: parsedate.3 6312 2003-05-04 21:40:11Z rra $
-.SH "SEE ALSO"
-date(1),
-ctime(3),
-libinn(3),
-time(2).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "PASSWD.NNTP 5"
-.TH PASSWD.NNTP 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-passwd.nntp \- passwords for connecting to remote NNTP servers
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIpasswd.nntp\fR in \fIpathetc\fR contains host / name / password
-triplets for use when authenticating client programs to \s-1NNTP\s0 servers.
-This file is normally interpreted by \fINNTPsendpassword()\fR in \fIlibinn\fR\|(3).
-Blank lines and lines beginning with a number sign (\f(CW\*(C`#\*(C'\fR) are ignored.
-All other lines should consist of three or four fields separated by
-colons:
-.PP
-.Vb 2
-\& host:name:password
-\& host:name:password:style
-.Ve
-.PP
-The first field is the name of a host, and is matched in a
-case-insensitive manner. (No detailed matching, such as comparing \s-1IP\s0
-addresses, is done.)
-.PP
-The second field is a user name, and the third is a password. If either
-the username or password is empty, then that portion of the
-authentication will not occur. (For example, when connecting to a
-remote \s-1INN\s0 for peering, only the password is needed.)
-.PP
-The optional fourth field specifies the type of authentication to use.
-At present, the only recognized \*(L"authentication style\*(R" is \f(CW\*(C`authinfo\*(C'\fR;
-this is also the default. It means that \s-1NNTP\s0 \*(L"authinfo\*(R" commands are
-used to authenticate to the remote host. (The \f(CW\*(C`authinfo\*(C'\fR command is a
-common extension to \s-1RFC\s0 977.)
-.PP
-For example:
-.PP
-.Vb 3
-\& ## UUNET needs a password, MIT doesn't.
-\& mit.edu:bbn::authinfo
-\& uunet.uu.net:bbn:yoyoma:authinfo
-.Ve
-.PP
-This file should not be world\-readable.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. This is
-revision \f(CW$Revision:\fR 5089 $, dated \f(CW$Date:\fR 2002\-02\-03 20:03:41 +0100 (dim, 03 fév 2002) $.
-.PP
-$Id: passwd.nntp.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fIlibinn\fR\|(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "PERL-NOCEM 8"
-.TH PERL-NOCEM 8 "2008-04-06" "INN 2.4.4" "InterNetNews Documentation"
-.SH "NAME"
-perl\-nocem \- A NoCeM\-on\-spool implementation for INN\ 2.x
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-perl-nocem
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-NoCeM, which is pronounced \fINo See 'Em\fR, is a protocol enabling
-authenticated third-parties to issue notices which can be used
-to cancel unwanted articles (like spam and articles in moderated
-newsgroups which were not approved by their moderators). It can
-also be used by readers as a \fIthird-party killfile\fR. It is
-intended to eventually replace the protocol for third-party cancel
-messages.
-.PP
-\&\fBperl-nocem\fR processes third\-party, PGP-signed article cancellation
-notices. It is possible not to honour all NoCeM notices but only those
-which are sent by people whom you trust (that is to say if you trust
-the \s-1PGP\s0 key they use to sign their NoCeM notices). Indeed, it is up
-to you to decide whether you wish to honour their notices, depending
-on the criteria they use.
-.PP
-Processing NoCeM notices is easy to set up:
-.IP "1." 4
-Import the keys of the NoCeM issuers you trust in order to check
-the authenticity of their notices. You can do:
-.Sp
-.Vb 3
-\& gpg \-\-no\-default\-keyring \-\-primary\-keyring=/etc/news/pgp/ncmring.gpg \e
-\& \-\-no\-options \-\-allow\-non\-selfsigned\-uid \-\-no\-permission\-warning \e
-\& \-\-batch \-\-import <key\-file>
-.Ve
-.Sp
-where <pathetc> is the value of the \fIpathetc\fR parameter set in \fIinn.conf\fR
-and <key\-file> the file containing the key(s) to import. The keyring
-must be located in \fIpathetc\fR/pgp/ncmring.gpg (create the directory
-before using \fBgpg\fR). For old PGP-generated keys, you may have to use
-\&\fB\-\-allow\-non\-selfsigned\-uid\fR if they are not properly self\-signed,
-but anyone creating a key really should self-sign the key. Current
-\&\s-1PGP\s0 implementations do this automatically.
-.Sp
-The keys of NoCeM issuers can be found in the web site of \fIThe NoCeM Registry\fR:
-<http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html>. You can even
-download there a unique file which contains all the keys.
-.IP "2." 4
-Create a \fInocem.ctl\fR config file in \fIpathetc\fR indicating the NoCeM issuers
-and notices you want to follow. This permission file contains lines like:
-.Sp
-.Vb 3
-\& annihilator\-1:*
-\& clewis@ferret.ocunix:mmf
-\& stephane@asynchrone:mmf,openproxy,spam
-.Ve
-.Sp
-This will remove all articles for which the issuer (first part of the line,
-before the colon \f(CW\*(C`:\*(C'\fR) has issued NoCeM notices corresponding to the
-criteria specified after the colon.
-.Sp
-You will also find information about that on the web site of
-\&\fIThe NoCeM Registry\fR.
-.IP "3." 4
-Add to the \fInewsfeeds\fR file an entry like this one in order to feed
-\&\fBperl-nocem\fR the NoCeM notices posted to alt.nocem.misc and
-news.lists.filters:
-.Sp
-.Vb 3
-\& nocem!\e
-\& :!*,alt.nocem.misc,news.lists.filters\e
-\& :Tc,Wf,Ap:<pathbin>/perl\-nocem
-.Ve
-.Sp
-with the correct path to \fBperl-nocem\fR, located in <pathbin>. Then, reload
-the \fInewsfeeds\fR file (\f(CW\*(C`ctlinnd reload newsfeeds 'NoCeM channel feed'\*(C'\fR).
-.Sp
-Note that you should at least carry news.lists.filters on your news
-server (or other newsgroups where NoCeM notices are sent) if you wish
-to process them.
-.IP "4." 4
-Everything should now work. However, do not hesitate to manually test
-\&\fBperl-nocem\fR with a NoCeM notice, using:
-.Sp
-.Vb 1
-\& grephistory '<Message\-ID>' | perl\-nocem
-.Ve
-.Sp
-Indeed, \fBperl-nocem\fR expects tokens on its standard input, and
-\&\fBgrephistory\fR can easily give it the token of a known article,
-thanks to its Message\-ID.
-.PP
-When you have verified that everything works, you can eventually turn
-off regular spam cancels, if you want, not processing any longer
-cancels containing \f(CW\*(C`cyberspam\*(C'\fR in the Path: header (see the
-\&\fIrefusecybercancels\fR parameter in \fIinn.conf\fR).
-.SH "FILES"
-.IX Header "FILES"
-.IP "\fIpathbin\fR/perl\-nocem" 4
-.IX Item "pathbin/perl-nocem"
-The Perl script itself used to process NoCeM notices.
-.IP "\fIpathetc\fR/nocem.ctl" 4
-.IX Item "pathetc/nocem.ctl"
-The configuration file which specifies the NoCeM notices to be processed.
-.IP "\fIpathetc\fR/pgp/ncmring.gpg" 4
-.IX Item "pathetc/pgp/ncmring.gpg"
-The keyring which contains the public keys of trusted NoCeM issuers.
-.SH "BUGS"
-.IX Header "BUGS"
-The Subject: header is not checked for the @@NCM string and there is no
-check for the presence of the References: header.
-.PP
-The Newsgroups: pseudo header is not checked, but this can be done in
-\&\fIlocal_want_cancel_id()\fR.
-.PP
-The Hierarchies: header is ignored.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Copyright 2000 by Miquel van Smoorenburg <miquels@cistron.nl>.
-.PP
-Copyright 2001 by Marco d'Itri <md@linux.it>.
-.PP
-$Id: perl-nocem.8 7733 2008-04-06 09:16:20Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIgpgv\fR\|(1), \fIgrephistory\fR\|(1), \fIinn.conf\fR\|(5), \fInewsfeeds\fR\|(5), \fIpgp\fR\|(1).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "PGPVERIFY 1"
-.TH PGPVERIFY 1 "2008-04-06" "INN 2.4.4" "InterNetNews Documentation"
-.SH "NAME"
-pgpverify \- Cryptographically verify Usenet control messages
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBpgpverify\fR [\fB\-test\fR] < \fImessage\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The \fBpgpverify\fR program reads (on standard input) a Usenet control
-message that has been cryptographically signed using the \fBsigncontrol\fR
-program (or some other program that produces a compatible format).
-\&\fBpgpverify\fR then uses a \s-1PGP\s0 implementation to determine who signed the
-control message. If the control message has a valid signature,
-\&\fBpgpverify\fR prints (to stdout) the user \s-1ID\s0 of the key that signed the
-message. Otherwise, it exits with a non-zero exit status.
-.PP
-If \fBpgpverify\fR is installed as part of \s-1INN\s0, it uses \s-1INN\s0's configuration
-to determine what signature verification program to use, how to log
-errors, what temporary directory to use, and what keyring to use.
-Otherwise, all of those parameters can be set by editing the beginning of
-this script.
-.PP
-By default, when running as part of \s-1INN\s0, \fBpgpverify\fR expects the \s-1PGP\s0 key
-ring to be found in \fIpathetc\fR/pgp (as either \fIpubring.pgp\fR or
-\&\fIpubring.gpg\fR depending on whether \s-1PGP\s0 or GnuPG is used to verify
-signatures). If that directory doesn't exist, it will fall back on using
-the default key ring, which is in a \fI.pgp\fR or \fI.gnupg\fR subdirectory of
-the running user's home directory.
-.PP
-\&\s-1INN\s0, when using GnuPG, configures \fBpgpverify\fR to use \fBgpgv\fR, which by
-default expects keys to be in a keyring named \fItrustedkeys.gpg\fR, since it
-doesn't implement trust checking directly. \fBpgpverify\fR uses that file if
-present but falls back to \fIpubring.gpg\fR if it's not found. This bypasses
-the trust model for checking keys, but is compatible with the way that
-\&\fBpgpverify\fR used to behave. Of course, if a keyring is found in
-\&\fIpathetc\fR/pgp or configured at the top of the script, that overrides all of
-this behavior.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-The \fB\-test\fR flag causes \fBpgpverify\fR to print out the input that it is
-passing to \s-1PGP\s0 (which is a reconstructed version of the input that
-supposedly created the control message) as well as the output from \s-1PGP\s0's
-analysis of the message.
-.SH "EXIT STATUS"
-.IX Header "EXIT STATUS"
-\&\fBpgpverify\fR may exit with the following statuses:
-.IP "0\&" 4
-.IX Item "0"
-The control message had a good \s-1PGP\s0 signature.
-.IP "1" 4
-.IX Item "1"
-The control message had no \s-1PGP\s0 signature.
-.IP "2" 4
-.IX Item "2"
-The control message had an unknown \s-1PGP\s0 signature.
-.IP "3" 4
-.IX Item "3"
-The control message had a bad \s-1PGP\s0 signature.
-.IP "255" 4
-.IX Item "255"
-A problem occurred not directly related to \s-1PGP\s0 analysis of signature.
-.SH "ENVIRONMENT"
-.IX Header "ENVIRONMENT"
-\&\fBpgpverify\fR does not modify or otherwise alter the environment before
-invoking the \fBpgp\fR or \fBgpgv\fR program. It is the responsibility of the
-person who installs \fBpgpverify\fR to ensure that when \fBpgp\fR or \fBgpgv\fR
-runs, it has the ability to locate and read a \s-1PGP\s0 key file that contains
-the \s-1PGP\s0 public keys for the appropriate Usenet hierarchy administrators.
-\&\fBpgpverify\fR can be pointed to an appropriate key ring by editing
-variables at the beginning of this script.
-.SH "NOTES"
-.IX Header "NOTES"
-Historically, Usenet news server administrators have configured their news
-servers to automatically honor Usenet control messages based on the
-originator of the control messages and the hierarchies for which the
-control messages applied. For example, in the past, David Lawrence always
-issued control messages for the \*(L"Big\ 8\*(R" hierarchies (comp, humanities,
-misc, news, rec, sci, soc, talk). Usenet news administrators would
-configure their news server software to automatically honor newgroup and
-rmgroup control messages that originated from David Lawrence and applied
-to any of the Big\ 8 hierarchies.
-.PP
-Unfortunately, Usenet news articles (including control messages) are
-notoriously easy to forge. Soon, malicious users realized they could
-create or remove (at least temporarily) any Big\ 8 newsgroup they wanted by
-simply forging an appropriate control message in David Lawrence's name.
-As Usenet became more widely used, forgeries became more common.
-.PP
-The \fBpgpverify\fR program was designed to allow Usenet news administrators
-to configure their servers to cryptographically verify control messages
-before automatically acting on them. Under the \fBpgpverify\fR system, a Usenet
-hierarchy maintainer creates a \s-1PGP\s0 public/private key pair and
-disseminates the public key. Whenever the hierarchy maintainer issues a
-control message, he uses the \fBsigncontrol\fR program to sign the control
-message with the \s-1PGP\s0 private key. Usenet news administrators configure
-their news servers to run the \fBpgpverify\fR program on the appropriate
-control messages, and take action based on the \s-1PGP\s0 key User \s-1ID\s0 that signed
-the control message, not the name and address that appear in the control
-message's From: or Sender: headers.
-.PP
-Thus, appropriate use of the \fBsigncontrol\fR and \fBpgpverify\fR programs
-essentially eliminates the possibility of malicious users forging Usenet
-control messages that sites will act upon, as such users would have to
-obtain the \s-1PGP\s0 private key in order to forge a control message that would
-pass the cryptographic verification step. If the hierarchy administrators
-properly protect their \s-1PGP\s0 private keys, the only way a malicious user
-could forge a validly-signed control message would be by breaking the
-public key encryption algorithm, which (at least at this time) is believed
-to be prohibitively difficult for \s-1PGP\s0 keys of a sufficient bit length.
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBpgpverify\fR was written by David C Lawrence <tale@isc.org>. Manual page
-provided by James Ralston. It is currently maintained by Russ Allbery
-<rra@stanford.edu>.
-.SH "COPYRIGHT AND LICENSE"
-.IX Header "COPYRIGHT AND LICENSE"
-David Lawrence wrote: \*(L"Our lawyer told me to include the following. The
-upshot of it is that you can use the software for free as much as you
-like.\*(R"
-.PP
-Copyright (c) 1996 \s-1UUNET\s0 Technologies, Inc.
-All rights reserved.
-.PP
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-.IP "1." 4
-Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-.IP "2." 4
-Redistributions in binary form must reproduce the above copyright notice,
-this list of conditions and the following disclaimer in the documentation
-and/or other materials provided with the distribution.
-.IP "3." 4
-All advertising materials mentioning features or use of this software must
-display the following acknowledgement:
-.Sp
-.Vb 1
-\& This product includes software developed by UUNET Technologies, Inc.
-.Ve
-.IP "4." 4
-The name of \s-1UUNET\s0 Technologies (\*(L"\s-1UUNET\s0\*(R") may not be used to endorse or
-promote products derived from this software without specific prior written
-permission.
-.PP
-\&\s-1THIS\s0 \s-1SOFTWARE\s0 \s-1IS\s0 \s-1PROVIDED\s0 \s-1BY\s0 \s-1UUNET\s0 \*(L"\s-1AS\s0 \s-1IS\s0\*(R" \s-1AND\s0 \s-1ANY\s0 \s-1EXPRESS\s0 \s-1OR\s0 \s-1IMPLIED\s0
-\&\s-1WARRANTIES\s0, \s-1INCLUDING\s0, \s-1BUT\s0 \s-1NOT\s0 \s-1LIMITED\s0 \s-1TO\s0, \s-1THE\s0 \s-1IMPLIED\s0 \s-1WARRANTIES\s0 \s-1OF\s0
-\&\s-1MERCHANTABILITY\s0 \s-1AND\s0 \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0 \s-1ARE\s0 \s-1DISCLAIMED\s0. \s-1IN\s0
-\&\s-1NO\s0 \s-1EVENT\s0 \s-1SHALL\s0 \s-1UUNET\s0 \s-1BE\s0 \s-1LIABLE\s0 \s-1FOR\s0 \s-1ANY\s0 \s-1DIRECT\s0, \s-1INDIRECT\s0, \s-1INCIDENTAL\s0,
-\&\s-1SPECIAL\s0, \s-1EXEMPLARY\s0, \s-1OR\s0 \s-1CONSEQUENTIAL\s0 \s-1DAMAGES\s0 (\s-1INCLUDING\s0, \s-1BUT\s0 \s-1NOT\s0 \s-1LIMITED\s0
-\&\s-1TO\s0, \s-1PROCUREMENT\s0 \s-1OF\s0 \s-1SUBSTITUTE\s0 \s-1GOODS\s0 \s-1OR\s0 \s-1SERVICES\s0; \s-1LOSS\s0 \s-1OF\s0 \s-1USE\s0, \s-1DATA\s0, \s-1OR\s0
-\&\s-1PROFITS\s0; \s-1OR\s0 \s-1BUSINESS\s0 \s-1INTERRUPTION\s0) \s-1HOWEVER\s0 \s-1CAUSED\s0 \s-1AND\s0 \s-1ON\s0 \s-1ANY\s0 \s-1THEORY\s0 \s-1OF\s0
-\&\s-1LIABILITY\s0, \s-1WHETHER\s0 \s-1IN\s0 \s-1CONTRACT\s0, \s-1STRICT\s0 \s-1LIABILITY\s0, \s-1OR\s0 \s-1TORT\s0 (\s-1INCLUDING\s0
-\&\s-1NEGLIGENCE\s0 \s-1OR\s0 \s-1OTHERWISE\s0) \s-1ARISING\s0 \s-1IN\s0 \s-1ANY\s0 \s-1WAY\s0 \s-1OUT\s0 \s-1OF\s0 \s-1THE\s0 \s-1USE\s0 \s-1OF\s0 \s-1THIS\s0
-\&\s-1SOFTWARE\s0, \s-1EVEN\s0 \s-1IF\s0 \s-1ADVISED\s0 \s-1OF\s0 \s-1THE\s0 \s-1POSSIBILITY\s0 \s-1OF\s0 \s-1SUCH\s0 \s-1DAMAGE\s0.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIgpgv\fR\|(1), \fIpgp\fR\|(1).
-.PP
-<ftp://ftp.isc.org/pub/pgpcontrol/> is where the most recent versions of
-\&\fBsigncontrol\fR and \fBpgpverify\fR live, along with \s-1PGP\s0 public keys used for
-hierarchy administration.
+++ /dev/null
-.\" $Revision: 5909 $
-.TH PRUNEHISTORY 8
-.SH NAME
-prunehistory \- remove tokens from Usenet history file
-.SH SYNOPSIS
-.B prunehistory
-[
-.BI \-f " filename"
-]
-[
-.B \-p
-]
-.SH DESCRIPTION
-.I Prunehistory
-modifies a
-.IR history (5)-format
-text file to ``remove'' a set of tokens from it.
-The tokens are removed by overwriting them with spaces, so that the
-size and position of any following entries does not change. This has an
-effect similar to expiring the article, in that it is still mentioned in
-the history database but cannot be retrieved.
-.PP
-.I Prunehistory
-reads the standard input.
-The input is taken as a set of lines.
-Blank lines and lines starting with a number sign (``#'') are ignored.
-All other lines are should consist of a Message-ID followed by zero or
-more other fields (which are ignored).
-.PP
-The Message-ID is used as the
-.IR dbz (3)
-key to get an offset into the text file.
-.PP
-Since
-.IR innd (8)
-only appends
-to the text file,
-.I prunehistory
-does not need to have any interaction with it.
-.SH OPTIONS
-.TP
-.B \-p
-.I Prunehistory
-will normally complain about lines that do not follow the correct format.
-If the ``\-p'' flag is used, then the program will silently print any
-invalid lines on its standard output.
-(Blank lines and comment lines are also passed through.)
-This can be useful when
-.I prunehistory
-is used as a filter for other programs such as
-.IR reap .
-.TP
-.BI \-f " filename"
-The default name of the history file is
-.IR <pathdb\ in\ inn.conf>/history ;
-to specify a different name, use the ``\-f'' flag.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: prunehistory.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-dbz(3),
-history(5),
-inn.conf(5),
-innd(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "PULLNEWS 1"
-.TH PULLNEWS 1 "2008-06-05" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-pullnews \- Pull news from multiple news servers and feed it to another
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBpullnews\fR [\fB\-hnqRx\fR] [\fB\-b\fR \fIfraction\fR] [\fB\-c\fR \fIconfig\fR] [\fB\-C\fR \fIwidth\fR]
-[\fB\-d\fR \fIlevel\fR] [\fB\-f\fR \fIfraction\fR] [\fB\-F\fR \fIfakehop\fR] [\fB\-g\fR \fIgroups\fR]
-[\fB\-G\fR \fInewsgroups\fR] [\fB\-H\fR \fIheaders\fR] [\fB\-k\fR \fIcheckpt\fR] [\fB\-l\fR \fIlogfile\fR]
-[\fB\-m\fR \fIheader_pats\fR] [\fB\-M\fR \fInum\fR] [\fB\-N\fR \fItimeout\fR] [\fB\-p\fR \fIport\fR]
-[\fB\-P\fR \fIhop_limit\fR] [\fB\-Q\fR \fIlevel\fR] [\fB\-r\fR \fIfile\fR] [\fB\-s\fR \fIto-server\fR[:\fIport\fR]]
-[\fB\-S\fR \fImax-run\fR] [\fB\-t\fR \fIretries\fR] [\fB\-T\fR \fIconnect-pause\fR] [\fB\-w\fR \fInum\fR]
-[\fB\-z\fR \fIarticle-pause\fR] [\fB\-Z\fR \fIgroup-pause\fR] [\fIfrom-server\fR ...]
-.SH "REQUIREMENTS"
-.IX Header "REQUIREMENTS"
-The \f(CW\*(C`Net::NNTP\*(C'\fR module must be installed. This module is available as part
-of the libnet distribution and comes with recent versions of Perl. For
-older versions of Perl, you can download it from <http://www.cpan.org/>.
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBpullnews\fR reads a config file in the running user's home directory
-(normally called \fI~/.pullnews\fR) and connects to the upstream servers
-given there as a reader client. By default, it connects to all servers
-listed in the configuration file, but you can limit \fBpullnews\fR to
-specific servers by listing them on the command line: a whitespace-separated
-list of server names can be specified, like \fIfrom-server\fR for one of them.
-For each server it connects to, it pulls over articles and feeds them to the
-destination server via the \s-1IHAVE\s0 or \s-1POST\s0 commands. This means that the system
-\&\fBpullnews\fR is run on must have feeding access to the destination news server.
-.PP
-\&\fBpullnews\fR is designed for very small sites that do not want to bother
-setting up traditional peering and is not meant for handling large feeds.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-b\fR \fIfraction\fR" 4
-.IX Item "-b fraction"
-Backtrack on server numbering reset. Specify the proportion (\f(CW0.0\fR to \f(CW1.0\fR)
-of a group's articles to pull when the server's article number is less than
-our high for that group. When \fIfraction\fR is \f(CW1.0\fR, pull all the articles on
-a renumbered server. The default is to do nothing.
-.IP "\fB\-c\fR \fIconfig\fR" 4
-.IX Item "-c config"
-Normally, the config file is stored in \fI~/.pullnews\fR for the user running
-\&\fBpullnews\fR. If \fB\-c\fR is given, \fIconfig\fR will be used as the config file
-instead. This is useful if you're running \fBpullnews\fR as a system user on
-an automated basis out of cron rather than as an individual user.
-.Sp
-See \*(L"\s-1CONFIG\s0 \s-1FILE\s0\*(R" below for the format of this file.
-.IP "\fB\-C\fR \fIwidth\fR" 4
-.IX Item "-C width"
-Use \fIwidth\fR characters per line for the progress table. The default value
-is \f(CW50\fR.
-.IP "\fB\-d\fR \fIlevel\fR" 4
-.IX Item "-d level"
-Set the debugging level to the integer \fIlevel\fR; more debugging output
-will be logged as this increases. The default value is \f(CW0\fR.
-.IP "\fB\-f\fR \fIfraction\fR" 4
-.IX Item "-f fraction"
-This changes the proportion of articles to get from each group to
-\&\fIfraction\fR and should be in the range \f(CW0.0\fR to \f(CW1.0\fR (\f(CW1.0\fR being
-the default).
-.IP "\fB\-F\fR \fIfakehop\fR" 4
-.IX Item "-F fakehop"
-Prepend \fIfakehop\fR as a host to the Path: header of articles fed.
-.IP "\fB\-g\fR \fIgroups\fR" 4
-.IX Item "-g groups"
-Specify a collection of groups to get. \fIgroups\fR is a list of
-newsgroups separated by commas (only commas, no spaces). Each group must
-be defined in the config file, and only the remote hosts that carry those
-groups will be contacted. Note that this is a simple list of groups, not
-a wildmat expression, and wildcards are not supported.
-.IP "\fB\-G\fR \fInewsgroups\fR" 4
-.IX Item "-G newsgroups"
-Add the comma-separated list of groups \fInewsgroups\fR to each server in the
-configuration file (see also \fB\-g\fR and \fB\-w\fR).
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Print a usage message and exit.
-.IP "\fB\-H\fR \fIheaders\fR" 4
-.IX Item "-H headers"
-Remove these named headers (colon\-separated list) from fed articles.
-.IP "\fB\-k\fR \fIcheckpt\fR" 4
-.IX Item "-k checkpt"
-Checkpoint (save) the config file every \fIcheckpt\fR articles
-(default is \f(CW0\fR, that is to say at the end of the session).
-.IP "\fB\-l\fR \fIlogfile\fR" 4
-.IX Item "-l logfile"
-Log progress/stats to \fIlogfile\fR (default is \f(CW\*(C`stdout\*(C'\fR).
-.IP "\fB\-m\fR \fIheader_pats\fR" 4
-.IX Item "-m header_pats"
-Feed an article based on header matching. The argument is a number of
-whitespace-separated tuples (each tuple being a colon-separated header and
-regular expression). For instance:
-.Sp
-.Vb 1
-\& Hdr1:regexp1 !Hdr2:regexp2
-.Ve
-.Sp
-specifies that the article will be passed only if the \f(CW\*(C`Hdr1:\*(C'\fR header
-matches \f(CW\*(C`regexp1\*(C'\fR and the \f(CW\*(C`Hdr2:\*(C'\fR header does not match \f(CW\*(C`regexp2\*(C'\fR.
-.IP "\fB\-M\fR \fInum\fR" 4
-.IX Item "-M num"
-Specify the maximum number of articles (per group) to process.
-The default is to process all new articles. See also \fB\-f\fR.
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-Do nothing but read articles \-\-\ does not feed articles downstream,
-writes no \fBrnews\fR file, does not update the config file.
-.IP "\fB\-N\fR \fItimeout\fR" 4
-.IX Item "-N timeout"
-Specify the timeout length, as \fItimeout\fR seconds,
-when establishing an \s-1NNTP\s0 connection.
-.IP "\fB\-p\fR \fIport\fR" 4
-.IX Item "-p port"
-Connect to the destination news server on a port other than the default of
-\&\f(CW119\fR. This option does not change the port used to connect to the source
-news servers.
-.IP "\fB\-P\fR \fIhop_limit\fR" 4
-.IX Item "-P hop_limit"
-Restrict feeding an article based on the number of hops it has already made.
-Count the hops in the Path: header (\fIhop_count\fR), feeding the article only
-when \fIhop_limit\fR is \f(CW\*(C`+num\*(C'\fR and \fIhop_count\fR is more than \fInum\fR;
-or \fIhop_limit\fR is \f(CW\*(C`\-num\*(C'\fR and \fIhop_count\fR is less than \fInum\fR.
-.IP "\fB\-q\fR" 4
-.IX Item "-q"
-Print out less status information while running.
-.IP "\fB\-Q\fR \fIlevel\fR" 4
-.IX Item "-Q level"
-Set the quietness level (\f(CW\*(C`\-Q 2\*(C'\fR is equivalent to \f(CW\*(C`\-q\*(C'\fR). The higher this
-value, the less gets logged. The default is \f(CW0\fR.
-.IP "\fB\-r\fR \fIfile\fR" 4
-.IX Item "-r file"
-Rather than feeding the downloaded articles to a destination server, instead
-create a batch file that can later be fed to a server using \fBrnews\fR. See
-\&\fIrnews\fR\|(1) for more information about the batch file format.
-.IP "\fB\-R\fR" 4
-.IX Item "-R"
-Be a reader (use \s-1MODE\s0 \s-1READER\s0 and \s-1POST\s0 commands) to the downstream
-server. The default is to use the \s-1IHAVE\s0 command.
-.IP "\fB\-s\fR \fIto-server\fR[:\fIport\fR]" 4
-.IX Item "-s to-server[:port]"
-Normally, \fBpullnews\fR will feed the articles it retrieves to the news
-server running on localhost. To connect to a different host, specify a
-server with the \fB\-s\fR flag. You can also specify the port with this same
-flag or use \fB\-p\fR.
-.IP "\fB\-S\fR \fImax-run\fR" 4
-.IX Item "-S max-run"
-Specify the maximum time \fImax-run\fR in seconds for \fBpullnews\fR to run.
-.IP "\fB\-t\fR \fIretries\fR" 4
-.IX Item "-t retries"
-The maximum number (\fIretries\fR) of attempts to connect to a server
-(see also \fB\-T\fR). The default is \f(CW0\fR.
-.IP "\fB\-T\fR \fIconnect-pause\fR" 4
-.IX Item "-T connect-pause"
-Pause \fIconnect-pause\fR seconds between connection retries (see also \fB\-t\fR).
-The default is \f(CW1\fR.
-.IP "\fB\-w\fR \fInum\fR" 4
-.IX Item "-w num"
-Set each group's high watermark (last received article number) to \fInum\fR.
-If \fInum\fR is negative, calculate \fICurrent\fR+\fInum\fR instead (i.e. get the last
-\&\fInum\fR articles). Therefore, a \fInum\fR of \f(CW0\fR will re-get all articles on the
-server; whereas a \fInum\fR of \f(CW\*(C`\-0\*(C'\fR will get no old articles, setting the
-watermark to \fICurrent\fR (the most recent article on the server).
-.IP "\fB\-x\fR" 4
-.IX Item "-x"
-If the \fB\-x\fR flag is used, an Xref: header is added to any article
-that lacks one. It can be useful for instance if articles are fed
-to a news server which has \fIxrefslave\fR set in \fIinn.conf\fR.
-.IP "\fB\-z\fR \fIarticle-pause\fR" 4
-.IX Item "-z article-pause"
-Sleep \fIarticle-pause\fR seconds between articles. The default is \f(CW0\fR.
-.IP "\fB\-Z\fR \fIgroup-pause\fR" 4
-.IX Item "-Z group-pause"
-Sleep \fIgroup-pause\fR seconds between groups. The default is \f(CW0\fR.
-.SH "CONFIG FILE"
-.IX Header "CONFIG FILE"
-The config file for \fBpullnews\fR is divided into blocks, one block for each
-remote server to connect to. A block begins with the host line, which
-must have no leading whitespace and contains just the hostname of the
-remote server, optionally followed by authentication details (username
-and password for that server).
-.PP
-Following the host line should be one or more newsgroup lines which start
-with whitespace followed by the name of a newsgroup to retrieve. Only one
-newsgroup should be listed on each line.
-.PP
-\&\fBpullnews\fR will update the config file to include the time the group was
-last checked and the highest numbered article successfully retrieved and
-transferred to the destination server. It uses this data to avoid doing
-duplicate work the next time it runs.
-.PP
-The full syntax is:
-.PP
-.Vb 3
-\& <host> [<username> <password>]
-\& <group> [<time> <high>]
-\& <group> [<time> <high>]
-.Ve
-.PP
-where the <host> line must not have leading whitespace and the <group>
-lines must.
-.PP
-A typical configuration file would be:
-.PP
-.Vb 7
-\& # Format group date high
-\& data.pa.vix.com
-\& rec.bicycles.racing 908086612 783
-\& rec.humor.funny 908086613 18
-\& comp.programming.threads
-\& nnrp.vix.com pull sekret
-\& comp.std.lisp
-.Ve
-.PP
-Note that an earlier run of \fBpullnews\fR has filled in details about the
-last article downloads from the two rec.* groups. The two comp.* groups
-were just added by the user and have not yet been checked.
-.PP
-The nnrp.vix.com server requires authentication, and \fBpullnews\fR will use
-the username \f(CW\*(C`pull\*(C'\fR and the password \f(CW\*(C`sekret\*(C'\fR.
-.SH "FILES"
-.IX Header "FILES"
-.IP "\fIpathbin\fR/pullnews" 4
-.IX Item "pathbin/pullnews"
-The Perl script itself used to pull news from upstream servers and feed
-it to another news server.
-.IP "\fI$HOME\fR/.pullnews" 4
-.IX Item "$HOME/.pullnews"
-The default config file. It is in the running user's home directory
-(normally called \fI~/.pullnews\fR).
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBpullnews\fR was written by James Brister for \s-1INN\s0. The documentation was
-rewritten in \s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-Geraint A. Edwards greatly improved \fBpullnews\fR, adding no more than 16\ new
-recognized flags, fixing some bugs and integrating the \fBbackupfeed\fR
-contrib script by Kai Henningsen, adding again 6\ other flags.
-.PP
-$Id: pullnews.pod 7853 2008\-05\-27 19:07:45Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIincoming.conf\fR\|(5), \fIrnews\fR\|(1).
+++ /dev/null
-#! /bin/sh
-## $Revision: 2790 $
-##
-## Prepare a manpage for installation, and install it. Usage:
-## putman <style> "<installitflags>" <source> <dest-dir>
-case $# in
-4)
- ;;
-*)
- echo "Can't install manpage: wrong number of arguments." 1>&2
-esac
-
-STYLE="$1"
-FLAGS="$2"
-SRC="$3"
-DEST="$4"
-
-case "X${STYLE}" in
-XNONE)
- exit 0
- ;;
-XSOURCE)
- exec /bin/sh ../../support/install-sh ${FLAGS} ${SRC} ${DEST}
- ;;
-XNROFF-PACK)
- T=${TMPDIR-/tmp}/man$$
- nroff -man ${SRC} >$T
- /bin/sh ../../support/install-sh ${FLAGS} $T ${DEST} && pack ${DEST}
- rm -f $T
- exit
- ;;
-XNROFF-PACK-SCO)
- T=${TMPDIR-/tmp}/man$$
- nroff -man ${SRC} >$T
- DEST2=`echo ${DEST} | sed -e 's/\..$/.INN/'`
- /bin/sh ../../support/install-sh ${FLAGS} $T ${DEST2} && pack ${DEST2}
- rm -f $T
- exit
- ;;
-XBSD4.4)
- T=${TMPDIR-/tmp}/man$$
- nroff -man ${SRC} >$T
- DEST2=`echo ${DEST} | sed -e 's/\..$/.0/'`
- /bin/sh ../../support/install-sh ${FLAGS} $T ${DEST2}
- rm -f $T
- exit
- ;;
-esac
-
-echo "Can't install manpage: unknown method ${STYLE}." 1>&2
-exit 1
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "qio 3"
-.TH qio 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-qio \- Quick I/O routines for reading files
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fB#include <inn/qio.h>\fR
-.PP
-\&\fB\s-1QIOSTATE\s0 *QIOopen(const char *\fR\fIname\fR\fB);\fR
-.PP
-\&\fB\s-1QIOSTATE\s0 *QIOfdopen(int\fR \fIfd\fR\fB);\fR
-.PP
-\&\fBvoid QIOclose(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBchar *QIOread(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBint QIOfileno(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBsize_t QIOlength(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBint QIOrewind(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBoff_t QIOtell(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBbool QIOerror(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.PP
-\&\fBbool QIOtoolong(\s-1QIOSTATE\s0 *\fR\fIqp\fR\fB);\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The routines described in this manual page are part of \fIlibinn\fR\|(3). They
-are used to provide quick read access to files; the \s-1QIO\s0 routines use
-buffering adapted to the block size of the device, similar to stdio, but
-with a more convenient syntax for reading newline-terminated lines. \s-1QIO\s0
-is short for \*(L"Quick I/O\*(R" (a bit of a misnomer, as \s-1QIO\s0 provides read-only
-access to files only).
-.PP
-The \s-1QIOSTATE\s0 structure returned by \fBQIOopen\fR and \fBQIOfdopen\fR is the
-analog to stdio's \s-1FILE\s0 structure and should be treated as a black box by
-all users of these routines. Only the above \s-1API\s0 should be used.
-.PP
-\&\fBQIOopen\fR opens the given file for reading. For regular files, if your
-system provides that information and the size is reasonable, \s-1QIO\s0 will use
-the block size of the underlying file system as its buffer size;
-otherwise, it will default to a buffer of 8 \s-1KB\s0. Returns a pointer to use
-for subsequent calls, or \s-1NULL\s0 on error. \fBQIOfdopen\fR performs the same
-operation except on an already-open file descriptor (\fIfd\fR must designate
-a file open for reading).
-.PP
-\&\fBQIOclose\fR closes the open file and releases any resources used by the
-\&\s-1QIOSTATE\s0 structure. The \s-1QIOSTATE\s0 pointer should not be used again after
-it has been passed to this function.
-.PP
-\&\fBQIOread\fR reads the next newline-terminated line in the file and returns
-a pointer to it, with the trailing newline replaced by nul. The returned
-pointer is a pointer into a buffer in the \s-1QIOSTATE\s0 object and therefore
-will remain valid until \fBQIOclose\fR is called on that object. If \s-1EOF\s0 is
-reached, an error occurs, or if the line is longer than the buffer size,
-\&\s-1NULL\s0 is returned instead. To distinguish between the error cases, use
-\&\fBQIOerror\fR and \fBQIOtoolong\fR.
-.PP
-\&\fBQIOfileno\fR returns the descriptor of the open file.
-.PP
-\&\fBQIOlength\fR returns the length in bytes of the last line returned by
-\&\fBQIOread\fR. Its return value is only defined after a successful call to
-\&\fBQIOread\fR.
-.PP
-\&\fBQIOrewind\fR sets the read pointer back to the beginning of the file and
-reads the first block of the file in anticipation of future reads. It
-returns 0 if successful and \-1 on error.
-.PP
-\&\fBQIOtell\fR returns the current value of the read pointer (the \fIlseek\fR\|(2)
-offset at which the next line will start).
-.PP
-\&\fBQIOerror\fR returns true if there was an error in the last call to
-\&\fBQIOread\fR, false otherwise. \fBQIOtoolong\fR returns true if there was an
-error and the error was that the line was too long. If \fBQIOread\fR returns
-\&\s-1NULL\s0, these functions should be called to determine what happened. If
-\&\fBQIOread\fR returned \s-1NULL\s0 and \fBQIOerror\fR is false, \s-1EOF\s0 was reached. Note
-that if \fBQIOtoolong\fR returns true, the next call to \fBQIOread\fR will try
-to read the remainder of the line and will likely return a partial line;
-users of this library should in general treat long lines as fatal errors.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-This block of code opens \fI/etc/motd\fR and reads it a line at a time,
-printing out each line preceeded by its offset in the file.
-.PP
-.Vb 3
-\& QIOSTATE *qp;
-\& off_t offset;
-\& char *p;
-.Ve
-.PP
-.Vb 12
-\& qp = QIOopen("/etc/motd");
-\& if (qp == NULL) {
-\& perror("Open error");
-\& exit(1);
-\& }
-\& for (p = QIOread(qp); p != NULL; p = QIOread(qp))
-\& printf("%ld: %s\en", (unsigned long) QIOtell(qp), p);
-\& if (QIOerror(qp)) {
-\& perror("Read error");
-\& exit(1);
-\& }
-\& QIOclose(qp);
-.Ve
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> for InterNetNews. Updated by
-Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: qio.3 7880 2008-06-16 20:37:13Z iulius $
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "RADIUS 8"
-.TH RADIUS 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-radius \- nnrpd RADIUS password authenticator
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBradius\fR [\fB\-h\fR] [\fB\-f\fR \fIconfig\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBradius\fR is an nnrpd authenticator, accepting a username and password
-from nnrpd (given to nnrpd by a reader connection) and attempting to
-authenticate that username and password against a \s-1RADIUS\s0 server. See
-\&\fIreaders.conf\fR\|(5) for more information on how to configure an nnrpd
-authenticator. It is useful for a site that already does user
-authentication via \s-1RADIUS\s0 and wants to authenticate news reading
-connections as well.
-.PP
-By default, \fBradius\fR reads \fIpathetc\fR/radius.conf for configuration
-information, but a different configuration file can be specified with
-\&\fB\-f\fR. See \fIradius.conf\fR\|(5) for a description of the configuration file.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-f\fR \fIconfig\fR" 4
-.IX Item "-f config"
-Read \fIconfig\fR instead of \fIpathetc\fR/radius.conf for configuration
-information.
-.IP "\fB\-h\fR" 4
-.IX Item "-h"
-Print out a usage message and exit.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-The following \fIreaders.conf\fR\|(5) fragment tells nnrpd to authenticate all
-connections using this authenticator:
-.PP
-.Vb 5
-\& auth radius {
-\& auth: radius
-\& default: <FAIL>
-\& default\-domain: example.com
-\& }
-.Ve
-.PP
-\&\f(CW\*(C`@example.com\*(C'\fR will be appended to the user-supplied identity, and if
-\&\s-1RADIUS\s0 authentication failes, the user will be assigned an identity of
-\&\f(CW\*(C`<FAIL>@example.com\*(C'\fR.
-.SH "BUGS"
-.IX Header "BUGS"
-It has been reported that this authenticator doesn't work with Ascend
-\&\s-1RADIUS\s0 servers, but does work with Cistron \s-1RADIUS\s0 servers. It's also
-believed to work with Livingston's \s-1RADIUS\s0 server. Contributions to make
-it work better with different types of \s-1RADIUS\s0 servers would be gratefully
-accepted.
-.PP
-This code has not been audited against the \s-1RADIUS\s0 protocol and may not
-implement it correctly.
-.SH "HISTORY"
-.IX Header "HISTORY"
-The \s-1RADIUS\s0 authenticator was originally written by Aidan Cully. This
-documentation was written by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: radius.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8), \fIradius.conf\fR\|(5), \fIreaders.conf\fR\|(5)
-.PP
-\&\s-1RFC\s0 2865, Remote Authentication Dial In User Service.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "RADIUS.CONF 5"
-.TH RADIUS.CONF 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-radius.conf \- Configuration for nnrpd RADIUS authenticator
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-This describes the format and attributes of the configuration file for the
-nnrpd \s-1RADIUS\s0 authenticator. See \fIradius\fR\|(1) for more information about the
-authenticator program. The default location for this file is
-\&\fIradius.conf\fR in \fIpathetc\fR.
-.PP
-Blank lines and lines beginning with \f(CW\*(C`#\*(C'\fR are ignored, as is anything
-after a \f(CW\*(C`#\*(C'\fR on a line. All other lines should begin with a parameter
-name followed by a colon and the value of that key, except that each
-section of configuration for a particular server should be enclosed in:
-.PP
-.Vb 3
-\& server <name> {
-\& # parameters...
-\& }
-.Ve
-.PP
-where <name> is just some convenient label for that server.
-.PP
-The available parameters are:
-.IP "\fIradhost\fR" 4
-.IX Item "radhost"
-The hostname of the \s-1RADIUS\s0 server to use for authentication. This
-parameter must be set.
-.IP "\fIradport\fR" 4
-.IX Item "radport"
-The port to query on the \s-1RADIUS\s0 server. Defaults to 1645 if not set.
-.IP "\fIlochost\fR" 4
-.IX Item "lochost"
-The hostname or \s-1IP\s0 address making the request. The \s-1RADIUS\s0 server expects
-an \s-1IP\s0 address; a hostname will be translated into an \s-1IP\s0 address with
-\&\fIgethostbyname()\fR. If not given, this information isn't included in the
-request (not all \s-1RADIUS\s0 setups require this information).
-.IP "\fIlocport\fR" 4
-.IX Item "locport"
-The port the client being authenticated is connecting to. If not given,
-defaults to 119. This doesn't need to be set unless readers are
-connecting to a non-standard port.
-.IP "\fIsecret\fR" 4
-.IX Item "secret"
-The shared secret with the \s-1RADIUS\s0 server. If your secret includes spaces,
-tabs, or \f(CW\*(C`#\*(C'\fR, be sure to include it in double quotes. This parameter
-must be set.
-.IP "\fIprefix\fR" 4
-.IX Item "prefix"
-Prepend the value of this parameter to all usernames before passing them
-to the \s-1RADIUS\s0 server. Can be used to prepend something like \f(CW\*(C`news\-\*(C'\fR to
-all usernames in order to put news users into a different namespace from
-other accounts served by the same server. If not set, nothing is
-prepended.
-.IP "\fIsuffix\fR" 4
-.IX Item "suffix"
-Append the value of this parameter to all usernames before passing them to
-the \s-1RADIUS\s0 server. This is often something like \f(CW\*(C`@example.com\*(C'\fR,
-depending on how your \s-1RADIUS\s0 server is set up. If not set, nothing is
-appended.
-.IP "\fIignore-source\fR" 4
-.IX Item "ignore-source"
-Can be set to \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`false\*(C'\fR. If set to false, the \s-1RADIUS\s0
-authenticator will check to ensure that the response it receives is from
-the same \s-1IP\s0 address as it sent the request to (for some added security).
-If set to true, it will skip this verification check (if your \s-1RADIUS\s0
-server has multiple \s-1IP\s0 addresses or if other odd things are going on, it
-may be perfectly normal for the response to come from a different \s-1IP\s0
-address).
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-Here is a configuration for a news server named news.example.com,
-authenticating users against radius.example.com and appending
-\&\f(CW\*(C`@example.com\*(C'\fR to all client-supplied usernames before passing them to
-the \s-1RADIUS\s0 server:
-.PP
-.Vb 6
-\& server example {
-\& radhost: radius.example.com
-\& lochost: news.example.com
-\& secret: IamARADIUSsecRET
-\& suffix: @example.com
-\& }
-.Ve
-.PP
-The shared secret with the \s-1RADIUS\s0 server is \f(CW\*(C`IamARADIUSsecRET\*(C'\fR.
-.SH "HISTORY"
-.IX Header "HISTORY"
-This documentation was written by Russ Allbery <rra@stanford.edu> based on
-the comments in the sample radius.conf file by Yury B. Razbegin.
-.PP
-$Id: radius.conf.5 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIradius\fR\|(1)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "RC.NEWS 8"
-.TH RC.NEWS 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-rc.news \- Start or stop INN daemons
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBrc.news\fR [start | stop]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBrc.news\fR can be used to start or stop \fBinnd\fR and supporting programs.
-It checks to make sure \s-1INN\s0 is not already running, handles cases of
-unclean shutdown, finishes up tasks which might have been interrupted by
-the preceeding shutdown, emails certain boot-time warnings to
-\&\fInewsmaster\fR (as set in \fIinn.conf\fR), and is generally safer and easier
-than starting and stopping everything directly. It needs to be run as the
-news user so that files in \fIpathrun\fR are created with the right ownership
-(though this is less important for \f(CW\*(C`rc.news stop\*(C'\fR), and therefore
-requires that \fIinndstart\fR be setuid root, see \fIinndstart\fR\|(8) for
-discussion.
-.PP
-Programs run and stopped by this script include:
-.IP "\(bu" 4
-Always: \fBinndstart\fR is run, and \fBinnd\fR is stopped.
-.IP "\(bu" 4
-If \fIdoinnwatch\fR is true in \fIinn.conf\fR: \fBinnwatch\fR is started and
-stopped.
-.IP "\(bu" 4
-If \fIdocnfsstat\fR is true in \fIinn.conf\fR: \fBovdb_init\fR is run;
-\&\fBovdb_server\fR and \fBovdb_monitor\fR are stopped.
-.IP "\(bu" 4
-If \fIrc.news.local\fR exists in \fIpathbin\fR: \fBrc.news.local\fR is run with
-argument \f(CW\*(C`start\*(C'\fR or \f(CW\*(C`stop\*(C'\fR (to perform site-specific startup or shutdown
-tasks).
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.ie n .IP """start""" 4
-.el .IP "\f(CWstart\fR" 4
-.IX Item "start"
-If the first argument is \f(CW\*(C`start\*(C'\fR, or no first argument is given,
-\&\fBrc.news\fR initiates \s-1INN\s0 startup.
-.ie n .IP """stop""" 4
-.el .IP "\f(CWstop\fR" 4
-.IX Item "stop"
-If the first argument is \f(CW\*(C`stop\*(C'\fR, \fBrc.news\fR initiates \s-1INN\s0 shutdown. It
-is recommended to throttle the server first as described in \fIctlinnd\fR\|(8).
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-To start \s-1INN\s0 and leave certain error messages going to the terminal:
-.PP
-.Vb 1
-\& su \- news \-c ~news/bin/rc.news
-.Ve
-.PP
-To run \s-1INN\s0 at startup time from appropriate system boot scripts:
-.PP
-.Vb 1
-\& su \- news \-c ~news/bin/rc.news >/dev/console
-.Ve
-.PP
-To stop \s-1INN\s0 (throttling first):
-.PP
-.Vb 2
-\& ~news/bin/ctlinnd throttle reason
-\& su \- news \-c '~news/bin/rc.news stop'
-.Ve
-.SH "BUGS"
-.IX Header "BUGS"
-Running \f(CW\*(C`rc.news start\*(C'\fR as root is never the right thing to do, so we
-should at minimum check for this and error, or perhaps change effective
-user \s-1ID\s0.
-.SH "HISTORY"
-.IX Header "HISTORY"
-// \s-1FIXME:\s0 any attribution for rc.news itself?
-.PP
-This manual page written by Jeffrey M. Vinocur <jeff@litech.org> for
-InterNetNews.
-.PP
-$Id: rc.news.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIctlinnd\fR\|(8),
-\&\fIcnfsstat\fR\|(8),
-\&\fIinn.conf\fR\|(5),
-\&\fIinndstart\fR\|(8),
-\&\fIinnwatch\fR\|(8),
-\&\fIovdb\fR\|(5).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "READERS.CONF 5"
-.TH READERS.CONF 5 "2008-06-22" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-readers.conf \- Access control and configuration for nnrpd
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fIreaders.conf\fR in \fIpathetc\fR specifies access control for \fInnrpd\fR\|(8). It
-controls who is allowed to connect as a news reader and what they're
-allowed to do after they connect. nnrpd reads this file when it starts
-up. This generally means that any changes take effect immediately on all
-subsequent connections, but \fBnnrpd\fR may have to be restarted if you use
-the \fB\-D\fR option. (The location \fIpathetc\fR/readers.conf is only the
-default; the same format applies to any file specified with \f(CW\*(C`nnrpd \-c\*(C'\fR.)
-.PP
-There are two types of entries in \fIreaders.conf\fR: parameter/value pairs
-and configuration groups. Blank lines and anything after a number sign
-(\f(CW\*(C`#\*(C'\fR) are ignored, unless the character \f(CW\*(C`#\*(C'\fR is escaped with \f(CW\*(C`\e\*(C'\fR. The
-maximum number of characters on each line is 8,191.
-.PP
-Parameter/value pairs consist of a keyword immediately followed by a
-colon, at least one whitespace character, and a value. The case of the
-parameter is significant (parameter should generally be in all lowercase),
-and a parameter may contain any characters except colon, \f(CW\*(C`#\*(C'\fR, and
-whitespace. An example:
-.PP
-.Vb 1
-\& hosts: *.example.com
-.Ve
-.PP
-Values that contain whitespace should be quoted with double quotes, as in:
-.PP
-.Vb 1
-\& hosts: "*.example.com, *.example.net"
-.Ve
-.PP
-If the parameter does not contain whitespace, such as:
-.PP
-.Vb 1
-\& hosts: *.example.com,*.example.net
-.Ve
-.PP
-it's not necessary to quote it, although you may wish to anyway for
-clarity.
-.PP
-There is no way to continue a line on the next line, and therefore no way
-to have a single parameter with a value longer than about 8,180
-characters.
-.PP
-Many parameters take a boolean value. For all such parameters, the value
-may be specified as \f(CW\*(C`true\*(C'\fR, \f(CW\*(C`yes\*(C'\fR, or \f(CW\*(C`on\*(C'\fR to turn it on and may be any
-of \f(CW\*(C`false\*(C'\fR, \f(CW\*(C`no\*(C'\fR, or \f(CW\*(C`off\*(C'\fR to turn it off. The case of these values is
-not significant.
-.PP
-There are two basic types of configuration groups, auth and access. The
-auth group provides mechanisms to establish the identity of the user, who
-they are. The access group determines, given the user's identity, what
-that user is permitted to do. Writing a \fIreaders.conf\fR file for your
-setup is a two-step process: first assigning an identity to each incoming
-connection using auth groups, and then giving each identity appropriate
-privileges with access group. We recommend \fInot\fR intermingling auth
-groups and access groups in the config file; it is often more sensible (in
-the absence of the \fIkey\fR parameter) to put all of the auth groups first,
-and all of the access groups below.
-.PP
-A user identity, as established by an auth group, looks like an e\-mail
-address; in other words, it's in the form \*(L"<username>@<domain>\*(R" (or
-sometimes just \*(L"<username>\*(R" if no domain is specified.
-.PP
-If \fInnrpdauthsender\fR is set in \fIinn.conf\fR, the user identity is also put
-into the Sender: header of posts made by that user. See the documentation
-of that option in \fIinn.conf\fR\|(5) for more details.
-.PP
-An auth group definition looks like:
-.PP
-.Vb 8
-\& auth <name> {
-\& hosts: <host\-wildmat>
-\& auth: <auth\-program>
-\& res: <res\-program>
-\& default: <defuser>
-\& default\-domain: <defdomain>
-\& # ...possibly other settings
-\& }
-.Ve
-.PP
-The <name> is used as a label for the group and is only for documentation
-purposes. (If your syslog configuration records the \f(CW\*(C`news.debug\*(C'\fR
-facility, the <name> will appear in the debugging output of nnrpd.
-Examining that output can be very helpful in understanding why your
-configuration doesn't do what you expect it to.)
-.PP
-A given auth group applies only to hosts whose name or \s-1IP\s0 address matches
-the wildmat expression given with the hosts: parameter (comma\-separated
-wildmat expressions allowed, but \f(CW\*(C`@\*(C'\fR is not supported). Rather than
-wildmat expressions, you may also use \s-1CIDR\s0 notation to match any \s-1IP\s0
-address in a netblock; for example, \*(L"10.10.10.0/24\*(R" will match any \s-1IP\s0
-address between 10.10.10.0 and 10.10.10.255 inclusive.
-.PP
-If compiled against the \s-1SSL\s0 libraries, an auth group with the require_ssl:
-parameter set to true only applies if the incoming connection is using
-\&\s-1SSL\s0.
-.PP
-For any connection from a host that matches that wildmat expression or
-netblock, each <res\-program> (multiple res: lines may be present in a
-block; they are run in sequence until one succeeds), if any, is run to
-determine the identity of the user just from the connection information.
-If all the resolvers fail, or if the res: parameter isn't present, the
-user is assigned an identity of \*(L"<defuser>@<defdomain>\*(R"; in other words,
-the values of the default: and default\-domain: parameters are used. If
-<res\-program> only returns a username, <defdomain> is used as the
-domain.
-.PP
-If the user later authenticates via the \s-1AUTHINFO\s0 \s-1USER/PASS\s0 commands, the
-provided username and password are passed to each <auth\-program> (multiple
-auth, perl_auth, or python_auth lines may be present in a block; they are
-run in sequence until one succeeds), if any. If one succeeds and returns
-a different identity than the one assigned at the time of the connection,
-it is matched against the available access groups again and the actions
-the user is authorized to do may change. The most common <auth\-program>
-to use is \fBckpasswd\fR, which supports several ways of checking passwords
-including using \s-1PAM\s0. See the \fIckpasswd\fR\|(8) man page for more details.
-.PP
-When matching auth groups, the last auth group in the file that matches a
-given connection and username/password combination is used.
-.PP
-An access group definition usually looks like:
-.PP
-.Vb 5
-\& access <name> {
-\& users: <identity\-wildmat>
-\& newsgroups: <group\-wildmat>
-\& # ...possibly other settings
-\& }
-.Ve
-.PP
-Again, <name> is just for documentation purposes. This says that all
-users whose identity matches <identity\-wildmat> can read and post to all
-newsgroups matching <group\-wildmat> (as before, comma-separated wildmat
-expressions are allowed, but \f(CW\*(C`@\*(C'\fR is not supported). Alternately, you can
-use the form:
-.PP
-.Vb 5
-\& access <name> {
-\& users: <identity\-wildmat>
-\& read: <read\-wildmat>
-\& post: <post\-wildmat>
-\& }
-.Ve
-.PP
-and matching users will be able to read any group that matches
-<read\-wildmat> and post to any group that matches <post\-wildmat>. You can
-also set several other things in the access group as well as override
-various \fIinn.conf\fR\|(5) parameters for just a particular group of users.
-.PP
-Just like with auth groups, when matching access groups the last matching
-one in the file is used to determine the user's permissions. There is
-an exception to this rule: if the auth group which matched the client
-contains a perl_access: or python_access: parameter, then the script
-given as argument is used to dynamically generate an access group.
-This new access group is then used to determine the access rights of
-the client; the access groups in the file are ignored.
-.PP
-There is one additional special case to be aware of. When forming
-particularly complex authentication and authorization rules, it is
-sometimes useful for the identities provided by a given auth group to only
-apply to particular access groups; in other words, rather than checking
-the identity against the users: parameter of every access group, it's
-checked against the users: parameter of only some specific access groups.
-This is done with the key: parameter. For example:
-.PP
-.Vb 5
-\& auth example {
-\& key: special
-\& hosts: *.example.com
-\& default: <SPECIAL>
-\& }
-.Ve
-.PP
-.Vb 5
-\& access example {
-\& key: special
-\& users: <SPECIAL>
-\& newsgroups: *
-\& }
-.Ve
-.PP
-In this case, the two key: parameters bind this auth group with this
-access group. For any incoming connection matching \*(L"*.example.com\*(R"
-(assuming there isn't any later auth group that also matches such hosts),
-no access group that doesn't have \*(L"key: special\*(R" will even be considered.
-Similarly, the above access group will only be checked if the user was
-authenticated with an auth group containing \*(L"key: special\*(R". This
-mechanism normally isn't useful; there is almost always a better way to
-achieve the same result.
-.PP
-Also note in the example that there's no default\-domain: parameter, which
-means that no domain is appended to the default username and the identity
-for such connections is just \*(L"<\s-1SPECIAL\s0>\*(R". Note that some additional
-add-ons to \s-1INN\s0 may prefer that authenticated identities always return a
-full e\-mail address (including a domain), so you may want to set up your
-system that way.
-.PP
-Below is the full list of allowable parameters for auth groups and access
-groups, and after that are some examples that may make this somewhat
-clearer.
-.SH "AUTH GROUP PARAMETERS"
-.IX Header "AUTH GROUP PARAMETERS"
-An access group without at least one of the res:, auth:, perl_auth:,
-python_auth:, or default: parameters makes no sense (and in practice will
-just be ignored).
-.IP "\fBhosts:\fR" 4
-.IX Item "hosts:"
-A comma-separated list of remote hosts, wildmat patterns matching either
-hostnames or \s-1IP\s0 addresses, or \s-1IP\s0 netblocks specified in \s-1CIDR\s0 notation. If
-a user connects from a host that doesn't match this parameter, this auth
-group will not match the connection and is ignored.
-.Sp
-Note that if you have a large number of patterns that can't be merged into
-broader patterns (such as a large number of individual systems scattered
-around the net that should have access), the hosts: parameter may exceed
-the maximum line length of 8,192 characters. In that case, you'll need to
-break that auth group into multiple auth groups, each with a portion of
-the hosts listed in its hosts: parameter, and each assigning the same user
-identity.
-.Sp
-All hosts match if this parameter is not given.
-.IP "\fBlocaladdress:\fR" 4
-.IX Item "localaddress:"
-A comma-separated list of local host or address patterns with the same
-syntax as the same as with the hosts: parameter. If this parameter is
-specified, its auth group will only match connections made to a matching
-local interface. (Obviously, this is only useful for servers with
-multiple interfaces.)
-.Sp
-All local addresses match if this parameter is not given.
-.IP "\fBres:\fR" 4
-.IX Item "res:"
-A simple command line for a user resolver (shell metacharacters are not
-supported). If a full path is not given, the program executed must be in
-the \fIpathbin\fR/auth/resolv directory. A resolver is an authentication
-program which attempts to figure out the identity of the connecting user
-using nothing but the connection information (in other words, the user
-has not provided a username and password). An examples of a resolver
-would be a program that assigns an identity from an ident callback or
-from the user's hostname.
-.Sp
-One auth group can have multiple res: parameters, and they will be tried
-in the order they're listed. The results of the first successful one
-will be used.
-.IP "\fBauth:\fR" 4
-.IX Item "auth:"
-A simple command line for a user authenticator (shell metacharacters are
-not supported). If a full path is not given, the program executed must be
-located in the \fIpathbin\fR/auth/passwd directory. An authenticator is a
-program used to handle a user-supplied username and password, via a
-mechanism such as \s-1AUTHINFO\s0 \s-1USER/PASS\s0. Like with res:, one auth group can
-have multiple auth: parameters; they will be tried in order and the
-results of the first successful one will be used. See also perl_auth:
-below.
-.Sp
-The most common authenticator to use is \fIckpasswd\fR\|(8); see its man page for
-more information.
-.IP "\fBperl_auth:\fR" 4
-.IX Item "perl_auth:"
-A path to a perl script for authentication. The perl_auth: parameter
-works exactly like auth:, except that it calls the named script using
-the perl hook rather then an external program. Multiple/mixed use of
-the auth, perl_auth, and python_auth parameters is permitted within any
-auth group; each line is tried in the order it appears. perl_auth:
-has more power than auth: in that it provides the authentication
-program with additional information about the client and the ability
-to return an error string and a username. This parameter is only
-valid if \s-1INN\s0 is compiled with Perl support (\fB\-\-with\-perl\fR passed to
-configure). More information may be found in \fIdoc/hook\-perl\fR.
-.IP "\fBpython_auth:\fR" 4
-.IX Item "python_auth:"
-A Python script for authentication. The \fIpython_auth\fR parameter works
-exactly like \fIauth\fR, except that it calls the named script (without its
-\&\f(CW\*(C`.py\*(C'\fR extension) using the Python hook rather then an external program.
-Multiple/mixed use of the \fIauth\fR, \fIperl_auth\fR, and \fIpython_auth\fR
-parameters is permitted within any auth group; each line is tried
-in the order it appears. \fIpython_auth\fR has more power than \fIauth\fR
-in that it provides the authentication program with additional information
-about the client and the ability to return an error string and a username.
-This parameter is only valid if \s-1INN\s0 is compiled with Python support
-(\fB\-\-with\-python\fR passed to \fBconfigure\fR). More information may be
-found in \fIdoc/hook\-python\fR.
-.IP "\fBdefault:\fR" 4
-.IX Item "default:"
-The default username for connections matching this auth group. This is
-the username assigned to the user at connection time if all resolvers fail
-or if there are no res: parameters. Note that it can be either a bare
-username, in which case default\-domain: (if present) is appended after
-an \f(CW\*(C`@\*(C'\fR, or a full identity string containing an \f(CW\*(C`@\*(C'\fR, in which case it
-will be used verbatim.
-.IP "\fBdefault\-domain:\fR" 4
-.IX Item "default-domain:"
-The default domain string for this auth group. If a user resolver or
-authenticator doesn't provide a domain, or if the default username is used
-and it doesn't contain a \f(CW\*(C`@\*(C'\fR, this domain is used to form the user
-identity. (Note that for a lot of setups, it's not really necessary for
-user identities to be qualified with a domain name, in which case there's
-no need to use this parameter.)
-.IP "\fBkey:\fR" 4
-.IX Item "key:"
-If this parameter is present, any connection matching this auth group will
-have its privileges determined only by the subset of access groups
-containing a matching key parameter.
-.IP "\fBrequire_ssl:\fR" 4
-.IX Item "require_ssl:"
-If set to true, an incoming connection only matches this auth group if
-it is encrypted using \s-1SSL\s0. This parameter is only valid if \s-1INN\s0 is
-compiled with \s-1SSL\s0 support (\fB\-\-with\-openssl\fR passed to configure).
-.IP "\fBperl_access:\fR" 4
-.IX Item "perl_access:"
-A path to a perl script for dynamically generating an access group. If
-an auth group matches successfully and contains a perl_access parameter,
-then the argument perl script will be used to create an access group.
-This group will then determine the access rights of the client,
-overriding any access groups in \fIreaders.conf\fR. If and only if a
-sucessful auth group contains the perl_access parameter, \fIreaders.conf\fR
-access groups are ignored and the client's rights are instead determined
-dynamically. This parameter is only valid if \s-1INN\s0 is compiled with Perl
-support (\fB\-\-with\-perl\fR passed to configure). More information may be
-found in the file \fIdoc/hook\-perl\fR.
-.IP "\fBpython_access:\fR" 4
-.IX Item "python_access:"
-A Python script for dynamically generating an access group. If
-an auth group matches successfully and contains a \fIpython_access\fR parameter,
-then the argument script (without its \f(CW\*(C`.py\*(C'\fR extension) will be used to
-create an access group. This group will then determine the access rights
-of the client, overriding any access groups in \fIreaders.conf\fR. If and only
-if a successful auth group contains the \fIpython_access\fR parameter, \fIreaders.conf\fR
-access groups are ignored and the client's rights are instead determined
-dynamically. This parameter is only valid if \s-1INN\s0 is compiled with Python
-support (\fB\-\-with\-python\fR passed to \fBconfigure\fR). More information may be
-found in the file \fIdoc/hook\-python\fR.
-.IP "\fBpython_dynamic:\fR" 4
-.IX Item "python_dynamic:"
-A Python script for applying access control dynamically on a per newsgroup
-basis. If an auth group matches successfully and contains a
-\&\fIpython_dynamic\fR parameter, then the argument script (without its
-\&\f(CW\*(C`.py\*(C'\fR extension) will be used to determine the clients rights each time
-the user attempts to view a newsgroup, or read or post an article. Access
-rights as determined by \fIpython_dynamic\fR override the values of access
-group parameters such as \fInewsgroups\fR, \fIread\fR and \fIpost\fR. This parameter
-is only valid if \s-1INN\s0 is compiled with Python support (\fB\-\-with\-python\fR
-passed to \fBconfigure\fR). More information may be found in the file
-\&\fIdoc/hook\-python\fR.
-.SH "ACCESS GROUP PARAMETERS"
-.IX Header "ACCESS GROUP PARAMETERS"
-.IP "\fBusers:\fR" 4
-.IX Item "users:"
-The privileges given by this access group apply to any user identity which
-matches this comma-separated list of wildmat patterns. If this parameter
-isn't given, the access group applies to all users (and is essentially
-equivalent to \f(CW\*(C`users: *\*(C'\fR).
-.IP "\fBnewsgroups:\fR" 4
-.IX Item "newsgroups:"
-Users that match this access group are allowed to read and post to all
-newsgroups matching this comma-separated list of wildmat patterns. The
-empty string is equivalent to \f(CW\*(C`newsgroups: *\*(C'\fR; if this parameter is
-missing, the connection will be rejected (unless read: and/or post: are
-used instead, see below).
-.IP "\fBread:\fR" 4
-.IX Item "read:"
-Like the newsgroups: parameter, but the client is only given permission to
-read the matching newsgroups. This parameter is often used with post:
-(below) to specify some read-only groups; it cannot be used in the same
-access group with a newsgroups: parameter. (If read: is used and post:
-is missing, the client will have only read-only access.)
-.IP "\fBpost:\fR" 4
-.IX Item "post:"
-Like the newsgroups: parameter, but the client is only given permission to
-post to the matching newsgroups. This parameter is often used with read:
-(above) to define the patterns for reading and posting separately (usually
-to give the user permission to read more newsgroups than they're permitted
-to post to). It cannot be used in the same access group with a
-newsgroups: parameter.
-.IP "\fBaccess:\fR" 4
-.IX Item "access:"
-A set of letters specifying the permissions granted to the client. The
-letters are chosen from the following set:
-.RS 4
-.IP "R" 3
-.IX Item "R"
-The client may read articles.
-.IP "P" 3
-.IX Item "P"
-The client may post articles.
-.IP "I" 3
-.IX Item "I"
-The client may inject articles with \s-1IHAVE\s0. Note that in order to
-inject articles with the \s-1IHAVE\s0 the user must also have \s-1POST\s0 permission
-(the \f(CW\*(C`P\*(C'\fR option).
-.IP "A" 3
-.IX Item "A"
-The client may post articles with Approved: headers (in other words, may
-approve articles for moderated newsgroups). By default, this is not
-allowed.
-.IP "N" 3
-.IX Item "N"
-The client may use the \s-1NEWNEWS\s0 command, overriding the global setting.
-.IP "L" 3
-.IX Item "L"
-The client may post to newsgroups that are set to disallow local posting
-(mode \f(CW\*(C`n\*(C'\fR in the \fIactive\fR\|(5) file).
-.RE
-.RS 4
-.Sp
-Note that if this parameter is given, \fIallownewnews\fR in \fIinn.conf\fR is
-ignored for connections matching this access group and the ability of the
-client to use \s-1NEWNEWS\s0 is entirely determined by the presence of \f(CW\*(C`N\*(C'\fR in
-the access string. If you want to support \s-1NEWNEWS\s0, make sure to include
-\&\f(CW\*(C`N\*(C'\fR in the access string when you use this parameter.
-.Sp
-Note that if this parameter is given and \f(CW\*(C`R\*(C'\fR isn't present in the access
-string, the client cannot read regardless of newsgroups: or read:
-parameters. Similarly, if this parameter is given and \f(CW\*(C`P\*(C'\fR isn't present,
-the client cannot post. This use of access: is deprecated and confusing;
-it's strongly recommended that if the access: parameter is used, \f(CW\*(C`R\*(C'\fR and
-\&\f(CW\*(C`P\*(C'\fR always be included in the access string and newsgroups:, read:, and
-post: be used to control access. (To grant read access but no posting
-access, one can have just a read: parameter and no post: parameter.)
-.RE
-.IP "\fBkey:\fR" 4
-.IX Item "key:"
-If this parameter is present, this access group is only considered when
-finding privileges for users matching auth groups with this same key:
-parameter.
-.IP "\fBreject_with:\fR" 4
-.IX Item "reject_with:"
-If this parameter is present, a client matching this block will be
-disconnected with a \*(L"Permission denied\*(R" message containing the contents
-(a \*(L"reason\*(R" string) of this parameter. Some newsreaders will then
-display the reason to the user.
-.IP "\fBmax_rate:\fR" 4
-.IX Item "max_rate:"
-If this parameter is present (and nonzero), it is used for \fBnnrpd\fR's
-rate-limiting code. The client will only be able to download at this
-speed (in bytes/second). Note that if \s-1SSL\s0 is being used, limiting
-is applied to the pre-encryption datastream.
-.IP "\fBlocaltime:\fR" 4
-.IX Item "localtime:"
-If a Date: header is not included in a posted article, \fInnrpd\fR\|(8) normally
-adds a new Date: header in \s-1UTC\s0. If this is set to true, the Date: header
-will be formatted in local time instead. This is a boolean value and the
-default is false.
-.IP "\fBnewsmaster:\fR" 4
-.IX Item "newsmaster:"
-Used as the contact address in the help message returned by \fInnrpd\fR\|(8), if
-the virtualhost: parameter is set to true.
-.IP "\fBstrippath:\fR" 4
-.IX Item "strippath:"
-If set to true, any Path: header provided by a user in a post is stripped
-rather than used as the beginning of the Path: header of the article.
-This is a boolean value and the default is false.
-.IP "\fBperlfilter:\fR" 4
-.IX Item "perlfilter:"
-If set to false, posts made by these users do not pass through the Perl
-filter even if it is otherwise enabled. This is a boolean value and the
-default is true.
-.IP "\fBpythonfilter:\fR" 4
-.IX Item "pythonfilter:"
-If set to false, posts made by these users do not pass through the Python
-filter even if it is otherwise enabled. This is a boolean value and the
-default is true.
-.IP "\fBvirtualhost:\fR" 4
-.IX Item "virtualhost:"
-Set this parameter to true in order to make \fBnnrpd\fR behave as if it is
-running on a server with a different name than it actually is. If you
-set this parameter to true, you must also set either pathhost: or domain:
-in the relevant access group in \fIreaders.conf\fR to something different
-than is set in \fIinn.conf\fR. All articles displayed to clients will then have
-their Path: and Xref: headers altered to appear to be from the server
-named in pathhost: or domain: (whichever is set), and posted articles will
-use that server name in the Path:, Message\-ID:, and X\-Trace: headers.
-.Sp
-Note that setting this parameter requires the server modify all posts
-before presenting them to the client and therefore may decrease
-performance slightly.
-.PP
-In addition, all of the following parameters are valid in access groups
-and override the global setting in \fIinn.conf\fR. See \fIinn.conf\fR\|(5) for the
-descriptions of these parameters:
-.PP
-.Vb 6
-\& addnntppostingdate, addnntppostinghost, backoff_auth, backoff_db,
-\& backoff_k, backoff_postfast, backoff_postslow, backoff_trigger,
-\& checkincludedtext, clienttimeout, complaints, domain,
-\& fromhost, localmaxartsize, moderatormailer, nnrpdauthsender,
-\& nnrpdcheckart, nnrpdoverstats, nnrpdposthost, nnrpdpostport, organization,
-\& pathhost, readertrack, spoolfirst, strippostcc.
-.Ve
-.SH "SUMMARY"
-.IX Header "SUMMARY"
-Here's a basic summary of what happens when a client connects:
-.IP "\(bu" 2
-All auth groups are scanned and the ones that don't match the client
-(due to hosts:, localaddress:, require_ssl:, etc) are eliminated.
-.IP "\(bu" 2
-The remaining auth groups are scanned from the last to the first, and an
-attempt is made to apply it to the current connection. This means running
-res: programs, if any, and otherwise applying default:. The first auth
-group (starting from the bottom) to return a valid user is kept as the
-active auth group.
-.IP "\(bu" 2
-If no auth groups yield a valid user (none have default: parameters or
-successful res: programs) but some of the auth groups have auth: lines
-(indicating a possibility that the user can authenticate and then obtain
-permissions), the connection is considered to have no valid auth group
-(which means that the access groups are ignored completely) but the
-connection isn't closed. Instead, 480 is returned for everything until
-the user authenticates.
-.IP "\(bu" 2
-When the user authenticates, the auth groups are rescanned, and only the
-matching ones which contain at least one auth, perl_auth, or
-python_auth line are considered. These auth groups are scanned from
-the last to the first, running auth: programs and perl_auth: or
-python_auth: scripts. The first auth group (starting from the bottom)
-to return a valid user is kept as the active auth group.
-.IP "\(bu" 2
-Regardless of how an auth group is established, as soon as one is, that
-auth group is used to assign a user identity by taking the result of the
-successful res, auth, perl_auth, or python_auth line (or the
-default: if necessary), and appending the default-domain if
-necessary. (If the perl_access: or python_access: parameter is
-present, see below.)
-.IP "\(bu" 2
-Finally, an access group is selected by scanning the access groups from
-bottom up and finding the first match. (If the established auth group
-contained a perl_access: or python_access line, the dynamically
-generated access group returned by the script is used instead.)
-User permissions are granted based on the established access group.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Probably the simplest useful example of a complete \fIreaders.conf\fR,
-this gives permissions to read and post to all groups to any connections
-from the \*(L"example.com\*(R" domain, and no privileges for anyone connecting
-elsewhere:
-.PP
-.Vb 4
-\& auth example.com {
-\& hosts: "*.example.com, example.com"
-\& default: <LOCAL>
-\& }
-.Ve
-.PP
-.Vb 3
-\& access full {
-\& newsgroups: *
-\& }
-.Ve
-.PP
-Note that the access realm has no users: key and therefore applies to any
-user identity. The only available auth realm only matches hosts in the
-\&\*(L"example.com\*(R" domain, though, so any connections from other hosts will be
-rejected immediately.
-.PP
-If you have some systems that should only have read-only access to the
-server, you can modify the example above slightly by adding an additional
-auth and access group:
-.PP
-.Vb 4
-\& auth lab {
-\& hosts: "*.lab.example.com"
-\& default: <LAB>
-\& }
-.Ve
-.PP
-.Vb 4
-\& access lab {
-\& users: <LAB>
-\& read: *
-\& }
-.Ve
-.PP
-If those are put in the file after the above example, they'll take
-precedence (because they're later in the file) for any user coming from a
-machine in the lab.example.com domain, everyone will only have read
-access, not posting access.
-.PP
-Here's a similar example for a news server that accepts connections from
-anywhere but requires the user to specify a username and password. The
-username and password are first checked against an external database of
-usernames and passwords, and then against the system shadow password file:
-.PP
-.Vb 4
-\& auth all {
-\& auth: "ckpasswd \-d <pathdb in inn.conf>/newsusers"
-\& auth: "ckpasswd \-s"
-\& }
-.Ve
-.PP
-.Vb 4
-\& access full {
-\& users: *
-\& newsgroups: *
-\& }
-.Ve
-.PP
-When the user first connects, there are no res: keys and no default, so
-they don't receive any valid identity and the connection won't match any
-access groups (even ones with \f(CW\*(C`users: *\*(C'\fR). Such users receive nothing
-but authentication-required responses from nnrpd until they authenticate.
-.PP
-If they then later authenticate, the username and password are checked
-first by running \fBckpasswd\fR with the \fB\-d\fR option for an external dbm
-file of encrypted passwords, and then with the \fB\-s\fR option to check the
-shadow password database (note that this option may require ckpasswd to
-be setgid to a shadow group, and there are security considerations; see
-\&\fIckpasswd\fR\|(8) for details). If both of those fail, the user will continue
-to have no identity; otherwise, an identity will be assigned (usually
-the supplied username, perhaps with a domain appended, although an
-authenticator technically can provide a completely different username
-for the identity), and the access group will match, giving full access.
-.PP
-It may be educational to consider how to combine the above examples;
-general groups always go first. The order of the auth groups actually
-doesn't matter, since the \*(L"hosts: example.com\*(R" one only matches
-connections before username/password is sent, and the \*(L"auth: ckpasswd\*(R"
-one only matches after; order would matter if either group applied to
-both cases. The order of the access groups in this case does matter,
-provided the newsgroups: lines differ; the access group with no users:
-line needs to be first, with the \*(L"users: <\s-1LOCAL\s0>\*(R" group after.
-.PP
-Here's a very complicated example. This is for an organization that has
-an internal hierarchy \*(L"example.*\*(R" only available to local shell users, who
-are on machines where identd can be trusted. Dialup users must provide a
-username and password, which is then checked against \s-1RADIUS\s0. Remote users
-have to use a username and password that's checked against a database on
-the news server. Finally, the admin staff (users \*(L"joe\*(R" and \*(L"jane\*(R") can
-post anywhere (including the \*(L"example.admin.*\*(R" groups that are read-only
-for everyone else), and are exempted from the Perl filter. For an
-additional twist, posts from dialup users have their Sender: header
-replaced by their authenticated identity.
-.PP
-Since this organization has some internal moderated newsgroups, the admin
-staff can also post messages with Approved: headers, but other users
-cannot.
-.PP
-.Vb 5
-\& auth default {
-\& auth: "ckpasswd \-f <pathdb in inn.conf>/newsusers"
-\& default: <FAIL>
-\& default\-domain: example.com
-\& }
-.Ve
-.PP
-.Vb 7
-\& auth shell {
-\& hosts: *.shell.example.com
-\& res: ident
-\& auth: "ckpasswd \-s"
-\& default: <FAIL>
-\& default\-domain: shell.example.com
-\& }
-.Ve
-.PP
-.Vb 6
-\& auth dialup {
-\& hosts: *.dialup.example.com
-\& auth: radius
-\& default: <FAIL>
-\& default\-domain: dialup.example.com
-\& }
-.Ve
-.PP
-.Vb 5
-\& access shell {
-\& users: *@shell.example.com
-\& read: *
-\& post: "*, !example.admin.*"
-\& }
-.Ve
-.PP
-.Vb 5
-\& access dialup {
-\& users: *@dialup.example.com
-\& newsgroups: *,!example.*
-\& nnrpdauthsender: true
-\& }
-.Ve
-.PP
-.Vb 4
-\& access other {
-\& users: "*@example.com, !<FAIL>@example.com"
-\& newsgroups: *,!example.*
-\& }
-.Ve
-.PP
-.Vb 4
-\& access fail {
-\& users: "<FAIL>@*"
-\& newsgroups: !*
-\& }
-.Ve
-.PP
-.Vb 6
-\& access admin {
-\& users: "joe@*,jane@*"
-\& newsgroups: *
-\& access: "RPA"
-\& perlfilter: false
-\& }
-.Ve
-.PP
-Note the use of different domains to separate dialup from shell users
-easily. Another way to do that would be with key: parameters, but this
-way provides slightly more intuitive identity strings. Note also that the
-fail access group catches not only failing connections from external users
-but also failed authentication of shell and dialup users and dialup users
-before they've authenticated. The identity string given for, say, dialup
-users before \s-1RADIUS\s0 authentication has been attempted matches both the
-dialup access group and the fail access group, since it's
-\&\*(L"<\s-1FAIL\s0>@dialup.example.com\*(R", but the fail group is last so it takes
-precedence.
-.PP
-The shell auth group has an auth: parameter so that users joe and jane
-can, if they choose, use username and password authentication to gain
-their special privileges even if they're logged on as a different user on
-the shell machines (or if ident isn't working). When they first connect,
-they'd have the default access for that user, but they could then send
-\&\s-1AUTHINFO\s0 \s-1USER\s0 and \s-1AUTHINFO\s0 \s-1PASS\s0 (or \s-1AUTHINFO\s0 \s-1SIMPLE\s0) and get their
-extended access.
-.PP
-Also note that if the users joe and jane are using their own accounts,
-they get their special privileges regardless of how they connect, whether
-the dialups, the shell machines, or even externally with a username and
-password.
-.PP
-Finally, here's a very simple example of a configuration for a public
-server for a particular hierarchy.
-.PP
-.Vb 4
-\& auth default {
-\& hosts: *
-\& default: <PUBLIC>
-\& }
-.Ve
-.PP
-.Vb 4
-\& access default {
-\& users: <PUBLIC>
-\& newsgroups: example.*
-\& }
-.Ve
-.PP
-Notice that clients aren't allowed to read any other groups; this keeps
-them from getting access to administrative groups or reading control
-messages, just as a precaution. When running a public server like this,
-be aware that many public hierarchies will later be pulled down and
-reinjected into the main Usenet, so it's highly recommended that you also
-run a Perl or Python filter to reject any messages crossposted out of your
-local hierarchy and any messages containing a Supersedes: header. This
-will keep messages posted to your public hierarchy from hurting any of the
-rest of Usenet if they leak out.
-.SH "SECURITY CONSIDERATIONS"
-.IX Header "SECURITY CONSIDERATIONS"
-In general, separate passwords should be used for \s-1NNTP\s0 wherever
-possible; the \s-1NNTP\s0 protocol itself does not protect passwords from
-casual interception, and many implementations (including this one) do
-not \*(L"lock out\*(R" accounts or otherwise discourage password-guessing
-attacks. So it is best to ensure that a compromised password has
-minimal effects.
-.PP
-Authentication using the \s-1AUTHINFO\s0 \s-1USER/PASS\s0 commands passes unencrypted
-over the network. Extreme caution should therefore be used especially
-with system passwords (e.g. \f(CW\*(C`auth: ckpasswd \-s\*(C'\fR). Passwords can be
-protected by using \s-1NNTP\s0 over \s-1SSL\s0 or through ssh tunnels, and this usage
-can be enforced by a well-considered server configuration that only
-permits certain auth groups to be applied in certain cases. Here are
-some ideas:
-.IP "\(bu" 4
-To restrict connections on the standard nntp port (119) to use \s-1SSL\s0 for
-some (or all) of the auth groups to match, use the require_ssl:
-parameter.
-.IP "\(bu" 4
-If you consider your local network (but not the internet) secure, have
-some auth groups with a restrictive hosts: parameter; they would go
-above, with ones having global applicability below.
-.IP "\(bu" 4
-Consider running a \f(CW\*(C`nnrpd \-S\*(C'\fR (with \f(CW\*(C`\-D\*(C'\fR, or out of \*(L"super\-server\*(R"
-like \fBinetd\fR) on the \s-1NNTPS\s0 port (563) for clients that support \s-1SSL\s0. See
-\&\fInnrpd\fR\|(8) for more details about how to configure that. You
-can use the require_ssl: parameter, or \f(CW\*(C`\-c\*(C'\fR to specify an alternate
-\&\fIreaders.conf\fR if you want a substantially different configuration for
-this case.
-.IP "\(bu" 4
-If you want to restrict an auth group to only match loopback connections
-(for users running newsreaders on localhost or connecting via an ssh
-tunnel), use the localaddress: parameter.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Aidan Cully <aidan@panix.com> for InterNetNews. Substantially
-expanded by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: readers.conf.5 7895 2008-06-22 17:54:10Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIauth_krb5\fR\|(8), \fIauth_smb\fR\|(8), \fIckpasswd\fR\|(8), \fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInewsfeeds\fR\|(5),
-\&\fInnrpd\fR\|(8), \fIuwildmat\fR\|(3).
+++ /dev/null
-.\" $Revision: 5909 $
-.TH RNEWS 1
-.SH NAME
-rnews \- receive news from a UUCP connection
-.SH SYNOPSIS
-.B rnews
-[
-.BI \-h " host"
-]
-[
-.B \-N
-]
-[
-.BI \-P " port"
-]
-[
-.BI \-r " remote"
-]
-[
-.BI \-S " remote"
-]
-[
-.B \-U
-]
-[
-.B \-v
-]
-[
-.I input
-]
-.SH DESCRIPTION
-.I Rnews
-reads messages typically queued by a UUCP newsfeed and
-sends them to the InterNetNews server (either ``localhost'', or the
-value defined by the variable
-.IR <nnrpdposthost\ in\ inn.conf> .
-.PP
-The message is read from the specified input file, or standard input
-if no input is named.
-.PP
-When sent over UUCP, Usenet articles are typically joined in a single
-batch to reduce the UUCP overhead.
-Batches can also be compressed, to reduce the communication time.
-If a message does not start with a number sign (``#'') and an exclamation
-point, then the entire input is taken as a single news article.
-If it does start with with those two characters, then the first line is
-read and interpreted as a batch command.
-.PP
-If the command is ``#! rnews nnn'' where
-.I nnn
-is a number, then the next
-.I nnn
-bytes (starting with the next line) are read as a news article.
-.PP
-If the command is ``#! cunbatch'' then the rest of input is fed to the
-.IR compress (1)
-program with the ``\-d'' flag to uncompress it, and
-the output of this pipe is read as
-.IR rnews 's
-input.
-This is for historical compatibility \(em there is no program named
-.IR cunbatch .
-A compressed batch will start with a ``#! cunbatch'' line, then contain a
-series of articles separated by ``#! rnews nnn'' lines.
-If
-.I <DO_RNEWSPROGS in include/config.h>
-is defined and the command is any other word, then
-.I rnews
-will try to execute a program with that name in the directory
-.IR <pathbin\ in\ inn.conf>/bin/rnews.libexec .
-
-The batch will be fed into the program's standard input, and the
-standard output will be read back as input into
-.IR rnews .
-If
-.I <DO_RNEWS_SAVE_BAD in include/config.h>
-is defined and
-.I rnews
-detects any problems with an article such as a missing header, or
-an unintelligible reply from the server, it will save a copy of the article
-in the
-.I <pathincoming in inn.conf>/bad
-directory.
-.SH OPTIONS
-.TP
-.B \-h
-If the ``\fB\-h\fP'' flag is given, then
-.I rnews
-will log the Message-ID and host via
-.IR syslog (3)
-for each article offered to the server.
-Logging will only be done if the value is not an empty string.
-If ``\fB\-h\fP'' is not set, the environment variable
-.I <_ENV_UUCPHOST in include/paths.h>
-(typically
-.IR $UU_MACHINE )
-will be examined for a similar string.
-.TP
-.B \-N
-Normally, if unpacking the input fails it is re-spooled to
-.I <pathincoming in inn.conf>
-for another attempt later. If the ``\fB\-N\fP'' flag is used then no such
-re-spooling is done and rnews exits with status value ``9'' to indicate
-this.
-.TP
-.B \-P
-If the ``\fB\-P\fP'' flag is used, then the articles will be sent to the
-specified port on the remote host.
-.TP
-.B \-r
-If the ``\fB\-r\fP'' flag is used, then the articles will be sent to the
-named remote host instead of the default host.
-.TP
-.B \-S
-\&``\fB\-S\fP'' flag is equivalent to ``\fB\-r\fP'' flag.
-.TP
-.B \-U
-If the server is not available, the message is spooled into a new file
-created in the
-.I <pathincoming in inn.conf>
-directory.
-The ``\fB\-U\fP'' flag may be used to send all spooled messages to the
-server once it becomes available again, and can be invoked regularly
-by
-.IR cron (8).
-.TP
-.B \-v
-If the ``\fB\-v\fP'' flag is used, it will print a notice of all errors on the
-standard error, naming the input file (if known) and printing the first
-few characters of the input.
-Errors are always logged through
-.IR syslog (3).
-.SH BUGS
-.I Rnews
-cannot process articles that have embedded ``\e0'' characters in them.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: rnews.1 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5),
-innd(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SASL.CONF 5"
-.TH SASL.CONF 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-sasl.conf \- SASL Configuration file for nnrpd.
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The file \fIsasl.conf\fR in \fIpathetc\fR specifies Simple Authentication
-and Security Layer (\s-1SASL\s0), defined in \s-1RFC\s0 2222, for nnrpd.
-Now nnrpd implements only Security Layer support, which is an extension
-of \s-1RFC\s0 2595. This means you can get \s-1SSL\s0 or \s-1TLS\s0 encrypted \s-1NNRP\s0 between
-your server and newsreaders. It requires OpenSSL 0.9.3 or newer from
-http://www.openssl.org/; it has been tested with versions 0.9.4 and 0.9.5.
-.SH "INSTALLATION"
-.IX Header "INSTALLATION"
-To use \s-1SSL\s0, a certificate and private key are needed that you can
-create using the openssl binary.
-Make certain that each keys are owned by your news user, news group,
-and are mode 0640 or 0660.
-.Sh "\s-1EXAMPLE\s0"
-.IX Subsection "EXAMPLE"
-.Vb 4
-\& openssl req \-new \-x509 \-nodes \-out /usr/local/news/lib/cert.pem\e
-\& \-days 366 \-keyout /usr/local/news/lib/cert.pem
-\& chown news:news /usr/local/news/lib/cert.pem
-\& chmod 640 /usr/local/news/lib/cert.pem
-.Ve
-.PP
-You also can make the keys as the root user with \f(CW\*(C`make cert\*(C'\fR.
-.SH "CONFIGURATION"
-.IX Header "CONFIGURATION"
-Comments begin with a number sign (\f(CW\*(C`#\*(C'\fR) and continue through the
-end of the line. Blank lines and comments are ignored.
-All other lines specify parameters, and should be of the form
-.PP
-.Vb 1
-\& <option>: <value>
-.Ve
-.PP
-where <option> is the name of the configuration option being set and
-<value> is the value that the configuration option is being set to.
-.PP
-Blank lines and lines beginning with (\f(CW\*(C`#\*(C'\fR) are ignored.
-For boolean options, the values \f(CW\*(C`yes\*(C'\fR, \f(CW\*(C`on\*(C'\fR, \f(CW\*(C`t\*(C'\fR,
-and \f(CW1\fR turn the option on; the values \f(CW\*(C`no\*(C'\fR, \f(CW\*(C`off\*(C'\fR,
-\&\f(CW\*(C`f\*(C'\fR, and \f(CW0\fR turn the option off.
-.IP "tls_cert_file" 4
-.IX Item "tls_cert_file"
-The path to a file containing the server's certificate.
-.IP "tls_key_file" 4
-.IX Item "tls_key_file"
-The path to a file containing the server's private key.
-.IP "tls_ca_path" 4
-.IX Item "tls_ca_path"
-The path to a directory containing the \s-1CA\s0's certificate.
-.IP "tls_ca_file" 4
-.IX Item "tls_ca_file"
-The path to a file containing the \s-1CA\s0's certificate.
-.SH "TO DO"
-.IX Header "TO DO"
-Implement methods of the authentication protocols of \s-1SASL\s0.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Kenichi \s-1OKADA\s0 <okada@opaopa.org> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinn.conf\fR\|(5), \fIinnd\fR\|(8), \fInnrpd\fR\|(8), \fIreaders.conf\fR\|(5)
+++ /dev/null
-.TH SCANLOGS 8
-.SH NAME
-scanlogs \- summarize INN log files.
-.SH SYNOPSIS
-.B scanlogs
-[
-.B norotate
-]
-.SH DESCRIPTION
-.I Scanlogs
-summarizes the information recorded in the INN log files (see
-.IR newslog (5)).
-By default, it also rotates and cleans out the logs.
-It is normally invoked by the
-.IR news.daily (8)
-script.
-.SH KEYWORDS
-.PP
-The following keywords are accepted:
-.TP
-.I norotate
-Using this keyword disables the rotating and cleaning aspect of the log
-processing: the logs files are only scanned for information and no contents
-are altered.
-.PP
-If
-.I scanlogs
-is invoked more than once a day, the ``norotate'' keyword should be used
-to prevent premature log cleaning.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: scanlogs.8 309 1998-01-28 04:08:10Z scrappy $
-.SH "SEE ALSO"
-innd(8),
-newslog(5),
-news.daily(8),
-nnrpd(8).
+++ /dev/null
-.TH SEND-UUCP 8
-.SH NAME
-send-nntp, send-ihave \- send Usenet articles to remote site
-.SH SYNOPSIS
-.B send-nntp
-[
-.B \-d
-]
-.B sitename:hostname | sitename
-[
-.B sitename:hostname | sitename ..
-]
-.PP
-.B send-ihave
-[
-.B \-d
-]
-.B sitename:hostname | sitename
-[
-.B sitename:hostname | sitename ..
-]
-.SH DESCRIPTION
-The send-* utilities are scripts that process the batch files written
-by
-.IR innd (8)
-to send Usenet articles to a remote NNTP site.
-.PP
-The sites to be fed may be specified by giving
-.I sitename
-.I hostname
-pairs on the command line.
-.PP
-The
-.I sitename
-is the label the site has in the
-.I newsfeeds
-file, the
-.I hostname
-is the real hostname of the remote site, a FQDN (Fully Qualified Domain Name).
-Normally, the
-.I sitename
-and the
-.I hostname
-are the same, and as such don't have to be specified as sitename:hostname
-pairs but just as a sitename.
-.PP
-.I send-nntp
-starts an innxmit to send the articles to the remote site.
-.PP
-.I send-ihave
-encapsulates the articles in an
-.I ihave
-control message and uses
-.I inews
-to send the articles to a
-.I to.sitename
-pseudo-group. Using
-.I send-ihave
-is discouraged, nobody uses it anymore and even the author of this manpage
-is unsure as to how it actually works or used to work.
-.PP
-.I send-*
-expect that the batchfile for a site is named
-.IR <pathoutgoing\ in\ inn.conf>/sitename .
-To prevent batchfile corruption,
-.IR shlock (1)
-is used to ``lock'' these files.
-.SH OPTIONS
-.TP
-.B "\-d"
-The ``\-d'' flag causes
-.I nntpsend
-to send output to stdout rather than the log file
-.IR <pathlog\ in\ inn.conf>/<program-name>.log .
-.SH NOTES
-You should probably not use send-nntp, but
-.IR innfeed ,
-or if that is not possible,
-.IR nntpsend .
-.PP
-The usual flags for a batch file for send-nntp are ``\fBTf,Wfm\fP''.
-.SH "SEE ALSO"
-newsfeeds(5),
-nntpsend(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SEND-UUCP 8"
-.TH SEND-UUCP 8 "2008-04-06" "INN 2.4.4" "InterNetNews Documentation"
-.SH "NAME"
-send\-uucp \- Send Usenet articles via UUCP
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBsend-uucp\fR [\fI\s-1SITE\s0\fR ...]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The \fBsend-uucp\fR program processes batch files written by \fIinnd\fR\|(8) to send
-Usenet articles to \s-1UUCP\s0 sites. It reads a configuration file to control how
-it behaves with various sites. Normally, it's run periodically out of cron
-to put together batches and send them to remote \s-1UUCP\s0 sites.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-Any arguments provided to the program are interpreted as a list of sites
-specfied in \fIsend\-uucp.cf\fR for which batches should be generated. If no
-arguments are supplied then batches will be generated for all sites listed
-in that configuration file.
-.SH "CONFIGURATION"
-.IX Header "CONFIGURATION"
-The sites to which articles are to be sent must be configured in the
-configuration file \fIsend\-uucp.cf\fR. Each site is specified with a line of
-the form:
-.PP
-.Vb 1
-\& site[:host[:funnel]] [compressor [maxsize [batchtime]]]
-.Ve
-.IP "\fIsite\fR" 4
-.IX Item "site"
-The news site name being configured. This must match a site name
-from \fInewsfeeds\fR\|(5).
-.IP "\fIhost\fR" 4
-.IX Item "host"
-The \s-1UUCP\s0 host name to which batches should be sent for this site.
-If omitted, the news site name will be used as the \s-1UUCP\s0 host name.
-.IP "\fIfunnel\fR" 4
-.IX Item "funnel"
-In the case of a site configured as a funnel, \fBsend-uucp\fR needs to flush
-the channel (or exploder) being used as the target of the funnel instead of
-flushing the site. This is the way to tell \fBsend-uucp\fR the name of the
-channel or exploder to flush for this site. If not specified, default to
-flushing the site.
-.IP "\fIcompressor\fR" 4
-.IX Item "compressor"
-The compression method to use for batches. This should be one of compress,
-gzip or none. Arguments for the compression command may be specified by
-using \f(CW\*(C`_\*(C'\fR instead of spaces. For example, \f(CW\*(C`gzip_\-9\*(C'\fR. The default value is
-\&\f(CW\*(C`compress\*(C'\fR.
-.IP "\fImaxsize\fR" 4
-.IX Item "maxsize"
-The maximum size of a single batch before compression. The default value is
-500,000 bytes.
-.IP "\fIbatchtime\fR" 4
-.IX Item "batchtime"
-A comma separated list of hours during which batches should be generated for
-a given site. When \fBsend-uucp\fR runs, a site will only be processed if the
-current hour matches one of the hours in \fIbatchtime\fR. The default is no
-limitation on when to generate batches.
-.PP
-Fields are seperated by spaces and only the site name needs to be specified,
-with defaults being used for unspecified values. If the first character on
-a line is a \f(CW\*(C`#\*(C'\fR then the rest of the line is ignored.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-Here is an example send\-uucp.cf configuration file:
-.PP
-.Vb 8
-\& zoetermeer gzip 1048576 5,18,22
-\& hoofddorp gzip 1048576 5,18,22
-\& pa3ebv gzip 1048576 5,18,22
-\& drinkel gzip 1048576 5,6,18,20,22,0,2
-\& manhole compress 1048576 5,18,22
-\& owl compress 1048576
-\& able
-\& pern::MYFUNNEL!
-.Ve
-.PP
-This defines eight \s-1UUCP\s0 sites. The first four use gzip compression and the
-last three use compress. The first six use a batch size of 1MB, and the
-last site (able) uses the default of 500,000 bytes. The zoetermeer,
-hoofddorp, pa3ebv, and manhole sites will only have batches generated for
-them during the hours of 05:00, 18:00, and 22:00, and the drinkel site will
-only have batches generated during those hours and 20:00, 00:00, and 02:00.
-There are no restrictions on when batches will be generated for owl or able.
-.PP
-The pern site is configured as a funnel into \f(CW\*(C`MYFUNNEL!\*(C'\fR. \fBsend-uucp\fR will
-issue \f(CW\*(C`ctlinnd flush MYFUNNEL!\*(C'\fR instead of \f(CW\*(C`ctlinnd flush pern\*(C'\fR.
-.SH "FILES"
-.IX Header "FILES"
-.IP "\fIpathetc\fR/send\-uucp.cf" 4
-.IX Item "pathetc/send-uucp.cf"
-Configuration file specifying a list of sites to be processed.
-.SH "NOTES"
-.IX Header "NOTES"
-The usual flags used for a \s-1UUCP\s0 feed in the \fInewsfeeds\fR file are \f(CW\*(C`Tf,Wfb\*(C'\fR.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIinnd\fR\|(8), \fInewsfeeds\fR\|(5), \fIuucp\fR\|(8)
-.SH "AUTHOR"
-.IX Header "AUTHOR"
-This program was originally written by Edvard Tuinder <ed@elm.net> and then
-maintained and extended by Miquel van Smoorenburg <miquels@cistron.nl>.
-Marco d'Itri <md@linux.it> cleaned up the code for inclusion in \s-1INN\s0. This
-manual page was written by Mark Brown <broonie@sirena.org.uk>.
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SENDINPATHS 8"
-.TH SENDINPATHS 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-sendinpaths \- Send Usenet Path statistics via e\-mail
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBsendinpaths\fR [\fB\-n\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBsendinpaths\fR checks \fIpathlog\fR/path for \fBninpaths\fR dump files, finds
-dump files generated in the past 30 days, makes sure they are valid by
-running \fBninpaths\fR on each one and making sure the exit status is zero,
-and passes them to \fBninpaths\fR to generate a cumulative report. That
-report is mailed to the e\-mail addresses configured at the beginning of
-this script (by default \*(L"pathsurvey@top1000.org\*(R" and
-\&\*(L"top1000@anthologeek.net\*(R").
-.PP
-When finished, \fBsendinpaths\fR deletes all dump files in \fIpathlog\fR/path
-that are older than 14 days (configurable at the beginning of the script).
-.PP
-For more information on how to set up \fBninpaths\fR, see \fIninpaths\fR\|(8).
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-n\fR" 4
-.IX Item "-n"
-Don't e\-mail the report; instead, just print it to standard output. Don't
-delete old dump files.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIninpaths\fR\|(8)
-.SH "HISTORY"
-.IX Header "HISTORY"
-\&\fBsendinpaths\fR was written by Olaf Titz <olaf@bigred.inka.de>.
+++ /dev/null
-.\" $Revision: 5794 $
-.TH SHLOCK 1
-.SH NAME
-shlock \- create lock files for use in shell scripts
-.SH SYNOPSIS
-.B shlock
-.BI \-p " pid"
-.BI \-f " name"
-[
-.B \-b
-]
-[
-.B \-u
-]
-[
-.B \-c
-]
-.SH DESCRIPTION
-.I Shlock
-tries to create a lock file named
-.I name
-and write the process ID
-.I pid
-into it.
-If the file already exists,
-.I shlock
-will read the process ID from the file and test to see if the process
-is currently running.
-If the process exists, then the file will not be created.
-.PP
-.I Shlock
-exits with a zero status if it was able to create the lock file, or
-non-zero if the file refers to currently-active process.
-.SH OPTIONS
-.TP
-.B \-b
-Process IDs are normally read and written in ASCII.
-If the ``\-b'' flag is used, then they will be written as a binary
-.IR int .
-For compatibility with other systems, the ``\-u'' flag is accepted as
-a synonym for ``\-b'' since binary locks are used by many UUCP packages.
-.TP
-.B \-c
-If the ``\-c'' flag is used, then
-.I shlock
-will not create a lock file, but will instead use the file to see if
-the lock is held by another program.
-If the lock is valid, the program will exit with a non-zero status; if
-the lock is not valid (i.e., invoking
-.I shlock
-without the flag would have succeeded), then the program will exit
-with a zero status.
-.SH EXAMPLES
-The following example shows how
-.I shlock
-would be used within a shell script:
-.RS
-.nf
-LOCK=<pathrun in inn.conf>/LOCK.send
-trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
-if shlock -p $$ -f ${LOCK} ; then
- # Do appropriate work
-else
- echo Locked by `cat ${LOCK}`
-f\&i
-.fi
-.RE
-.SH BUGS
-.I shlock
-assumes that it will not be used in an environment with multiple
-locks/unlocks in a short time (due to a race condition). That is,
-.I shlock
-is intended for daily or hourly jobs.
-.SH HISTORY
-Written by Rich $alz <rsalz@uunet.uu.net> after a description of HDB UUCP
-locking given by Peter Honeyman.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: shlock.1 5794 2002-10-01 23:31:53Z vinocur $
-.SH "SEE ALSO"
-inn.conf(5)
+++ /dev/null
-.\" $Revision: 5909 $
-.TH SHRINKFILE 1
-.SH NAME
-shrinkfile \- shrink a file on a line boundary
-.SH SYNOPSIS
-.B shrinkfile
-[
-.B \-n
-]
-[
-.BI \-m " maxsize"
-]
-[
-.BI \-s " size"
-]
-[
-.B \-v
-]
-.I file...
-.SH DESCRIPTION
-The
-.I shrinkfile
-program shrinks files to a given
-.I size
-if the size is larger than
-.IR maxsize ,
-preserving the data at the end of the file.
-Truncation is performed on line boundaries, where a line is a series
-of bytes ending with a newline, ``\en''.
-There is no line length restriction and files may contain any binary data.
-.PP
-Temporary files are created in the
-.I <pathtmp in inn.conf>
-directory.
-The ``TMPDIR'' environment variable may be used to specify a
-different directory.
-.PP
-A newline will be added to any non-empty file that does not end with a newline.
-The maximum file size will not be exceeded by this addition.
-.SH OPTIONS
-.TP
-.B \-s
-By default,
-.I size
-is assumed to be zero and files are truncated to zero bytes.
-By default,
-.I maxsize
-is the same as
-.IR size .
-If
-.I maxsize
-is less than
-.IR size ,
-.I maxsize
-is reset to
-.IR size .
-The ``\fB\-s\fP'' flag may be used to change the truncation size.
-Because the program truncates only on line boundaries, the final size
-may be smaller then the specified truncation size.
-The
-.I size
-and
-.I maxsize
-parameter may end with a ``k'', ``m'', or ``g'', indicating
-kilobyte (1024), megabyte (1048576) or gigabyte (1073741824) lengths.
-Uppercase letters are also allowed.
-The maximum file size is 2147483647 bytes.
-.TP
-.B \-v
-If the ``\fB\-v\fP'' flag is used, then
-.I shrinkfile
-will print a status line if a file was shrunk.
-.TP
-.B \-n
-If the ``\fB\-n\fP'' flag is used, then
-.I shrinkfile
-will exit 0 if any file is larger than
-.I maxsize
-and exit 1 otherwise.
-No files will be altered.
-.SH EXAMPLES
-.PP
-Example usage:
-.sp 1
-.RS
-.nf
-shrinkfile -s 4m curds
-shrinkfile -s 1g -v whey
-shrinkfile -s 500k -m 4m -v curds whey
-if shrinkfile -n -s 100m whey; then echo whey is way too big; fi
-.fi
-.RE
-.PP
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.SH "SEE ALSO"
-inn.conf(5)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SIMPLEFTP 1"
-.TH SIMPLEFTP 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-simpleftp \- Rudimentary FTP client
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBsimpleftp\fR \fIurl\fR [...]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBsimpleftp\fR is a Perl script that provides basic support for
-fetching files with \s-1FTP\s0 in a batch oriented fashion. It takes one or more
-\&\s-1FTP\s0 URLs on the command line. The file(s) will be retrieved from the
-remote server and placed in the current directory with the same basename
-as on the remote; e.g., <ftp://ftp.isc.org/pub/usenet/CONFIG/active.gz>
-is stored as \fIactive.gz\fR in the current directory.
-.PP
-The script properly understands usernames, passwords and ports specified
-as follows:
-.PP
-.Vb 1
-\& ftp://user:password@host:port/path/file
-.Ve
-.SH "BUGS"
-.IX Header "BUGS"
-\&\fBsimpleftp\fR is an extremely poor substitute for more complete programs
-like the freely available \fBwget\fR or \fBncftp\fR utilities. It was written
-only to provide elementary support in \s-1INN\s0 for non-interactive fetching of
-the files in <ftp://ftp.isc.org/pub/pgpcontrol/> or
-<ftp://ftp.isc.org/pub/usenet/CONFIG/> without requiring
-administrators to install yet another package. Its shortcomings as a
-general purpose program are too numerous to mention, but one that stands
-out is that downloaded files by \fBsimpleftp\fR override existing files
-with the same name in the local directory.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Tossed off by David C Lawrence <tale@isc.org> for InterNetNews.
-Rewritten to use Net::FTP by Julien Elie <julien@trigofacile.com>.
-.PP
-$Id: simpleftp.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIactsync\fR\|(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SM 1"
-.TH SM 1 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-sm \- Command\-line interface to the INN storage manager
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBsm\fR [\fB\-dHiqRrS\fR] [\fItoken\fR ...]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The \s-1INN\s0 storage manager is the subsystesm that stores and keeps track of
-all of the articles and what storage backend they're in. All stored
-articles are assigned a storage \s-1API\s0 token. \fBsm\fR is a command-line
-interface to that storage manager, primarily used to retrieve articles by
-those tokens but also to perform other operations on the storage
-subsystem.
-.PP
-\&\fItoken\fR is the token of an article (the same thing that's returned by
-\&\fBgrephistory\fR or stored in the history file). It looks something like:
-.PP
-.Vb 1
-\& @0502000005A4000000010000000000000000@
-.Ve
-.PP
-Any number of tokens can be given on the command line. If none are, \fBsm\fR
-reads tokens from standard input, one per line. The default operation is
-to retrieve and write to standard output the corresponding article for
-each token given.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-d\fR, \fB\-r\fR" 4
-.IX Item "-d, -r"
-Rather than retrieving the specified article, remove the article. This
-will delete the article out of the news spool and it will not subsequently
-be retrievable by any part of \s-1INN\s0. It's equivalent to \f(CW\*(C`ctlinnd cancel\*(C'\fR
-except it takes a storage \s-1API\s0 token instead of a message \s-1ID\s0.
-.IP "\fB\-H\fR" 4
-.IX Item "-H"
-Retrieve only the header of the article rather than the entire article.
-This option cannot be used with \fB\-d\fR, \fB\-r\fR, \fB\-i\fR, or \fB\-S\fR.
-.IP "\fB\-i\fR" 4
-.IX Item "-i"
-Show the newsgroup name and article number associated with the token
-rather than the article itself. Note that for crossposted articles, only
-the first newsgroup and article number to which the article is associated
-will be returned.
-.IP "\fB\-q\fR" 4
-.IX Item "-q"
-Suppress all error messages except usage errors.
-.IP "\fB\-R\fR" 4
-.IX Item "-R"
-Display the raw article. This means that line endings won't be converted
-to native line endings and will be left as \s-1CRLF\s0 sequences, leading periods
-will still be escaped for sending over \s-1NNTP\s0, and the article will end in
-a \s-1CRLF\s0.CRLF sequence.
-.IP "\fB\-S\fR" 4
-.IX Item "-S"
-Write the article to standard output in the format used by rnews spool
-files. Multiple articles can be written in this format, and the resulting
-output can be fed to rnews (on another system, for example) to inject
-those articles into \s-1INN\s0. This option cannot be used with \fB\-d\fR, \fB\-r\fR,
-\&\fB\-H\fR, \fB\-i\fR, or \fB\-R\fR.
-.SH "EXIT STATUS"
-.IX Header "EXIT STATUS"
-If all operations were successful, \fBsm\fR exits with status 0. If an
-operation on any of the provided tokens fails, \fBsm\fR will exit with status
-1, even if the operations on other tokens were successful. In other
-words, if twenty tokens are fed to \f(CW\*(C`sm \-r\*(C'\fR on stdin, 19 articles were
-successfully removed, but the sixth article couldn't be found, \fBsm\fR will
-still exit with status 1.
-.PP
-This means that if you need to be sure whether a particular operation
-succeeded, you should run sm on one token at a time.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-Rewritten in \s-1POD\s0 by Russ Allbery <rra@stanford.edu>.
-.PP
-$Id: sm.1 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIctlinnd\fR\|(8), \fIgrephistory\fR\|(1), \fIhistory\fR\|(5), \fIrnews\fR\|(1), \fIstorage.conf\fR\|(5).
+++ /dev/null
-.TH STARTINNFEED 8 "Nov 7, 1997"
-.SH NAME
-startinnfeed \- setuid root program to start innfeed
-.SH SYNOPSIS
-.B startinnfeed
-.RB [innfeed-options]
-.sp
-.B startinnfeed
-.RB imapfeed
-.RB [imapfeed-options]
-.SH DESCRIPTION
-.B Startinnfeed
-sets all resources (files opened, memory usage) to unlimited. It then executes
-innfeed(8) with the options specified.
-
-If the first argument to
-.B startinnfeed
-is ``\fIimapfeed\fP'' then
-.B imapfeed
-will be executed (instead of innfeed(8)) with the remaining argument as
-options.
-.SH HISTORY
-Written by James Brister.
-.SH "SEE ALSO"
-.BR innfeed (8)
+++ /dev/null
-.\" $Revision: 6124 $
-.TH STORAGE.CONF 5
-.SH NAME
-storage.conf \- configuration file for storage manager
-.SH DESCRIPTION
-The storage manager is a
-unified interface between INN and a variety of different storage method,
-allowing the news administrator to choose between different storage methods
-with different tradeoffs (or even use several at the same time for
-different newsgroups, or articles of different sizes). The rest of INN
-need not care what type of storage method was used for a given article;
-the storage manager will figure this out automatically when that article
-is retrieved via the storage API.
-.PP
-The
-.I <pathetc in inn.conf>/storage.conf
-file contains the rules to be used in assigning
-articles to different storage methods.
-.PP
-The file consists of a series of storage method entries.
-Blank lines and lines beginning with a number sign (``#'') are ignored.
-The maximum number of characters in each line is 255.
-The order of entries in this file is important, see below.
-.PP
-Each entry specifies a storage method and a set of rules. Articles that
-match all of the rules of a storage method entry will be stored using that
-storage method; if an article matches multiple storage method entries,
-the first will be used. Each entry is formatted as follows:
-.RS
-.nf
-
-method <methodname> {
- class: <storage_class>
- newsgroups: <wildmat>
- size: <minsize>[,<maxsize>]
- expires: <mintime>[,<maxtime>]
- options: <options>
- exactmatch: <bool>
-}
-
-.fi
-.RE
-If spaces or tabs are included in a value, that value must be quoted
-with ``"''.
-If either ``#'' or ``"'' are meant to be included verbatim in a value,
-they should be escaped with ``\\''.
-.PP
-<methodname> is the name of a storage method to use for articles that
-match the rules of this entry. The currently available storage methods
-are
-\&``timecaf'', ``timehash'', ``cnfs'', ``tradspool'' and ``trash''.
-See the STORAGE METHODS section below for more details.
-.PP
-The meanings of the keys in each entry are as follows:
-.TP
-.B class
-An identifier for this storage method entry. <storage_class> should be a
-number and should be unique across all of the entries in this file. It's
-used mainly for specifying expiration times by storage class as described in
-.IR expire.ctl (5).
-.TP
-.B newsgroups
-What newsgroups are stored using this storage method. <wildmat> is a
-.IR uwildmat (3)
-pattern that is matched against the newsgroups an article is posted to.
-If ``storeonxref'' in inn.conf is ``true'', this pattern will be matched
-against the newsgroup names in the ``Xref'' header; otherwise, it will be
-matched against newsgroup names in the ``Newsgroups'' header (see
-.IR inn.conf (5)
-for discussion of the differences between these possibilities). Poison
-wildmat expressions (expressions starting with ``@'') are allowed and can
-be used to exclude certain group patterns. ``!'' cannot be used, however.
-The <wildmat> pattern is matched in order. There is no default newsgroups
-pattern; if an entry should match all newsgroups, use an explicit
-\&``newsgroups: *''.
-.TP
-.B size
-A range of article sizes (in bytes) that should be stored using this
-storage method.
-If <maxsize> is ``0'' or not given, the upper size of articles is limited
-only by ``maxartsize'' in
-.IR inn.conf .
-The ``size'' field is optional and may be omitted entirely if you want
-articles of any size (that otherwise fulfill the requirements of this
-storage method entry) to be stored in this storage method.
-.TP
-.B expires
-A range of article expiration times that should be stored using this
-storage method. Be careful; this is less useful than it may appear at
-first. This is based
-.B only
-on the ``Expires'' header of the article, not on any local expiration
-policies or anything in
-.IR expire.ctl !
-If <mintime> is non-zero, then this entry
-.B will not match
-any article without an ``Expires'' header.
-This key is therefore only really useful for assigning articles with
-requested longer expire times to a separate storage method. Articles only
-match if the time until expiration (that is, the amount of time into the
-future that the ``Expires'' header of the article requests that it remain
-around) falls in the interval specified by <mintime> and <maxtime>. The
-format of these parameters is 0d0h0m0s (days, hours, minutes, and
-seconds into the future). If <maxtime> is ``0s'' or is not specified,
-there is no upper bound on expire times falling into this entry (note that
-this key has no effect on when the article will actually be expired, only
-on whether or not the article will be stored using this storage method).
-This field is also optional and may be omitted entirely if all articles
-with or without an ``Expires'' header (that otherwise fulfill the
-requirements of this storage method entry) should be stored according to
-it.
-.TP
-.B options
-This key is for passing special options to storage methods that require
-them (currently only ``cnfs''). See the STORAGE METHODS section below for
-a description of its use.
-.TP
-.B exactmatch
-If this key is set to ``true'', all newsgroups will be examined to see if
-they match newsgroups patterns. (Normally, any nonzero number of matching
-newsgroups is sufficient, provided no newsgroup matches a poison wildmat as
-described above.) This is a boolan value and ``true'', ``yes''
-and ``on'' are usable to enable this key. The case of these values is not
-significant. The default is false.
-.PP
-If an article matches all of the constraints of an entry, it is stored via
-that storage method and is associated with that <storage_class>. This
-file is scanned in order and the first matching entry is used to store the
-article.
-.PP
-If an article doesn't match any entry, either by being posted to a
-newsgroup that doesn't match any of the <wildmat> patterns or by being
-outside the size and expires ranges of all entries whose newsgroups
-pattern it does match, the article is not stored and is rejected by
-.IR innd (8).
-When this happens, the error message
-.RS
-.nf
-
-cant store article: no matching entry in storage.conf
-
-.fi
-.RE
-is logged to syslog. If you want to silently drop articles matching
-certain newsgroup patterns or size or expires ranges, assign them to the
-\&``trash'' storage method rather than having them not match any storage
-method entry.
-.SH STORAGE METHODS
-Currently, there are four storage methods available. Each method has its
-pros and cons; you can choose any mixture of them as is suitable for your
-environment. Note that each method has an attribute ``EXPENSIVESTAT'' which
-indicates whether checking the existence of an article is expensive or not.
-This is used to run
-.IR expireover (8).
-.TP
-.B cnfs
-The ``cnfs'' storage method stores articles in large cyclic buffers (CNFS
-stands for Cyclic News File System). It's by far the fastest of all
-storage methods (except for ``trash''), since it eliminates the overhead
-of dealing with a file system and creating new files. Articles are stored
-in CNFS buffers in arrival order, and when the buffer fills, it wraps
-around to the beginning and stores new articles over top of the oldest
-articles in the buffer. The expire time of articles stored in CNFS
-buffers is therefore entirely determined by how long it takes the buffer
-to wrap around, which depends on how quickly data is being stored in it.
-(This method is therefore said to have self-expire functionality.)
-\&``EXPENSIVESTAT'' is ``false'' for this method.
-CNFS has its own configuration file,
-.IR cycbuff.conf ,
-which describes some subtlties to the basic description given above.
-Storage method entries for the ``cnfs'' storage method must have an
-\&``options'' field specifying the metacycbuff into which articles
-matching that entry should be stored; see
-.IR cycbuff.conf (5)
-for details on metacycbuffs.
-.TP
-.B timecaf
-This method stores multiple articles in one file, whose name is based on
-the article's arrival time and the storage class. The file name will be
-.IR <patharticles\ in\ inn.conf>/timecaf-nn/bb/aacc.CF ,
-where ``nn'' is the hexadecimal value of <storage_class>, ``bb'' and
-\&``aacc'' are hexadecimal components of the arrival time, and ``CF'' is a
-hardcoded extension. (The arrival time, in seconds since the epoch, is
-converted to hexadecimal and interpreted as 0xaabbccdd, with ``aa'',
-``bb'', and ``cc'' used to build the path.) This method does not have
-self-expire functionality (meaning
-.IR expire (8)
-has to run periodically to delete old articles).
-\&``EXPENSIVESTAT'' is ``false'' for this method.
-.TP
-.B timehash
-This method is very similar to ``timecaf'' except that each article is
-stored in a separate file. The name of the file for a given article will
-be
-.IR <patharticles\ in\ inn.conf>/time-nn/bb/cc/yyyy-aadd ,
-where ``nn'' is the hexadecimal value of <storage_class>, ``yyyy'' is a
-hexadecimal sequence number, and ``bb'', ``cc'', and ``aadd'' are
-components of the arrival time in hexadecimal (the arrival time is
-interpreted as documented above under ``timecaf''). This method does not
-have self-expire functionality.
-\&``EXPENSIVESTAT'' is ``true'' for this method.
-.TP
-.B tradspool
-Traditional spool, or ``tradspool'', is the traditional news article
-storage format. Each article is stored in a file named:
-.IR <patharticles\ in\ inn.conf>/news/group/name/nnnnn ,
-where ``news/group/name'' is the name of the newsgroup to which the
-article was posted with each period changed to a slash, and ``nnnnn'' is
-the sequence number of the article in that newsgroup. For crossposted
-articles, the article is linked into each newsgroup to which it is
-crossposted (using either hard or symbolic links). This is the way
-versions of INN prior to 2.0 stored all articles, as well as being the
-article storage format used by C News and earlier news systems.
-This method does not have self-expire functionality.
-\&``EXPENSIVESTAT'' is ``true'' for this method.
-.TP
-.B trash
-This method silently discards all articles stored in it. Its only real
-uses are for testing and for silently discarding articles matching a
-particular storage method entry (for whatever reason). Articles stored in
-this method take up no disk space and can never be retrieved, so this
-method has self-expire functionality of a sort.
-\&``EXPENSIVESTAT'' is ``false'' for this method.
-.SH EXAMPLE
-The following sample storage.conf file would store all articles posted to
-alt.binaries.* in the ``BINARIES'' CNFS metacycbuff, all articles over
-roughly 50 KB in any other hierarchy in the ``LARGE'' CNFS metacycbuff,
-all other articles in alt.* in one timehash class, and all other articles
-in any newsgroups in a second timehash class, except for the internal.*
-hierarchy which is stored in traditional spool format.
-.RS
-.nf
-
-method tradspool {
- class: 1
- newsgroups: internal.*
-}
-
-method cnfs {
- class: 2
- newsgroups: alt.binaries.*
- options: BINARIES
-}
-
-method cnfs {
- class: 3
- newsgroups: *
- size: 50000
- options: LARGE
-}
-
-method timehash {
- class: 4
- newsgroups: alt.*
-}
-
-method timehash {
- class: 5
- newsgroups: *
-}
-
-.fi
-.RE
-Notice that the last storage method entry will catch everything. This is
-a good habit to get into; make sure that you have at least one catch-all
-entry just in case something you didn't expect falls through the cracks.
-Notice also that the special rule for the internal.* hierarchy is first,
-so it will catch even articles crossposted to alt.binaries.* or over 50 KB
-in size.
-.SH HISTORY
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: storage.conf.5 6124 2003-01-14 06:03:29Z rra $
-.SH "SEE ALSO"
-cycbuff.conf(5),
-expire.ctl(5),
-inn.conf(5),
-innd(8),
-newsfeeds(5),
-uwildmat(3).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "SUBSCRIPTIONS 5"
-.TH SUBSCRIPTIONS 5 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-subscriptions \- Default recommended subscriptions
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-The \fIpathetc\fR/\fIsubscriptions\fR file contains a list of newsgroups that is
-returned by the \s-1NNTP\s0 command \s-1LIST\s0 \s-1SUBSCRIPTIONS\s0.
-.PP
-Clients that support this command and send it the first time they connect
-to a new news server use the returned list to initialize the list of
-subscribed newsgroups. The \fIsubscriptions\fR file therefore should contain
-groups intented for new users, for testing, or that contain FAQs and other
-useful information for first-time Usenet users.
-.PP
-The syntax of the \fIsubscriptions\fR file is trivial; it is a simple list of
-newsgroup names, one per line. The order of newsgroups may be
-significant; the news reading client may present the groups in that order
-to the user.
-.SH "EXAMPLE"
-.IX Header "EXAMPLE"
-A typical \fIsubscriptions\fR file may look like:
-.PP
-.Vb 9
-\& news.announce.newusers
-\& news.newusers.questions
-\& local.test
-\& local.general
-\& local.talk
-\& misc.test
-\& misc.test.moderated
-\& news.answers
-\& news.announce.newgroups
-.Ve
-.PP
-This gives the client the FAQs and question newsgroup for new users first,
-then a local newsgroup for testing and various commonly-read local
-discussion groups, followed by the world-wide test groups, all the FAQs,
-and announcements of new world-wide newsgroups. If there is a local new
-users group, one might want to list it first.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Bettina Fink <laura@hydrophil.de> for InterNetNews.
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fInnrpd\fR\|(8).
+++ /dev/null
-.TH TALLY.CONTROL 8
-.SH NAME
-tally.control \- keep track of newsgroup creations and deletions.
-.SH SYNOPSIS
-tally.control
-.SH DECSRIPTION
-tally.control is normally invoked by
-.IR scanlogs (8).
-It
-reads its standard input, which should be the
-.I newgroup.log
-and
-.I rmgroup.log
-log files.
-It updates the cumulative list of newsgroup creations and deletions,
-.IR control.log .
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: tally.control.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-newslog(5),
-news.daily(8),
-scanlogs(8),
-tally.unwanted(8),
-writelog(8).
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "TDX-UTIL 8"
-.TH TDX-UTIL 8 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-tdx\-util \- Tradindexed overview manipulation utility
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fBtdx-util\fR [\fB\-AFgio\fR] [\fB\-a\fR \fIarticle\fR] [\fB\-n\fR \fInewsgroup\fR]
-[\fB\-p\fR \fIpath\fR] [\fB\-R\fR \fIpath\fR]
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBtdx-util\fR is an administrative interface to the tradindexed overview
-method for \s-1INN\s0. It only works on tradindexed overview databases, not on
-any other type of \s-1INN\s0 overview. It allows the administrator to dump
-various information about the internal state of the overview, audit it for
-errors, and rebuild portions of the overview database.
-.PP
-The tradindexed overview method should lock properly and therefore it
-should be safe to run this utility and perform any operation it performs,
-including full repairs or per-group overview rebuilds, while the server is
-running. However, note that some of the operations performed by this
-utility can take an extended period of time and will hold locks in the
-overview database during that period, which depending on what the server
-is doing may cause the server to stall until \fBtdx-util\fR completes its
-operation.
-.PP
-The dump operations are \fB\-i\fR, which dumps the master index for the
-overview database, \fB\-g\fR, which dumps the index for an individual group,
-and \fB\-o\fR, which dumps the overview information for a particular group
-(including the additional metadata stored in the index). For \fB\-g\fR and
-\&\fB\-o\fR, the \fB\-n\fR option must also be given to specify a newsgroup to
-operate on.
-.PP
-To audit the entire overview database for problems, use \fB\-A\fR. Any
-problems found will be reported to standard error. There is not (yet) a
-corresponding option to correct the errors found.
-.PP
-To rebuild the database for a particular newsgroup, use \fB\-R\fR. The \fB\-R\fR
-option takes a path to a directory which contains all of the articles for
-that newsgroup, one per file. The names of the files must be the numbers
-of the articles in that group. (In other words, this directory must be a
-traditional spool directory for that group.) The \fB\-n\fR option must also
-be given to specify the newsgroup for which the overview is being rebuilt.
-.PP
-For all operations performed by \fBtdx-util\fR, a different overview database
-than the one specified in \fIinn.conf\fR may be specified using the \fB\-p\fR
-option.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.IP "\fB\-A\fR" 4
-.IX Item "-A"
-Audit the entire overview database for problems. This runs the internal
-consistency checks built into the tradindexed overview implementation,
-checking such things as the validity and reachability of all group index
-entries, the format of the individual overview entries, the correspondance
-of index entries to overview data, and similar such things. No changes
-will be made to the database, but problems will be reported to standard
-error.
-.IP "\fB\-a\fR \fIarticle\fR" 4
-.IX Item "-a article"
-The article number to act on. Only useful in combination with the \fB\-o\fR
-option to dump overview information.
-.IP "\fB\-F\fR" 4
-.IX Item "-F"
-Audit the entire overview database for problems, fixing them as they're
-detected where possible. This runs the internal consistency checks built
-into the tradindexed overview implementation, checking such things as the
-validity and reachability of all group index entries, the format of the
-individual overview entries, the correspondance of index entries to
-overview data, and similar such things. The strategy used when fixing
-problems is to throw away data that's unrecoverable, so be warned that
-using this option may result in inaccessible articles if their overview
-data has been corrupted.
-.Sp
-To see what would be changed by \fB\-F\fR, run \fBtdx-util\fR with \fB\-A\fR first.
-.IP "\fB\-g\fR" 4
-.IX Item "-g"
-Dump the master index of the overview database. This contains similar
-information to the server active file, such as high and low water marks
-and moderation status, and is the information that nnrpd hands out to
-clients.
-.Sp
-The fields are, in order, the newsgroup name, the high water mark, the low
-water mark, the base article number (the point at which the group index
-begins), the count of articles in the group, the group status flag, the
-time (in seconds since epoch) when that newsgroup was deleted or 0 if it
-hasn't been, and the inode of the index file for that group.
-.IP "\fB\-i\fR" 4
-.IX Item "-i"
-Dump the index of a particular group. The fields are, in order, the
-article number, the offset of the data for that article in the overview
-data file for that group, the length of the overview data, the time (in
-seconds since epoch) when the article arrived on the server, the time (in
-seconds since epoch) when the article should expire based on its Expires
-header (or 0 if there is no Expires header), and the storage \s-1API\s0 token of
-the article.
-.Sp
-If this option is given, the \fB\-n\fR option must also be given to specify
-the newsgroup on which to act.
-.IP "\fB\-n\fR \fInewsgroup\fR" 4
-.IX Item "-n newsgroup"
-Specify the newsgroup on which to act, required for the \fB\-i\fR, \fB\-o\fR, and
-\&\fB\-R\fR options.
-.IP "\fB\-o\fR" 4
-.IX Item "-o"
-Dump the overview information for a newsgroup, in the same format as it
-would be returned to clients but with one modification. Appended to the
-end of each entry will be four additional pieces of data: the article
-number according to the index file for that group, the storage \s-1API\s0 token
-for that article, the arrival date for that article on the server in \s-1RFC\s0
-822 date format, and the expiration date for that article (from the
-Expires header) in \s-1RFC\s0 822 date format if there is any.
-.Sp
-If this option is given, the \fB\-n\fR option must also be given to specify
-the newsgroup on which to act. By default, all of the overview
-information for that newsgroup is dumped, but the \fB\-a\fR option may be
-given to restrict the dump to the information for a single article.
-.IP "\fB\-p\fR \fIpath\fR" 4
-.IX Item "-p path"
-Act on the overview database rooted in \fIpath\fR, overriding the overview
-path specified in \fIinn.conf\fR.
-.IP "\fB\-R\fR \fIpath\fR" 4
-.IX Item "-R path"
-Rebuild the overview for a given group from the articles stored in
-\&\fIpath\fR. The articles must be in the form of a traditional spool
-directory; in other words, each article must be in a separate file and the
-name of the file must match the article number of the article.
-.Sp
-If this option is given, the \fB\-n\fR option must also be given to specify
-the newsgroup on which to act.
-.SH "EXAMPLES"
-.IX Header "EXAMPLES"
-Dump the master index for the overview database in \fI/news/overview\fR,
-regardless of the overview path specified in \fIinn.conf\fR:
-.PP
-.Vb 1
-\& tdx\-util \-i \-p /news/overview
-.Ve
-.PP
-Dump the group index for example.test:
-.PP
-.Vb 1
-\& tdx\-util \-g \-n example.test
-.Ve
-.PP
-Dump the complete overview information for example.test:
-.PP
-.Vb 1
-\& tdx\-util \-o \-n example.test
-.Ve
-.PP
-Audit the entire overview database for any problems:
-.PP
-.Vb 1
-\& tdx\-util \-A
-.Ve
-.PP
-Rebuild the overview information for example.test from a traditional spool
-directory:
-.PP
-.Vb 1
-\& tdx\-util \-R /news/spool/articles/example/test \-n example.test
-.Ve
-.PP
-The last command may be useful for recovering from a bad crash or
-corrupted overview information for a particular group, if you are also
-using the tradspool article storage method.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-.PP
-$Id: tdx-util.8 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fImakehistory\fR\|(8)
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "tst 3"
-.TH tst 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-tst \- ternary search trie functions
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fB#include <inn/tst.h>\fR
-.PP
-\&\fBstruct tst;\fR
-.PP
-\&\fBstruct tst *tst_init(int \fR\fInode_line_width\fR\fB);\fR
-.PP
-\&\fBvoid tst_cleanup(struct tst *\fR\fItst\fR\fB);\fR
-.PP
-\&\fBint tst_insert(struct tst *\fR\fItst\fR\fB, const unsigned char *\fR\fIkey\fR\fB, void *\fR\fIdata\fR\fB, int \fR\fIoption\fR\fB, void **\fR\fIexist_ptr\fR\fB);\fR
-.PP
-\&\fBvoid *tst_search(struct tst *\fR\fItst\fR\fB, const unsigned char *\fR\fIkey\fR\fB);\fR
-.PP
-\&\fBvoid *tst_delete(struct tst *\fR\fItst\fR\fB, const unsigned char *\fR\fIkey\fR\fB);\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBtst_init\fR allocates memory for members of \fIstruct tst\fR, and
-allocates the first \fInode_line_width\fR nodes. A \s-1NULL\s0 pointer is
-returned by \fBtst_init\fR if any part of the memory allocation fails. On
-success, a pointer to a \fIstruct tst\fR is returned.
-.PP
-The value for \fInode_line_width\fR must be chosen very carefully. One
-node is required for every character in the tree. If you choose a
-value that is too small, your application will spend too much time
-calling \fImalloc\fR\|(3) and your node space will be too spread out. Too large
-a value is just a waste of space.
-.PP
-\&\fBtst_cleanup\fR frees all memory allocated to nodes, internal structures,
-as well as \fItst\fR itself.
-.PP
-\&\fBtst_insert\fR inserts the string \fIkey\fR into the tree. Behavior when a
-duplicate key is inserted is controlled by \fIoption\fR. If \fIkey\fR is
-already in the tree then \fB\s-1TST_DUPLICATE_KEY\s0\fR is returned, and the
-data pointer for the existing key is placed in \fIexist_ptr\fR. If
-\&\fIoption\fR is set to \fB\s-1TST_REPLACE\s0\fR then the existing data pointer for
-the existing key is replaced by \fIdata\fR. Note that the old data
-pointer will still be placed in \fIexist_ptr\fR.
-.PP
-If a duplicate key is encountered and \fIoption\fR is not set to
-\&\fB\s-1TST_REPLACE\s0\fR then \fB\s-1TST_DUPLICATE_KEY\s0\fR is returned. If \fIkey\fR is
-zero length then \fB\s-1TST_NULL_KEY\s0\fR is returned. A successful insert or
-replace returns \fB\s-1TST_OK\s0\fR. A return value of \fB\s-1TST_ERROR\s0\fR indicates
-that a memory allocation error occurred while trying to grow the node
-free.
-.PP
-Note that the \fIdata\fR argument must never be \fB\s-1NULL\s0\fR. If it is, then
-calls to \fBtst_search\fR will fail for a key that exists because the
-data value was set to \fB\s-1NULL\s0\fR, which is what \fBtst_search\fR returns. If
-you just want a simple existence tree, use the \fBtst\fR pointer as the
-data pointer.
-.PP
-\&\fBtst_search\fR finds the string \fIkey\fR in the tree if it exists and
-returns the data pointer associated with that key.
-.PP
-If \fIkey\fR is not found then \fB\s-1NULL\s0\fR is returned, otherwise the data pointer
-associated with \fIkey\fR is returned.
-.PP
-\&\fBtst_delete\fR deletes the string \fIkey\fR from the tree if it exists and
-returns the data pointer assocaited with that key.
-.PP
-If \fIkey\fR is not found then \fB\s-1NULL\s0\fR is returned, otherwise the data
-pointer associated with \fIkey\fR is returned.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Converted to \s-1POD\s0 from Peter A. Friend's ternary search trie
-documentation by Alex Kiernan <alex.kiernan@thus.net> for InterNetNews
-2.4.0.
-.PP
-$Id: tst.3 7880 2008-06-16 20:37:13Z iulius $
+++ /dev/null
-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
-.\"
-.\" Standard preamble:
-.\" ========================================================================
-.de Sh \" Subsection heading
-.br
-.if t .Sp
-.ne 5
-.PP
-\fB\\$1\fR
-.PP
-..
-.de Sp \" Vertical space (when we can't use .PP)
-.if t .sp .5v
-.if n .sp
-..
-.de Vb \" Begin verbatim text
-.ft CW
-.nf
-.ne \\$1
-..
-.de Ve \" End verbatim text
-.ft R
-.fi
-..
-.\" Set up some character translations and predefined strings. \*(-- will
-.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
-.\" double quote, and \*(R" will give a right double quote. \*(C+ will
-.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
-.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
-.\" nothing in troff, for use with C<>.
-.tr \(*W-
-.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
-.ie n \{\
-. ds -- \(*W-
-. ds PI pi
-. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
-. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
-. ds L" ""
-. ds R" ""
-. ds C` ""
-. ds C' ""
-'br\}
-.el\{\
-. ds -- \|\(em\|
-. ds PI \(*p
-. ds L" ``
-. ds R" ''
-'br\}
-.\"
-.\" If the F register is turned on, we'll generate index entries on stderr for
-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
-.\" entries marked with X<> in POD. Of course, you'll have to process the
-.\" output yourself in some meaningful fashion.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
-.\" way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-. \" fudge factors for nroff and troff
-.if n \{\
-. ds #H 0
-. ds #V .8m
-. ds #F .3m
-. ds #[ \f1
-. ds #] \fP
-.\}
-.if t \{\
-. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
-. ds #V .6m
-. ds #F 0
-. ds #[ \&
-. ds #] \&
-.\}
-. \" simple accents for nroff and troff
-.if n \{\
-. ds ' \&
-. ds ` \&
-. ds ^ \&
-. ds , \&
-. ds ~ ~
-. ds /
-.\}
-.if t \{\
-. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
-. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
-. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
-. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
-. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
-. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
-.\}
-. \" troff and (daisy-wheel) nroff accents
-.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
-.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
-.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
-.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
-.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
-.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
-.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
-.ds ae a\h'-(\w'a'u*4/10)'e
-.ds Ae A\h'-(\w'A'u*4/10)'E
-. \" corrections for vroff
-.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
-.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
-. \" for low resolution devices (crt and lpr)
-.if \n(.H>23 .if \n(.V>19 \
-\{\
-. ds : e
-. ds 8 ss
-. ds o a
-. ds d- d\h'-1'\(ga
-. ds D- D\h'-1'\(hy
-. ds th \o'bp'
-. ds Th \o'LP'
-. ds ae ae
-. ds Ae AE
-.\}
-.rm #[ #] #H #V #F C
-.\" ========================================================================
-.\"
-.IX Title "uwildmat 3"
-.TH uwildmat 3 "2008-04-06" "INN 2.4.5" "InterNetNews Documentation"
-.SH "NAME"
-uwildmat, uwildmat_simple, uwildmat_poison \- Perform wildmat matching
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-\&\fB#include <libinn.h>\fR
-.PP
-\&\fBbool uwildmat(const char *\fR\fItext\fR\fB, const char *\fR\fIpattern\fR\fB);\fR
-.PP
-\&\fBbool uwildmat_simple(const char *\fR\fItext\fR\fB, const char *\fR\fIpattern\fR\fB);\fR
-.PP
-\&\fBenum uwildmat uwildmat_poison(const char *\fR\fItext\fR\fB,
-const char *\fR\fIpattern\fR\fB);\fR
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-\&\fBuwildmat\fR compares \fItext\fR against the wildmat expression \fIpattern\fR,
-returning true if and only if the expression matches the text. \f(CW\*(C`@\*(C'\fR has
-no special meaning in \fIpattern\fR when passed to \fBuwildmat\fR. Both \fItext\fR
-and \fIpattern\fR are assumed to be in the \s-1UTF\-8\s0 character encoding, although
-malformed \s-1UTF\-8\s0 sequences are treated in a way that attempts to be mostly
-compatible with single-octet character sets like \s-1ISO\s0 8859\-1. (In other
-words, if you try to match \s-1ISO\s0 8859\-1 text with these routines everything
-should work as expected unless the \s-1ISO\s0 8859\-1 text contains valid \s-1UTF\-8\s0
-sequences, which thankfully is somewhat rare.)
-.PP
-\&\fBuwildmat_simple\fR is identical to \fBuwildmat\fR except that neither \f(CW\*(C`!\*(C'\fR
-nor \f(CW\*(C`,\*(C'\fR have any special meaning and \fIpattern\fR is always treated as a
-single pattern. This function exists solely to support legacy interfaces
-like \s-1NNTP\s0's \s-1XPAT\s0 command, and should be avoided when implementing new
-features.
-.PP
-\&\fBuwildmat_poison\fR works similarly to \fBuwildmat\fR, except that \f(CW\*(C`@\*(C'\fR as the
-first character of one of the patterns in the expression (see below)
-\&\*(L"poisons\*(R" the match if it matches. \fBuwildmat_poison\fR returns
-\&\fB\s-1UWILDMAT_MATCH\s0\fR if the expression matches the text, \fB\s-1UWILDMAT_FAIL\s0\fR if
-it doesn't, and \fB\s-1UWILDMAT_POISON\s0\fR if the expression doesn't match because
-a poisoned pattern matched the text. These enumeration constants are
-defined in the \fBlibinn.h\fR header.
-.SH "WILDMAT EXPRESSIONS"
-.IX Header "WILDMAT EXPRESSIONS"
-A wildmat expression follows rules similar to those of shell filename
-wildcards but with some additions and changes. A wildmat \fIexpression\fR is
-composed of one or more wildmat \fIpatterns\fR separated by commas. Each
-character in the wildmat pattern matches a literal occurance of that same
-character in the text, with the exception of the following metacharacters:
-.IP "?" 8
-Matches any single character (including a single \s-1UTF\-8\s0 multibyte
-character, so \f(CW\*(C`?\*(C'\fR can match more than one byte).
-.IP "*\&" 8
-Matches any sequence of zero or more characters.
-.IP "\e" 8
-.IX Item ""
-Turns off any special meaning of the following character; the following
-character will match itself in the text. \f(CW\*(C`\e\*(C'\fR will escape any character,
-including another backslash or a comma that otherwise would separate a
-pattern from the next pattern in an expression. Note that \f(CW\*(C`\e\*(C'\fR is not
-special inside a character range (no metacharacters are).
-.IP "[...]" 8
-A character set, which matches any single character that falls within that
-set. The presence of a character between the brackets adds that character
-to the set; for example, \f(CW\*(C`[amv]\*(C'\fR specifies the set containing the
-characters \f(CW\*(C`a\*(C'\fR, \f(CW\*(C`m\*(C'\fR, and \f(CW\*(C`v\*(C'\fR. A range of characters may be specified
-using \f(CW\*(C`\-\*(C'\fR; for example, \f(CW\*(C`[0\-5abc]\*(C'\fR is equivalent to \f(CW\*(C`[012345abc]\*(C'\fR. The
-order of characters is as defined in the \s-1UTF\-8\s0 character set, and if the
-start character of such a range falls after the ending character of the
-range in that ranking the results of attempting a match with that pattern
-are undefined.
-.Sp
-In order to include a literal \f(CW\*(C`]\*(C'\fR character in the set, it must be the
-first character of the set (possibly following \f(CW\*(C`^\*(C'\fR); for example, \f(CW\*(C`[]a]\*(C'\fR
-matches either \f(CW\*(C`]\*(C'\fR or \f(CW\*(C`a\*(C'\fR. To include a literal \f(CW\*(C`\-\*(C'\fR character in the
-set, it must be either the first or the last character of the set.
-Backslashes have no special meaning inside a character set, nor do any
-other of the wildmat metacharacters.
-.IP "[^...]" 8
-A negated character set. Follows the same rules as a character set above,
-but matches any character \fBnot\fR contained in the set. So, for example,
-\&\f(CW\*(C`[^]\-]\*(C'\fR matches any character except \f(CW\*(C`]\*(C'\fR and \f(CW\*(C`\-\*(C'\fR.
-.PP
-In addition, \f(CW\*(C`!\*(C'\fR (and possibly \f(CW\*(C`@\*(C'\fR) have special meaning as the first
-character of a pattern; see below.
-.PP
-When matching a wildmat expression against some text, each comma-separated
-pattern is matched in order from left to right. In order to match, the
-pattern must match the whole text; in regular expression terminology, it's
-implicitly anchored at both the beginning and the end. For example, the
-pattern \f(CW\*(C`a\*(C'\fR matches only the text \f(CW\*(C`a\*(C'\fR; it doesn't match \f(CW\*(C`ab\*(C'\fR or \f(CW\*(C`ba\*(C'\fR
-or even \f(CW\*(C`aa\*(C'\fR. If none of the patterns match, the whole expression
-doesn't match. Otherwise, whether the expression matches is determined
-entirely by the rightmost matching pattern; the expression matches the
-text if and only if the rightmost matching pattern is not negated.
-.PP
-For example, consider the text \f(CW\*(C`news.misc\*(C'\fR. The expression \f(CW\*(C`*\*(C'\fR matches
-this text, of course, as does \f(CW\*(C`comp.*,news.*\*(C'\fR (because the second pattern
-matches). \f(CW\*(C`news.*,!news.misc\*(C'\fR does not match this text because both
-patterns match, meaning that the rightmost takes precedence, and the
-rightmost matching pattern is negated. \f(CW\*(C`news.*,!news.misc,*.misc\*(C'\fR does
-match this text, since the rightmost matching pattern is not negated.
-.PP
-Note that the expression \f(CW\*(C`!news.misc\*(C'\fR can't match anything. Either the
-pattern doesn't match, in which case no patterns match and the expression
-doesn't match, or the pattern does match, in which case because it's
-negated the expression doesn't match. \f(CW\*(C`*,!news.misc\*(C'\fR, on the other hand,
-is a useful pattern that matches anything except \f(CW\*(C`news.misc\*(C'\fR.
-.PP
-\&\f(CW\*(C`!\*(C'\fR has significance only as the first character of a pattern; anywhere
-else in the pattern, it matches a literal \f(CW\*(C`!\*(C'\fR in the text like any other
-non\-metacharacter.
-.PP
-If the \fBuwildmat_poison\fR interface is used, then \f(CW\*(C`@\*(C'\fR behaves the same as
-\&\f(CW\*(C`!\*(C'\fR except that if an expression fails to match because the rightmost
-matching pattern began with \f(CW\*(C`@\*(C'\fR, \fB\s-1UWILDMAT_POISON\s0\fR is returned instead of
-\&\fB\s-1UWILDMAT_FAIL\s0\fR.
-.PP
-If the \fBuwildmat_simple\fR interface is used, the matching rules are the
-same as above except that none of \f(CW\*(C`!\*(C'\fR, \f(CW\*(C`@\*(C'\fR, or \f(CW\*(C`,\*(C'\fR have any special
-meaning at all and only match those literal characters.
-.SH "BUGS"
-.IX Header "BUGS"
-All of these functions internally convert the passed arguments to const
-unsigned char pointers. The only reason why they take regular char
-pointers instead of unsigned char is for the convenience of \s-1INN\s0 and other
-callers that may not be using unsigned char everywhere they should. In a
-future revision, the public interface should be changed to just take
-unsigned char pointers.
-.SH "HISTORY"
-.IX Header "HISTORY"
-Written by Rich \f(CW$alz\fR <rsalz@uunet.uu.net> in 1986, and posted to Usenet
-several times since then, most notably in comp.sources.misc in
-March, 1991.
-.PP
-Lars Mathiesen <thorinn@diku.dk> enhanced the multi-asterisk failure
-mode in early 1991.
-.PP
-Rich and Lars increased the efficiency of star patterns and reposted it to
-comp.sources.misc in April, 1991.
-.PP
-Robert Elz <kre@munnari.oz.au> added minus sign and close bracket handling
-in June, 1991.
-.PP
-Russ Allbery <rra@stanford.edu> added support for comma-separated patterns
-and the \f(CW\*(C`!\*(C'\fR and \f(CW\*(C`@\*(C'\fR metacharacters to the core wildmat routines in July,
-2000. He also added support for \s-1UTF\-8\s0 characters, changed the default
-behavior to assume that both the text and the pattern are in \s-1UTF\-8\s0, and
-largely rewrote this documentation to expand and clarify the description
-of how a wildmat expression matches.
-.PP
-Please note that the interfaces to these functions are named \fBuwildmat\fR
-and the like rather than \fBwildmat\fR to distinguish them from the
-\&\fBwildmat\fR function provided by Rich \f(CW$alz\fR's original implementation.
-While this code is heavily based on Rich's original code, it has
-substantial differences, including the extension to support \s-1UTF\-8\s0
-characters, and has noticable functionality changes. Any bugs present in
-it aren't Rich's fault.
-.PP
-$Id: uwildmat.3 7880 2008-06-16 20:37:13Z iulius $
-.SH "SEE ALSO"
-.IX Header "SEE ALSO"
-\&\fIgrep\fR\|(1), \fIfnmatch\fR\|(3), \fIregex\fR\|(3), \fIregexp\fR\|(3).
+++ /dev/null
-.TH WRITELOG 8
-.SH NAME
-writelog \- add a entry to an INN log file.
-.SH SYNOPSIS
-.B writelog
-.I name
-.I text...
-.SH DESCRIPTION
-.PP
-The
-.I writelog
-script is used to write a log entry or send it as mail.
-The
-.I name
-parameter specifies the name of the log file where the entry should
-be written.
-If it is the word ``mail'' then the entry is mailed to the news administrator,
-.IR <USER\ specified\ with\ \-\-with\-news\-master\ at\ configure> .
-The data that is written or sent consists of the
-.I text
-given on the command line, followed by standard input indented by
-four spaces.
-.IR Shlock (1)
-is used to avoid simultaneous updates to a single log file.
-.SH HISTORY
-Written by Landon Curt Noll <chongo@toad.com> and Rich $alz
-<rsalz@uunet.uu.net> for InterNetNews.
-.de R$
-This is revision \\$3, dated \\$4.
-..
-.R$ $Id: writelog.8 5909 2002-12-03 05:17:18Z vinocur $
-.SH "SEE ALSO"
-innd(8),
-innstat(8),
-news.daily(8),
-newslog(5),
-nnrpd(8),
-scanlogs(8).
+++ /dev/null
-## $Id: Makefile 7458 2005-12-12 00:25:05Z eagle $
-##
-## This Makefile contains rules to generate the files derived from POD
-## source. Normal make commands at the top level of the source tree don't
-## recurse into this directory. These targets are only used by
-## maintainers.
-
-include ../../Makefile.global
-
-TEXT = ../../HACKING ../../INSTALL ../../NEWS ../../README ../hook-perl \
- ../hook-python ../external-auth ../checklist
-
-MAN1 = ../man/convdate.1 ../man/fastrm.1 ../man/grephistory.1 \
- ../man/inews.1 ../man/innconfval.1 ../man/innmail.1 \
- ../man/pullnews.1 ../man/simpleftp.1 ../man/sm.1
-
-MAN3 = ../man/libauth.3 ../man/libinnhist.3 ../man/list.3 ../man/qio.3 \
- ../man/tst.3 ../man/uwildmat.3
-
-MAN5 = ../man/active.5 ../man/active.times.5 ../man/control.ctl.5 \
- ../man/cycbuff.conf.5 ../man/distrib.pats.5 ../man/expire.ctl.5 \
- ../man/inn.conf.5 ../man/motd.news.5 ../man/newsfeeds.5 ../man/ovdb.5 \
- ../man/passwd.nntp.5 ../man/radius.conf.5 ../man/readers.conf.5 \
- ../man/sasl.conf.5 ../man/subscriptions.5
-
-MAN8 = ../man/auth_krb5.8 ../man/auth_smb.8 ../man/ckpasswd.8 \
- ../man/domain.8 ../man/expireover.8 ../man/ident.8 ../man/innd.8 \
- ../man/inndf.8 ../man/nnrpd.8 ../man/inndstart.8 ../man/innupgrade.8 \
- ../man/mailpost.8 ../man/makehistory.8 ../man/ninpaths.8 \
- ../man/ovdb_init.8 ../man/ovdb_monitor.8 ../man/ovdb_server.8 \
- ../man/ovdb_stat.8 ../man/radius.8 ../man/rc.news.8 \
- ../man/sendinpaths.8 ../man/tdx-util.8
-
-ALL = $(TEXT) $(MAN1) $(MAN3) $(MAN5) $(MAN8)
-
-all: $(ALL)
-
-clean:
- rm -f $(ALL)
-
-../../HACKING: hacking.pod ; $(POD2TEXT) $? > $@
-../../INSTALL: install.pod ; $(POD2TEXT) $? > $@
-../../NEWS: news.pod ; $(POD2TEXT) $? > $@
-../../README: readme.pod ; $(POD2TEXT) $? > $@
-../hook-perl: hook-perl.pod ; $(POD2TEXT) $? > $@
-../hook-python: hook-python.pod ; $(POD2TEXT) $? > $@
-../external-auth: external-auth.pod ; $(POD2TEXT) $? > $@
-../checklist: checklist.pod ; $(POD2TEXT) $? > $@
-
-../man/convdate.1: convdate.pod ; $(POD2MAN) -s 1 $? > $@
-../man/fastrm.1: fastrm.pod ; $(POD2MAN) -s 1 $? > $@
-../man/grephistory.1: grephistory.pod ; $(POD2MAN) -s 1 $? > $@
-../man/inews.1: inews.pod ; $(POD2MAN) -s 1 $? > $@
-../man/innconfval.1: innconfval.pod ; $(POD2MAN) -s 1 $? > $@
-../man/innmail.1: innmail.pod ; $(POD2MAN) -s 1 $? > $@
-../man/pullnews.1: pullnews.pod ; $(POD2MAN) -s 1 $? > $@
-../man/simpleftp.1: simpleftp.pod ; $(POD2MAN) -s 1 $? > $@
-../man/sm.1: sm.pod ; $(POD2MAN) -s 1 $? > $@
-
-../man/libauth.3: libauth.pod ; $(POD2MAN) -s 3 $? > $@
-../man/libinnhist.3: libinnhist.pod ; $(POD2MAN) -s 3 $? > $@
-../man/list.3: list.pod ; $(POD2MAN) -s 3 $? > $@
-../man/qio.3: qio.pod ; $(POD2MAN) -s 3 $? > $@
-../man/tst.3: tst.pod ; $(POD2MAN) -s 3 $? > $@
-../man/uwildmat.3: uwildmat.pod ; $(POD2MAN) -s 3 $? > $@
-
-../man/active.5: active.pod ; $(POD2MAN) -s 5 $? > $@
-../man/active.times.5: active.times.pod ; $(POD2MAN) -s 5 $? > $@
-../man/control.ctl.5: control.ctl.pod ; $(POD2MAN) -s 5 $? > $@
-../man/cycbuff.conf.5: cycbuff.conf.pod ; $(POD2MAN) -s 5 $? > $@
-../man/distrib.pats.5: distrib.pats.pod ; $(POD2MAN) -s 5 $? > $@
-../man/expire.ctl.5: expire.ctl.pod ; $(POD2MAN) -s 5 $? > $@
-../man/inn.conf.5: inn.conf.pod ; $(POD2MAN) -s 5 $? > $@
-../man/motd.news.5: motd.news.pod ; $(POD2MAN) -s 5 $? > $@
-../man/newsfeeds.5: newsfeeds.pod ; $(POD2MAN) -s 5 $? > $@
-../man/ovdb.5: ovdb.pod ; $(POD2MAN) -s 5 $? > $@
-../man/passwd.nntp.5: passwd.nntp.pod ; $(POD2MAN) -s 5 $? > $@
-../man/radius.conf.5: radius.conf.pod ; $(POD2MAN) -s 5 $? > $@
-../man/readers.conf.5: readers.conf.pod ; $(POD2MAN) -s 5 $? > $@
-../man/sasl.conf.5: sasl.conf.pod ; $(POD2MAN) -s 5 $? > $@
-../man/subscriptions.5: subscriptions.pod ; $(POD2MAN) -s 5 $? > $@
-
-../man/auth_krb5.8: auth_krb5.pod ; $(POD2MAN) -s 8 $? > $@
-../man/auth_smb.8: auth_smb.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ckpasswd.8: ckpasswd.pod ; $(POD2MAN) -s 8 $? > $@
-../man/domain.8: domain.pod ; $(POD2MAN) -s 8 $? > $@
-../man/expireover.8: expireover.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ident.8: ident.pod ; $(POD2MAN) -s 8 $? > $@
-../man/innd.8: innd.pod ; $(POD2MAN) -s 8 $? > $@
-../man/inndf.8: inndf.pod ; $(POD2MAN) -s 8 $? > $@
-../man/inndstart.8: inndstart.pod ; $(POD2MAN) -s 8 $? > $@
-../man/innupgrade.8: innupgrade.pod ; $(POD2MAN) -s 8 $? > $@
-../man/mailpost.8: mailpost.pod ; $(POD2MAN) -s 8 $? > $@
-../man/makehistory.8: makehistory.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ninpaths.8: ninpaths.pod ; $(POD2MAN) -s 8 $? > $@
-../man/nnrpd.8: nnrpd.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ovdb_init.8: ovdb_init.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ovdb_monitor.8: ovdb_monitor.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ovdb_server.8: ovdb_server.pod ; $(POD2MAN) -s 8 $? > $@
-../man/ovdb_stat.8: ovdb_stat.pod ; $(POD2MAN) -s 8 $? > $@
-../man/radius.8: radius.pod ; $(POD2MAN) -s 8 $? > $@
-../man/rc.news.8: rc.news.pod ; $(POD2MAN) -s 8 $? > $@
-../man/sendinpaths.8: sendinpaths.pod ; $(POD2MAN) -s 8 $? > $@
-../man/tdx-util.8: tdx-util.pod ; $(POD2MAN) -s 8 $? > $@
+++ /dev/null
-=head1 NAME
-
-active - List of newsgroups carried by the server
-
-=head1 DESCRIPTION
-
-The file I<pathdb>/active lists the newsgroups carried by INN. This file
-is generally maintained using ctlinnd(8) to create and remove groups, or
-by letting controlchan(8) do so on the basis of received control messages.
-This file should not be edited directly without throttling B<innd>, and
-must be reloaded using B<ctlinnd> before B<innd> is unthrottled. Editing
-it directly even with those precautions may make it inconsistent with the
-overview database and won't update F<active.times>, so B<ctlinnd> should
-be used to make modifications whenever possible.
-
-Each newsgroup should be listed only once. Each line specifies one group.
-The order of groups does not matter. Within each newsgroup, received
-articles for that group are assigned monotonically increasing numbers as
-unique names. If an article is posted to newsgroups not mentioned in this
-file, those newsgroups are ignored.
-
-If none of the newsgroups listed in the Newsgroups header of an article
-are present in this file, the article is either rejected (if I<wanttrash>
-is false in F<inn.conf>), or is filed into the newsgroup C<junk> and only
-propagated to sites that receive the C<junk> newsgroup (if I<wanttrash> is
-true).
-
-Each line of this file consists of four fields separated by a space:
-
- <name> <high> <low> <flag>
-
-The first field is the name of the newsgroup. The newsgroup C<junk> is
-special, as mentioned above. The newsgroup C<control> and any newsgroups
-beginning with C<control.> are also special; control messages are filed
-into a control.* newsgroup named after the type of control message if that
-group exists, and otherwise are filed into the newsgroup C<control>
-(without regard to what newsgroups are listed in the Newsgroups header).
-If I<mergetogroups> is set to true in F<inn.conf>, newsgroups that begin
-with C<to.> are also treated specially; see innd(8).
-
-The second field is the highest article number that has been used in that
-newsgroup. The third field is the lowest article number in the group;
-this number is not guaranteed to be accurate, and should only be taken to
-be a hint. It is normally updated nightly as part of the expire process;
-see news.daily(8) and look for C<lowmark> or C<renumber> for more details.
-Note that because of article cancellations, there may be gaps in the
-numbering sequence. If the lowest article number is greater then the
-highest article number, then there are no articles in the newsgroup. In
-order to make it possible to update an entry in-place without rewriting
-the entire file, the second and third fields are padded out with leading
-zeros to make them a fixed width.
-
-The fourth field contains one of the following flags:
-
- y Local postings are allowed.
- m The group is moderated and all postings must be approved.
- n No local postings are allowed, only articles from peers.
- j Articles are filed in the junk group instead.
- x No local postings and ignored for articles from peers.
- =foo.bar Articles are filed in the group foo.bar instead.
-
-If a newsgroup has the C<j> flag, no articles will be filed in that
-newsgroup, and local postings to that group will be rejected. If an
-article for that newsgroup is received from a remote site, and it is not
-crossposted to some other valid group, it will be filed into the C<junk>
-newsgroup instead. This is different than simply not listing the group,
-since the article will still be accepted and can be propagated to other
-sites, and the C<junk> group can be made available to readers if wished.
-
-If the <flag> field begins with an equal sign, the newsgroup is an alias.
-Articles cannot be posted to that newsgroup, but they can be received from
-other sites. Any articles received from peers for that newsgroup are
-treated as if they were actually posted to the group named after the equal
-sign. Note that the Newsgroups header of the articles are not modified.
-(Alias groups are typically used during a transition and are typically
-created manually with ctlinnd(8).) An alias should not point to another
-alias.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Converted to
-POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: active.pod 6773 2004-05-17 05:48:54Z rra $
-
-=head1 SEE ALSO
-
-active.times(5), controlchan(8), ctlinnd(8), inn.conf(5), innd(8),
-news.daily(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-active.times - List of local creation times of newsgroups
-
-=head1 DESCRIPTION
-
-The file I<pathdb>/active.times provides a chronological record of when
-newsgruops were created on the local server. This file is normally
-updated by B<innd> whenever a newgroup control message is processed or a
-C<ctlinnd newgroup> command is issued, and is used by B<nnrpd> to answer
-NEWGROUPS requests.
-
-Each line consists of three fields:
-
- <name> <time> <creator>
-
-The first field is the name of the newsgroup. The second field is the
-time it was created, expressed as the number of seconds since the epoch.
-The third field is the e-mail addrses of the person who created the group,
-as specified in the control message or on the B<ctlinnd> command line, or
-the newsmaster specified at configure time if no creator argument was
-given to B<ctlinnd>.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Converted to
-POD by Russ Allbery <rra@stanford.edu>
-
-$Id: active.times.pod 6282 2003-04-06 21:50:07Z rra $
-
-=head1 SEE ALSO
-
-active(5), ctlinnd(8), inn.conf(5), innd(8), nnrpd(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-auth_krb5 - nnrpd Kerberos v5 authenticator
-
-=head1 SYNOPSIS
-
-B<auth_krb5> [B<-i> I<instance>]
-
-=head1 DESCRIPTION
-
-This program does authentication for B<nnrpd> against a Kerberos v5 KDC.
-This is NOT real Kerberos authentication using service tickets; instead, a
-username and password is used to attempt to obtain a Kerberos v5 TGT to
-confirm that they are valid. As such, this authenticator assumes that
-B<nnrpd> has been given the user's username and password, and therefore is
-not as secure as real Kerberos authentication. It generally should only
-be used with NNTP over SSL to protect the password from sniffing.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-i> I<instance>
-
-If this option is given, I<instance> will be used as the instance of the
-principal received from B<nnrpd> and authentication will be done against
-that principal instead of the base principal. In other words, a principal
-like C<user>, when passed to B<auth_krb5> invoked with C<-i nntp>, will be
-transformed into C<user/nntp> before attempting Kerberos authentication.
-
-Since giving one's password to B<nnrpd> is not as secure as normal
-Kerberos authentication, this option supports a configuration where all
-users are given a separate instance just for news authentication with its
-own password, so their regular account password isn't exposed via NNTP.
-
-=back
-
-=head1 EXAMPLE
-
-The following readers.conf(5) fragment tells nnrpd to authenticate users
-by attempting to obtain Kerberos v5 TGTs for them, appending an instance
-of C<nntp> to usernames before doing so:
-
- auth kerberos {
- auth: "auth_krb5 -i nntp"
- }
-
- access kerberos {
- users: "*/nntp"
- newsgroups: example.*
- }
-
-Access is granted to the example.* groups for all users who successfully
-authenticate.
-
-=head1 BUGS
-
-Currently, any username containing realm information (containing C<@>) is
-rejected. This is to prevent someone from passing in a username
-corresponding to a principal in another realm that they have access to and
-gaining access to the news server via it. However, this is also something
-that people may wish to do under some circumstances, so there should be a
-better way of handling it (such as, perhaps, a list of acceptable realms
-or a -r flag specifying the realm in which to attempt authentication).
-
-It's not clear the right thing to do when the username passed in contains
-a C</> and B<-i> was also given. Right now, B<auth_krb5> will create a
-malformed Kerberos principal with multiple instances and attempt to
-authenticate against it, which will fail but perhaps not with the best
-error message.
-
-=head1 HISTORY
-
-Originally written by Christopher P. Lindsey. This documentation was
-written by Russ Allbery <rra@stanford.edu> based on Christopher's original
-README file.
-
-$Id: auth_krb5.pod 5897 2002-12-03 03:41:06Z rra $
-
-=head1 SEE ALSO
-
-nnrpd(8), readers.conf(5)
-
-The latest version of Christopher's original B<nnrpkrb5auth> may be found
-on his web site at L<http://www.mallorn.com/tools/>.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-auth_smb - nnrpd Samba authenticator
-
-=head1 SYNOPSIS
-
-B<auth_smb> B<server> [B<backup_server>] B<domain>
-
-=head1 DESCRIPTION
-
-This program does authentication for B<nnrpd> against an SMB server. It
-passes the received username and password to B<server> for validation in
-the specified SMB B<domain>. A backup server may optionally be
-supplied; if it is missing, only B<server> is used.
-
-If authentication is successful, the original username is returned as
-the authentication identity. Brief errors, including incorrect password
-and failure contacting the server, are logged.
-
-=head1 EXAMPLE
-
-The following readers.conf(5) fragment grants access to users who can
-authenticate against an SMB server:
-
- auth windows {
- auth: "auth_smb pdc.example.com bdc.example.com USERS"
- default-domain: "users.example.com"
- }
-
- access internal {
- users: "*@users.example.com"
- newsgroups: example.*
- }
-
-Access is granted to the example.* groups after successful
-authentication.
-
-=head1 BUGS
-
-We should link against an external SMB library rather than maintain one
-within the INN source tree.
-
-=head1 HISTORY
-
-Originally written October 2000 by Krischan Jodies <krischan@jodies.cx>,
-based heavily on pam_smb v1.1.6 by David Airlie <airlied@samba.org>.
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-
-$Id: auth_smb.pod 5988 2002-12-12 23:02:14Z vinocur $
-
-=head1 SEE ALSO
-
-nnrpd(8), readers.conf(5)
-
-=cut
+++ /dev/null
-=head1 Introduction
-
-$Id: checklist.pod 5909 2002-12-03 05:17:18Z vinocur $
-
-This is an installation checklist written by Rebecca Ore, intended to be
-the beginning of a different presentation of the information in INSTALL,
-since getting started with installing INN can be complex. Further
-clarifications, updates, and expansion are welcome.
-
-=head1 Setup
-
-=over 4
-
-=item *
-
-Make sure there is a "news" user (and a "news" group)
-
-=item *
-
-Create a home directory for news (perhaps F</usr/local/news/>) and make
-sure it (and subdirectories) are owned by "news", group "news".
-
-You want to be careful that things in that directory stay owned by
-"news" -- but you can't just C<chown -R news.news> after the install,
-because you may have binaries that are SUID root. You can do the build
-as any user, because C<make install> will set the permissions
-correctly. After that point, though, you may want to C<su news> to
-avoid creating any files as root. (For routine maintenance once INN is
-working, you can generally be root.)
-
-=item *
-
-If necessary, add F<~news/bin> to the news user's path and F<~news/man>
-to the news user's manpath in your shell config files. (You may want to
-do this, especially the second part, on your regular account; the
-manpages are very useful.)
-
-You can do this now or later, but you will certainly want the manpages
-to help with configuring INN.
-
-For bash, try:
-
- PATH=~news/bin:$PATH
- export PATH
- MANPATH=~news/man:$MANPATH
- export MANPATH
-
-or csh:
-
- setenv PATH ~news/bin:$PATH
- setenv MANPATH ~news/man:$MANPATH
-
-although if you don't already have MANPATH set, the above may give an
-error or override your defaults (making it so you can only read the news
-manpages); if C<echo $MANPATH> does not give some reasonable path,
-you'll need to look up what the default is for your system (such as
-F</usr/man> or F</usr/share/man>).
-
-=back
-
-=head1 Compile
-
-=over 4
-
-=item *
-
-Download the INN tarball and unpack.
-
-=item *
-
-Work out configure options (C<./configure --help> for a list). If you
-aren't working out of F</usr/local/news>, or want to put some files on a
-different partition, you can set the directories now (or later in
-F<inn.conf> if you change your mind).
-
-You probably want C<--with-perl>. If you're not using NetBSD with
-cycbuffs or OpenBSD, perhaps C<--with-tagged-hash>. You might want to
-compile in SSL and Berkeley DB, if your system supports them.
-
- ./configure --with-perl ...
- make
-
- su
- make install
-
-(If you do the last step as root, all of the ownerships and permissions
-will be correct.)
-
-=back
-
-=head1 Configure
-
-=over 4
-
-=item *
-
-Find F<INSTALL> and open a separate window for it. A printout is
-probably a good idea -- it's long but very helpful. Any time the
-instructions below ask you to make a decision, you can probably find
-help in INSTALL.
-
-=item *
-
-Now it's time to work on the files in F<~news/etc/>. Start with
-F<inn.conf>; you must fill in the default moderators address, your fully
-qualified domain names and path. Fill in all the blanks. Change the
-file descriptor limits to something like 500.
-
-=item *
-
-If using cycbuffs (the CNFS storage method), open F<cycbuff.conf> in one
-window and a shell in another to create the cycbuff as described in
-INSTALL. As you create them, record in cycbuff.conf the paths and
-sizes. Save paths and sizes in a separate text file on another machine
-in case you ever blow away the wrong file.
-
-Name the metacycbuff, then configure F<storage.conf>.
-
-=item *
-
-In F<storage.conf>, be sure that all sizes of articles can be
-accomodated. If you want to throw away large articles, do it explicitly
-by using the "trash" storage method.
-
-=item *
-
-The default options in F<expire.ctl> work fine if you have cycbuffs, if
-not, configure to suit.
-
-=item *
-
-Check over F<moderators> and F<control.ctl>.
-
-=item *
-
-Run F<~news/bin/inncheck> and fix anything noted.
-
-Inncheck gives a rough check on the appropriateness of the configuration
-files as you go. (It's the equivalent of C<perl -cw yourfile.pl> for
-perl scripts.)
-
-Note that inncheck is very conservative about permissions; there's no
-reason most of the config files can't be world-readable if you prefer
-that.
-
-=item *
-
-Import an active file (F<~news/db/active>) and run inncheck again.
-Change where noted (there's a gotcha in the ISC's active list 000000
-000000 (whatever number of zeros) should be 0000000 00000001).
-
-=item *
-
-Create empty initial db files. Be sure these end up owned by news.
-
- cd ~news/db
-
- touch newsgroups
- touch active.times
-
- touch history
- ~news/bin/makedbz -i
- mv history.n.hash history.hash
- mv history.n.index history.index
- mv history.n.dir history.dir
-
- chmod 644 *
-
-=item *
-
-Create the cron jobs and make the changes to your system's
-F<syslog.conf> as noted in INSTALL. Also create the cron job for
-nntpsend if you've chosen that over innfeed.
-
-Create the log files.
-
-=item *
-
-For the time being, we can see if everything initially works without
-worrying about feeds or reader access.
-
-=back
-
-=head1 Run
-
-=over 4
-
-=item *
-
-Start inn by running ~news/bin/rc.news I<as the news user>.
-
-Check F<~news/log/news.notice> to see if everything went well, also use
-C<ps> to see if innd is running.
-
-C<telnet localhost 119> and you should see either a welcome banner or a
-"no permission to talk" message. If not, investigate.
-
-=item *
-
-C<man ctlinnd> now; you'll use C<ctlinnd reload> as you complete your
-configuration.
-
-=back
-
-=head1 Feeds
-
-All of this can be done while INN is running.
-
-=over 4
-
-=item *
-
-To get your incoming feeds working, edit F<incoming.conf>. When done,
-C<ctlinnd reload incoming.conf reason> (where "reason" is some text that
-will show up in the logs, anything will do).
-
-=item *
-
-To get your outgoing feeds working, decide whether to use innfeed or
-nntpsend. Edit F<newsfeeds> and either F<innfeed.conf> or
-F<nntpsend.ctl>.
-
-In newsfeeds, if using innfeed, use the option which doens't require you
-to do a separate innfeed configuration unless you know more than I do.
-
-Then C<ctlinnd reload newsfeeds reason>.
-
-=item *
-
-In readers.conf, remember that auth and access can be separated.
-
-Begin with auth. Your auth for password users could look like this:
-
- auth "foreignokay" {
- auth: "ckpasswd -d ~news/db/newsusers"
- default: "<unauthenticated>"
- }
-
-There is a perl script in the ckpasswd man page if you want to do
-authentications by password and have the appropriate libraries. Copy it
-to ~news/bin, name the file something like makepasswd.pl and change the
-internal paths to whatever you're using and wherever you're putting the
-newsusers database. The standard Apache C<htpasswd> tool also works
-just fine to create INN password files.
-
-Follow with the access stanzas. Something for people with passwords:
-
- access "generalpeople" {
- users: "*"
- newsgroups: "*,!junk,!control,!control.*"
- }
-
-And then something like one of the following two, depending on whether
-unauthenticated users get any access:
-
- access "restrictive" {
- users: "<unauthenticated>"
- newsgroups: "!*"
- }
-
- access "readonly" {
- users: "<unauthenticated>"
- read: "local.*"
- post: "!*"
- }
-
-You don't need to reload anything after modifying F<readers.conf>; every
-time an nnrpd launches it reads its configuration from disk.
-
-=back
-
+++ /dev/null
-=head1 NAME
-
-ckpasswd - nnrpd password authenticator
-
-=head1 SYNOPSIS
-
-B<ckpasswd> [B<-gs>] [B<-d> I<database>] [B<-f> I<filename>]
-[B<-u> I<username> B<-p> I<password>]
-
-=head1 DESCRIPTION
-
-B<ckpasswd> is the basic password authenticator for nnrpd, suitable for
-being run from an auth stanza in I<readers.conf>. See readers.conf(5) for
-more information on how to configure an nnrpd authenticator.
-
-B<ckpasswd> accepts a username and password from nnrpd and tells nnrpd(8)
-whether that's the correct password for that username. By default, when
-given no arguments, it tries to check the password using PAM if support
-for PAM was found when INN was built. Failing that, it tries to check the
-password against the password field returned by getpwnam(3). Note that
-these days most systems no longer make real passwords available via
-getpwnam(3) (some still do if and only if the program calling getpwnam(3)
-is running as root).
-
-When using PAM, B<ckpasswd> identifies itself as C<nnrpd>, not as
-C<ckpasswd>, and the PAM configuration must be set up accordingly. The
-details of PAM configuration are different on different operating systems
-(and even different Linux distributions); see L<EXAMPLES> below for help
-getting started, and look for a pam(7) or pam.conf(4) manual page on your
-system.
-
-When using any method other than PAM, B<ckpasswd> expects all passwords to
-be stored encrypted by the system crypt(3) function and calls crypt(3) on
-the supplied password before comparing it to the expected password. IF
-you're using a different password hash scheme (like MD5), you must use
-PAM.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-d> I<database>
-
-Read passwords from a database (ndbm or dbm format depending on what your
-system has) rather than by using getpwnam(3). B<ckpasswd> expects
-I<database>.dir and I<database>.pag to exist and to be a database keyed by
-username with the encrypted passwords as the values.
-
-While INN doesn't come with a program intended specifically to create such
-databases, on most systems it's fairly easy to write a Perl script to do
-so. Something like:
-
- #!/usr/bin/perl
- use NDBM_File;
- use Fcntl;
- tie (%db, 'NDBM_File', '/path/to/database', O_RDWR|O_CREAT, 0640)
- or die "Cannot open /path/to/database: $!\n";
- $| = 1;
- print "Username: ";
- my $user = <STDIN>;
- chomp $user;
- print "Password: ";
- my $passwd = <STDIN>;
- chomp $passwd;
- my @alphabet = ('.', '/', 0..9, 'A'..'Z', 'a'..'z');
- my $salt = join '', @alphabet[rand 64, rand 64];
- $db{$user} = crypt ($passwd, $salt);
- untie %db;
-
-Note that this will echo back the password when typed; there are obvious
-improvements that could be made to this, but it should be a reasonable
-start. Sometimes a program like this will be available with the name
-B<dbmpasswd>.
-
-This option will not be available on systems without dbm or ndbm
-libraries.
-
-=item B<-f> I<filename>
-
-Read passwords from the given file rather than using getpwnam(3). The
-file is expected to be formatted like a system password file, at least
-vaguely. That means each line should look something like:
-
- username:pdIh9NCNslkq6
-
-(and each line may have an additional colon after the encrypted password
-and additional data; that data will be ignored by B<ckpasswd>). Lines
-starting with a number sign (`#') are ignored. INN does not come with a
-utility to create the encrypted passwords, but B<htpasswd> (which comes
-with Apache) can do so and it's a quick job with Perl (see the example
-script under B<-d>). If using Apache's B<htpasswd> program, be sure to
-give it the B<-d> option so that it will use crypt(3).
-
-=item B<-g>
-
-Attempt to look up system group corresponding to username and return a
-string like "user@group" to be matched against in F<readers.conf>. This
-option is incompatible with the B<-d> and B<-f> options.
-
-=item B<-p> I<password>
-
-Use I<password> as the password for authentication rather than reading a
-password using the nnrpd authenticator protocol. This option is useful
-only for testing your authentication system (particularly since it
-involves putting a password on the command line), and does not work when
-B<ckpasswd> is run by B<nnrpd>. If this option is given, B<-u> must also
-be given.
-
-=item B<-s>
-
-Check passwords against the result of getspnam(3) instead of getpwnam(3).
-This function, on those systems that supports it, reads from /etc/shadow
-or similar more restricted files. If you want to check passwords supplied
-to nnrpd(8) against system account passwords, you will probably have to
-use this option on most systems.
-
-Most systems require special privileges to call getspnam(3), so in order
-to use this option you may need to make B<ckpasswd> setgid to some group
-(like group "shadow") or even setuid root. B<ckpasswd> has not been
-specifically audited for such uses! It is, however, a very small program
-that you should be able to check by hand for security.
-
-This configuration is not recommended if it can be avoided, for serious
-security reasons. See L<readers.confZ<>(5)/SECURITY CONSIDERATIONS> for
-discussion.
-
-=item B<-u> I<username>
-
-Authenticate as I<username>. This option is useful only for testing (so
-that you can test your authentication system easily) and does not work
-when B<ckpasswd> is run by B<nnrpd>. If this option is given, B<-p> must
-also be given.
-
-=back
-
-=head1 EXAMPLES
-
-See readers.conf(5) for examples of nnrpd(8) authentication configuration
-that uses B<ckpasswd> to check passwords.
-
-An example PAM configuration for F</etc/pam.conf> that tells B<ckpasswd>
-to check usernames and passwords against system accounts is:
-
- nnrpd auth required pam_unix.so
- nnrpd account required pam_unix.so
-
-Your system may want you to instead create a file named F<nnrpd> in
-F</etc/pam.d> with lines like:
-
- auth required pam_unix.so
- account required pam_unix.so
-
-This is only the simplest configuration. You may be able to include
-common shared files, and you may want to stack other modules, either to
-allow different authentication methods or to apply restrictions like lists
-of users who can't authenticate using B<ckpasswd>. The best guide is the
-documentation for your system and the other PAM configurations you're
-already using.
-
-To test to make sure that B<ckpasswd> is working correctly, you can run it
-manually and then give it the username (prefixed with C<ClientAuthname:>)
-and password (prefixed with C<ClientPassword:>) on standard input. For
-example:
-
- (echo 'ClientAuthname: test' ; echo 'ClientPassword: testing') \
- | ckpasswd -f /path/to/passwd/file
-
-will check a username of C<test> and a password of C<testing> against the
-username and passwords stored in F</path/to/passwd/file>. On success,
-B<ckpasswd> will print C<User:test> and exit with status 0. On failure,
-it will print some sort of error message and exit a non-zero status.
-
-=head1 HISTORY
-
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-
-$Id: ckpasswd.pod 7526 2006-08-12 22:31:11Z eagle $
-
-=head1 SEE ALSO
-
-readers.conf(5), nnrpd(8)
-
-Linux users who want to use PAM should read the Linux-PAM System
-Administrator's Guide at
-L<http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/Linux-PAM_SAG.html>.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-control.ctl - Specify handling of Usenet control messages
-
-=head1 DESCRIPTION
-
-F<control.ctl> in I<pathetc> is used to determine what action is taken
-when a control message is received. It is read by B<controlchan>, which
-is normally invoked as a channel program by B<innd>. When F<control.ctl>
-is modified, B<controlchan> notices this automatically and reloads it.
-
-Blank lines and lines beginning with a number sign (C<#>) are ignored.
-All other lines should consist of four fields separated by colons:
-
- <type>:<from>:<newsgroups>:<action>
-
-The first field, <type>, is the type of control message for which this
-line is valid. It should either be the name of a control message or the
-word C<all> to indicate that it applies to all control messages.
-
-The second field, <from>, is a shell-style pattern that matches the e-mail
-address of the person posting the message (with the address first
-converted to lowercase). The matching is done with rules equivalent to
-those of the shell's I<case> statement; see sh(1) for more details.
-
-If the control message is a newgroup or rmgroup, the third field,
-<newsgroups>, is a shell-style pattern matching the newsgroup affected by
-the control message. If the control message is a checkgroups, the third
-field is a shell-style pattern matching the newsgroups that should be
-processed for checking. If the control message is of any other type, the
-third field is ignored.
-
-The fourth field, <action>, specifies what action to take with control
-messages that match this line. The following actions are understood:
-
-=over 4
-
-=item B<doit>
-
-The action requested by the control message should be performed. For
-checkgroups messages, this means that the shell commands that should
-be run will be mailed to the news administrator (the argument to
-B<--with-news-master> given at configure time, C<usenet> by default); for
-other commands, this means that the change will be silently performed. If
-you always want notification of actions taken, use C<doit=mail> instead (see
-below).
-
-=item B<doifarg>
-
-If the control message has an argument, this is equivalent to B<doit>. If
-it does not have an argument, this is equivalent to B<mail>. This is only
-useful for entries for sendsys control messages, allowing a site to
-request its own F<newsfeeds> entry by posting a C<sendsys mysite> control
-message, but not allowing the entire F<newsfeeds> file to be sent. This
-was intended to partially counter so-called "sendsys bombs," where forged
-sendsys control messages were used to mailbomb people.
-
-Processing sendsys control messages is not recommended even with this
-work-around unless they are authenticated in some fashion. The risk of
-having news servers turned into anonymous mail bombing services is too
-high.
-
-=item B<doit>=I<file>
-
-The action is performed as in B<doit>, and additionally a log entry is
-written to the specified log file I<file>. If I<file> is the word
-C<mail>, the log entry is mailed to the news administrator instead. An
-empty string is equivalent to F</dev/null> and says to log nothing.
-
-If I<file> starts with a slash, it is taken as the absolute filename to
-use for the log file. Otherwise, the filename is formed by prepending
-I<pathlog> and a slash and appending C<.log>. In other words, an action
-of C<doit=newgroup> will log to I<pathlog>/newgroup.log.
-
-=item B<drop>
-
-No action is taken and the message is ignored.
-
-=item B<verify-*>
-
-If the action starts with the string C<verify->, as in:
-
- verify-news.announce.newgroups
-
-then PGP verification of the control message will be done and the user ID
-of the key of the authenticated signer will be checked against the
-expected identity defined by the rest of the string
-(C<news.announce.newgroups> in the above example. This verification is
-done via B<pgpverify>; see pgpverify(8) for more details.
-
-If no logging is specified (with =I<file> as mentioned below), logging will
-be done the same as with B<doit> as described above.
-
-=item B<verify-*>=B<mail>
-
-PGP verification is done as for the B<verify-*> action described above, and
-notification of successful newgroup and rmgroup control messages and the
-output of checkgroups messages will be mailed to the news administrator.
-(In the case of checkgroups messages, this means that the shell script that
-should be run will be mailed to the administrator.)
-
-=item B<verify-*>=I<file>
-
-PGP verification is done as for the B<verify-*> action described above,
-and a log entry is written to the specified file as described in
-B<doit>=I<file> above. (In the case of checkgroups messages, this means
-that the shell script output of the checkgroups message will be written to
-that file.)
-
-=item B<log>
-
-A one-line log message is sent to standard error. B<innd> normally
-directs this to I<pathlog>/errlog.
-
-=item B<log>=I<file>
-
-A log entry is written to the specified log file, which is interpreted as
-in B<doit>=I<file> described above.
-
-=item B<mail>
-
-A mail message is sent to the news administrator without taking any other
-action.
-
-=back
-
-Processing of a checkgroups message will never actually change the
-F<active> file (the list of groups carried by the server). The difference
-between a B<doit> or B<verify> action and a B<mail> action for a
-checkgroups control message lies only in what e-mail is sent; B<doit> or
-B<verify> will mail the news administrator a shell script to create,
-delete, or modify newsgroups to match the checkgroups message, whereas
-B<mail> will just mail the entire message. In either case, the news
-administrator will have to take action to implement the checkgroups
-message, and if that mail is ignored, nothing will be changed.
-
-Lines are matched in order and the last matching line in the file will be
-used.
-
-Use of the B<verify> action for processing newgroup, rmgroup, and
-checkgroups messages is STRONGLY recommended. Abuse of control messages
-is rampant, and authentication via PGP signature is currently the only
-reliable way to be sure that a control message comes from who it claims to
-be from. Most major hierarchies are now issuing PGP-authenticated control
-messages.
-
-In order to use B<verify> actions, the PGP key ring of the news user must
-be populated with the PGP keys of the hierarchy maintainers whose control
-messages you want to honor. For more details on PGP-authenticated control
-messages and the URL for downloading the PGP keys of major hierarchies,
-see pgpverify(8).
-
-Control messages of type cancel are handled internally by B<innd> and
-cannot be affected by any of the mechanisms described here.
-
-=head1 EXAMPLE
-
-With the following three lines in F<control.ctl>:
-
- newgroup:*:*:drop
- newgroup:group-admin@isc.org:comp.*:verify-news.announce.newgroups
- newgroup:kre@munnari.oz.au:aus.*:mail
-
-a newgroup coming from C<group-admin@isc.org> will be honored if it is for
-a newsgroup in the comp.* hierarchy and if it has a valid signature
-corresponding to the PGP key with a user ID of C<news.announce.newgroups>.
-If any newgroup claiming to be from C<kre@munnari.oz.au> for a newsgroup
-in the aus.* hierarchy is received, it too will be honored. All other
-newgroup messages will be ignored.
-
-=head1 WARNINGS
-
-The third argument for a line affecting checkgroups does B<not> affect
-whether the line matches. It is only used after a matching line is found,
-to filter out which newsgroups listed in the checkgroups will be
-processed. This means that a line like:
-
- checkgroups:*:*binaries*:drop
-
-will cause B<all> checkgroups control messages to be dropped unless they
-match a line after this one in F<control.ctl>, not just ignore newsgroups
-containing C<binaries> in the name. The general rule is to never use C<*>
-in the second field for a line matching checkgroups messages. There is
-unfortunately no way to do what the author of a line like the above
-probably intended to do (yet).
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: control.ctl.pod 7569 2006-08-30 18:12:53Z eagle $
-
-=head1 SEE ALSO
-
-controlchan(8), inn.conf(5), innd(8), newsfeeds(5), pgpverify(8), sh(1).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-convdate - Convert time/date strings and numbers
-
-=head1 SYNOPSIS
-
-B<convdate> [B<-dhl>] [B<-c> | B<-n> | B<-s>] [I<date> ...]
-
-=head1 DESCRIPTION
-
-B<convdate> translates the date/time strings given on the command line,
-outputting the results one to a line. The input can either be a date in
-some format that parsedate(3) can parse or the number of seconds since
-epoch (if B<-c> is given). The output is either ctime(3) results, the
-number of seconds since epoch, or a Usenet Date: header, depending on the
-options given.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-c>
-
-Each argument is taken to be the number of seconds since epoch (a time_t)
-rather than a date.
-
-=item B<-d>
-
-Output a valid Usenet Date: header instead of the results of ctime(3) for
-each date given on the command line. This is useful for testing the
-algorithm used to generate Date: headers for local posts. Normally, the
-date will be in UTC, but see the B<-l> option.
-
-=item B<-h>
-
-Print usage information and exit.
-
-=item B<-l>
-
-Only makes sense in combination with B<-d>. If given, Date: headers
-generated will use the local time zone instead of UTC.
-
-=item B<-n>
-
-Rather than outputting the results of ctime(3) or a Date: header, output
-each date given as the number of seconds since epoch (a time_t). This
-option doesn't make sense in combination with B<-d>.
-
-=item B<-s>
-
-Pass each given date to parsedate(3) and print the results of ctime(3) (or
-a Date: header if B<-d> is given). This is the default behavior.
-
-=back
-
-=head1 EXAMPLES
-
-Note that relative times or times with partial information use the current
-time to fill in the rest of the date, so dates like "12pm" are taken to be
-12pm of the day when convdate is run. This is a property of parsedate(3);
-see the man page for more information. Most of these examples are from
-the original man page dating from 1991 and were run in the -0400 time
-zone.
-
- % convdate 'feb 10 10am'
- Sun Feb 10 10:00:00 1991
-
- % convdate 12pm 5/4/90
- Fri Dec 13 00:00:00 1991
- Fri May 4 00:00:00 1990
-
-Note that 12pm and 5/4/90 are two *separate* arguments and therefore
-result in two results. Note also that a date with no time is taken to be
-at midnight.
-
- % convdate -n 'feb 10 10am' '12pm 5/4/90'
- 666198000
- 641880000
-
- % convdate -c 666198000
- Sun Feb 10 10:00:00 1991
-
-ctime(3) results are in the local time zone. Compare to:
-
- % convdate -dc 666198000
- Sun, 10 Feb 1991 15:00:00 +0000 (UTC)
-
- % env TZ=PST8PDT convdate -dlc 666198000
- Sun, 10 Feb 1991 07:00:00 -0800 (PST)
-
- % env TZ=EST5EDT convdate -dlc 666198000
- Sun, 10 Feb 1991 10:00:00 -0500 (EST)
-
-The system library functions generally use the environment variable TZ to
-determine (or at least override) the local time zone.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net>, rewritten and updated by Russ
-Allbery <rra@stanford.edu> for the B<-d> and B<-l> flags.
-
-$Id: convdate.pod 3362 2000-06-13 02:57:51Z rra $
-
-=head1 SEE ALSO
-
-parsedate(3).
+++ /dev/null
-=head1 NAME
-
-cycbuff.conf - Configuration file for INN CNFS storage method
-
-=head1 DESCRIPTION
-
-This file defines the cyclical buffers that make up the storage pools for
-CNFS (Cyclic News File System). Some options controlling the behavior of
-the CNFS storage system can also be set here. F<cycbuff.conf> is required
-if the CNFS (Cyclic News File System) storage method is used. INN will
-look for it in I<pathetc> (as set in F<inn.conf>).
-
-For information about how to configure INN to use CNFS, see
-storage.conf(5).
-
-Blank lines and lines beginning with a hash sign (C<#>) are ignored. All
-other lines must be of one of the following forms:
-
- cycbuffupdate:<interval>
- refreshinterval:<interval>
- cycbuff:<name>:<file>:<size>
- metacycbuff:<name>:<buffer>[,<buffer>,...][:<mode>]
-
-(where items enclosed in [] are optional). Order is mostly not
-significant, but all I<cycbuff> lines must occur before all I<metacycbuff>
-lines. Long lines can be continued on the next line by ending the line
-with a backslash (C<\>).
-
-=over 4
-
-=item cycbuffupdate:<interval>
-
-Sets the number of articles are written before the cycbuff header is
-written back to disk to <interval>. Under most operating systems, the
-header doesn't have to be written to disk for the updated data to be
-available to other processes on the same system that are reading articles
-out of CNFS, but any accesses to the CNFS cycbuffs over NFS will only see
-the data present at the last write of the header. After a system crash,
-all updates since the last write of the CNFS header may be lost. The
-default value, if this line is omitted, is 25, meaning that the header is
-written to disk after every 25 articles stored in that cycbuff.
-
-=item refreshinterval:<interval>
-
-Sets the interval (in seconds) between re-reads of the cycbuff header to
-<interval>. This primarily affects B<nnrpd> and controls the frequency
-with which it updates its knowledge of the current contents of the CNFS
-cycbuffs. The default value, if this line is omitted, is 30.
-
-=item cycbuff:<name>:<file>:<size>
-
-Configures a particular CNFS cycbuff. <name> is a symbolic name for the
-buffer, to be used later in a metacycbuff line. It must be no longer than
-seven characters. <file> is the full path to the buffer file or block
-device, and must be no longer than 63 characters. <size> is the length of
-the buffer in kilobytes (1KB is 1024 bytes). If <file> is not a block
-device, it should be <size> * 1024 bytes long.
-
-=item metacycbuff:<name>:<buffer>[,<buffer>,...][:<mode>]
-
-Specifies a collection of CNFS buffers that make up a single logical
-storage location from the perspective of INN. Metacycbuffs are referred
-to in F<storage.conf> as storage locations for articles, so in order to
-actually put articles in a cycbuff, it has to be listed as part of some
-metacycbuff which is then referenced in F<storage.conf>.
-
-<name> is the symbolic name of the metacycbuff, referred to in the options
-field of cnfs entries in F<storage.conf>. <buffer> is the name of a
-cycbuff (the <name> part of a cycbuff line), and any number of cycbuffs
-may be specified, separated by commas.
-
-If there is more than one cycbuff in a metacycbuff, there are two ways
-that INN can distribute articles between the cycbuffs. The default mode,
-INTERLEAVE, stores the articles in each cycbuff in a round-robin fashion,
-one article per cycbuff in the order listed. If the cycbuffs are of
-wildly different sizes, this can cause some of them to roll over much
-faster than others, and it may not give the best performance depending on
-your disk layout. The other storage mode, SEQUENTIAL, instead writes to
-each cycbuff in turn until that cycbuff is full and then moves on to the
-next one, returning to the first and starting a new cycle when the last
-one is full. To specify a mode rather than leaving it at the default, add
-a colon and the mode (INTERLEAVE or SEQUENTIAL) at the end of the
-metacycbuff line.
-
-=back
-
-B<innd> only reads F<cycbuff.conf> on startup, so if you change anything
-in this file and want B<innd> to pick up the changes, you have to stop and
-restart it. C<ctlinnd reload all ''> is not sufficient.
-
-When articles are stored, the cycbuff into which they're stored is saved
-as part of the article token. In order for INN to retrieve articles from
-a cycbuff, that cycbuff must be listed in F<cycbuff.conf>. However, if
-INN should not write to a cycbuff, it doesn't need to be (and shouldn't
-be) listed in a metacycbuff.
-
-This provides an easy way to retire a cycbuff. Just remove it from its
-metacycbuff, leaving in the cycbuff line, and restart B<innd> (with, for
-example, C<ctlinnd xexec innd>). No new articles will be put into the
-cycbuff, but neither will any articles expire from it. After you no
-longer need the articles in the cycbuff, just remove it entirely from
-F<cycbuff.conf>. Then all of the articles will appear to have been
-deleted to INN, and the next nightly expire run will clean up any
-remaining references to them.
-
-Adding a new cycbuff just requires creating it (see below), adding a
-cycbuff line, adding it to a metacycbuff, and then restarting B<innd>.
-
-=head1 CREATING CYCBUFFS
-
-When creating a new cycbuff, there are two different methods for creating
-the buffers in which the articles will be stored.
-
-=over 4
-
-=item 1.
-
-Create a large file on top of a regular file system. The easiest way to
-do this is probably with dd(1), using a command like:
-
- dd if=/dev/zero of=/path/to/cycbuff bs=1024 count=<size>
-
-where <size> is the size from the cycbuff line in F<cycbuff.conf>.
-F<INSTALL> contains a script that will generate these commands for you
-from your F<cycbuff.conf> file.
-
-This is the simplest method, but has the disadvantage that very large
-files on regular file systems can be fairly slow to access, particularly
-at the end of the file, and INN incurs unnecessary file system overhead
-when accessing the cycbuff.
-
-=item 2.
-
-Use block devices directly. If your operating system allows you to call
-mmap() on block devices (Solaris and recent versions of Linux do, FreeBSD
-at last report does not), this is the recommended method since you can
-avoid all of the native file system overhead. Note, however, that each
-cycbuff cannot be larger than 2GB with this method, so if you need a lot
-of spool space, you may have to go back to disk files.
-
-Partition the disk to make each partition equal to or smaller than 2GB.
-If you're using Solaris, set up your partitions to avoid the first
-cylinder of the disk (or otherwise the cycbuff header will overwrite the
-disk partition table and render the cycbuffs inaccessible). Then, create
-device files for each block device you're going to use.
-
-It's not recommended to use the block device files in F</dev>, since the
-news system doesn't have permission to write to them and changing the
-permissions of the system device files may affect something else.
-Instead, use mknod(1) to create a new set of block devices (in somewhere
-like I<pathspool>/cycbuffs that's only writable by the news user). To do
-this, run C<ls -Ll> on the devices in F</dev> that correspond to the block
-devices that you want to use. The major and minor device numbers are in
-the fifth and sixth columns (right before the date), respectively. Then
-run mknod like:
-
- mknod <file> b <major> <minor>
-
-where <file> is the path to the device to create (matching the <file> part
-of the cycbuff line) and <major> and <minor> are the major and minor
-device numbers as discovered above.
-
-Here's a short script to do this when given the path to the system device
-file as an argument:
-
- #!/bin/sh
- base=`echo "$1" | sed 's%.*/%%'`
- major=`ls -Ll "$1" | awk '{print $5}' | tr -d ,`
- minor=`ls -Ll "$1" | awk '{print $6}`
- mkdir -p /usr/local/news/spool/cycbuffs
- mknod /usr/local/news/spool/cycbuffs/"$base" b "$major" "$minor"
- chown news:news /usr/local/news/spool/cycbuffs/"$base"
- chmod 644 /usr/local/news/spool/cycbuffs/"$base"
-
-Make sure that the created files are owned by the news user and news
-group, as specified at configure time (the default being C<news> for
-both). Also make sure that the permissions on the devices allow the news
-user to read and write, and if you want other users on the system to be
-able to use B<sm> to retrieve articles, make sure they're world-readable.
-
-=back
-
-Once you have everything configured properly and you start B<innd>, you
-should see messages in F<news.notice> that look like:
-
- innd: CNFS-sm No magic cookie found for cycbuff ONE, initializing
-
-where ONE will be whatever you called your cycbuff.
-
-=head1 HISTORY
-
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-Rewritten into POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: cycbuff.conf.pod 7860 2008-06-07 12:46:49Z iulius $
-
-=head1 SEE ALSO
-
-ctlinnd(8), innd(8), nnrpd(8), sm(1), storage.conf(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-distrib.pats - Default values for the Distribution header
-
-=head1 DESCRIPTION
-
-The file I<pathetc>/distrib.pats is used by B<nnrpd> to determine the
-default value of the Distribution header. Blank lines and lines beginning
-with a number sign (C<#>) are ignored. All other lines consist of three
-fields separated by a colon:
-
- <weight>:<pattern>:<value>
-
-The first field is the weight to assign to this match. If a newsgroup
-matches multiple lines, the line with the highest weight is used. This
-should be an arbitrary integer greater than zero. The order of lines in
-the file is only important if groups have equal weight (in which case, the
-first matching line will be used).
-
-The second field is either the name of a newsgroup or a uwildmat(3)-style
-pattern to specify a set of newsgroups.
-
-The third field is the value that should be used for the Distribution
-header of a posted article, if this line was picked as the best match and
-no Distribution header was supplied by the user. It can be an empty
-string, specifying that no Distribution header should be added.
-
-When a post is received by B<nnrpd> that does not already contain a
-Distribution header, each newsgroup to which an article is posted will be
-checked against this file in turn, and the matching line with the highest
-weight will be used as the value of the Distribution header. If no lines
-match, or if the matching line has an empty string for its third field, no
-header will be added.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Converted to
-POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: distrib.pats.pod 6282 2003-04-06 21:50:07Z rra $
-
-=head1 SEE ALSO
-
-inn.conf(5), nnrpd(8), uwildmat(3)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-domain - nnrpd domain resolver
-
-=head1 SYNOPSIS
-
-B<domain> B<domainname>
-
-=head1 DESCRIPTION
-
-This program can be used in F<readers.conf> to grant access based on the
-subdomain part of the remote hostname. In particular, it only returns
-success if the remote hostname ends in B<domainname>. (A leading dot on
-B<domainname> is optional; even without it, the argument must match on
-dot-separated boundaries). The "username" returned is whatever initial
-part of the remote hostname remains after B<domainname> is removed. It
-is an error if there is no initial part (that is, if the remote hostname
-is I<exactly> the specified B<domainname>).
-
-=head1 EXAMPLE
-
-The following readers.conf(5) fragment grants access to hosts with
-internal domain names:
-
- auth internal {
- res: "domain .internal"
- default-domain: "example.com"
- }
-
- access internal {
- users: "*@example.com"
- newsgroups: example.*
- }
-
-Access is granted to the example.* groups for all connections from hosts
-that resolve to hostnames ending in C<.internal>; a connection from
-"foo.internal" would match access groups as "foo@example.com".
-
-=head1 BUGS
-
-It seems the code does not confirm that the matching part is actually at
-the end of the remote hostname (e.g., "domain: example.com" would match
-the remote host "foo.example.com.org" by ignoring the trailing ".org"
-part).
-
-Does this resolver actually provide any useful functionality not
-available by using wildcards in the readers.conf(5) I<hosts> parameter?
-If so, the example above should reflect this functionality.
-
-=head1 HISTORY
-
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-
-$Id: domain.pod 5988 2002-12-12 23:02:14Z vinocur $
-
-=head1 SEE ALSO
-
-nnrpd(8), readers.conf(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-expire.ctl - Configuration file for article expiration
-
-=head1 DESCRIPTION
-
-The file I<pathetc>/expire.ctl is the default configuration file for
-B<expire> and B<expireover>, which read it at start-up. It serves two
-purposes: it defines how long history entries for expired or rejected
-articles are remembered, and it determines how long articles stored on the
-server are retained.
-
-Normally, if all of the storage methods used by the server are
-self-expiring (such as CNFS), all lines except the C</remember/> setting
-(described below) are ignored. This can be changed with the B<-N> option
-to B<expire> or B<expireover>.
-
-Black lines and lines beginning with a number sign (C<#>) are ignored.
-All other lines should be in one of two formats. The order of the file is
-significant, and the last matching entry will be used.
-
-The first format specifies how long to keep history entries for articles
-that aren't present in the news spool. These are articles that have
-either already expired, or articles which the server rejected (when
-I<remembertrash> is set to true in F<inn.conf>). There should be one and
-only one line in this format, which looks like:
-
- /remember/:<days>
-
-where <days> is a decimal number that specifies the minimum number of days
-a history record for a given message ID is retained, regardless of whether
-the article is present in the spool. (History entries for articles still
-present in the spool are always retained.)
-
-The primary reason to retain a record of old articles is in case a peer
-offers old articles that were previously accepted but have already
-expired. Without a history record for such articles, the server would
-accept the article again and readers would see duplicate articles.
-Articles older than a certain number of days won't be accepted by the
-server at all (see I<artcutoff> in inn.conf(5) and the B<-c> flag in
-innd(8)), and this setting should probably match that time period (10 days
-by default) to ensure that the server never accepts duplicates.
-
-Most of the lines in this file will be in the second format, which
-consists of either four or five colon-separated fields:
-
- <pattern>:<flag>:<min>:<default>:<max>
-
-if I<groupbaseexpiry> is true in F<inn.conf> (the default), and otherwise:
-
- <classnum>:<min>:<default>:<max>
-
-All lines must be in the correct format given the current setting of
-I<groupbaseexpiry>, and therefore the two formats cannot co-exist in the
-same file.
-
-Normally, a rule matches a newsgroup through the combination of the
-<pattern> and <flag> fields. <pattern> is a uwildmat(3)-style pattern,
-specifying the newsgroups to which the line is applied. Note that the
-last matching entry will be used, so general patterns (such as defaults
-for all groups where <pattern> is C<*>) should appear at the beginning of
-the file before more specific settings.
-
-The <flag> field can be used to further limit newsgroups to which the line
-applies, and should be chosen from the following set:
-
- M Only moderated groups
- U Only unmoderated groups
- A All groups
- X Remove the article from all groups it appears in
-
-One of M, U, or A must be specified. X should be used in combination with
-one of the other letters, not by itself.
-
-An expiration policy is applied to every article in a newsgroup it
-matches. There is no way to set an expiration policy for articles
-crossposted to groups you don't carry that's different than other articles
-in the same group. Normally, articles are not completely deleted until
-they expire out of every group to which they were posted, but if an
-article is expired following a rule where <flag> contains X, it is deleted
-out of all newsgroups to which it was posted immediately.
-
-If I<groupbaseexpiry> is instead set to false, there is no <pattern> and
-<flag> field and the above does not apply. Instead, there is a single
-<classnum> field, which is either a number matching the storage class
-number specified in F<storage.conf> or C<*> to specify a default for all
-storage classes. All articles stored in a storage class will be expired
-following the instructions in the line with a matching <classnum>, and
-when articles are expired, they're always removed from all groups to which
-they were posted.
-
-The remaining three fields are the same in either format, and are used to
-determine how long an article should be kept. Each field should be either
-a decimal number of days (fractions like C<8.5> are allowed, but remember
-that articles are only removed when B<expire> or B<expireover> is run,
-normally once a day by B<news.daily>) or the word C<never>.
-
-The middle field, <default>, will be used as the expiration period for
-most articles. The other two fields, <min> and <max>, only come into
-play if the article requests a particular expiration date with an Expires
-header. Articles with an Expires header will be expired at the date given
-in that header, subject to the constraints that they will be retained at
-least <min> days and no longer than <max> days.
-
-If <min> is set to C<never>, no article matching that line will ever be
-expired. If <default> is set to C<never>, no article matching that line
-without an explicit Expires header will ever be expired. If <max> is
-set to C<never>, Expires headers will be honored no matter how far into
-the future they are.
-
-One should think of the fields as a lower bound, the default, and an upper
-bound. Since most articles do not have an Expires header, the second
-field is the most important and most commonly applied.
-
-Articles that do not match any expiration rule will not be expired, but
-this is considered an error and will result in a warning. There should
-always be a default line (a line with a <pattern> of C<*> and <flag> of
-C<A>, or a line with a <classnum> of C<*>), which can explicitly state
-that articles should never expire by default if that's the desired
-configuration. The default line should generally be the first line of the
-file (except for C</remember/>) so that other expiration rules can
-override it.
-
-It is often useful to honor the Expires header in articles, especially
-those in moderated groups. To do this, set <min> to zero, <default> to
-whatever normal expiration you wish, and <max> to C<never> or some large
-number, like 365 days for a maximum article life of a year.
-
-To ignore any Expires header, set all three fields to the same value.
-
-=head1 EXAMPLES
-
-When I<groupbaseexpiry> is true (the default):
-
- # Keep expired article history for 10 days, matching artcutoff.
- /remember/:10
-
- # Most articles stay for two weeks, ignoring Expires.
- *:A:14:14:14
-
- # Accept Expires headers in moderated groups for up to a year and
- # retain moderated groups for a bit longer.
- *:M:1:30:365
-
- # Keep local groups for a long time and local project groups forever.
- example.*:A:90:90:90
- example.project.*:A:never:never:never
-
-When I<groupbaseexpiry> is false, for class-based expiration:
-
- # Keep expired article history for 10 days, matching artcutoff.
- /remember/:10
-
- # Set a default expiration of seven days.
- *:7:7:7
-
- # Class 0 is retained for two weeks.
- 0:14:14:14
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Converted to
-POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: expire.ctl.pod 7207 2005-04-11 18:18:40Z rra $
-
-=head1 SEE ALSO
-
-expire(8), expireover(8), inn.conf(5), innd(8), news.daily(8),
-storage.conf(5), uwildmat(3)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-expireover - Expire entries from the news overview database
-
-=head1 SYNOPSIS
-
-B<expireover> [B<-ekNpqs>] [B<-f> I<file>] [B<-w> I<offset>]
-[B<-z> I<rmfile>] [B<-Z> I<lowmarkfile>]
-
-=head1 DESCRIPTION
-
-B<expireover> expires old entries from the news overview database. It
-reads in a list of newsgroups (by default from I<pathdb>/active, but a
-different file can be specified with the B<-f> option) and then removes
-from the overview database mentions of any articles that no longer exist
-in the news spool.
-
-If I<groupbaseexpiry> in I<inn.conf> is true, B<expireover> also removes
-old articles from the news spool according to the expiration rules in
-F<expire.ctl>. Otherwise it only removes overview entries for articles
-that have already been removed by some other process, and B<-e>, B<-k>,
-B<-N>, B<-p>, B<-q>, B<-w>, and B<-z> are all ignored.
-
-When I<groupbaseexpiry> is set, the default behavior of B<expireover> is
-to remove the article from the spool once it expires out of all of the
-newsgroups to which it was crossposted. The article is, however, removed
-from the overview database of each newsgroup as soon as it expires out of
-that individual newsgroup. The effect is that an article crossposted to
-several groups will be removed from the overview database from each group
-one-by-one as its age passes the expiration threshold for that group as
-set in F<expire.ctl>, and then when it expires out of the last newsgroup,
-it will be deleted from the news spool.
-
-Articles that are stored in self-expiring storage backends such as CNFS
-are normally treated differently and not expired until they expire out of
-the backend regardless of F<expire.ctl>. See B<-N>, however.
-
-By default, B<expireover> purges all overview information for newsgroups
-that have been removed from the server; this behavior is suppressed if
-B<-f> is given.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-e>
-
-Remove articles from the news spool and all overview databases as soon as
-they expire out of any newsgroup to which they are posted, rather than
-retain them until they expire out of all newsgroups. B<-e> and B<-k>
-cannot be used at the same time. This flag is ignored if
-I<groupbaseexpiry> is false.
-
-=item B<-f> I<file>
-
-Use I<file> as the newsgroup list instead of I<pathdb>/active. I<file>
-can be C<-> to indicate standard input. Using this flag suppresses the
-normal purge of all overview information from newsgroups that have been
-removed from the server.
-
-=item B<-k>
-
-Retain all overview information for an article, as well as the article
-itself, until it expires out of all newsgroups to which it was posted.
-This can cause articles to stick around in a newsgroup for longer than the
-F<expire.ctl> rules indicate, when they're crossposted. B<-e> and B<-k>
-cannot be used at the same time. This flag is ignored if
-I<groupbaseexpiry> is false.
-
-=item B<-N>
-
-Apply F<expire.ctl> rules to expire articles even from storage methods
-that have self-expire functionality. This may remove articles from
-self-expiring storage methods before the articles "naturally" expire.
-This flag is ignored if I<groupbaseexpiry> is false.
-
-=item B<-p>
-
-By default, B<expireover> bases decisions on whether to remove an article
-on the arrival time on the server. This means that articles may be kept a
-little longer than if the decision were based on the article's posting
-date. If this option is given, expiration decisions are based on the
-article posting date instead. This flag is ignored if I<groupbaseexpiry>
-is false.
-
-=item B<-q>
-
-B<expireover> normally prints statistics at the end of the expiration
-process. B<-q> suppresses this report. This flag is ignored if
-I<groupbaseexpiry> is false.
-
-=item B<-s>
-
-B<expireover> normally only checks the existence of articles in the news
-spool if querying the storage method for that article to see if it still
-exists is considered "inexpensive." To always check the existence of all
-articles regardless of how resource-intensive this may be, use the B<-s>
-flag. See storage.conf(5) for more information about this metric.
-
-=item B<-w> I<offset>
-
-"Warps" time so that B<expireover> thinks that it's running at some time
-other than the current time. This is occasionally useful to force groups
-to be expired or not expired without changing F<expire.ctl> for the expire
-run. I<offset> should be a signed floating point number specifying the
-number of days difference from the current time to use as "now." This
-flag is ignored if I<groupbaseexpiry> is false.
-
-=item B<-z> I<rmfile>
-
-Don't remove articles immediately but instead write the path to the
-article or the token of the article to I<rmfile>, which is suitable input
-for fastrm(1). This can substantially speed up deletion of expired
-articles for those storage methods where each article is a single file
-(such as tradspool and timehash). See the description of I<delayrm> in
-news.daily(8) for more details. This flag is ignored if
-I<groupbaseexpiry> is false.
-
-=item B<-Z> I<lowmarkfile>
-
-Write the lowest article numbers for each newsgroup as it's expired to the
-specified file. This file is then suitable for C<ctlinnd lowmark>. See
-ctlinnd(8) for more information.
-
-=back
-
-=head1 EXAMPLES
-
-Normally B<expireover> is invoked from news.daily(8), which handles such
-things as processing the I<rmfile> and I<lowmarkfile> if necessary.
-Sometimes it's convenient to manually expire a particular newsgroup,
-however. This can be done with a command like:
-
- echo example.test | expireover -f - -Z /usr/local/news/tmp/lowmark
- ctlinnd lowmark /usr/local/news/tmp/lowmark
-
-This can be particularly useful if a lot of articles in a particular group
-have expired but the overview information is still present, causing some
-clients to see a lot of "this article may have been cancelled" messages
-when they first enter the newsgroup.
-
-=head1 HISTORY
-
-Written by Rob Robertson <rob@violet.berkeley.edu> and Rich $alz
-<rsalz@uunet.uu.net> (with help from Dave Lawrence <tale@uunet.uu.net>)
-for InterNetNews.
-
-$Id: expireover.pod 5909 2002-12-03 05:17:18Z vinocur $
-
-=head1 SEE ALSO
-
-active(5), ctlinnd(8), expire(8), expire.ctl(5), inn.conf(5),
-news.daily(8).
-
-=cut
+++ /dev/null
-=head1 NNRPD External Authentication Support
-
-This is $Revision: 7141 $ dated $Date: 2005-03-17 03:42:46 -0800 (Thu, 17 Mar 2005) $.
-
-A fundamental part of the readers.conf(5)-based authorization mechanism
-is the interface to external authenticator and resolver programs. This
-interface is documented below.
-
-INN ships with a number of such programs (all written in C, although any
-language can be used). Code for them can be found in F<authprogs/> of
-the source tree; the authenticators are installed to
-I<pathbin>/auth/passwd, and the resolvers are installed to
-I<pathbin>/auth/resolv.
-
-=head1 Reading information from nnrpd
-
-When nnrpd spawns an external auth program, it passes information on
-standard input as a sequence of "key: value" lines. Each line ends with
-CRLF, and a line consisting of only "." indicates the end of the input.
-The order of the fields is not significant. Additional fields not
-mentioned below may be included; this should not be cause for alarm.
-
-(For robustness as well as ease of debugging, it is probably wise to
-accept line endings consisting only of LF, and to treat EOF as
-indicating the end of the input even if "." has not been received.)
-
-Code which reads information in the format discussed below and parses it
-into convenient structures is available authenticators and resolvers
-written in C; see libauth(3) for details. Use of the libauth library
-will make these programs substantially easier to write and more robust.
-
-=head2 For authenticators
-
-When nnrpd calls an authenticator, the lines it passes are
-
- ClientAuthname: user\r\n
- ClientPassword: pass\r\n
-
-where I<user> and I<pass> are the username and password provided by the
-client (e.g. using AUTHINFO). In addition, nnrpd generally also passes
-the fields mentioned as intended for resolvers; it rare instances this
-data may be useful for authenticators.
-
-=head2 For resolvers
-
-When nnrpd calls a resolver, the lines it passes are
-
- ClientHost: hostname\r\n
- ClientIP: IP-address\r\n
- ClientPort: port\r\n
- LocalIP: IP-address\r\n
- LocalPort: port\r\n
- .\r\n
-
-where I<hostname> indicates a string representing the hostname if
-available, I<IP-address> is a numeric IP address (dotted-quad for IPv4,
-equivalent for IPv6 if appropriate), and I<port> is a numeric port
-number. (The I<LocalIP> paramter may be useful for determining which
-interface was used for the incoming connection.)
-
-If information is not available, nnrpd will omit the corresponding
-fields. In particular, this applies to the unusual situation of nnrpd
-not being connected to a socket; TCP-related information is not
-available for standard input.
-
-=head1 Returning information to nnrpd
-
-=head2 Exit status and signals
-
-The external auth program must exit with a status of C<0> to indicate
-success; any other exit status indicates failure. (The non-zero exit
-value will be logged.)
-
-If the program dies due to catching a signal (for example, a
-segmentation fault occurs), this will be logged and treated as a
-failure.
-
-=head2 Returning a username and domain
-
-If the program succeeds, it must return a username string (optionally
-with a domain appended) by writing to standard output. The line it
-should write is exactly:
-
- user:username\r\n
-
-where I<username> is the string that nnrpd should use in matching
-readers.conf access blocks.
-
-There should be no extra spaces in lines sent from the hook to nnrpd;
-C<user:aidan> is read by nnrpd as a different username than C<user:
-aidan>.
-
-=head1 Error messages
-
-As mentioned above, errors can be indicated by a non-zero exit value, or
-termination due to an unhandled signal; both cases are logged by nnrpd.
-However, external auth programs may wish to log error messages
-separately.
-
-Although nnrpd will syslog() anything an external auth program writes to
-standard error, it is generally better to use the F<messages.h>
-functions, such as warn() and die().
-
-Please use the ckpasswd.c program as an example for any authenticators
-you write, and ident.c as an example for any resolvers.
-
-=head1 HISTORY
-
-Written by Aidan Cully for InterNetNews. This documentation rewritten
-in POD by Jeffrey M. Vinocur <jeff@litech.org>.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-fastrm - Quickly remove a list of files
-
-=head1 SYNOPSIS
-
-B<fastrm> [B<-de>] [B<-u>|B<-u>I<N>] [B<-s>|B<-s>I<M>] [B<-c>|B<-c>I<I>]
-I<base-directory>
-
-=head1 DESCRIPTION
-
-B<fastrm> reads a list of either file names or storage API tokens, one per
-line, from its standard input and removes them. Storage API tokens are
-removed via the SMcancel() interface. B<fastrm> does not delete files
-safely or with an eye to security, but rather cuts every corner it can to
-delete files as fast as it can. It should therefore never be run on
-publically writable directories, or in any other environment where a
-hostile party may control the directory structure in which it is working.
-
-If a file name is not an absolute path name, it is considered to be
-relative to I<base-directory> as given on the command line. The
-I<base-directory> parameter must be a simple absolute pathname (it must
-not contain multiple consecutive slashes or references to the special
-directories C<.> or C<..>).
-
-B<fastrm> is designed to be faster than the typical C<| xargs rm> pipeline
-when given a sorted list of file names as input. For example, B<fastrm>
-will usually chdir(2) into a directory before removing files from it,
-meaning that if its input is sorted, most names passed to unlink(2) will
-be simple names. This can substantially reduce the operating system
-overhead from directory lookups.
-
-B<fastrm> assumes that its input is valid and that it is safe to call
-unlink(2) on every file name it is given. As a safety measure, however,
-B<fastrm> when running as root will check with stat(2) that a file name
-doesn't specify a directory before removing it. (In some operating
-systems, root is allowed to unlink directories, even directories which
-aren't empty, which can cause file system corruption.)
-
-The input to B<fastrm> should always be sorted -- or even better be in the
-order file names are output by find(1) -- if speed is an issue and the
-input isn't solely storage API tokens. (It deals fine with unsorted
-input, but is unlikely to be any faster in that case than a simple C<xargs
-rm> command.) Sorting may even slightly speed up the removal of storage
-API tokens due to caching effects, since sorting will tend to keep all of
-the tokens from a particular storage method together.
-
-Various additional optimizations for removing files can be turned on
-and/or tuned with options (see below). Which options will be most
-effective depends heavily on the underlying structure of the file system,
-the way in which directories are stored and searched, and similar, often
-underdocumented, operating system implementation details. The more
-sophisticated the underlying operating system and file system, the more
-likely that it will already perform the equivalent of these optimizations
-internally.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-d>
-
-Don't remove any files. Instead, print a list of the files that would be
-removed to standard output. Each line contains either the current
-directory of B<fastrm> at the time it would do the unlink and the relative
-path name it would pass to unlink(2) as two fields separated by whitespace
-and a C</>, the absolute path name (as a single field) that would be
-passed to unlink(2), or the string C<Token> and the storage API token that
-would be removed.
-
-=item B<-e>
-
-Treat an empty input file as an error. This is most useful when B<fastrm>
-is last in a pipeline after a preceding sort(1) command, ensuring that
-B<fastrm> will fail if the sort fails.
-
-=item B<-c>I<I>
-
-Controls when B<fastrm> calls chdir(2). If the number of files to be
-unlinked from a given directory is at least I<I>, then B<fastrm> will
-change to that directory before unlinking those files. Otherwise, it will
-use either the absolute path names or a path name relative to the current
-directory (whichever is likely more efficient). The I<I> parameter is
-optional; if just B<-c> is given, B<-c1> is assumed, which will cause
-B<fastrm> to always chdir before calling unlink(2). The default is
-B<-c3>. Use B<-c0> to prevent B<fastrm> from ever using chdir(2).
-
-=item B<-s>I<M>
-
-When B<-s> is given and the number of files to remove in a directory is
-greater than I<M>, rather than remove files in the order given, B<fastrm>
-will open the directory and read it, unlinking files in the order that
-they appear in the directory. On systems with a per-process directory
-cache or that use a linear search to find files in a directory, this
-should make directory lookups faster. The I<M> parameter is optional; if
-just B<-s> is given, B<-s5> is assumed.
-
-When this option is in effect, B<fastrm> won't attempt to remove files
-that it doesn't see in the directory, possibly significantly speeding it
-up if most of the files to be removed have already been deleted. However,
-using this option requires B<fastrm> to do more internal work and it also
-assumes that the order of directory listings is stable in the presence of
-calls to unlink(2) between calls to readdir(3). This may be a dangerous
-assumption with some sophisticated file systems (and in general this
-option is only useful with file systems that use unindexed linear searches
-to find files in directories or when most of the files to be removed have
-already been deleted).
-
-This optimization is off by default.
-
-=item B<-u>I<N>
-
-Specifying this option promises that there are no symbolic links in the
-directory tree from which files are being removed. This allows B<fastrm>
-to make an additional optimization to its calls to chdir(2), constructing
-a relative path using C<../..> and the like to pass to chdir(2) rather
-than always using absolute paths. Since this reduces the number of
-directory lookups needed with deeply nested directory structures (such as
-that typically created by traditional news spool storage), it can be a
-significant optimization, but it breaks horribly in the presence of
-symbolic links to directories.
-
-When B<-u> is given, B<fastrm> will use at most I<N> levels of C<..>
-segments to construct paths. I<N> is optional; if just B<-u> is given,
-B<-u1> is assumed.
-
-This optimization is off by default.
-
-=back
-
-B<fastrm> also accepts B<-a> and B<-r> options, which do nothing at all
-except allow you to say C<fastrm -usa>, C<fastrm -ussr>, or C<fastrm
--user>. These happen to often be convenient sets of options to use.
-
-=head1 EXIT STATUS
-
-B<fastrm> exits with a status of zero if there were no problems, and an
-exit status of 1 if something went wrong. Attempting to remove a file
-that does not exist is not considered a problem.
-
-=head1 EXAMPLES
-
-B<fastrm> is typically invoked by INN via expirerm(8) using a command
-like:
-
- fastrm -e /usr/local/news/spool/articles < expire.list
-
-To enable all optimizations and see the affect on the order of removal
-caused by B<-s>, use:
-
- fastrm -d -s -e -u ~news/spool/articles < expire.list
-
-If your file system has indexed directory lookups, but you have a deeply
-nested directory structure, you may want to use a set of flags like:
-
- fastrm -e -u3 ~news/spool/articles < expire.list
-
-to strongly prefer relative paths but not to use readdir(2) to order the
-calls to unlink(2).
-
-You may want to edit expirerm(8) to change the flags passed to B<fastrm>.
-
-=head1 WARNINGS
-
-B<fastrm> cuts corners and does not worry about security, so it does not
-use chdir(2) safely and could be tricked into removing files other than
-those that were intended if run on a specially constructed file tree or a
-file tree that is being modified while it is running. It should therefore
-never be used with world-writable directories or any other directory that
-might be controlled or modified by an attacker.
-
-=head1 NOTES
-
-B<fastrm> defers opening the storage subsystem or attempting to parse any
-INN configuration files until it encounters a token in the list of files
-to remove. It's therefore possible to use B<fastrm> outside of INN as a
-general fast file removal program.
-
-=head1 HISTORY
-
-B<fastrm> was originally written by kre@munnari.oz.au. This manual page
-rewritten in POD by Russ Allbery <rra@stanford.edu> for InterNetNews.
-
-$Id: fastrm.pod 7422 2005-10-09 04:46:53Z eagle $
-
-=head1 SEE ALSO
-
-expirerm(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-grephistory - Query the INN history database
-
-=head1 SYNOPSIS
-
-B<grephistory> [B<-eilnqsv>] [B<-f> I<db>] [I<message-id>]
-
-=head1 DESCRIPTION
-
-B<grephistory> queries the INN history database for information about the
-specified message ID. If no flags are given, the program prints the
-storage API token of the corresponding article, or C</dev/null> if the
-article is listed in the history database but not stored on the server.
-If the message ID cannot be found in the database, B<grephistory> will
-print C<grephistory: not found> and exit with a non-zero status.
-
-Be sure to escape any special characters in the message ID from the shell.
-Single quotes are recommended for this purpose since many message IDs
-contain dollar signs.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-e>
-
-Only print the storage token if the article is stored on the system. (In
-other words, suppress the C</dev/null> or C<not found> output for missing
-or remembered articles.)
-
-=item B<-f> I<db>
-
-Query the history database I<db> rather than the default history database.
-
-=item B<-i>
-
-Rather than expecting a message ID on the command line, B<grephistory>
-will read a list of message IDs on standard input, one per line. Leading
-and trailing whitespace is ignored, as are any malformed lines. It will
-print out standard output those message IDs which are not found in the
-history database. This is used when processing C<ihave> control messages.
-
-=item B<-l>
-
-Display the entire line from the history database, rather than just the
-storage API token.
-
-=item B<-n>
-
-If the message ID is present in the history database but has no storage
-API token, print C</dev/null> and exit successfully. This can happen if
-an article has been cancelled or expired, but history information has
-still been retained. This is the default behavior.
-
-=item B<-q>
-
-Don't print any message, but still exit with the appropriate status.
-
-=item B<-s>
-
-Rather than expecting a message ID on the command line, B<grephistory>
-will read a list of message IDs on standard input, one per line. Leading
-and trailing whitespace is ignored, as are any malformed lines. It will
-print on standard output the storage API tokens for any articles that are
-still available, one per line. This flag is used when processing
-C<sendme> control messages.
-
-=item B<-v>
-
-Print out the hash of the message ID for diagnostic purposes, as well as
-any other requested information. This flag is not useful with B<-s>.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: grephistory.pod 7045 2004-12-19 19:37:45Z rra $
-
-=head1 SEE ALSO
-
-history(5), inn.conf(5)
-
-=cut
+++ /dev/null
-=head1 Hacking INN
-
-This file is for people who are interested in making modifications to INN.
-Normal users can safely skip reading it. It is intended primarily as a
-guide, resource, and accumulation of tips for maintainers and
-contributors, and secondarily as documentation of some of INN's internals.
-
-This is $Revision: 7518 $ dated $Date: 2006-04-14 19:52:06 -0700 (Fri, 14 Apr 2006) $.
-
-First of all, if you plan on working on INN source, please start from the
-current development tree. There may be significant changes from the
-previous full release, so starting from development sources will make it
-considerably easier to integrate your work. You can get nightly snapshots
-of the current development source from ftp.isc.org in /isc/inn/snapshots
-(the snapshots named inn-CURRENT-*.tar.gz), or you can get the current CVS
-tree by using CVSup (see L<"Using CVSup">).
-
-=head1 Configuring and Portability
-
-All INN code should be written expecting ANSI C and POSIX. There is no
-need to attempt to support pre-ANSI compilers, and ANSI-only features such
-as <stdarg.h>, string concatenation, #elif, and token pasting may be used
-freely. So far as possible, INN is written to attempt to be portable to
-any system new enough that someone is likely to want to run a news server
-on it, but whenever possible this portability should be provided by
-checking for standard behavior in configure and supplying replacements for
-standard functions that are missing.
-
-When there is a conflict between ANSI C and C99, INN code should be
-written expecting C99 and autoconf used to patch up the differences.
-
-Try to avoid using #ifdef and the like in the middle of code as much as
-possible. Instead, try to isolate the necessary portability bits and
-include them in libinn or at least in conditional macros separate from the
-code. Trying to read code littered with conditional compilation
-directives is much more difficult.
-
-The shell script F<configure> at the top level of the source tree is
-generated by autoconf from F<configure.in>, and F<include/config.h.in> is
-generated by autoheader from F<configure.in> and F<include/acconfig.h>.
-At configure time, configure generates F<include/config.h> and several
-other files based on options it was given and what it discovers about the
-target system.
-
-All modifications to configure should instead be made to F<configure.in>.
-Similarly, modifications to F<include/config.h.in> should instead be made
-to F<include/acconfig.h>. The autoconf manual (available using info
-autoconf if you have autoconf and the GNU info utilities installed on your
-system) is a valuable reference when making any modifications.
-
-To regenerate configure, just run C<autoconf>. To regenerate
-F<include/config.h.in>, run:
-
- autoheader -l include
-
-to tell it where to find acconfig.h. Please don't include patches to
-either F<configure> or F<include/config.h.in> when sending patches to INN;
-instead, note in your patch that those files must be regenerated.
-
-The generated files are checked into the CVS repository so that people
-working on INN don't have to have autoconf on their system, and to make
-packaging easier.
-
-At the time of this writing, autoconf 2.13 is required.
-
-The supporting files for autoconf are in the F<support> subdirectory,
-including the files F<config.guess> and F<config.sub> to determine the
-system name and and F<ltmain.sh> for libtool support. The latter file
-comes from the libtool distribution; the canonical version of the former
-two are available from ftp.gnu.org in /gnu/config. In addition,
-F<m4/libtool.m4> is just a copy of F<libtool.m4> from the libtool
-distribution. (Using libtool without using automake requires a few odd
-hacks.) These files used to be on a separate vendor branch so that we
-could make local modifications, but local modifications have not been
-necessary for some time. Now, new versions can just be checked in like
-any other file modifications.
-
-INN should not compile with libtool by default, only when requested, since
-otherwise normal compilations are quite slow. (Using libtool is not
-without some cost.) Basic compilation with libtool works fine as of this
-writing, with both static and shared compiles, but the dependencies aren't
-quite right for make -j using libtool.
-
-=head1 Documentation
-
-INN's documentation is currently somewhat in a state of flux. The vast
-majority is still in the form of man pages written directly in nroff.
-Some parts of the documentation have been rewritten in POD; that
-documentation can be found in F<doc/pod>. The canonical source for
-F<README>, F<INSTALL>, F<NEWS>, F<doc/hook-perl>, F<doc/hook-python>, and
-this file are also in POD.
-
-If you're modifying some part of INN's documentation and see that it has a
-POD version in F<doc/pod>, it's preferred if you can make the
-modifications to the POD source and then regenerate the derived files.
-For a quick introduction to POD, see the perlpod(1) man page on your
-system (it should be installed if you have Perl installed).
-
-When writing new documentation, write in whatever format you care to; if
-necessary, we can always convert it to POD or whatever else we want to
-use. Having the documentation exist in I<some> form is more important
-than what language you write it in. If you really don't have any
-particular preference, there's a slight preference currently for POD.
-
-If you use POD or regenerate POD documentation, please install something
-close to the latest versions of the POD processing utilities to avoid
-changes to the documentation depending on who generated it last. You can
-find the latest version on CPAN (ftp.perl.org or another mirror) in
-F<modules/by-module/Pod>. You'll need PodParser (for versions of Perl
-before 5.6.1; 5.6.1 and later come with a recent enough version) and the
-latest version of podlators. For versions of Perl earlier than 5.005,
-you'll also need File::Spec in F<modules/by-module/File>.
-
-podlators 1.25 or later will build INN's documentation without significant
-changes from the versions that are checked into the repository.
-
-There are Makefile rules in F<doc/pod/Makefile> to build all of the
-documentation whose master form is POD; if you add additional
-documentation, please add a rule there as well. Documentation should be
-generated by cd'ing to F<doc/pod> and typing C<make file> where C<file> is
-the relative path to the documentation file. This will get all of the
-various flags right for pod2text or pod2man.
-
-=head1 Error Handling
-
-INN has a set of generic error handling routines that should be used as
-much as possible so that the same syntax can be used for reporting errors
-everywhere in INN. The four basic functions are warn, syswarn, die, and
-sysdie; warn prints or logs a warning, and die does the same and then
-exits the current program. The sys* versions add a colon, a space, and
-the value of strerror(errno) to the end of the message, and should be used
-to report failing system calls.
-
-All of the actual error reporting is done via error handlers, and a
-program can register its own handlers in addition to or instead of the
-default one. The default error handler (error_log_stderr) prints to
-stderr, prepending the value of error_program_name if it's set to
-something other than NULL. Three other error handlers are available,
-error_log_syslog_crit, error_log_syslog_err, and error_log_syslog_warning,
-which log the message to syslog at LOG_CRIT, LOG_ERR, or LOG_WARNING
-priority, respectively.
-
-There is a different set of error handlers for warn/syswarn and
-die/sysdie. To set them, make calls like:
-
- warn_set_handlers(2, error_log_stderr, error_log_syslog_warning);
- die_set_handlers(2, error_log_stderr, error_log_syslog_err);
-
-The first argument is the number of handlers, and the remaining arguments
-are pointers to functions taking an int (the length of the formatted
-message), a const char * (the format), a va_list (the arguments), and an
-int that's 0 if warn or die was called and equal to the value of errno if
-syswarn or sysdie was called. The length of the formatted message is
-obtained by calling vsnprintf with the provided format and arguments, and
-therefore is reliable to use as the size of a buffer to malloc to hold the
-result of formatting the message provided that vsnprintf is used to format
-it (warning: the system vsprintf may produce more output under some
-circumstances, so always use vsnprintf).
-
-The error handler can do anything it wishes; each error handler is called
-in the sequence given. Error handlers shouldn't call warn or die unless
-great caution is taken to prevent infinite recursion. Also be aware that
-sysdie is called if malloc fails in xmalloc, so if the error handler needs
-to allocate memory, it must not use xmalloc or a related function to do
-so and it shouldn't call die to report failure. The default syslog
-handlers report memory allocation failure to stderr and exit.
-
-Finally, die and sysdie support an additional handler that's called
-immediate before exiting, takes no arguments, and returns an int which is
-used as the argument for exit. It can do any necessary global cleanup,
-call abort instead to generate a core dump or the like.
-
-The advantage of using this system everywhere in INN is that library code
-can use warn and die to report errors and each calling program can set up
-the error handlers as appropriate to make sure the errors go to the right
-place. The default handler is fine for interactive programs; for programs
-that run from interactive scripts, adding something like:
-
- error_program_name = "program";
-
-to the beginning of main (where program is the name of the program) will
-make it easier to figure out which program the script calls is failing.
-For programs that may also be called non-interactively, like inndstart,
-one may want to set up handlers like:
-
- warn_set_handlers(2, error_log_stderr, error_log_syslog_warning);
- die_set_handlers(2, error_log_stderr, error_log_syslog_err);
-
-Finally, for daemons and other non-interactive programs, one may want to
-do:
-
- warn_set_handlers(1, error_log_syslog_warning);
- die_set_handlers(1, error_log_syslog_err);
-
-to report errors only via syslog. (Note that if you use syslog error
-handlers, the program should call openlog first thing to make sure they
-are logged with the right facility.)
-
-For historical reasons, error messages that are fatal to the news
-subsystem are logged at the LOG_CRIT priority, and therefore die in innd
-should use error_log_syslog_crit.
-
-=head1 Test Suite
-
-The test suite for INN is located in the tests directory and is just
-getting started. The test suite consists of a set of programs listed in
-F<tests/TESTS> and the scaffolding in the F<runtests> program.
-
-Adding new tests is very straightforward and very flexible. Just write a
-program that tests some part of INN, put it in a directory under tests
-named after the part of INN it's testing (all the tests so far are in lib
-because they're testing libinn routines), and have it output first a line
-containing the count of test cases in that file, and then for each test a
-line saying "ok n" or "not ok n" where n is the test case number. (If a
-test is skipped for some reason, such as a test of an optional feature
-that wasn't compiled into INN, the test program should output
-S<"ok n # skip">.) Add any rules necessary to build the test to
-tests/Makefile (note that for simplicity it doesn't recurse into
-subdirectories) and make sure it creates an executable ending in F<.t>.
-Then add the name of the test to tests/TESTS, without the .t ending.
-
-One naming convention: to distinguish more easily between e.g.
-lib/error.c (the implementation) and tests/lib/error-t.c (the test suite),
-we add -t to the end of the test file names. So tests/lib/error-t.c is
-the source that compiles into an executable tests/lib/error.t which is run
-by putting a line in tests/TESTS of just "lib/error".
-
-Note that tests don't have to be written in C; in fact, lib/xmalloc.t is
-just a shell script (that calls a supporting C program). Tests can be
-written in shell or Perl (but other languages should be avoided because
-someone who wants to run the test suite may not have it) and just have to
-follow the above output conventions.
-
-Additions to the test suite, no matter how simple, are very welcome.
-
-=head1 Makefiles
-
-All INN makefiles include Makefile.global at the top level, and only that
-makefile is a configure substitution target. This has the disadvantage
-that configure's normal support for building in a tree outside of the
-source tree doesn't work, but it has the significant advantage of making
-configure run much faster and allowing one to run make in any subdirectory
-and pick up all the definitions and settings from the top level
-configuration.
-
-All INN makefiles should also set $(top) to be the path to the top of the
-build directory (usually relative). This path is used to find various
-programs like fixscript and libtool so that the same macros (set in
-Makefile.global) can be used all over INN.
-
-The format of INN's makefiles is mostly standardized; the best examples of
-the format are probably F<frontends/Makefile> and F<backends/Makefile>, at
-least for directories with lots of separate programs. The ALL variable
-holds all the files that should be generated, EXTRA those additional files
-that were generated by configure, and SOURCES the C source files for
-generating tag information.
-
-There are a set of standard installation commands defined in make
-variables by Makefile.global, and these should be used for all file
-installations. See the comment blocks in Makefile.global.in for
-information on what commands are available and when they should be used.
-There are also variables set for each of the installation directories that
-INN uses, for use in building the list of installed paths to files.
-
-Each subdirectory makefile should have the targets all (the default),
-clean, clobber, install, tags, and profiled. The tags target generates vi
-tags files, and the profiled target generates a profiling version of the
-programs (although this hasn't been tested much recently). These rules
-should be present and empty in those directories where they don't apply.
-
-Be sure to test compiling with both static and dynamic libraries and make
-sure that all the libtool support works correctly. All linking steps, and
-the compile steps for all library source, should be done through
-$(LIBTOOL) (which will be set to empty in Makefile.global if libtool
-support isn't desired).
-
-=head1 Scripts
-
-INN comes with and installs a large number of different scripts, both
-Bourne shell and Perl, and also comes with support for Tcl scripts
-(although it doesn't come with any). Shell variables containing both
-configure-time information and configuration information from inn.conf are
-set by the innshellvars support libraries, so the only system-specific
-configuration that should have to be done is fixing the right path to the
-interpretor and adding a line to load the appropriate innshellvars.
-
-F<support/fixscript>, built by configure, does this. It takes a .in file
-and generates the final script (removing the .in) by fixing the path to
-the interpretor on the first line and replacing the second line, whatever
-it is, with code to load the innshellvars appropriate for that
-interpretor. (If invoked with -i, it just fixes the interpretor path.)
-
-Scripts should use innshellvars (via fixscript) to get the right path and
-the right variables whenever possible, rather than having configure
-substitute values in them. Any values needed at run-time should instead
-be available from all of the different innshellvars.
-
-See the existing scripts for examples of how this is done.
-
-=head1 Include Files
-
-Include files relevant to all of INN, or relevant to the two libraries
-built as part of INN (the utility libinn library and the libstorage
-library that contains all storage and overview functions) are found in the
-include directory; other include files relevant only to a portion of INN
-are found in the relevant directory.
-
-Practically all INN source files will start with:
-
- #include "config.h"
- #include "clibrary.h"
-
-The first picks up all defines generated by autoconf and is necessary for
-types that may not be present on all systems (uid_t, pid_t, size_t,
-int32_t, and the like). It therefore should be included before any other
-headers that use those types, as well as to get general configuration
-information.
-
-The second is portably equivalent to:
-
- #include <sys/types.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <string.h>
- #include <unistd.h>
-
-except that it doesn't include headers that are missing on a given system,
-replaces functions not found on the system with the INN equivalents,
-provides macros that INN assumes are available but which weren't found,
-and defines some additional portability things. Even if this is more
-headers than the source file actually needs, it's generally better to just
-include F<clibrary.h> rather than trying to duplicate the autoconf-driven
-hackery that it does to do things portably. The primary exception is for
-source files in lib that only define a single function and are used for
-portability; those may want to include only F<config.h> so that they can
-be easily used in other projects that use autoconf. F<config.h> is a
-fairly standard header name for this purpose.
-
-F<clibrary.h> does also include F<config.h>, but it's somewhat poor form
-to rely on this; it's better to explicitly list the header dependencies
-for the benefit of someone else reading the code.
-
-There are portable wrappers around several header files that have known
-portability traps or that need some fixing up on some platforms. Look in
-include/portable and familiarize yourself with them and use them where
-appropriate.
-
-Another frequently included header file is F<libinn.h>, which among other
-things defines xmalloc(), xrealloc(), xstrdup(), and xcalloc(), which are
-checked versions of the standard memory allocation routines that terminate
-the program if the memory allocation fails. These should generally always
-be used instead of the regular C versions. F<libinn.h> also provides
-various other utility functions that are frequently used.
-
-F<paths.h> includes a wide variety of paths determined at configure time,
-both default paths to various parts of INN and paths to programs. Don't
-just use the default paths, though, if they're also configurable in
-F<inn.conf>; instead, call ReadInnConf() and use the global innconf
-structure.
-
-Other files in include are interfaces to particular bits of INN library
-functionality or are used for other purposes; see the comments in each
-file.
-
-Eventually, the header files will be separated into installed header files
-and uninstalled header files; the latter are those headers that are used
-only for compiling INN and aren't useful for users of INN's libraries
-(such as clibrary.h). All of the installed headers will live in
-include/inn and be installed in a subdirectory named inn in the configured
-include directory. This conversion is still in progress.
-
-When writing header files, remember that C reserves all identifiers
-beginning with two underscores and all identifiers beginning with an
-underscore and a capital letter for the use of the implementation; don't
-use any identifiers with names like that. Additionally, any identifier
-beginning with an underscore and a lower-case letter is reserved in file
-scope, which means that such identifiers can only be used by INN for the
-name of structure members or function arguments in function prototypes.
-
-Try to pay attention to the impact of a header file on the program
-namespace, particularly for installed header files in include/inn. All
-symbols defined by a header file should ideally begin with INN_, inn_, or
-some other unique prefix indicating the subsystem that symbol is part of,
-to avoid accidental conflicts with symbols defined by the program that
-uses that header file.
-
-=head1 Coding Style
-
-INN has quite a variety of coding styles intermixed. As with all
-programs, it's preferrable when making minor modifications to keep the
-coding style of the code you're modifying. In INN, that will vary by
-file. (Over time we're trying to standardize on one coding style, so
-changing the region you worked on to fit the general coding style is also
-acceptable).
-
-If you're writing a substantial new piece of code, the prevailing
-"standard" INN coding style appears to be something like the following:
-
-=over 3
-
-=item *
-
-Write in regular ANSI C whenever possible. Use the normal ANSI and POSIX
-constructs and use autoconf or portability wrappers to fix things up
-beforehand so that the code itself can read like regular ANSI or POSIX
-code. Code should be written so that it works as expected on a modern
-platform and is fixed up with portability tricks for older platforms, not
-the other way around. You may assume an ANSI C compiler.
-
-Try to use const wherever appropriate. Don't use register; modern
-compilers will do as good of a job as you will in choosing what to put
-into a register. Don't bother with restrict (at least yet).
-
-=item *
-
-Use string handling functions that take counts for the size of the buffer
-whenever possible. This means using snprintf in preference to sprintf and
-using strlcpy and strlcat in preference to strcpy and strcat. Also, use
-strlcpy and strlcat instead of strncpy and strncat unless the behavior of
-the latter is specifically required, as it is much easier to audit uses of
-the former than the latter. (strlcpy is like strncpy except that it
-always nul-terminates and doesn't fill the rest of the buffer with nuls,
-making it more efficient. strlcat is like strncat except that it always
-nul-terminates and it takes the total size of the buffer as its third
-argument rather than just the amount of space left.) All of these
-functions are guaranteed to be available; there are replacements in lib
-for systems that don't have them.
-
-=item *
-
-Avoid #ifdef and friends whenever possible. Particularly avoid using them
-in the middle of code blocks. Try to hide all portability preprocessor
-magic in header files or in portability code in lib. When something just
-has to be done two completely different ways depending on the platform or
-compile options or the like, try to abstract that functionality out into a
-generic function and provide two separate implementations using #ifdef;
-then the main code can just call that function.
-
-If you do have to use preprocessor defines, note that if you always define
-them to either 0 or 1 (never use #define without a second argument), you
-can use the preprocessor define in a regular if statement rather than
-using #if or #ifdef. Make use of this instead of #ifdef when possible,
-since that way the compiler will still syntax-check the other branch for
-you and it makes it far easier to convert the code to use a run-time check
-if necessary. (Unfortunately, this trick can't be used if one branch may
-call functions unavailable on a particular platform.)
-
-=item *
-
-Avoid uses of fixed-width buffers except in performance-critical code, as
-it's harder to be sure that such code is correct and it tends to be less
-flexible later on. If you need a reusable, resizable memory buffer, one
-is provided in lib/buffer.c.
-
-=item *
-
-Avoid uses of static variables whenever possible, particularly in
-libraries, because it interferes with making the code re-entrant down the
-road and makes it harder to follow what's going on. Similarly, avoid
-using global variables whenever possible, and if they are required, try to
-wrap them into structures that could later be changed into arguments to
-the affected functions.
-
-=item *
-
-Roughly BSD style but with four-space indents. This means no space before
-the parens around function arguments, open brace on the same line as
-if/while/for, and close and open brace on the same line as else).
-
-=item *
-
-Introductory comments for functions or files are generally written as:
-
- /*
- ** Introductory comment.
- */
-
-Other multiline comments in the source are generally written as:
-
- /* This is a
- multiline comment. */
-
-Comments before functions saying what they do are nice to have. In
-general, the RCS/CVS Id tag is on the first line of each source file since
-it's useful to know when a file was last modified.
-
-=item *
-
-Checks for NULL pointers are preferrably written out explicitly; in other
-words, use:
-
- if (p != NULL)
-
-rather than:
-
- if (p)
-
-to make it clearer what the code is assuming.
-
-=item *
-
-It's better to always put the body of an if statement on a separate line,
-even if it's only a single line. In other words, write:
-
- if (p != NULL)
- return p;
-
-and not:
-
- if (p != NULL) return p;
-
-This is in part for a practical reason: some code coverage analysis tools
-like purecov will count the second example above as a single line and
-won't notice if the condition always evaluates the same way.
-
-=item *
-
-Plain structs make perfectly reasonable abstract data types; it's not
-necessary to typedef the struct to something else. Structs are actually
-very useful for opaque data structures, since you can predeclare them and
-then manipulate pointers to them without ever having to know what the
-contents look like. Please try to avoid typedefs except for function
-pointers or other extremely confusing data types, or for data types where
-we really gain some significant data abstraction from hiding the
-underlying data type. Also avoid using the _t suffix for any type; all
-types ending in _t are reserved by POSIX. For typedefs of function
-pointer types, a suffix of _func usually works.
-
-This style point is currently widely violated inside of INN itself; INN
-originally made extensive use of typedefs.
-
-=item *
-
-When noting something that should be improved later, add a comment
-containing "FIXME:" so that one can easily grep for such comments.
-
-=back
-
-INN's indentation style roughly corresponds to that produced by GNU indent
-2.2.6 with the following options:
-
- -bad -bap -nsob -fca -lc78 -cd41 -cp1 -br -ce -cdw -cli0 -ss -npcs
- -ncs -di1 -nbc -psl -brs -i4 -ci4 -lp -ts8 -nut -ip5 -lps -l78 -bbo
- -hnl
-
-Unfortunately, indent currently doesn't get everything right (it has
-problems with spacing around struct pointer arguments in functions, wants
-to put in a space between a dereference of a function pointer and the
-arguments to the called function, misidentifies some macro calls as being
-type declarations, and fouls up long but simple case statements). It
-would be excellent if someday we could just run all of INN's code through
-indent routinely to enforce a consistant coding style, but indent isn't
-quite ready for that.
-
-For users of emacs cc-mode, use the "bsd" style but with:
-
- (setq c-basic-offset 4)
-
-Finally, if possible, please don't use tabs in source files, since they
-can expand differently in different environments. In particular, please
-try not to use the mix of tabs and spaces that is the default in emacs.
-If you use emacs to edit INN code, you may want to put:
-
- ; Use only spaces when indenting or centering, no tabs.
- (setq-default indent-tabs-mode nil)
-
-in your ~/.emacs file.
-
-Note that this is only a rough guideline and the maintainers aren't style
-nazis; we're more interested in your code contribution than in how you
-write it.
-
-=head1 Using CVSup
-
-If you want to get updated INN source more easily or more quickly than by
-downloading nightly snapshots, or if you want to see the full CVS history,
-you may want to use CVSup to download the source. CVSup is a client and
-server designed for replicating CVS repositories between sites.
-
-Unfortunately, CVSup is written in Modula-3, so getting a working binary
-can be somewhat difficult. Binaries are available in the *BSD ports
-collection or (for a wide variety of different platforms) available from
-<ftp://ftp.freebsd.org/pub/FreeBSD/CVSup/binaries/> and its mirrors.
-Alternately, you can get a compiler from <http://m3.polymtl.ca/m3/> (this
-is more actively maintained than the DEC Modula-3 compiler) and the source
-from <ftp://ftp.freebsd.org/pub/FreeBSD/CVSup/>.
-
-After you have the CVSup client, you need to have space to download the
-INN repository and space for CVSup to store its data files. You also need
-to write a configuration file (a supfile) for CVSup. The following
-supfile will download the latest versions from the mainline source:
-
- *default host=inn-cvs.isc.org
- *default base=<data-location>
- *default prefix=<download-location>
- *default release=cvs
- *default tag=.
- *default delete use-rel-suffix
- inn
-
-where <data-location> should be a directory where CVSup can put its data
-files and <download-location> is where the downloaded source will go (it
-will be put into a subdirectory named inn). If you want to pull down the
-entire CVS repository instead (warning: this is much larger than just the
-latest versions of the source), delete the C<*default tag=.> line. The
-best way to download the CVS repository is to download it into a portion
-of a locally-created CVS repository, so that then you can perform standard
-CVS operations (like cvs log) against the downloaded repository. Creating
-your own local CVS repository is outside the scope of this document.
-
-Note that only multiplexed mode is supported (this mode should be the
-default).
-
-For more general information on using CVSup, see the FreeBSD page on it at
-<http://www.freebsd.org/handbook/mirrors-cvsup.html>.
-
-=head1 Making a Release
-
-This is a checklist that INN maintainers should go through when preparing
-a new release of INN.
-
-=over 4
-
-=item 1.
-
-If making a major release, branch the source tree and create a new STABLE
-branch tag. This branch will be used for minor releases based on that
-major release and can be done a little while before the .0 release of that
-major release. At the same time as the branch is cut, tag the trunk with
-a STABLE-<version>-branch marker tag so that it's easy to refer to the
-trunk at the time of the branch.
-
-=item 2.
-
-Update doc/pod/news.pod and regenerate NEWS. Be more detailed for a minor
-release than for a major release. For a major release, also add
-information on how to upgrade from the last major release, including
-anything special to be aware of. (Minor releases shouldn't require any
-special care when upgrading.)
-
-=item 3.
-
-Make sure that support/config.sub and support/config.guess are the latest
-versions (from <ftp://ftp.gnu.org/gnu/config/>). See the instructions in
-L<"Configuring and Portability"> for details on how to update these files.
-
-=item 4.
-
-Make sure that samples/control.ctl is in sync with the master version at
-<ftp://ftp.isc.org/pub/usenet/CONFIG/control.ctl>.
-
-=item 5.
-
-Check out a copy of the release branch. It's currently necessary to run
-configure to generate Makefile.global. Then run C<make check-manifest>.
-The only differences should be files that are generated by configure; if
-there are any other differences, fix the MANIFEST.
-
-=item 6.
-
-Run C<make release>. Note that you need to have a copy of svn2cl from
-<http://ch.tudelft.nl/~arthur/svn2cl/> to do this; at least version 0.7
-is required. Start the ChangeLog at the time of the previous release.
-(Eventually, the script will be smart enough to do this for you.)
-
-=item 7.
-
-Make the resulting tar file available for testing in a non-listable
-directory on ftp.isc.org and announce its availability on inn-workers.
-Install it on at least one system and make sure that system runs fine for
-at least a few days. This is also a good time to send out a draft of the
-release announcement to inn-workers for proof-reading.
-
-=item 8.
-
-Generate a diff between this release and the previous release if feasible
-(always for minor releases, possibly not a good idea due to the length of
-the diff for major releases).
-
-=item 9.
-
-Move the release into the public area of the ftp site and update the
-inn.tar.gz link. Make an MD5 checksum of the release tarball and put it
-on the ftp site as well, and update the inn.tar.gz.md5 link. Put the diff
-up on the ftp site as well. Contact the ISC folks to get the release
-PGP-signed. Possibly move older releases off into the OLD directory.
-
-=item 10.
-
-Announce the new release on inn-announce and in news.software.nntp.
-
-=item 11.
-
-Tag the checked-out tree that was used for generating the release with a
-release tag (INN-<version>).
-
-=item 12.
-
-Bump the revision number in Makefile.global.in.
-
-=back
-
-=head1 References
-
-Some additional references that may be hard to find and may be of use to
-people working on INN:
-
-=over 4
-
-=item <http://www.eyrie.org/~eagle/nntp/>
-
-The home page for the IETF NNTP standardization effort, including links
-to the IETF NNTP working group archives and copies of the latest drafts
-of the new NNTP standard. The old archived mailing list traffic contains
-a lot of interesting discussion of why NNTP is the way it is.
-
-=item <http://www.imc.org/ietf-usefor/>
-
-The archives for the USEFOR IETF working group, the working group for the
-RFC 1036 replacement (the format of Usenet articles). Also contains a lot
-of references to other relevant work, such as the RFC 822 replacement
-work.
-
-=item <http://www.mibsoftware.com/userkt/inn/dev/>
-
-Forrest Cavalier provides several tools for following INN development at
-this page and elsewhere in the Usenet RKT. Under here is a web-accessible
-checked-out copy of the current INN source tree and pointers to how to use
-CVSup.
-
-=item <http://www.sas.com/standards/large.file/>
-
-The standards for large file support on Unix that are being generally
-implemented by vendors. INN sort of partially uses these, but a good full
-audit of the code to check them should really be done and there are
-occasional problems.
-
-=item <http://v6web.litech.org/ipv6primer/>
-
-A primer on IPv6 with pointers to the appropriate places for more
-technical details as needed, useful when working on IPv6 support in INN.
-
-=back
+++ /dev/null
-=head1 INN Perl Filtering and Authentication Support
-
-This is $Revision: 7860 $ dated $Date: 2008-06-07 05:46:49 -0700 (Sat, 07 Jun 2008) $.
-
-This file documents INN's built-in support for Perl filtering and reader
-authentication. The code is based very heavily on work by Christophe
-Wolfhugel <wolf@pasteur.fr>, and his work was in turn inspired by the
-existing TCL support. Please send any bug reports to inn-bugs@isc.org,
-not to Christophe, as the code has been modified heavily since he
-originally wrote it.
-
-The Perl filtering support is described in more detail below. Basically,
-it allows you to supply a Perl function that is invoked on every article
-received by innd from a peer (the innd filter) or by nnrpd from a reader
-(the nnrpd filter). This function can decide whether to accept or reject
-the article, and can optionally do other, more complicated processing
-(such as add history entries, cancel articles, spool local posts into a
-holding area, or even modify the headers of locally submitted posts).
-The Perl authentication hooks allow you to replace or supplement the
-readers.conf mechanism used by nnrpd.
-
-For Perl filtering support, you need to have Perl version 5.004 or newer.
-Earlier versions of Perl will fail with a link error at compilation time.
-http://language.perl.com/info/software.html should have the latest Perl
-version.
-
-To enable Perl support, you have to specify B<--with-perl> when you run
-configure. See F<INSTALL> for more information.
-
-=head1 The innd Perl Filter
-
-When innd starts, it first loads the file _PATH_PERL_STARTUP_INND (defined
-in F<include/paths.h>, by default F<startup_innd.pl>) and then loads the
-file _PATH_PERL_FILTER_INND (also defined in F<include/paths.h>, by
-default F<filter_innd.pl>). Both of these files must be located in the
-directory specified by pathfilter in F<inn.conf>
-(F</usr/local/news/bin/filter> by default). The default directory for
-filter code can be specified at configure time by giving the flag
-B<--with-filter-dir> to configure.
-
-INN doesn't care what Perl functions you define in which files. The only
-thing that's different about the two files is when they're loaded.
-F<startup_innd.pl> is loaded only once, when innd first starts, and is
-never reloaded as long as innd is running. Any modifications to that file
-won't be noticed by innd; only stopping and restarting innd can cause it
-to be reloaded.
-
-F<filter_innd.pl>, on the other hand, can be reloaded on command (with
-C<ctlinnd reload filter.perl 'reason'>). Whenever F<filter_innd.pl> is loaded,
-including the first time at innd startup, the Perl function
-filter_before_reload() is called before it's reloaded and the function
-filter_after_reload() is called after it's reloaded (if the functions
-exist). Additionally, any code in either F<startup_innd.pl> or
-F<filter_innd.pl> at the top level (in other words, not inside a sub { })
-is automatically executed by Perl when the files are loaded.
-
-This allows one to do things like write out filter statistics whenever the
-filter is reloaded, load a cache into memory, flush cached data to disk,
-or other similar operations that should only happen at particular times or
-with manual intervention. Remember, any code not inside functions in
-F<startup_innd.pl> is executed when that file is loaded, and it's loaded
-only once when innd first starts. That makes it the ideal place to put
-initialization code that should only run once, or code to load data that
-was preserved on disk across a stop and restart of innd (perhaps using
-filter_mode() -- see below).
-
-As mentioned above, C<ctlinnd reload filter.perl 'reason'> (or C<ctlinnd reload
-all 'reason'>) will cause F<filter_innd.pl> to be reloaded. If the function
-filter_art() is defined after the file has been reloaded, filtering is
-turned on. Otherwise, filtering is turned off. (Note that due to the way
-Perl stores functions, once you've defined filter_art(), you can't
-undefine it just by deleting it from the file and reloading the filter.
-You'll need to replace it with an empty sub.)
-
-The Perl function filter_art() is the heart of a Perl filter. Whenever an
-article is received from a peer, via either IHAVE or TAKETHIS,
-filter_art() is called if Perl filtering is turned on. It receives no
-arguments, and should return a single scalar value. That value should be
-the empty string to indicate that INN should accept the article, or some
-rejection message to indicate that the article should be rejected.
-
-filter_art() has access to a global hash named %hdr, which contains all of
-the standard headers present in the article and their values. The
-standard headers are:
-
- Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock,
- Content-Base, Content-Disposition, Content-Transfer-Encoding,
- Content-Type, Control, Date, Date-Received, Distribution, Expires,
- Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info,
- Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups,
- NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator,
- Path, Posted, Posting-Version, Received, References, Relay-Version,
- Reply-To, Sender, Subject, Supersedes, User-Agent,
- X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face,
- X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace,
- X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID,
- X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig,
- X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To,
- X-Trace, X-Usenet-Provider, Xref.
-
-Note that all the above headers are as they arrived, not modified by
-your INN (especially, the Xref: header, if present, is the one of
-the remote site which sent you the article, and not yours).
-
-For example, the Newsgroups: header of the article is accessible
-inside the Perl filter as C<$hdr{'Newsgroups'}>. In addition,
-C<$hdr{'__BODY__'}> will contain the full body of the article and
-C<$hdr{'__LINES__'}> will contain the number of lines in the body of the
-article.
-
-The contents of the %hdr hash for a typical article may therefore look
-something like this:
-
- %hdr = (Subject => 'MAKE MONEY FAST!!',
- From => 'Joe Spamer <him@example.com>',
- Date => '10 Sep 1996 15:32:28 UTC',
- Newsgroups => 'alt.test',
- Path => 'news.example.com!not-for-mail',
- Organization => 'Spammers Anonymous',
- Lines => '5',
- Distribution => 'usa',
- 'Message-ID' => '<6.20232.842369548@example.com>',
- __BODY__ => 'Send five dollars to the ISC, c/o ...',
- __LINES__ => 5
- );
-
-Note that the value of C<$hdr{Lines}> is the contents of the Lines: header
-of the article and may bear no resemblence to the actual length of the
-article. C<$hdr{__LINES__}> is the line count calculated by INN, and is
-guaranteed to be accurate.
-
-The %hdr hash should not be modified inside filter_art(). Instead, if any
-of the contents need to be modified temporarily during filtering (smashing
-case, for example), copy them into a seperate variable first and perform
-the modifications on the copy. Currently, C<$hdr{__BODY__}> is the only
-data that will cause your filter to die if you modify it, but in the
-future other keys may also contain live data. Modifying live INN data in
-Perl will hopefully only cause a fatal exception in your Perl code that
-disables Perl filtering until you fix it, but it's possible for it to
-cause article munging or even core dumps in INN. So always, always make a
-copy first.
-
-As mentioned above, if filter_art() returns the empty string (''), the
-article is accepted. Note that this must be the empty string, not 0 or
-undef. Otherwise, the article is rejected, and whatever scalar
-filter_art() returns (typically a string) will be taken as the reason why
-the article was rejected. This reason will be returned to the remote peer
-as well as logged to the news logs. (innreport, in its nightly report,
-will summarize the number of articles rejected by the Perl filter and
-include a count of how many articles were rejected with each reason
-string.)
-
-One other type of filtering is also supported. If Perl filtering is
-turned on and the Perl function filter_messageid() is defined, that
-function will be called for each message ID received from a peer (via
-either CHECK or IHAVE). The function receives a single argument, the
-message ID, and like filter_art() should return an empty string to accept
-the article or an error string to refuse the article. This function is
-called before any history lookups and for every article offered to innd
-with CHECK or IHAVE (before the actual article is sent). Accordingly, the
-message ID is the only information it has about the article (the %hdr hash
-will be empty). This code would sit in a performance-critical hot path in
-a typical server, and therefore should be as fast as possible, but it can
-do things like refuse articles from certain hosts or cancels for already
-rejected articles (if they follow the $alz convention) without having to
-take the network bandwidth hit of accepting the entire article first.
-
-Note that you cannot rely on filter_messageid() being called for every
-incoming article; articles sent via TAKETHIS without an earlier CHECK will
-never pass through filter_messageid() and will only go through
-filter_art().
-
-Finally, whenever ctlinnd throttle, ctlinnd pause, or ctlinnd go is run,
-the Perl function filter_mode() is called if it exists. It receives no
-arguments and returns no value, but it has access to a global hash %mode
-that contains three values:
-
- Mode The current server mode (throttled, paused, or running)
- NewMode The new mode the server is going to
- reason The reason that was given to ctlinnd
-
-One possible use for this function is to save filter state across a
-restart of innd. There isn't any Perl function which is called when INN
-shuts down, but using filter_mode() the Perl filter can dump it's state to
-disk whenever INN is throttled. Then, if the news administrator follows
-the strongly recommended shutdown procedure of throttling the server
-before shutting it down, the filter state will be safely saved to disk and
-can be reloaded when innd restarts (possibly by F<startup_innd.pl>).
-
-The state of the Perl interpretor in which all of these Perl functions run
-is preserved over the lifetime of innd. In other words, it's permissible for
-the Perl code to create its own global Perl variables, data structures,
-saved state, and the like, and all of that will be available to
-filter_art() and filter_messageid() each time they're called. The only
-variable INN fiddles with (or pays any attention to at all) is %hdr, which
-is cleared after each call to filter_art().
-
-Perl filtering can be turned off with C<ctlinnd perl n> and back on again
-with C<ctlinnd perl y>. Perl filtering is turned off automatically if
-loading of the filter fails or if the filter code returns any sort of a
-fatal error (either due to Perl itself or due to a C<die> in the Perl code).
-
-=head1 Supported innd Callbacks
-
-innd makes seven functions available to any of its embedded Perl code.
-Those are:
-
-=over 4
-
-=item INN::addhist(I<messageid>, I<arrival>, I<articledate>, I<expire>, I<paths>)
-
-Adds I<messageid> to the history database. All of the arguments except
-the first one are optional; the times default to the current time and the
-paths field defaults to the empty string. (For those unfamiliar with the
-fields of a history(5) database entry, the I<arrival> is normally the time at
-which the server accepts the article, the I<articledate> is from the Date
-header of the article, the I<expire> is from the Expires header of the
-article, and the I<paths> field is the storage API token. All three times
-as measured as a time_t since the epoch.) Returns true on success, false
-otherwise.
-
-=item INN::article(I<messageid>)
-
-Returns the full article (as a simple string) identified by I<messageid>,
-or undef if it isn't found. Each line will end with a simple \n, but
-leading periods may still be doubled if the article is stored in wire
-format.
-
-=item INN::cancel(I<messageid>)
-
-Cancels I<messageid>. (This is equivalent to C<ctlinnd cancel>; it
-cancels the message on the local server, but doesn't post a cancel message
-or do anything else that affects anything other than the local server.)
-Returns true on success, false otherwise.
-
-=item INN::filesfor(I<messageid>)
-
-Returns the I<paths> field of the history entry for the given
-I<messageid>. This will be the storage API token for the message. If
-I<messageid> isn't found in the history database, returns undef.
-
-=item INN::havehist(I<messageid>)
-
-Looks up I<messageid> in the history database and returns true if it's
-found, false otherwise.
-
-=item INN::head(I<messageid>)
-
-Returns the header (as a simple string) of the article identified by
-I<messageid>, or undef if it isn't found. Each line will end with a
-simple \n (in other words, regardless of the format of article storage,
-the returned string won't be in wire format).
-
-=item INN::newsgroup(I<newsgroup>)
-
-Returns the status of I<newsgroup> (the last field of the active file
-entry for that newsgroup). See active(5) for a description of the
-possible values and their meanings (the most common are "y" for an
-unmoderated group and "m" for a moderated group). If I<newsgroup> isn't
-in the active file, returns undef.
-
-=back
-
-These functions can only be used from inside the innd Perl filter; they're
-not available in the nnrpd filter.
-
-=head1 Common Callbacks
-
-The following additional function is available from inside filters
-embedded in innd, and is also available from filters embedded in nnrpd
-(see below):
-
-=over 4
-
-=item INN::syslog(level, message)
-
-Logs a message via syslog(2). This is quite a bit more reliable and
-portable than trying to use Sys::Syslog from inside the Perl filter. Only
-the first character of the level argument matters; the valid letters are
-the first letters of ALERT, CRIT, ERR, WARNING, NOTICE, INFO, and DEBUG
-(case-insensitive) and specify the priority at which the message is
-logged. If a level that doesn't match any of those levels is given, the
-default priority level is LOG_NOTICE. The second argument is the message
-to log; it will be prefixed by "filter: " and logged to syslog with
-facility LOG_NEWS.
-
-=back
-
-=head1 The nnrpd Posting Filter
-
-Whenever Perl support is needed in nnrpd, it first loads the file
-_PATH_PERL_FILTER_NNRPD (defined in F<include/paths.h>, by default
-F<filter_nnrpd.pl>). This file must be located in the directory
-specified by pathfilter in F<inn.conf> (F</usr/local/news/bin/filter>
-by default). The default directory for filter code can be specified
-at configure time by giving the flag B<--with-filter-dir> to
-configure.
-
-If F<filter_nnrpd.pl> loads successfully and defines the Perl function
-filter_post(), Perl filtering is turned on. Otherwise, it's turned off.
-If filter_post() ever returns a fatal error (either from Perl or from a
-C<die> in the Perl code), Perl filtering is turned off for the life of that
-nnrpd process and any further posts made during that session won't go
-through the filter.
-
-While Perl filtering is on, every article received by nnrpd via the POST
-command is passed to the filter_post() Perl function before it is passed
-to INN (or mailed to the moderator of a moderated newsgroup). If
-filter_post() returns an empty string (''), the article is accepted and
-normal processing of it continues. Otherwise, the article is rejected and
-the string returned by filter_post() is returned to the client as the
-error message (with some exceptions; see below).
-
-filter_post() has access to a global hash %hdr, which contains all of the
-headers of the article. (Unlike the innd Perl filter, %hdr for the nnrpd
-Perl filter contains *all* of the headers, not just the standard ones. If
-any of the headers are duplicated, though, %hdr will contain only the
-value of the last occurance of the header. nnrpd will reject the
-article before the filter runs if any of the standard headers are
-duplicated.) It also has access to the full body of the article in the
-variable $body, and if the poster authenticated via AUTHINFO (or if either
-Perl authentication or a readers.conf authentication method is used and
-produces user information), it has access to the authenticated username of
-the poster in the variable $user.
-
-Unlike the innd Perl filter, the nnrpd Perl filter can modify the %hdr
-hash. In fact, if the Perl variable $modify_headers is set to true after
-filter_post() returns, the contents of the %hdr hash will be written back
-to the article replacing the original headers. filter_post() can
-therefore make any modifications it wishes to the headers and those
-modifications will be reflected in the article as it's finally posted.
-The article body cannot be modified in this way; any changes to $body will
-just be ignored.
-
-Be careful when using the ability to modify headers. filter_post() runs
-after all the normal consistency checks on the headers and after server
-supplied headers (like Message-ID: and Date:) are filled in. Deleting
-required headers or modifying headers that need to follow a strict format
-can result in nnrpd trying to post nonsense articles (which will probably
-then be rejected by innd). If $modify_headers is set, I<everything> in
-the %hdr hash is taken to be article headers and added to the article.
-
-If filter_post() returns something other than the empty string, this
-message is normally returned to the client as an error. There are two
-exceptions: If the string returned begins with "DROP", the post will be
-silently discarded and success returned to the client. If the string
-begins with "SPOOL", success is returned to the client, but the post is
-saved in a directory named "spam" under the directory specified by
-pathincoming in F<inn.conf> (in a directory named "spam/mod" if the post
-is to a moderated group). This is intended to allow manual inspection of
-the suspect messages; if they should be posted, they can be manually moved
-out of the subdirectory to the directory specified by pathincoming in
-F<inn.conf>, where they can be posted by running C<rnews -U>. If you use
-this functionality, make sure those directories exist.
-
-=head1 Changes to Perl Authentication Support for nnrpd
-
-The old authentication functionality has been combined with the new
-readers.conf mechanism by Erik Klavon <erik@eriq.org>; bug reports
-should however go to inn-bugs@isc.org, not Erik.
-
-The remainder of this section is an introduction to the new mechanism
-(which uses the perl_auth: and perl_access: F<readers.conf> parameters)
-with porting/migration suggestions for people familiar with the old
-mechanism (identifiable by the nnrpperlauth: parameter in F<inn.conf>).
-
-Other people should skip this section.
-
-The perl_auth parameter allows the use of Perl to authenticate a user.
-Scripts (like those from the old mechanism) are listed in F<readers.conf>
-using perl_auth in the same manner other authenticators are using auth:
-
- perl_auth: "/path/to/script/auth1.pl"
-
-The file given as argument to perl_auth should contain the same
-procedures as before. The global hash %attributes remains the same,
-except for the removal of the "type" entry which is no longer needed
-in this modification and the addition of several new entries (port,
-intipaddr, intport) described below. The return array now only
-contains either two or three elements, the first of which is the NNTP
-return code. The second is an error string which is passed to the
-client if the error code indicates that the authentication attempt has
-failed. This allows a specific error message to be generated by the
-perl script in place of "Authentication failed". An optional third
-return element if present will be used to match the connection with
-the users: parameter in access groups and will also be the username
-logged. If this element is absent, the username supplied by the client
-during authentication will be used as was the previous behavior.
-
-The perl_access parameter (described below) is also new; it allows the
-dynamic generation of an access group for an incoming connection using
-a Perl script. If a connection matches an auth group which has a
-perl_access parameter, all access groups in readers.conf are ignored;
-instead the procedure described below is used to generate an access group.
-This concept is due to Jeffrey M. Vinocur.
-
-The new functionality should provide all of the existing capabilities
-of the Perl hook, in combination with the flexibility of readers.conf
-and the use of other authentication and resolving programs. To use
-Perl authentication code that predates the readers.conf mechanism, you
-would need to modify the code slightly (see below for the new
-specification) and supply a simple readers.conf file. If you don't want
-to modify your code, the samples directory has F<nnrpd_auth_wrapper.pl>
-and F<nnrpd_access_wrapper.pl> which should allow you to use your old
-code without needing to change it.
-
-However, before trying to use your old Perl code, you may want to
-consider replacing it entirely with non-Perl authentication. (With
-readers.conf and the regular authenticator and resolver programs, much
-of what once required Perl can be done directly.) Even if the
-functionality is not available directly, you may wish to write a new
-authenticator or resolver (which can be done in whatever language you
-prefer to work in).
-
-
-=head1 Perl Authentication Support for nnrpd
-
-Support for authentication via Perl is provided in nnrpd by the
-inclusion of a perl_auth: parameter in a F<readers.conf> auth
-group. perl_auth: works exactly like the auth: parameter in
-F<readers.conf>, except that it calls the script given as argument using
-the Perl hook rather then treating it as an external program.
-
-If the processing of readers.conf requires that a perl_auth: statement
-be used for authentication, Perl is loaded (if it has yet to be) and
-the file given as argument to the perl_auth: parameter is loaded as
-well. If a Perl function auth_init() is defined by that file, it is called
-immediately after the file is loaded. It takes no arguments and returns
-nothing.
-
-Provided the file loads without errors, auth_init() (if present) runs
-without fatal errors, and a Perl function authenticate() is defined,
-authenticate() will then be called. authenticate() takes no arguments,
-but it has access to a global hash %attributes which contains
-information about the connection as follows: C<$attributes{hostname}>
-will contain the hostname (or the IP address if it doesn't resolve) of
-the client machine, C<$attributes{ipaddress}> will contain its IP
-address (as a string), C<$attributes{port}> will contain the client
-port (as an integer), C<$attributes{interface}> contains the hostname
-of the interface the client connected on, C<$attributes{intipaddr}>
-contains the IP address (as a string) of the interface the client
-connected on, C<$attributes{intport}> contains the port (as an
-integer) on the interface the client connected on,
-C<$attributes{username}> will contain the provided username and
-C<$attributes{password}> the password.
-
-authenticate() should return a two or three element array. The first
-element is the NNTP response code to return to the client, the second
-element is an error string which is passed to the client if the
-response code indicates that the authentication attempt has failed. An
-optional third return element if present will be used to match the
-connection with the users: parameter in access groups and will also be
-the username logged. If this element is absent, the username supplied
-by the client during authentication will be used for matching and
-logging.
-
-The NNTP response code should probably be either 281 (authentication
-successful) or 502 (authentication unsuccessful). If the code
-returned is anything other than 281, nnrpd will print an
-authentication error message and drop the connection and exit.
-
-If authenticate() dies (either due to a Perl error or due to calling die),
-or if it returns anything other than the two or three element array
-described above, an internal error will be reported to the client, the
-exact error will be logged to syslog, and nnrpd will drop the
-connection and exit.
-
-
-=head1 Dynamic Generation of Access Groups
-
-A Perl script may be used to dynamically generate an access group
-which is then used to determine the access rights of the client. This
-occurs whenever the perl_access: is specified in an auth group which
-has successfully matched the client. Only one perl_access:
-statement is allowed in an auth group. This parameter should not be
-mixed with a python_access: statement in the same auth group.
-
-When a perl_access: parameter is encountered, Perl is loaded (if it
-has yet to be) and the file given as argument is loaded as
-well. Provided the file loads without errors, and a Perl function
-access() is defined, access() will then be called. access() takes no
-arguments, but it has access to a global hash %attributes which
-contains information about the connection as follows:
-C<$attributes{hostname}> will contain the hostname (or the IP address
-if it doesn't resolve) of the client machine,
-C<$attributes{ipaddress}> will contain its IP address (as a string),
-C<$attributes{port}> will contain the client port (as an integer),
-C<$attributes{interface}> contains the hostname of the interface the
-client connected on, C<$attributes{intipaddr}> contains the IP address
-(as a string) of the interface the client connected on,
-C<$attributes{intport}> contains the port (as an integer) on the
-interface the client connected on, C<$attributes{username}> will
-contain the provided username and domain (in username@domain form).
-
-access() returns a hash, containing the desired access parameters and
-values. Here is an untested example showing how to dynamically generate a
-list of newsgroups based on the client's username and domain.
-
- my %hosts = ( "example.com" => "example.*", "isc.org" => "isc.*" );
-
- sub access {
- %return_hash = (
- "max_rate" => "10000",
- "addnntppostinghost" => "true",
- # ...
- );
- if( defined $attributes{username} &&
- $attributes{username} =~ /.*@(.*)/ )
- {
- $return_hash{"virtualhost"} = "true";
- $return_hash{"path"} = $1;
- $return_hash{"newsgroups"} = $hosts{$1};
- } else {
- $return_hash{"read"} = "*";
- $return_hash{"post"} = "local.*"
- }
- return %return_hash;
- }
-
-Note that both the keys and values are quoted strings. These values
-are to be returned to a C program and must be quoted strings. For
-values containing one or more spaces, it is not necessary to include
-extra quotes inside the string.
-
-While you may include the users: parameter in a dynamically generated
-access group, some care should be taken (unless your pattern is just
-* which is equivalent to leaving the parameter out). The group created
-with the values returned from the Perl script is the only one
-considered when nnrpd attempts to find an access group matching the
-connection. If a users: parameter is included and it doesn't match the
-connection, then the client will be denied access since there are no
-other access groups which could match the connection.
-
-If access() dies (either due to a Perl error or due to calling die),
-or if it returns anything other than a hash as described
-above, an internal error will be reported to the client, the exact error
-will be logged to syslog, and nnrpd will drop the connection and exit.
-
-=head1 Notes on Writing Embedded Perl
-
-All Perl evaluation is done inside an implicit eval block, so calling die
-in Perl code will not kill the innd or nnrpd process. Neither will Perl
-errors (such as syntax errors). However, such errors will have negative
-effects (fatal errors in the innd or nnrpd filter will cause filtering to
-be disabled, and fatal errors in the nnrpd authentication code will cause
-the client connection to be terminated).
-
-Calling exit directly, however, *will* kill the innd or nnrpd process, so
-don't do that. Similarly, you probably don't want to call fork (or any
-other function that results in a fork such as system, IPC::Open3::open3(),
-or any use of backticks) since there are possibly unflushed buffers that
-could get flushed twice, lots of open state that may not get closed
-properly, and innumerable other potential problems. In general, be aware
-that all Perl code is running inside a large and complicated C program,
-and Perl code that impacts the process as a whole is best avoided.
-
-You can use print and warn inside Perl code to send output to STDOUT or
-STDERR, but you probably shouldn't. Instead, open a log file and print to
-it instead (or, in the innd filter, use INN::syslog() to write messages
-via syslog like the rest of INN). If you write to STDOUT or STDERR, where
-that data will go depends on where the filter is running; inside innd, it
-will go to the news log or the errlog, and inside nnrpd it will probably
-go nowhere but could go to the client. The nnrpd filter takes some steps
-to try to keep output from going across the network connection to the
-client (which would probably result in a very confused client), but best
-not to take the chance.
-
-For similar reasons, try to make your Perl code -w clean, since Perl
-warnings are written to STDERR. (INN won't run your code under -w, but
-better safe than sorry, and some versions of Perl have some mandatory
-warnings you can't turn off.)
-
-You *can* use modules in your Perl code, just like you would in an
-ordinary Perl script. You can even use modules that dynamically load C
-code. Just make sure that none of the modules you use go off behind your
-back to do any of the things above that are best avoided.
-
-Whenever you make any modifications to the Perl code, and particularly
-before starting INN or reloading filter.perl with new code, you should run
-perl -wc on the file. This will at least make sure you don't have any
-glaring syntax errors. Remember, if there are errors in your code,
-filtering will be disabled, which could mean that posts you really wanted
-to reject will leak through and authentication of readers may be totally
-broken.
-
-The samples directory has example F<startup_innd.pl>, F<filter_innd.pl>,
-F<filter_nnrpd.pl>, and F<nnrpd_auth.pl> files that contain some
-simplistic examples. Look them over as a starting point when writing your
-own.
-
-=head1 Available Packages
-
-This is an unofficial list of known filtering packages at the time of
-publication. This is not an endorsement of these filters by the ISC or
-the INN developers, but is included as assistance in locating packages
-which make use of this filter mechanism.
-
- CleanFeed Jeremy Nixon <jeremy@exit109.com>
- <URL:http://www.exit109.com/~jeremy/news/cleanfeed.html>
- A spam filter catching excessive multi-posting and a host of
- other things. Uses filter_innd.pl exclusively, requires the MD5
- Perl module. Probably the most popular and widely-used Perl
- filter around.
-
- Usenet II Filter Edward S. Marshall <emarshal@xnet.com>
- <URL:http://www.xnet.com/~emarshal/inn/filter_nnrpd.pl>
- Checks for "soundness" according to Usenet II guidelines in the
- net.* hierarchy. Designed to use filter_nnrpd.pl.
-
- News Gizmo Aidan Cully <aidan@panix.com>
- <URL:http://www.panix.com/gizmo/>
- A posting filter for helping a site enforce Usenet-II soundness,
- and for quotaing the number of messages any user can post to
- Usenet daily.
+++ /dev/null
-=head1 INN Python Filtering and Authentication Support
-
-This file documents INN's built-in optional support for Python article
-filtering. It is patterned after the Perl and (now obsolete) TCL hooks
-previously added by Bob Heiney and Christophe Wolfhugel.
-
-For this filter to work successfully, you will need to have at least
-S<Python 1.5.2> installed. You can obtain it from L<http://www.python.org/>.
-
-The B<innd> Python interface and the original Python filtering documentation
-were written by Greg Andruk (nee Fluffy) <gerglery@usa.net>. The Python
-authentication and authorization support for B<nnrpd> as well as the original
-documentation for it were written by Ilya Etingof <ilya@glas.net> in
-December 1999.
-
-=head1 Installation
-
-Once you have built and installed Python, you can cause INN to use it by
-adding the B<--with-python> switch to your C<configure> command. You will
-need to have all the headers and libraries required for embedding Python
-into INN; they can be found in Python development packages, which include
-header files and static libraries.
-
-You will then be able to use Python authentication, dynamic access group
-generation and dynamic access control support in B<nnrpd> along with
-filtering support in B<innd>.
-
-See the ctlinnd(8) manual page to learn how to enable, disable and reload
-Python filters on a running server (especially C<ctlinnd mode>,
-C<ctlinnd python y|n> and C<ctlinnd reload filter.python 'reason'>).
-
-Also, see the F<filter_innd.py>, F<nnrpd_auth.py>, F<nnrpd_access.py>
-and F<nnrpd_dynamic.py> samples in your filters directory for
-a demonstration of how to get all this working.
-
-=head1 Writing an B<innd> Filter
-
-=head2 Introduction
-
-You need to create a F<filter_innd.py> module in INN's filter directory
-(see the I<pathfilter> setting in F<inn.conf>). A heavily-commented sample
-is provided; you can use it as a template for your own filter. There is
-also an F<INN.py> module there which is not actually used by INN; it is
-there so you can test your module interactively.
-
-First, define a class containing the methods you want to provide to B<innd>.
-Methods B<innd> will use if present are:
-
-=over 4
-
-=item __init__(I<self>)
-
-Not explicitly called by B<innd>, but will run whenever the filter module is
-(re)loaded. This is a good place to initialize constants or pick up where
-C<filter_before_reload> or C<filter_close> left off.
-
-=item filter_before_reload(I<self>)
-
-This will execute any time a C<ctlinnd reload all 'reason'> or C<ctlinnd reload
-filter.python 'reason'> command is issued. You can use it to save statistics or
-reports for use after reloading.
-
-=item filter_close(I<self>)
-
-This will run when a C<ctlinnd shutdown 'reason'> command is received.
-
-=item filter_art(I<self>, I<art>)
-
-I<art> is a dictionary containing an article's headers and body. This method
-is called every time B<innd> receives an article. The following can be
-defined:
-
- Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock,
- Content-Base, Content-Disposition, Content-Transfer-Encoding,
- Content-Type, Control, Date, Date-Received, Distribution, Expires,
- Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info,
- Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups,
- NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator,
- Path, Posted, Posting-Version, Received, References, Relay-Version,
- Reply-To, Sender, Subject, Supersedes, User-Agent,
- X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face,
- X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace,
- X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID,
- X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig,
- X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To,
- X-Trace, X-Usenet-Provider, Xref, __BODY__, __LINES__.
-
-Note that all the above values are as they arrived, not modified
-by your INN (especially, the Xref: header, if present, is the one
-of the remote site which sent you the article, and not yours).
-
-These values will be buffer objects holding the contents of the
-same named article headers, except for the special C<__BODY__> and C<__LINES__>
-items. Items not present in the article will contain C<None>.
-
-C<art('__BODY__')> is a buffer object containing the article's entire body, and
-C<art('__LINES__')> is an int holding B<innd>'s reckoning of the number of lines
-in the article. All the other elements will be buffers with the contents
-of the same-named article headers.
-
-The Newsgroups: header of the article is accessible inside the Python
-filter as C<art['Newsgroups']>.
-
-If you want to accept an article, return C<None> or an empty string. To
-reject, return a non-empty string. The rejection strings will be shown to
-local clients and your peers, so keep that in mind when phrasing your
-rejection responses.
-
-=item filter_messageid(I<self>, I<msgid>)
-
-I<msgid> is a buffer object containing the ID of an article being offered by
-IHAVE or CHECK. Like with C<filter_art>, the message will be refused if
-you return a non-empty string. If you use this feature, keep it light
-because it is called at a rather busy place in B<innd>'s main loop. Also, do
-not rely on this function alone to reject by ID; you should repeat the
-tests in C<filter_art> to catch articles sent with TAKETHIS but no CHECK.
-
-=item filter_mode(I<self>, I<oldmode>, I<newmode>, I<reason>)
-
-When the operator issues a B<ctlinnd> C<pause>, C<throttle>, C<go>, C<shutdown>
-or C<xexec> command, this function can be used to do something sensible in accordance
-with the state change. Stamp a log file, save your state on throttle,
-etc. I<oldmode> and I<newmode> will be strings containing one of the values in
-(C<running>, C<throttled>, C<paused>, C<shutdown>, C<unknown>). I<oldmode> is
-the state B<innd> was in before B<ctlinnd> was run, I<newmode> is the state B<innd>
-will be in after the command finishes. I<reason> is the comment string
-provided on the B<ctlinnd> command line.
-
-=back
-
-=head2 How to Use these Methods with B<innd>
-
-To register your methods with B<innd>, you need to create an instance of your
-class, import the built-in INN module, and pass the instance to
-C<INN.set_filter_hook>. For example:
-
- class Filter:
- def filter_art(self, art):
- ...
- blah blah
- ...
-
- def filter_messageid(self, id):
- ...
- yadda yadda
- ...
-
- import INN
- myfilter = Filter()
- INN.set_filter_hook(myfilter)
-
-When writing and testing your Python filter, don't be afraid to make use
-of C<try:>/C<except:> and the provided C<INN.syslog> function. stdout and stderr
-will be disabled, so your filter will die silently otherwise.
-
-Also, remember to try importing your module interactively before loading
-it, to ensure there are no obvious errors. One typo can ruin your whole
-filter. A dummy F<INN.py> module is provided to facilitate testing outside
-the server. To test, change into your filter directory and use a command
-like:
-
- python -ic 'import INN, filter_innd'
-
-You can define as many or few of the methods listed above as you want in
-your filter class (it is fine to define more methods for your own use; B<innd>
-will not be using them but your filter can). If you I<do> define the above
-methods, GET THE PARAMETER COUNTS RIGHT. There are checks in B<innd> to see
-whether the methods exist and are callable, but if you define one and get the
-parameter counts wrong, B<innd> WILL DIE. You have been warned. Be careful
-with your return values, too. The C<filter_art> and C<filter_messageid>
-methods have to return strings, or C<None>. If you return something like an
-int, B<innd> will I<not> be happy.
-
-=head2 A Note regarding Buffer Objects
-
-Buffer objects are cousins of strings, new in S<Python 1.5.2>. Using buffer
-objects may take some getting used to, but we can create buffers much faster
-and with less memory than strings.
-
-For most of the operations you will perform in filters (like C<re.search>,
-C<string.find>, C<md5.digest>) you can treat buffers just like strings, but
-there are a few important differences you should know about:
-
- # Make a string and two buffers.
- s = "abc"
- b = buffer("def")
- bs = buffer("abc")
-
- s == bs # - This is false because the types differ...
- buffer(s) == bs # - ...but this is true, the types now agree.
- s == str(bs) # - This is also true, but buffer() is faster.
- s[:2] == bs[:2] # - True. Buffer slices are strings.
-
- # While most string methods will take either a buffer or a string,
- # string.join (in the string module) insists on using only strings.
- import string
- string.join([str(b), s], '.') # Returns 'def.abc'.
- '.'.join([str(b), s]) # Returns 'def.abc' too.
- '.'.join([b, s]) # This raises a TypeError.
-
- e = s + b # This raises a TypeError, but...
-
- # ...these two both return the string 'abcdef'. The first one
- # is faster -- choose buffer() over str() whenever you can.
- e = buffer(s) + b
- f = s + str(b)
-
- g = b + '>' # This is legal, returns the string 'def>'.
-
-=head2 Functions Supplied by the Built-in B<innd> Module
-
-Besides C<INN.set_filter_hook> which is used to register your methods
-with B<innd> as it has already been explained above, the following functions
-are available from Python scripts:
-
-=over 4
-
-=item addhist(I<message-id>)
-
-=item article(I<message-id>)
-
-=item cancel(I<message-id>)
-
-=item havehist(I<message-id>)
-
-=item hashstring(I<string>)
-
-=item head(I<message-id>)
-
-=item newsgroup(I<groupname>)
-
-=item syslog(I<level>, I<message>)
-
-=back
-
-Therefore, not only can B<innd> use Python, but your filter can use some of
-B<innd>'s features too. Here is some sample Python code to show what you get
-with the previously listed functions.
-
- import INN
-
- # Python's native syslog module isn't compiled in by default,
- # so the INN module provides a replacement. The first parameter
- # tells the Unix syslogger what severity to use; you can
- # abbreviate down to one letter and it's case insensitive.
- # Available levels are (in increasing levels of seriousness)
- # Debug, Info, Notice, Warning, Err, Crit, and Alert. (If you
- # provide any other string, it will be defaulted to Notice.) The
- # second parameter is the message text. The syslog entries will
- # go to the same log files innd itself uses, with a 'python:'
- # prefix.
- syslog('warning', 'I will not buy this record. It is scratched.')
- animals = 'eels'
- vehicle = 'hovercraft'
- syslog('N', 'My %s is full of %s.' % (vehicle, animals))
-
- # Let's cancel an article! This only deletes the message on the
- # local server; it doesn't send out a control message or anything
- # scary like that. Returns 1 if successful, else 0.
- if INN.cancel('<meow$123.456@solvangpastries.edu>'):
- cancelled = "yup"
- else:
- cancelled = "nope"
-
- # Check if a given message is in history. This doesn't
- # necessarily mean the article is on your spool; cancelled and
- # expired articles hang around in history for a while, and
- # rejected articles will be in there if you have enabled
- # remembertrash in inn.conf. Returns 1 if found, else 0.
- if INN.havehist('<z456$789.abc@isc.org>'):
- comment = "*yawn* I've already seen this article."
- else:
- comment = 'Mmm, fresh news.'
-
- # Here we are running a local spam filter, so why eat all those
- # cancels? We can add fake entries to history so they'll get
- # refused. Returns 1 on success, 0 on failure.
- cancelled_id = buffer('<meow$123.456@isc.org>')
- if INN.addhist("<cancel." + cancelled_id[1:]):
- thought = "Eat my dust, roadkill!"
- else:
- thought = "Darn, someone beat me to it."
-
- # We can look at the header or all of an article already on spool,
- # too. Might be useful for long-memory despamming or
- # authentication things. Each is returned (if present) as a
- # string object; otherwise you'll end up with an empty string.
- artbody = INN.article('<foo$bar.baz@bungmunch.edu>')
- artheader = INN.head('<foo$bar.baz@bungmunch.edu>')
-
- # As we can compute a hash digest for a string, we can obtain one
- # for artbody. It might be of help to detect spam.
- digest = INN.hashstring(artbody)
-
- # Finally, do you want to see if a given newsgroup is moderated or
- # whatever? INN.newsgroup returns the last field of a group's
- # entry in active as a string.
- froupflag = INN.newsgroup('alt.fan.karl-malden.nose')
- if froupflag == '':
- moderated = 'no such newsgroup'
- elif froupflag == 'y':
- moderated = "nope"
- elif froupflag == 'm':
- moderated = "yep"
- else:
- moderated = "something else"
-
-=head1 Writing an B<nnrpd> Filter
-
-=head2 Changes to Python Authentication and Access Control Support for B<nnrpd>
-
-The old authentication and access control functionality has been
-combined with the new F<readers.conf> mechanism by Erik Klavon
-<erik@eriq.org>; bug reports should however go to <inn-bugs@isc.org>,
-not Erik.
-
-The remainder of this section is an introduction to the new mechanism
-(which uses the I<python_auth>, I<python_access>, and I<python_dynamic>
-F<readers.conf> parameters) with porting/migration suggestions for
-people familiar with the old mechanism (identifiable by the now
-deprecated I<nnrpperlauth> parameter in F<inn.conf>).
-
-Other people should skip this section.
-
-The I<python_auth> parameter allows the use of Python to authenticate a
-user. Authentication scripts (like those from the old mechanism) are
-listed in F<readers.conf> using I<python_auth> in the same manner other
-authenticators are using I<auth>:
-
- python_auth: "nnrpd_auth"
-
-It uses the script named F<nnrpd_auth.py> (note that C<.py> is not present
-in the I<python_auth> value).
-
-Scripts should be placed as before in the filter directory (see the
-I<pathfilter> setting in F<inn.conf>). The new hook method C<authen_init>
-takes no arguments and its return value is ignored; its purpose is to
-provide a means for authentication specific initialization. The hook
-method C<authen_close> is the more specific analogue to the old C<close>
-method. These two method hooks are not required, contrary to
-C<authenticate>, the main method.
-
-The argument dictionary passed to C<authenticate> remains the same,
-except for the removal of the I<type> entry which is no longer needed
-in this modification and the addition of several new entries (I<port>,
-I<intipaddr>, I<intport>) described below. The return tuple now only
-contains either two or three elements, the first of which is the NNTP
-response code. The second is an error string which is passed to the
-client if the response code indicates that the authentication attempt
-has failed. This allows a specific error message to be generated by
-the Python script in place of the generic message C<Authentication
-failed>. An optional third return element, if present, will be used to
-match the connection with the I<user> parameter in access groups and
-will also be the username logged. If this element is absent, the
-username supplied by the client during authentication will be used, as
-was the previous behaviour.
-
-The I<python_access> parameter (described below) is new; it allows the
-dynamic generation of an access group of an incoming connection using
-a Python script. If a connection matches an auth group which has a
-I<python_access> parameter, all access groups in F<readers.conf> are
-ignored; instead the procedure described below is used to generate an
-access group. This concept is due to Jeffrey S<M. Vinocur> and you can
-add this line to F<readers.conf> in order to use the F<nnrpd_access.py>
-Python script in I<pathfilter>:
-
- python_access: "nnrpd_access"
-
-In the old implementation, the authorization method allowed for access
-control on a per-group basis. That functionality is preserved in the
-new implementation by the inclusion of the I<python_dynamic> parameter in
-F<readers.conf>. The only change is the corresponding method name of
-C<dynamic> as opposed to C<authorize>. Additionally, the associated
-optional housekeeping methods C<dynamic_init> and C<dynamic_close>
-may be implemented if needed. In order to use F<nnrpd_dynamic.py> in
-I<pathfilter>, you can add this line to F<readers.conf>:
-
- python_dynamic: "nnrpd_dynamic"
-
-This new implementation should provide all of the previous
-capabilities of the Python hooks, in combination with the flexibility
-of F<readers.conf> and the use of other authentication and resolving
-programs (including the Perl hooks!). To use Python code that predates
-the new mechanism, you would need to modify the code slightly (see
-below for the new specification) and supply a simple F<readers.conf>
-file. If you do not want to modify your code, the sample directory has
-F<nnrpd_auth_wrapper.py>, F<nnrpd_access_wrapper.py> and
-F<nnrpd_dynamic_wrapper.py> which should allow you to use your old
-code without needing to change it.
-
-However, before trying to use your old Python code, you may want to
-consider replacing it entirely with non-Python authentication. (With
-F<readers.conf> and the regular authenticator and resolver programs, much
-of what once required Python can be done directly.) Even if the
-functionality is not available directly, you may wish to write a new
-authenticator or resolver (which can be done in whatever language you
-prefer).
-
-=head2 Python Authentication Support for B<nnrpd>
-
-Support for authentication via Python is provided in B<nnrpd> by the
-inclusion of a I<python_auth> parameter in a F<readers.conf> auth
-group. I<python_auth> works exactly like the I<auth> parameter in
-F<readers.conf>, except that it calls the script given as argument
-using the Python hook rather then treating it as an external
-program. Multiple, mixed use of I<python_auth> with other I<auth>
-statements including I<perl_auth> is permitted. Each I<auth> statement
-will be tried in the order they appear in the auth group until either
-one succeeds or all are exhausted.
-
-If the processing of F<readers.conf> requires that a I<python_auth>
-statement be used for authentication, Python is loaded (if it has yet
-to be) and the file given as argument to the I<python_auth> parameter is
-loaded as well (do not include the C<.py> extension of this file in
-the value of I<python_auth>). If a Python object with a method
-C<authen_init> is hooked in during the loading of that file, then
-that method is called immediately after the file is loaded. If no
-errors have occurred, the method C<authenticate> is called. Depending
-on the NNTP response code returned by C<authenticate>, the authentication
-hook either succeeds or fails, after which the processing of the
-auth group continues as usual. When the connection with the client
-is closed, the method C<authen_close> is called if it exists.
-
-=head2 Dynamic Generation of Access Groups
-
-A Python script may be used to dynamically generate an access group
-which is then used to determine the access rights of the client. This
-occurs whenever the I<python_access> parameter is specified in an auth group
-which has successfully matched the client. Only one I<python_access>
-statement is allowed in an auth group. This parameter should not be
-mixed with a I<perl_access> statement in the same auth group.
-
-When a I<python_access> parameter is encountered, Python is loaded (if
-it has yet to be) and the file given as argument is loaded as well (do not
-include the C<.py> extension of this file in the value of I<python_access>).
-If a Python object with a method C<access_init> is hooked in during the
-loading of that file, then that method is called immediately after the
-file is loaded. If no errors have occurred, the method C<access> is
-called. The dictionary returned by C<access> is used to generate an
-access group that is then used to determine the access rights of the
-client. When the connection with the client is closed, the method
-C<access_close> is called, if it exists.
-
-While you may include the I<users> parameter in a dynamically generated
-access group, some care should be taken (unless your pattern is just
-C<*> which is equivalent to leaving the parameter out). The group created
-with the values returned from the Python script is the only one
-considered when B<nnrpd> attempts to find an access group matching the
-connection. If a I<users> parameter is included and it does not match the
-connection, then the client will be denied access since there are no
-other access groups which could match the connection.
-
-=head2 Dynamic Access Control
-
-If you need to have access control rules applied immediately without
-having to restart all the B<nnrpd> processes, you may apply access
-control on a per newsgroup basis using the Python dynamic hooks (as
-opposed to F<readers.conf>, which does the same on per user
-basis). These hooks are activated through the inclusion of the
-I<python_dynamic> parameter in a F<readers.conf> auth group. Only one
-I<python_dynamic> statement is allowed in an auth group.
-
-When a I<python_dynamic> parameter is encountered, Python is loaded (if
-it has yet to be) and the file given as argument is loaded as well (do not
-include the C<.py> extension of this file in the value of I<python_dynamic>).
-If a Python object with a method C<dynamic_init> is hooked in during the
-loading of that file, then that method is called immediately after the
-file is loaded. Every time a reader asks B<nnrpd> to read or post an
-article, the Python method C<dynamic> is invoked before proceeding with
-the requested operation. Based on the value returned by C<dynamic>, the
-operation is either permitted or denied. When the connection with the
-client is closed, the method C<access_close> is called if it exists.
-
-=head2 Writing a Python B<nnrpd> Authentication Module
-
-You need to create a F<nnrpd_auth.py> module in INN's filter directory
-(see the I<pathfilter> setting in F<inn.conf>) where you should define a
-class holding certain methods depending on which hooks you want to use.
-
-Note that you will have to use different Python scripts for authentication
-and access: the values of I<python_auth>, I<python_access> and I<python_dynamic>
-have to be distinct for your scripts to work.
-
-The following methods are known to B<nnrpd>:
-
-=over 4
-
-=item __init__(I<self>)
-
-Not explicitly called by B<nnrpd>, but will run whenever the auth module is
-loaded. Use this method to initialize any general variables or open
-a common database connection. This method may be omitted.
-
-=item authen_init(I<self>)
-
-Initialization function specific to authentication. This method may be
-omitted.
-
-=item authenticate(I<self>, I<attributes>)
-
-Called when a I<python_auth> statement is reached in the processing of
-F<readers.conf>. Connection attributes are passed in the I<attributes>
-dictionary. Returns a response code, an error string, and an optional
-string to be used in place of the client-supplied username (both for
-logging and for matching the connection with an access group).
-
-=item authen_close(I<self>)
-
-This method is invoked on B<nnrpd> termination. You can use it to save
-state information or close a database connection. This method may be omitted.
-
-=item access_init(I<self>)
-
-Initialization function specific to generation of an access group. This
-method may be omitted.
-
-=item access(I<self>, I<attributes>)
-
-Called when a I<python_access> statement is reached in the processing of
-F<readers.conf>. Connection attributes are passed in the I<attributes>
-dictionary. Returns a dictionary of values representing statements to
-be included in an access group.
-
-=item access_close(I<self>)
-
-This method is invoked on B<nnrpd> termination. You can use it to save
-state information or close a database connection. This method may be omitted.
-
-=item dynamic_init(I<self>)
-
-Initialization function specific to dynamic access control. This
-method may be omitted.
-
-=item dynamic(I<self>, I<attributes>)
-
-Called when a client requests a newsgroup, an article or attempts to
-post. Connection attributes are passed in the I<attributes> dictionary.
-Returns C<None> to grant access, or a non-empty string (which will be
-reported back to the client) otherwise.
-
-=item dynamic_close(I<self>)
-
-This method is invoked on B<nnrpd> termination. You can use it to save
-state information or close a database connection. This method may be omitted.
-
-=back
-
-=head2 The I<attributes> Dictionary
-
-The keys and associated values of the I<attributes> dictionary are
-described below.
-
-=over 4
-
-=item I<type>
-
-C<read> or C<post> values specify the authentication type; only valid
-for the C<dynamic> method.
-
-=item I<hostname>
-
-It is the resolved hostname (or IP address if resolution fails) of
-the connected reader.
-
-=item I<ipaddress>
-
-The IP address of the connected reader.
-
-=item I<port>
-
-The port of the connected reader.
-
-=item I<interface>
-
-The hostname of the local endpoint of the NNTP connection.
-
-=item I<intipaddr>
-
-The IP address of the local endpoint of the NNTP connection.
-
-=item I<intport>
-
-The port of the local endpoint of the NNTP connection.
-
-=item I<user>
-
-The username as passed with AUTHINFO command, or C<None> if not
-applicable.
-
-=item I<pass>
-
-The password as passed with AUTHINFO command, or C<None> if not
-applicable.
-
-=item I<newsgroup>
-
-The name of the newsgroup to which the reader requests read or post access;
-only valid for the C<dynamic> method.
-
-=back
-
-All the above values are buffer objects (see the notes above on what
-buffer objects are).
-
-=head2 How to Use these Methods with B<nnrpd>
-
-To register your methods with B<nnrpd>, you need to create an instance of
-your class, import the built-in B<nnrpd> module, and pass the instance to
-C<nnrpd.set_auth_hook>. For example:
-
- class AUTH:
- def authen_init(self):
- ...
- blah blah
- ...
-
- def authenticate(self, attributes):
- ...
- yadda yadda
- ...
-
- import nnrpd
- myauth = AUTH()
- nnrpd.set_auth_hook(myauth)
-
-When writing and testing your Python filter, don't be afraid to make use
-of C<try:>/C<except:> and the provided C<nnrpd.syslog> function. stdout and stderr
-will be disabled, so your filter will die silently otherwise.
-
-Also, remember to try importing your module interactively before loading
-it, to ensure there are no obvious errors. One typo can ruin your whole
-filter. A dummy F<nnrpd.py> module is provided to facilitate testing outside
-the server. It is not actually used by B<nnrpd> but provides the same set
-of functions as built-in B<nnrpd> module. This stub module may be used
-when debugging your own module. To test, change into your filter directory
-and use a command like:
-
- python -ic 'import nnrpd, nnrpd_auth'
-
-=head2 Functions Supplied by the Built-in B<nnrpd> Module
-
-Besides C<nnrpd.set_auth_hook> used to pass a reference to the instance
-of authentication and authorization class to B<nnrpd>, the B<nnrpd> built-in
-module exports the following function:
-
-=over 4
-
-=item syslog(I<level>, I<message>)
-
-It is intended to be a replacement for a Python native syslog. It works
-like C<INN.syslog>, seen above.
-
-=back
-
-$Id: hook-python.pod 7926 2008-06-29 08:27:41Z iulius $
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ident - nnrpd ident resolver
-
-=head1 SYNOPSIS
-
-B<ident> [B<-p> I<port>] [B<-t>]
-
-=head1 DESCRIPTION
-
-This program attempts to resolve usernames for B<nnrpd> by using the
-ident protocol to query the remote host. It contacts the remote host
-using either IPv4 or IPv6 depending on which protocol was used for the
-incoming NNTP connection.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-p> I<port>
-
-If this option is given, attempt to contact identd on the specified
-remote port (which can be a numeric or symbolic specification).
-Non-numeric values will be looked up using getservbyname(3). The
-default value is the result of C<getservbyname("ident")> if available,
-or port 113 otherwise.
-
-=item B<-t>
-
-If this option is given, the identity returned will never have a domain
-part. That is, if the remote server returns a result containing an C<@>
-character, B<ident> truncates the response at the C<@>. This is useful
-to allow the I<default-domain> parameter in F<reaers.conf> to override
-the domain supplied by the remote host (particularly if the supplied
-domain part is an unqualified local machine name rather than a full
-domain name).
-
-=back
-
-=head1 EXAMPLE
-
-The following readers.conf(5) fragment tells nnrpd to trust ident
-information for hosts on a local network, but to replace the domain
-returned from the ident query:
-
- auth LAN {
- hosts: "192.168/16"
- res: "ident -t"
- default-domain: "internal.example.com"
- }
-
- access LAN {
- users: "*@internal.example.com"
- newsgroups: example.*
- }
-
-Access is granted to the example.* groups for all users on the local
-network whose machines respond to ident queries.
-
-=head1 HISTORY
-
-This documentation was written by Jeffrey M. Vinocur <jeff@litech.org>.
-
-$Id: ident.pod 5988 2002-12-12 23:02:14Z vinocur $
-
-=head1 SEE ALSO
-
-nnrpd(8), readers.conf(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-inews - Post a Usenet article to the local news server
-
-=head1 SYNOPSIS
-
-B<inews> [B<-ADhNORSVW>] [B<-acdeFfnortwx> I<value>] [B<-p> I<port>] [I<file>]
-
-=head1 DESCRIPTION
-
-B<inews> reads a Usenet news article, perhaps with headers, from I<file>
-or standard input if no file is given. It adds some headers and performs
-some consistency checks. If the article does not meet those checks, the
-article is rejected. If it passes the checks, B<inews> sends the article
-to the local news server as specified in F<inn.conf>.
-
-By default, if a file named F<.signature> exists in the home directory of
-the posting user, it is appended to the post, preceeded by a line that
-contains only C<-- >. Signatures are not allowed to be more than four
-lines long.
-
-Cancel messages can only be posted with B<inews> if the sender of the
-cancel message matches the sender of the original message being
-cancelled. The same check is also applied to Supersedes. Sender in this
-case means the contents of the Sender header if present, otherwise the
-From header.
-
-Control messages other than cancel messages are only allowed if B<inews>
-is being run by the news user or by a user in the news group and if the
-control message is recognized. If the article contains a Distribution
-header with a distribution that matches one of the bad distribution
-patterns in F<inn/options.h> (anything containing a period by default),
-the message will be rejected. The message will also be rejected if
-I<checkincludedtext> is true in F<inn.conf>, it contains more quoted text
-than original text, and it is over 40 lines long.
-
-If not provided, the Path header of an article is constructed as follows:
-The basic Path header will be "not-for-mail". If I<pathhost> is specified
-in F<inn.conf>, it will be added to the beginning Path. Otherwise, if
-I<server> is specified, the full domain of the local host will be added to
-the beginning of the Path. Then, if B<-x> was given, its value will be
-added to the beginning of the Path.
-
-If posting fails, a copy of the failed post will be saved in a file named
-F<dead.article> in the home directory of the user running B<inews>.
-B<inews> exits with a non-zero status if posting failed or with a zero
-status if posting was successful.
-
-=head1 OPTIONS
-
-Most of the options to B<inews> take a single value and set the
-corresponding header in the message that is posted. If the value is more
-than one word or contains any shell metacharacters, it must be quoted to
-protect it from the shell. Here are all the options that set header
-fields and the corresponding header:
-
- -a Approved
- -c Control
- -d Distribution
- -e Expires
- -F References
- -f From
- -n Newsgroups
- -o Organization
- -r Reply-To
- -t Subject
- -w Followup-To
- -x Path prefix
-
-The B<-x> argument will be added to the beginning of the normal Path
-header; it will not replace it.
-
-=over 4
-
-=item B<-A>, B<-V>, B<-W>
-
-Accepted for compatibility with C News. These options have no affect.
-
-=item B<-D>, B<-N>
-
-Perform the consistency checks and add headers where appropriate, but then
-print the article to standard output rather than sending it to the server.
-B<-N> is accepted as as synonym for compatibility with C News.
-
-=item B<-h>
-
-Normally, this flag should always be given. It indicates that the article
-consists of headers, a blank line, and then the message body. If it is
-omitted, the input is taken to be just the body of the message, and any
-desired headers have to be specified with command-line options as
-described above.
-
-=item B<-O>
-
-By default, an Organization header will be added if none is present in the
-article. To prevent adding the default (from I<organization> in
-F<inn.conf>), use this flag.
-
-=item B<-p> I<port>
-
-Connect to the specified port on the server rather than to the default
-(port 119).
-
-=item B<-R>
-
-Reject all control messages.
-
-=item B<-S>
-
-Do not attempt to append F<~/.signature> to the message, even if it
-exists.
-
-=back
-
-=head1 NOTES
-
-If the NNTP server requests authentication, B<inews> will try to read
-F<passwd.nntp> to get the username and password to use and will therefore
-need read access to that file. This is typically done by making that file
-group-readable and adding all users who should be able to use B<inews> to
-post to that server to the appropriate group.
-
-B<inews> used to do even more than it does now, and all of the remaining
-checks that are not dependent on the user running B<inews> should probably
-be removed in favor of letting the news server handle them.
-
-Since INN's B<inews> uses F<inn.conf> and some other corners of an INN
-installation, it's not very appropriate as a general stand-alone B<inews>
-program for general use on a system that's not running a news server.
-Other, more suitable versions of B<inews> are available as part of various
-Unix news clients or by themselves.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Rewritten in
-POD by Russ Allbery <rra@stanford.edu>.
-
-=head1 SEE ALSO
-
-inn.conf(5), rnews(1)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-inn.conf - Configuration data for InterNetNews programs
-
-=head1 DESCRIPTION
-
-F<inn.conf> in I<pathetc> is the primary general configuration file for
-all InterNetNews programs. Settings which control the general operation
-of various programs, as well as the paths to all portions of the news
-installation, are found here. The INNCONF environment variable, if set,
-specifies an alternate path to F<inn.conf>.
-
-This file is intended to be fairly static. Any changes made to it will
-generally not affect any running programs until they restart. Unlike
-nearly every other configuration file, F<inn.conf> cannot be reloaded
-dynamically using ctlinnd(8); innd(8) must be stopped and restarted for
-relevant changes to F<inn.conf> to take effect (C<ctlinnd xexec innd> is
-the fastest way to do this.)
-
-Blank lines and lines starting with a number sign (C<#>) are ignored. All
-other lines specify parameters, and should be of the following form:
-
- <name>: <value>
-
-(Any amount of whitespace can be put after the colon and is optional.) If
-the value contains embedded whitespace or any of the characers C<[]<>"\:>,
-it must be enclosed in double quotes (""). A backslash (C<\>) can be used
-to escape quotes and backslashes inside double quotes. <name> is
-case-sensitive; C<server> is not the same as C<Server> or C<SERVER>.
-(F<inn.conf> parameters are generally all in lowercase.)
-
-If <name> occurs more than once in the file, the first value is used.
-Some parameters specified in the file may be overridden by environment
-variables. Most parameters have default values if not specified in
-F<inn.conf>; those defaults are noted in the description of each
-parameter.
-
-Many parameters take a boolean value. For all such parameters, the value
-may be specified as C<true>, C<yes>, or C<on> to turn it on and may be any
-of C<false>, C<no>, or C<off> to turn it off. The case of these values is
-significant.
-
-This documentation is extremely long and organized as a reference manual
-rather than as a tutorial. If this is your first exposure to INN and
-these parameters, it would be better to start by reading other man pages
-and referring to this one only when an F<inn.conf> parameter is explicitly
-mentioned. Those parameters which need to be changed when setting up a
-new server are discussed in F<INSTALL>.
-
-=head1 PARAMETERS
-
-=head2 General Settings
-
-These parameters are used by a wide variety of different components of
-INN.
-
-=over 4
-
-=item I<domain>
-
-This should be the domain name of the local host. It should not have a
-leading period, and it should not be a full host address. It is used only
-if the GetFQDN() routine in libinn(3) cannot get the fully-qualified
-domain name by using either the gethostname(3) or gethostbyname(3) calls.
-The check is very simple; if either routine returns a name with a period
-in it, then it is assumed to have the full domain name. As this parameter
-is rarely used, do not use it to affect the righthand side of
-autogenerated Message-IDs; see instead I<virtualhost> and I<domain> in
-L<readers.conf>. The default value is unset.
-
-=item I<innflags>
-
-The flags to pass to innd on startup. See innd(8) for details on the
-possible flags. The default value is unset.
-
-=item I<mailcmd>
-
-The path to the program to be used for mailing reports and control
-messages. The default is I<pathbin>/innmail. This should not normally
-need to be changed.
-
-=item I<mta>
-
-The command to use when mailing postings to moderators and for the use of
-innmail(1). The message, with headers and an added To: header, will be
-piped into this program. The string C<%s>, if present, will be replaced
-by the e-mail address of the moderator. It's strongly recommended for
-this command to include C<%s> on the command line rather than use the
-addresses in the To: and Cc: headers of the message, since the latter
-approach allows the news server to be abused as a mechanism to send mail
-to arbitrary addresses and will result in unexpected behavior. There is
-no default value for this parameter; it must be set in F<inn.conf> or a
-fatal error message will be logged via syslog.
-
-For most systems, C</usr/lib/sendmail -oi -oem %s> (adjusted for the
-correct path to sendmail) is a good choice.
-
-=item I<pathhost>
-
-What to put into the Path: header to represent the local site. This is
-added to the Path: header of all articles that pass through the system,
-including locally posted articles, and is also used when processing some
-control messages and when naming the server in status reports. There is
-no default value; this parameter must be set in F<inn.conf> or INN will
-not start. A good value to use is the fully-qualified hostname of the
-system.
-
-=item I<server>
-
-The name of the default NNTP server. If I<nnrpdposthost> is not set and
-UNIX domain sockets are not supported, nnrpd(8) tries to hand off
-locally-posted articles through an INET domain socket to this server.
-actsync(8), nntpget(8), and getlist(8) also use this value as the default
-server to connect to. In the latter cases, the value of the NNTPSERVER
-environment variable, if it exists, overrides this. The default value is
-unset.
-
-=back
-
-=head2 Feed Configuration
-
-These parameters govern incoming and outgoing feeds: what size of
-articles are accepted, what filtering and verification is performed on
-them, whether articles in groups not carried by the server are still
-stored and propagated, and other similar settings.
-
-=over 4
-
-=item I<artcutoff>
-
-Articles older than this number of days are dropped. This setting should
-probably match the setting on the C</remember/> line in F<expire.ctl>.
-The default value is C<10>.
-
-=item I<bindaddress>
-
-Which IP address innd(8) should bind itself to. This must be in
-dotted-quad format (nnn.nnn.nnn.nnn). If set to C<all> or not set, innd
-defaults to listening on all interfaces. The value of the
-INND_BIND_ADDRESS environment variable, if set, overrides this setting.
-The default value is unset.
-
-=item I<bindaddress6>
-
-Like I<bindaddress> but for IPv6 sockets. If only one of the I<bindaddress>
-and I<bindaddress6> parameters is used, then only the socket for the
-corresponding address family is created. If both parameters are used
-then two sockets are created. If neither of them is used, the list of
-sockets to listen on will be determined by the system library
-I<getaddrinfo(3)> function. The value of the INND_BIND_ADDRESS6, if set,
-overrides this setting. The default value is unset.
-
-Note that you will generally need to put double quotes ("") around this
-value if you set it, since IPv6 addresses contain colons.
-
-=item I<hiscachesize>
-
-If set to a value other than C<0>, a hash of recently received message IDs
-is kept in memory to speed history lookups. The value is the amount of
-memory to devote to the cache in kilobytes. The cache is only used for
-incoming feeds and a small cache can hold quite a few message IDs, so
-large values aren't necessarily useful unless you have incoming feeds that
-are badly delayed. A good value for a system with more than one incoming
-feed is C<256>; systems with only one incoming feed should probably leave
-this at C<0>. The default value is C<0>.
-
-=item I<ignorenewsgroups>
-
-Whether newsgroup creation control messages (newgroup and rmgroup) should
-be fed as if they were posted to the newsgroup they are creating or
-deleting rather than to the newsgroups listed in the Newsgroups: header.
-If this parameter is set, the newsgroup affected by the control message
-will be extracted from the Control: header and the article will be fed as
-if its Newsgroups: header contained solely that newsgroup. This is useful
-for routing control messages to peers when they are posted to irrelevant
-newsgroups that shouldn't be matched against the peer's desired newsgroups
-in F<newsfeeds>. This is a boolean value and the default is false.
-
-=item I<immediatecancel>
-
-When using the timecaf storage method, article cancels are normally just
-cached to be cancelled, not cancelled immediately. If this is set to
-true, they will instead by cancelled as soon as the cancel is processed.
-This is a boolean value and the default is false.
-
-This setting is ignored unless the timecaf storage method is used.
-
-=item I<linecountfuzz>
-
-If set to something other than C<0>, the line count of the article is
-checked against the Lines: header of the article (if present) and the
-artice is rejected if the values differ by more than this amount. A
-reasonable setting is C<5>, which is the standard maximum signature length
-plus one (some injection software calculates the Lines: header before
-adding the signature). The default value is C<0>, which tells INN not to
-check the Lines: header of incoming articles.
-
-=item I<maxartsize>
-
-The maximum size of article (headers and body) that will be accepted by
-the server, in bytes. A value of C<0> allows any size of article, but
-note that B<innd> will crash if system memory is exceeded. The default
-value is C<1000000> (approximately 1 MB). See also I<localmaxartsize>.
-
-=item I<maxconnections>
-
-The maximum number of incoming NNTP connections innd(8) will accept. The
-default value is C<50>.
-
-=item I<pathalias>
-
-If set, this value is prepended to the Path: header of accepted posts
-(before I<pathhost>) if it doesn't already appear in the Path: header.
-The main purpose of this parameter is to configure all news servers within
-a particular organization to add a common identity string to the
-Path: header. The default value is unset.
-
-=item I<pathcluster>
-
-If set, this value is appended to the Path: header of accepted posts
-(after I<pathhost>) if it isn't already present as the last element
-of the Path: header. The main purpose of this parameter is to make
-several news servers appear as one server. The default value is unset.
-
-Note that the Path: header reads right to left, so appended means inserted
-at the leftmost side of the Path: header.
-
-=item I<pgpverify>
-
-Whether to enable PGP verification of control messages other than cancel.
-This is a boolean value and the default is based on whether configure found
-pgp, pgpv, or gpgv.
-
-=item I<port>
-
-What TCP port innd(8) should listen on. The default value is C<119>, the
-standard NNTP port.
-
-=item I<refusecybercancels>
-
-Whether to refuse all articles whose message IDs start with
-C<E<lt>cancel.>. This message ID convention is widely followed by spam
-cancellers, so the vast majority of such articles will be cancels of spam.
-This check, if enabled, is done before the history check and the message
-ID is not written to the history file. This is a boolean value and the
-default is false.
-
-This is a somewhat messy, inefficient, and inexact way of refusing spam
-cancels. A much better way is to ask all of your upstream peers to not
-send to you any articles with C<cyberspam> in the Path: header (usually
-accomplished by having them mark C<cyberspam> as an alias for your machine
-in their feed configuration). The filtering enabled by this parameter is
-hard-coded; general filtering of message IDs can be done via the embedded
-filtering support.
-
-=item I<remembertrash>
-
-By default, innd(8) records rejected articles in history so that, if
-offered the same article again, it can be refused before it is sent. If
-you wish to disable this behavior, set this to false. This can cause a
-substantial increase in the amount of bandwidth consumed by incoming news
-if you have several peers and reject a lot of articles, so be careful with
-it. Even if this is set to true, INN won't log some rejected articles to
-history if there's reason to believe the article might be accepted if
-offered by a different peer, so there is usually no reason to set this to
-false (although doing so can decrease the size of the history file). This
-is a boolean value and the default is true.
-
-=item I<sourceaddress>
-
-Which local IP address to bind to for outgoing NNTP sockets (used by
-innxmit(8) among other programs, but I<not> innfeed(8) -- see
-I<bindaddress> in innfeed.conf(5) for that). This must be in dotted-quad
-format (nnn.nnn.nnn.nnn). If set to C<all> or not set, the operating
-system will choose the source IP address for outgoing connections. The
-default value is unset.
-
-=item I<sourceaddress6>
-
-Like I<sourceaddress> but for IPv6 sockets.
-
-=item I<verifycancels>
-
-Set this to true to enable a simplistic check on all cancel messages,
-attempting to verify (by simple header comparison) that the cancel message
-is from the same person as the original post. This can't be done if the
-cancel arrives before the article does, and is extremely easy to spoof.
-While this check may once have served a purpose, it's now essentially
-security via obscurity, commonly avoided by abusers, and probably not
-useful. This is a boolean value, and the default is false.
-
-=item I<wanttrash>
-
-Set this to true if you want to file articles posted to unknown newsgroups
-(newsgroups not in the F<active> file) into the C<junk> newsgroup rather
-than rejecting them. This is sometimes useful for a transit news server
-that needs to propagate articles in all newsgroups regardless if they're
-carried locally. This is a boolean value and the default is false.
-
-=item I<wipcheck>
-
-If INN is offered an article by a peer on one channel, it will return
-deferral responses (code 436) to all other offers of that article for this
-many seconds. (After this long, if the peer that offered the article
-still hasn't sent it, it will be accepted from other channels.) The
-default value is C<5> and probably doesn't need to be changed.
-
-=item I<wipexpire>
-
-How long, in seconds, to keep track of message IDs offered on a channel
-before expiring articles that still haven't been sent. The default value
-is C<10> and probably doesn't need to be changed.
-
-=item I<dontrejectfiltered>
-
-Normally innd(8) rejects incoming articles when directed to do so by any
-enabled article filters (Perl, Python, and TCL). However, this parameter
-causes such articles I<not> to be rejected; instead filtering can be
-applied on outbound articles. If this parameter is set, all articles will
-be accepted on the local machine, but articles rejected by the filter will
-I<not> be fed to any peers specified in F<newsfeeds> with the C<Af> flag.
-
-=back
-
-=head2 Article Storage
-
-These parameters affect how articles are stored on disk.
-
-=over 4
-
-=item I<cnfscheckfudgesize>
-
-If set to a value other than C<0>, the claimed size of articles in CNFS
-cycbuffs is checked against I<maxartsize> plus this value, and if larger,
-the CNFS cycbuff is considered corrupt. This can be useful as a sanity
-check after a system crash, but be careful using this parameter if you
-have changed I<maxartsize> recently. The default value is C<0>.
-
-=item I<enableoverview>
-
-Whether to write out overview data for articles. If set to false, INN
-will run much faster, but reading news from the system will be impossible
-(the server will be for news transit only). If this option is set to
-true, I<ovmethod> must also be set. This is a boolean value and the
-default is true.
-
-=item I<groupbaseexpiry>
-
-Whether to enable newsgroup-based expiry. If set to false, article expiry
-is done based on storage class of storing method. If set to true (and
-overview information is available), expiry is done by newsgroup name.
-This affects the format of F<expire.ctl>. This is a boolean value and the
-default is true.
-
-=item I<mergetogroups>
-
-Whether to file all postings to C<to.*> groups in the pseudonewsgroup
-C<to>. If this is set to true, the newsgroup C<to> must exist in the
-F<active> file or INN will not start. (See the discussion of C<to.>
-groups in innd(8) under CONTROL MESSAGES.) This is a boolean value and
-the default is false.
-
-=item I<overcachesize>
-
-How many cache slots to reserve for open overview files. If INN is
-writing overview files (see I<enableoverview>), I<ovmethod> is set to
-C<tradindexed>, and this is set to a value other than C<0>, INN will keep
-around and open that many recently written-to overview files in case more
-articles come in for those newsgroups. Every overview cache slot consumes
-two file descriptors, so be careful not to set this value too high. You
-may be able to use the C<limit> command to see how many open file
-descriptors your operating system allows. innd(8) also uses an open file
-descriptor for each incoming feed and outgoing channel or batch file, and
-if it runs out of open file descriptors it may throttle and stop accepting
-new news. The default value is C<15> (which is probably way too low if
-you have a large number of file descriptors available).
-
-This setting is ignored unless I<ovmethod> is set to C<tradindexed>.
-
-=item I<ovgrouppat>
-
-If set, restricts the overview data stored by INN to only the newsgroups
-matching this comma-separated list of wildmat expressions. Newsgroups not
-matching this setting may not be readable, and if I<groupbaseexpiry> is
-set to true and the storage method for these newsgroups does not have
-self-expire functionality, storing overview data will fail.
-The default is unset.
-
-=item I<ovmethod>
-
-Which overview storage method to use. Currently supported values are
-C<tradindexed>, C<buffindexed>, and C<ovdb>. There is no default value;
-this parameter must be set if I<enableoverview> is true (the default).
-
-=over 4
-
-=item C<buffindexed>
-
-Stores overview data and index information into buffers, which are
-preconfigured files defined in F<buffinedexed.conf>. C<buffindexed> never
-consumes additional disk space beyond that allocated to these buffers.
-
-=item C<tradindexed>
-
-Uses two files per newsgroup, one containing the overview data and one
-containing the index. Fast for readers, but slow to write to.
-
-=item C<ovdb>
-
-Stores data into a Berkeley DB database. See the ovdb(5) man page.
-
-=back
-
-=item I<hismethod>
-
-Which history storage method to use. The only currently supported
-value is C<hisv6>. There is no default value; this parameter must
-be set.
-
-=over 4
-
-=item C<hisv6>
-
-Stores history data in the INN history v6 format: history(5) text
-file and a number of dbz(3) database files; this may be in true history
-v6 format, or tagged hash format, depending on the build
-options. Separation of these two is a project which has not yet been
-undertaken.
-
-=back
-
-=item I<storeonxref>
-
-If set to true, articles will be stored based on the newsgroup names in
-the Xref: header rather than in the Newsgroups: header. This affects what
-the patterns in F<storage.conf> apply to. The primary interesting effect
-of setting this to true is to enable filing of all control messages
-according to what storage class the control pseudogroups are filed in
-rather than according to the newsgroups the control messages are posted
-to. This is a boolean value and the default is true.
-
-=item I<useoverchan>
-
-Whether to innd(8) should create overview data internally through
-libstorage(3). If set to false, innd creates overview data by itself. If
-set to true, innd does not create; instead overview data must be created
-by overchan(8) from an appropriate entry in F<newsfeeds>. Setting to true
-may be useful, if innd cannot keep up with incoming feed and the
-bottleneck is creation of overview data within innd. This is a boolean
-value and the default is false.
-
-=item I<wireformat>
-
-Only used with the tradspool storage method, this says whether to write
-articles in wire format. Wire format means storing articles with C<\r\n> at
-the end of each line and with periods at the beginning of lines doubled,
-the article format required by the NNTP protocol. Articles stored in this
-format are suitable for sending directly to a network connection without
-requiring conversion, and therefore setting this to true can make the
-server more efficient. The primary reason not to set this is if you have
-old existing software that looks around in the spool and doesn't
-understand how to read wire format. Storage methods other than tradspool
-always store articles in wire format. This is a boolean value and the
-default is false.
-
-=item I<xrefslave>
-
-Whether to act as the slave of another server. If set, INN attempts to
-duplicate exactly the article numbering of the server feeding it by
-looking at the Xref: header of incoming articles and assigning the same
-article numbers to articles as was noted in the Xref: header from the
-upstream server. The result is that clients should be able to point at
-either server interchangeably (using some load balancing scheme, for
-example) and see the same internal article numbering. Servers with this
-parameter set should generally only have one upstream feed, and should
-always have I<nnrpdposthost> set to hand locally posted articles off to
-the master server. The upstream should be careful to always feed articles
-in order (innfeed(8) can have problems with this in the event of a
-backlog). This is a boolean value and the default is false.
-
-=item I<nfswriter>
-
-For servers writing articles, determine whether the article spool is
-on NFS storage. If set, INN attempts to flush articles to the spool
-in a more timely manner, rather than relying on the operating system
-to flush things such as the CNFS article bitmaps. You should only set
-this parameter if you are attempting to use a shared NFS spool on a
-machine acting as a single writer within a cluster. This is a boolean
-value and the default is false.
-
-=item I<nfsreader>
-
-For servers reading articles, determine whether the article spool is
-on NFS storage. If set, INN will attempt to force articles and
-overviews to be read directly from the NFS spool rather than from
-cached copies. You should only set this parameter if you are
-attempting to use a shared NFS spool on a machine acting a reader a
-cluster. This is a boolean value and the default is false.
-
-=item I<nfsreaderdelay>
-
-For servers reading articles, determine whether the article spool is
-on NFS storage. If I<nfsreader> is set, INN will use the value of
-I<nfsreaderdelay> to delay the apparent arrival time of articles to
-clients by this amount; this value should be tuned based on the NFS
-cache timeouts locally. This default is 60 (1 minute).
-
-=item I<msgidcachesize>
-
-How many cache slots to reserve for Message ID to storage token
-translations. When serving overview data to clients (NEWNEWS, XOVER
-etc.), nnrpd(8) can cache the storage token associated with a Message
-ID and save the cost of looking it up in the history file; for some
-configurations setting this parameter can save more than 90% of the
-wall clock time for a session. The default value is 10000.
-
-=item I<tradindexedmmap>
-
-Whether to attempt to mmap() tradindexed overviews articles. Setting
-this to true will give better performance on most systems, but some
-systems have problems with mmap(). If this is set to false, overviews
-will be read into memory before being sent to readers. This is a
-boolean value and the default is true.
-
-=back
-
-=head2 Reading
-
-These parameters affect the behavior of INN for readers. Most of them are
-used by nnrpd(8). There are some special sets of settings that are broken
-out separately after the initial alphabetized list.
-
-=over 4
-
-=item I<allownewnews>
-
-Whether to allow use of the NEWNEWS command by clients. This command used
-to put a heavy load on the server in older versions of INN, but is now
-reasonably efficient, at least if only one newsgroup is specified by the
-client. This is a boolean value and the default is true. If you use the
-I<access> parameter in F<readers.conf>, be sure to read about the way it
-overrides I<allownewnews>.
-
-=item I<articlemmap>
-
-Whether to attempt to mmap() articles. Setting this to true will give
-better performance on most systems, but some systems have problems with
-mmap(). If this is set to false, articles will be read into memory before
-being sent to readers. This is a boolean value and the default is false.
-
-=item I<clienttimeout>
-
-How long (in seconds) a client connection can be idle before it exits.
-When setting this parameter, be aware that some newsreaders use the same
-connection for reading and posting and don't deal well with the connection
-timing out while a post is being composed. If the system isn't having a
-problem with too many long-lived connections, it may be a good idea to
-increase this value to C<3600> (an hour). The default value is C<600>
-(ten minutes).
-
-=item I<initialtimeout>
-
-How long (in seconds) B<nnrpd> will wait for the first command from a
-reader connection before dropping the connection. This is a defensive
-timeout intended to protect the news server from badly behaved reader
-clients that open and abandon a multitude of connections without every
-closing them. The default value is C<10> (ten seconds), which may need to
-be increased if many clients connect via slow network links.
-
-=item I<nnrpdcheckart>
-
-Whether B<nnrpd> should check the existence of an article before listing
-it as present in response to an NNTP command. The primary use of this
-setting is to prevent nnrpd from returning information about articles
-which are no longer present on the server but which still have overview
-data available. Checking the existence of articles before returning
-overview information slows down the overview commands, but reduces the
-number of "article is missing" errors seen by the client. This is a
-boolean value and the default is true.
-
-=item I<nnrpperlauth>
-
-This parameter is now obsolete; see "Changes to Perl Authentication
-Support for nnrpd" in F<doc/hook-perl>.
-
-=item I<nnrppythonauth>
-
-This parameter is now obsolete; see "Changes to Python Authentication and
-Access Control Support for nnrpd" in F<doc/hook-python>.
-
-=item I<noreader>
-
-Normally, innd(8) will fork a copy of nnrpd(8) for all incoming
-connections from hosts not listed in F<incoming.conf>. If this parameter
-is set to true, those connections will instead be rejected with a 502
-error code. This should be set to true for a transit-only server that
-doesn't support readers, or if nnrpd is running in daemon mode or being
-started out of inetd. This is a boolean value and the default is false.
-
-=item I<readerswhenstopped>
-
-Whether to allow readers to connect even if the server is paused or
-throttled. This is only applicable if nnrpd(8) is spawned from innd(8)
-rather than run out of inetd or in daemon mode. This is a boolean value
-and the default is false.
-
-=item I<readertrack>
-
-Whether to enable the tracking system for client behavior. Tracked
-information is recorded to I<pathlog>/tracklogs/log-ID, where ID is
-determined by nnrpd's PID and launch time.) Currently the information
-recorded includes initial connection and posting; only information about
-clients listed in F<nnrpd.track> is recorded. This is a boolean value and
-the default is false.
-
-=item I<nnrpdflags>
-
-When nnrpd(8) is spawned from innd(8), these flags are passed as
-arguments to the nnrpd process. This setting does not affect instances
-of nnrpd that are started in daemon mode, or instances that are started
-via another listener process such as inetd(8) or xinetd(8). Shell
-quoting and metacharacters are not supported. This is a string value
-and the default is unset.
-
-=item I<nnrpdloadlimit>
-
-If set to a value other than C<0>, connections to nnrpd will be refused
-if the system load average is higher than this value. The default value
-is C<16>.
-
-=back
-
-INN has optional support for generating keyword information automatically
-from article body text and putting that information in overview for the
-use of clients that know to look for it. The following parameters control
-that feature.
-
-This may be too slow if you're taking a substantial feed, and probably
-will not be useful for the average news reader; enabling this is not
-recommended unless you have some specific intention to take advantage of
-it.
-
-=over 4
-
-=item I<keywords>
-
-Whether the keyword generation support should be enabled. This is a
-boolean value and the default is false.
-
-FIXME: Currently, support for keyword generation is configured into INN
-semi-randomly (based on whether configure found the regex library); it
-should be an option to configure and that option should be mentioned here.
-
-=item I<keyartlimit>
-
-Articles larger than this value in bytes will not have keywords generated
-for them (since it would take too long to do so). The default value is
-C<100000> (approximately 100 KB).
-
-=item I<keylimit>
-
-Maximum number of bytes allocated for keyword data. If there are more
-keywords than will fit into this many bytes when separated by commas, the
-rest are discarded. The default value is C<512>.
-
-=item I<keymaxwords>
-
-Maximum number of keywords that will be generated for an article. (The
-keyword generation code will attempt to discard "noise" words, so the
-number of keywords actually writen into the overview will usually be
-smaller than this even if the maximum number of keywords is found.) The
-default value is C<250>.
-
-=back
-
-=head2 Posting
-
-These parameters are only used by nnrpd(8), inews(1), and other programs
-that accept or generate postings. There are some special sets of settings
-that are broken out separately after the initial alphabetized list.
-
-=over 4
-
-=item I<addnntppostingdate>
-
-Whether to add an NNTP-Posting-Date: header to all local posts. This is a
-boolean value and the default is true. Note that INN either does not add
-this header or adds the name or IP address of the client. There is no
-intrinsic support for obfuscating the name of the client. That has to be
-done with a user-written Perl filter, if desired.
-
-=item I<addnntppostinghost>
-
-Whether to add an NNTP-Posting-Host: header to all local posts giving the
-FQDN or IP address of the system from which the post was received. This
-is a boolean value and the default is true.
-
-=item I<checkincludedtext>
-
-Whether to check local postings for the ratio of new to quoted text and
-reject them if that ratio is under 50%. Included text is recognized by
-looking for lines beginning with C<E<gt>>, C<|>, or C<:>. This is a
-boolean value and the default is false.
-
-=item I<complaints>
-
-The value of the X-Complaints-To: header added to all local posts. The
-default is the newsmaster's e-mail address. (If the newsmaster, selected
-at configure time and defaulting to C<usenet>, doesn't contain C<@>, the
-address will consist of the newsmaster, a C<@>, and the value of
-I<fromhost>.)
-
-=item I<fromhost>
-
-Contains a domain used to construct e-mail addresses. The address of the
-local news administrator will be given as <user>@I<fromhost>, where <user>
-is the newsmaster user set at compile time (C<usenet> by default). This
-setting will also be used by mailpost(8) to fully qualify addresses and by
-inews(1) to generate the Sender: header (and From: header if missing).
-The value of the FROMHOST environment variable, if set, overrides this
-setting. The default is the fully-qualified domain name of the local
-host.
-
-=item I<localmaxartsize>
-
-The maximum article size (in bytes) for locally posted articles. Articles
-larger than this will be rejected. A value of C<0> allows any size of
-article, but note that B<nnrpd> and B<innd> will crash if system memory is
-exceeded. See also I<maxartsize>, which applies to all articles including
-those posted locally. The default value is C<1000000> (approximately 1
-MB).
-
-=item I<moderatormailer>
-
-The address to which to send submissions for moderated groups. It is only
-used if the F<moderators> file doesn't exist, or if the moderated group to
-which an article is posted is not matched by any entry in that file, and
-takes the same form as an entry in the F<moderators> file. In most cases,
-C<%s@moderators.isc.org> is a good value for this parameter (C<%s> is
-expanded into a form of the newsgroup name). See moderators(5) for more
-details about the syntax. The default is unset. If this parameter isn't
-set and an article is posted to a moderated group that does not have a
-matching entry in the F<moderators> file, the posting will be rejected
-with an error.
-
-=item I<nnrpdauthsender>
-
-Whether to generate a Sender: header based on reader authentication. If
-this parameter is set, a Sender: header will be added to local posts
-containing the identity assigned by F<readers.conf>. If the assigned
-identity does not include an C<@>, the reader's hostname is used. If this
-parameter is set but no identity is be assigned, the Sender: header will
-be removed from all posts even if the poster includes one. This is a
-boolean value and the default is false.
-
-=item I<nnrpdposthost>
-
-If set, nnrpd(8) and rnews(1) will pass all locally posted articles to the
-specified host rather than trying to inject them locally. See also
-I<nnrpdpostport>. This should always be set if I<xrefslave> is true. The
-default value is unset.
-
-=item I<nnrpdpostport>
-
-The port on the remote server to connect to to post when I<nnrpdposthost>
-is used. The default value is C<119>.
-
-=item I<organization>
-
-What to put in the Organization: header if it is left blank by the poster.
-The value of the ORGANIZATION environment variable, if set, overrides this
-setting. The default is unset, which tells INN not to insert an
-Organization: header.
-
-=item I<spoolfirst>
-
-If true, nnrpd(8) will spool new articles rather than attempting to send
-them to innd(8). If false, nnrpd will spool articles only if it receives
-an error trying to send them to innd. Setting this to true can be useful
-if nnrpd must respond as fast as possible to the client; however, when
-set, articles will not appear to readers until they are given to innd.
-nnrpd won't do this; C<rnews -U> must be run periodically to take the
-spooled articles and post them. This is a boolean value and the default
-is false.
-
-=item I<strippostcc>
-
-Whether to strip To:, Cc:, and Bcc: headers out of all local posts via
-nnrpd(8). The primary purpose of this setting is to prevent abuse of the
-news server by posting to a moderated group and including To: or Cc:
-headers in the post so that the news server will send the article to
-arbitrary addresses. INN now protects against this abuse in other ways
-provided I<mta> is set to a command that includes C<%s> and honors it, so
-this is generally no longer needed. This is a boolean value and the
-default is false.
-
-=back
-
-nnrpd(8) has support for controlling high-volume posters via an
-exponential backoff algorithm, as configured by the following parameters.
-
-Exponential posting backoff works as follows: News clients are indexed by
-IP address (or username, see I<backoffauth> below). Each time a post is
-received from an IP address, the time of posting is stored (along with the
-previous sleep time, see below). After a configurable number of posts in
-a configurable period of time, nnrpd(8) will activate posting backoff and
-begin to sleep for increasing periods of time before actually posting
-anything. Posts will still be accepted, but at an increasingly reduced
-rate.
-
-After backoff has been activated, the length of time to sleep is computed
-based on the difference in time between the last posting and the current
-posting. If this difference is less than I<backoffpostfast>, the new
-sleep time will be 1 + (previous sleep time * I<backoffk>). If this
-difference is less than I<backoffpostslow> but greater than
-I<backoffpostfast>, then the new sleep time will equal the previous sleep
-time. If this difference is greater than I<backoffpostslow>, the new
-sleep time is zero and posting backoff is deactivated for this poster.
-
-Exponential posting backoff will not be enabled unless I<backoffdb> is set
-and I<backoffpostfast> and I<backoffpostslow> are set to something other
-than their default values.
-
-Here are the parameters that control exponential posting backoff:
-
-=over 4
-
-=item I<backoffauth>
-
-Whether to index posting backoffs by user rather than by source IP
-address. You must be using authentication in nnrpd(8) for a value of true
-to have any meaning. This is a boolean value and the default is false.
-
-=item I<backoffdb>
-
-The path to a directory, writeable by the news user, that will contain the
-backoff database. There is no default for this parameter; you must
-provide a path to a creatable or writeable directory to enable exponential
-backoff.
-
-=item I<backoffk>
-
-The amount to multiply the previous sleep time by if the user is still
-posting too quickly. A value of C<2> will double the sleep time for each
-excessive post. The default value is C<1>.
-
-=item I<backoffpostfast>
-
-Postings from the same identity that arrive in less than this amount of
-time (in seconds) will trigger increasing sleep time in the backoff
-algorithm. The default value is C<0>.
-
-=item I<backoffpostslow>
-
-Postings from the same identity that arrive in greater than this amount of
-time (in seconds) will reset the backoff algorithm. Another way to look
-at this constant is to realize that posters will be allowed to generate at
-most 86400/I<backoffpostslow> posts per day. The default value is C<1>.
-
-=item I<backofftrigger>
-
-This many postings are allowed before the backoff algorithm is triggered.
-The default value is C<10000>.
-
-=back
-
-=head2 Monitoring
-
-These parameters control the behavior of innwatch(8), the program that
-monitors INN and informs the news administrator if anything goes wrong
-with it.
-
-=over 4
-
-=item I<doinnwatch>
-
-Whether to start innwatch(8) from rc.news. This is a boolean value, and
-the default is true.
-
-=item I<innwatchbatchspace>
-
-Free space in I<pathoutgoing>, in inndf(8) output units (normally
-kilobytes), at which innd(8) will be throttled by innwatch(8), assuming a
-default F<innwatch.ctl>. The default value is C<800>.
-
-=item I<innwatchlibspace>
-
-Free space in I<pathdb>, in inndf(8) output units (normally kilobytes), at
-which innd(8) will be throttled by innwatch(8), assuming a default
-F<innwatch.ctl>. The default value is C<25000>.
-
-=item I<innwatchloload>
-
-Load average times 100 at which innd(8) will be restarted by innwatch(8)
-(undoing a previous pause or throttle), assuming a default
-F<innwatch.ctl>. The default value is C<1000> (that is, a load average of
-10.00).
-
-=item I<innwatchhiload>
-
-Load average times 100 at which innd(8) will be throttled by innwatch(8),
-assuming a default F<innwatch.ctl>. The default value is C<2000> (that
-is, a load average of 20.00).
-
-=item I<innwatchpauseload>
-
-Load average times 100 at which innd(8) will be paused by innwatch(8),
-assuming a default F<innwatch.ctl>. The default value is C<1500> (that
-is, a load average of 15.00).
-
-=item I<innwatchsleeptime>
-
-How long (in seconds) innwatch(8) will sleep between each check of INN.
-The default value is C<600>.
-
-=item I<innwatchspoolnodes>
-
-Free inodes in I<patharticles> at which innd(8) will be throttled by
-innwatch(8), assuming a default F<innwatch.ctl>. The default value is
-C<200>.
-
-=item I<innwatchspoolspace>
-
-Free space in I<patharticles> and I<pathoverview>, in inndf(8) output
-units (normally kilobytes), at which innd(8) will be throttled by
-innwatch(8), assuming a default F<innwatch.ctl>. The default value is
-C<8000>.
-
-=back
-
-=head2 Logging
-
-These parameters control what information INN logs.
-
-=over 4
-
-=item I<docnfsstat>
-
-Whether to start cnfsstat(8) when innd(8) is started. cnfsstat will log
-the status of all CNFS cycbuffs to syslog on a periodic basis (frequency
-is the default for C<cnfsstat -l>, currently 600 seconds). This is a
-boolean value and the default is false.
-
-=item I<logartsize>
-
-Whether the size of accepted articles (in bytes) should be written to the
-article log file. This is useful for flow rate statistics and is
-recommended. This is a boolean value and the default is true.
-
-=item I<logcancelcomm>
-
-Set this to true to log C<ctlinnd cancel> commands to syslog. This is a
-boolean value and the default is false.
-
-=item I<logcycles>
-
-How many old logs scanlogs(8) keeps. scanlogs(8) is generally run by
-news.daily(8) and will archive compressed copies of this many days worth
-of old logs. The default value is C<3>.
-
-=item I<logipaddr>
-
-Whether the verified name of the remote feeding host should be logged to
-the article log for incoming articles rather than the last entry in the
-Path: header. The only reason to ever set this to false is due to some
-interactions with F<newsfeeds> flags; see newsfeeds(5) for more
-information. This is a boolean value and the default is true.
-
-=item I<logsitename>
-
-Whether the names of the sites to which accepted articles will be sent
-should be put into the article log file. This is useful for debugging and
-statistics and can be used by newsrequeue(8). This is a boolean value and
-the default is true.
-
-=item I<nnrpdoverstats>
-
-Whether nnrpd overview statistics should be logged via syslog. This can
-be useful for measuring overview performance. This is a boolean value and
-the default is false.
-
-=item I<nntpactsync>
-
-How many articles to process on an incoming channel before logging the
-activity. The default value is C<200>.
-
-FIXME: This is a rather unintuitive name for this parameter.
-
-=item I<nntplinklog>
-
-Whether to put the storage API token for accepted articles (used by
-nntplink) in the article log. This is a boolean value and the default is
-false.
-
-=item I<stathist>
-
-Where to write history statistics for analysis with
-F<contrib/stathist.pl>; this can be modified with ctlinnd(8) while innd is
-running. Logging does not occur unless a path is given, and there is no
-default value.
-
-=item I<status>
-
-How frequently (in seconds) innd(8) should write out a status report. The
-report is written to I<pathhttp>/inn_status.html. If this is set to C<0> or
-C<false>, status reporting is disabled. The default value is C<0>.
-
-=item I<timer>
-
-How frequently (in seconds) innd(8) should report performance timings to
-syslog. If this is set to C<0>, performance timing is disabled. Enabling
-this is highly recommended, and innreport(8) can produce a nice summary of
-the timings. If set to C<0>, performance timings in nnrpd(8) are also
-disabled, although nnrpd always reports statistics on exit and therefore
-any non-zero value is equivalent for it. The default value is C<0>.
-
-=back
-
-=head2 System Tuning
-
-The following parameters can be modified to tune the low-level operation
-of INN. In general, you shouldn't need to modify any of them except
-possibly I<rlimitnofile> unless the server is having difficulty.
-
-=over 4
-
-=item I<badiocount>
-
-How many read or write failures until a channel is put to sleep or
-closed. The default value is C<5>.
-
-=item I<blockbackoff>
-
-Each time an attempted write returns EAGAIN or EWOULDBLOCK, innd(8) will
-wait for an increasing number of seconds before trying it again. This is
-the multiplier for the sleep time. If you're having trouble with channel
-feeds not keeping up, it may be good to change this value to C<2> or C<3>,
-since then when the channel fills INN will try again in a couple of
-seconds rather than waiting two minutes. The default value is C<120>.
-
-=item I<chaninacttime>
-
-The time (in seconds) to wait between noticing inactive channels. The
-default value is C<600>.
-
-=item I<chanretrytime>
-
-How many seconds to wait before a channel restarts. The default value is
-C<300>.
-
-=item I<datamovethreshold>
-
-The threshold for deciding whether to move already-read data to the top of
-buffer or extend the buffer. The buffer described here is used for reading
-NNTP data. Increasing this value may improve performance, but it should
-not be increased on Systems with insufficient memory. Permitted values
-are between C<0> and C<1048576> (out of range values are treated as
-C<1048576>) and the default value is C<8192>.
-
-=item I<icdsynccount>
-
-How many article writes between updating the active and history files.
-The default value is C<10>.
-
-=item I<keepmmappedthreshold>
-
-When using buffindexed, retrieving overview data (that is, responding to
-XOVER or running expireover) causes mmapping of all overview data blocks
-which include requested overview data for newsgroup. But for high volume
-newsgroups like control.cancel, this may cause too much mmapping at once
-leading to system resource problems. To avoid this, if the amount to be
-mmapped exceeds I<keepmmappedthreshold> (in KB), buffindexed mmap's just
-one overview block (8 KB). This parameter is specific to buffindexed
-overview storage method. The default value is C<1024> (1 MB).
-
-=item I<maxcmdreadsize>
-
-If set to anything other than C<0>, maximum buffer size (in bytes) for
-reading NNTP command will have this value. It should not be large on
-systems which are slow to process and store articles, as that would lead
-to innd(8) spending a long time on each channel and keeping other channels
-waiting. The default value is BUFSIZ defined in stdio.h (C<1024> in most
-environments, see setbuf(3)).
-
-=item I<maxforks>
-
-How many times to attempt a fork(2) before giving up. The default value
-is C<10>.
-
-=item I<nicekids>
-
-If set to anything other than C<0>, all child processes of innd(8) will
-have this nice(2) value. This is usually used to give all child processes
-of innd(8) a lower priority (higher nice value) so that innd(8) can get
-the lion's share of the CPU when it needs it. The default value is C<4>.
-
-=item I<nicenewnews>
-
-If set to anything greater than C<0>, all nnrpd(8) processes that receive
-and process a NEWNEWS command will nice(2) themselves to this value
-(giving other nnrpd processes a higher priority). The default value is
-C<0>. Note that this value will be ignored if set to a lower value than
-I<nicennrpd> (or I<nicekids> if nnrpd(8) is spawned from innd(8)).
-
-=item I<nicennrpd>
-
-If set to anything greater than C<0>, all nnrpd(8) processes will nice(1)
-themselves to this value. This gives other news processes a higher
-priority and can help overchan(8) keep up with incoming news (if that's
-the object, be sure overchan(8) isn't also set to a lower priority via
-I<nicekids>). The default value is C<0>, which will cause nnrpd(8)
-processes spawned from innd(8) to use the value of I<nicekids>, while
-nnrpd(8) run as a daemon will use the system default priority. Note that
-for nnrpd(8) processes spawned from innd(8), this value will be ignored if
-set to a value lower than I<nicekids>.
-
-=item I<pauseretrytime>
-
-Wait for this many seconds before noticing inactive channels.
-Wait for this many seconds before innd processes articles when it's paused
-or the number of channel write failures exceeds I<badiocount>. The
-default value is C<300>.
-
-=item I<peertimeout>
-
-How long (in seconds) an innd(8) incoming channel may be inactive before
-innd closes it. The default value is C<3600> (an hour).
-
-=item I<rlimitnofile>
-
-The maximum number of file descriptors that innd(8) or innfeed(8) can have
-open at once. If innd(8) or innfeed(8) attempts to open more file
-descriptors than this value, it is possible the program may throttle or
-otherwise suffer reduced functionality. The number of open file
-descriptors is roughly the maximum number of incoming feeds and outgoing
-batches for innd(8) and the number of outgoing streams for innfeed(8). If
-this parameter is set to a negative value, the default limit of the
-operating system will be used; this will normally be adequate on systems
-other than Solaris. Nearly all operating systems have some hard maximum
-limit beyond which this value cannot be raised, usually either 128, 256,
-or 1024. The default value of this parameter is C<-1>. Setting it to
-C<256> on Solaris systems is highly recommended.
-
-=back
-
-=head2 Paths and File Names
-
-=over 4
-
-=item I<patharchive>
-
-Where to store archived news. The default value is I<pathspool>/archive.
-
-=item I<patharticles>
-
-The path to where the news articles are stored (for storage methods other
-than CNFS). The default value is I<pathspool>/articles.
-
-=item I<pathbin>
-
-The path to the news binaries. The default value is I<pathnews>/bin.
-
-=item I<pathcontrol>
-
-The path to the files that handle control messages. The code for handling
-each separate type of control message is located here. Be very careful
-what you put in this directory with a name ending in C<.pl>, as it can
-potentially be a severe security risk. The default value is
-I<pathbin>/control.
-
-=item I<pathdb>
-
-The path to the database files used and updated by the server (currently,
-F<active>, F<active.times>, F<history> and its indices, and
-F<newsgroups>). The default value is I<pathnews>/db.
-
-=item I<pathetc>
-
-The path to the news configuration files. The default value is
-I<pathnews>/etc.
-
-=item I<pathfilter>
-
-The path to the Perl, Tcl, and Python filters. The default value is
-I<pathbin>/filter.
-
-=item I<pathhttp>
-
-Where any HTML files (such as periodic status reports) are placed. If the
-news reports should be available in real-time on the web, the files in
-this directory should be served by a web server. The default value is
-the value of I<pathlog>.
-
-=item I<pathincoming>
-
-Location where incoming batched news is stored. The default value is
-I<pathspool>/incoming.
-
-=item I<pathlog>
-
-Where the news log files are written. The default value is
-I<pathnews>/log.
-
-=item I<pathnews>
-
-The home directory of the news user and usually the root of the news
-hierarchy. There is no default; this parameter must be set in F<inn.conf>
-or INN will refuse to start.
-
-=item I<pathoutgoing>
-
-Default location for outgoing feed files. The default value is
-I<pathspool>/outgoing.
-
-=item I<pathoverview>
-
-The path to news overview files. The default value is
-I<pathspool>/overview.
-
-=item I<pathrun>
-
-The path to files required while the server is running and run-time state
-information. This includes lock files and the sockets for communicating
-with innd(8). This directory and the control sockets in it should be
-protected from unprivileged users other than the news user. The default
-value is I<pathnews>/run.
-
-=item I<pathspool>
-
-The root of the news spool hierarchy. This used mostly to set the
-defaults for other parameters, and to determine the path to the backlog
-directory for innfeed(8). The default value is I<pathnews>/spool.
-
-=item I<pathtmp>
-
-Where INN puts temporary files. For security reasons, this is not the
-same as the system temporary files directory (INN creates a lot of
-temporary files with predictable names and does not go to particularly
-great lengths to protect against symlink attacks and the like; this
-is safe provided that normal users can't write into its temporary
-directory). The default value is set at configure time and defaults to
-I<pathnews>/tmp.
-
-=back
-
-=head1 EXAMPLE
-
-Here is a very minimalist example that only sets those parameters that are
-required.
-
- mta: /usr/lib/sendmail -oi -oem %s
- ovmethod: tradindexed
- pathhost: news.example.com
- pathnews: /usr/local/news
- hismethod: hisv6
-
-For a more comprehensive example, see the sample F<inn.conf> distributed
-with INN and installed as a starting point; it contains all of the default
-values for reference.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews and since
-modified, updated, and reorganized by innumerable other people.
-
-$Id: inn.conf.pod 7751 2008-04-06 14:35:40Z iulius $
-
-=head1 SEE ALSO
-
-inews(1), innd(8), innwatch(8), nnrpd(8), rnews(1).
-
-Nearly every program in INN uses this file to one degree or another. The
-above are just the major and most frequently mentioned ones.
+++ /dev/null
-=head1 NAME
-
-innconfval - Get configuration parameters from inn.conf
-
-=head1 SYNOPSIS
-
-B<innconfval> [B<-pstv>] [B<-i> I<file>] [I<parameter> ...]
-
-B<innconfval> B<-C> [B<-i> I<file>]
-
-=head1 DESCRIPTION
-
-B<innconfval> normally prints the values of the parameters specified on
-the command line. By default, it just prints the parameter values, but if
-B<-p>, B<-s>, or B<-t> are given, it instead prints the parameter and
-value in the form of a variable assignment in Perl, Bourne shell, or Tcl
-respectively. If no parameters are specifically requested, B<innconfval>
-prints out all parameter values (this isn't particularly useful unless one
-of B<-p>, B<-s>, or B<-t> were specified).
-
-All parameters are taken from F<inn.conf> except for I<version>, which is
-always the version string of INN.
-
-If given the B<-C> option, B<innconfval> instead checks F<inn.conf>,
-reporting any problems found to standard error. B<innconfval> will exit
-with status 0 if no problems are found and with status 1 otherwise.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-C>
-
-Check F<inn.conf> rather than printing out the values of parameters.
-
-=item B<-i> I<file>
-
-Use I<file> as the source configuration file rather than F<inn.conf>.
-I<file> must be a valid F<inn.conf> file and will be parsed the same as
-F<inn.conf> would be.
-
-=item B<-p>
-
-Print out parameters as Perl assignment statements. The variable name
-will be the same as the F<inn.conf> parameter, and string values will be
-enclosed in single quotes with appropriate escaping. Boolean values will
-be mapped to C<true> or C<false>, and string parameters that are set to
-NULL will be mapped to empty strings.
-
-=item B<-s>
-
-Print out parameters as Bourne shell assignment statements. The variable
-name will be the F<inn.conf> parameter name in all capitals, and all
-variables will be exported. String values will be enclosed in single
-quotes with appropriate escaping, and boolean values will be mapped to
-C<true> or C<false>. String parameters that are set to NULL will be
-mapped to empty strings.
-
-=item B<-t>
-
-Print out parameters as Tcl assignment statements. The variable name will
-be the same as the F<inn.conf> parameter name but with C<inn_> prepended,
-and string variables will be escaped appropriately. Boolean values will
-be mapped to C<true> or C<false> and string parameters that are set to
-NULL will be mapped to empty strings.
-
-=item B<-v>
-
-Print INN's version. This is equivalent to C<innconfval version>.
-
-=back
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-
-$Id: innconfval.pod 5962 2002-12-08 19:52:13Z rra $
-
-=head1 SEE ALSO
-
-inn.conf(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-innd - InterNetNews daemon
-
-=head1 SYNOPSIS
-
-B<innd> [B<-aCdfNrsu>] [B<-c> I<days>] [B<-H> I<count>] [B<-i> I<count>]
-[B<-I> I<address>] [B<-l> I<size>] [B<-m> I<mode>] [B<-n> I<flag>]
-[B<-o> I<count>] [B<-p> I<fd>] [B<-P> I<port>] [B<-t> I<timeout>]
-[B<-T> I<count>] [B<-X> I<seconds>]
-
-=head1 DESCRIPTION
-
-B<innd>, the InterNetNews daemon, handles all incoming NNTP feeds,
-coordinates the storage, retransmission, and overview generation for all
-accepted articles, and manages the active(5) and history(5) databases. It
-handles incoming connections on the NNTP port, and also creates and
-listens to a local Unix-domain stream socket in order to receive articles
-from local processes such as nnrpd(8) and rnews(1).
-
-As the master daemon, B<innd> should generally be started at boot and be
-always running. It listens to a Unix-domain datagram socket for commands
-to control its activites, commands that can be sent using ctlinnd(8). The
-current status of B<innd> can be obtained by running C<ctlinnd mode>, or
-for more detailed output, innstat(8).
-
-B<innd> can be in one of three operating modes: running, paused, or
-throttled. Running is the normal mode; when the server is throttled, it
-closes connections and rejects new ones. Paused is like a temporary
-throttle, suspending B<innd>'s activities but not causing the server to
-shut down existing connections. The mode is normally changed via
-ctlinnd(8), either by various automated processes (such as nightly article
-expiration) or manually by the news administrator, but B<innd> will also
-throttle itself if it encounters ENOSPC errors in writing data or an
-excessive number of I/O errors (among other problems).
-
-B<innd> normally takes care of spawning nnrpd(8) to handle connections
-from news reading clients, but it can be run on a separate port from
-nnrpd(8) so that feed connections and news reading connections are handled
-separately (this can often be faster). Normally, B<innd> listens on port
-119, the assigned port for NNTP; if it is desireable to run B<innd> and
-nnrpd(8) on separate ports, it's recommended that nnrpd(8) be given port
-119 (since many news reading clients connect only to that port) and that
-port 433 be used for B<innd>.
-
-The primary configuration files that control B<innd>'s activities are
-F<incoming.conf>, which specifies what remote sites B<innd> will accept
-connections from, F<newsfeeds>, which specifies what is to be done with
-incoming articles besides storing them, and F<inn.conf>, which sets a wide
-variety of configuration parameters. Some parameters in inn.conf(5) can
-also be set with command-line flags; for these, the command-line flags
-take precedence if used.
-
-B<innd> should normally not run directly. It must run as the news user or
-all sorts of file ownership problems may result, and normally the port it
-listens on (119 or 433) is privileged and must be opened by root.
-Instead, B<innd> should normally be started via inndstart(8), a small
-setuid-root program that opens the appropriate port, cleans up the
-environment, changes to the news user, and then runs B<innd>, passing
-along any command-line arguments.
-
-To use IPv6, B<innd> must be started by B<inndstart>.
-
-=head1 OPTIONS
-
-For the options below that override F<inn.conf> settings, see inn.conf(5)
-for the default values if neither the F<inn.conf> setting nor the
-command-line option is given.
-
-=over 4
-
-=item B<-a>
-
-By default, if a host connects to B<innd> but is not listed in
-F<incoming.conf>, the connection is handed off to B<nnrpd> (or rejected if
-I<noreader> is set in F<inn.conf>). If B<-a> is given, F<incoming.conf>
-is ignored and any host can connect and transfer articles. This flag
-should never be used with an accessible server connected to Usenet; it
-would open the server up for all sorts of abuse.
-
-=item B<-c> I<days>
-
-B<innd> normally rejects any article that is older (in days) than the
-value of I<artcutoff> in F<inn.conf>. This option, if given, overrides
-the value of that setting. If I<days> is 0, this check is suppressed and
-B<innd> will accept articles regardless of how old they are.
-
-=item B<-C>
-
-This flag tells B<innd> to accept and propagate but not actually process
-cancel or supersede messages. This is intended for sites concerned about
-abuse of cancels, or that wish to use another cancel mechanism with
-stronger authentication.
-
-=item B<-d>, B<-f>
-
-B<innd> normally puts itself into the background, points its standard
-output and error to log files, and disassociates itself from the
-terminal. Using B<-d> prevents all of this, resulting in log messages
-being written to standard output; this is generally useful only for
-debugging. Using B<-f> prevents the backgrounding and disassociation but
-still redirects output; it may be useful if you want to monitor B<innd>
-with a program that would be confused by forks.
-
-=item B<-H> I<count>, B<-T> I<count>, B<-X> I<seconds>
-
-These flags control the number of connections per minute that are allowed.
-This code is meant to protect your server from newsreader clients that
-make too many connections per minute (and therefore these flags are
-probably only useful when B<innd> is spawning B<nnrpd>). You probably
-should not use these options unless you're having problems. The table
-used for this check is fixed at 128 entries and is used as a ring; the
-size was chosen to make calculating the index easy and to be fairly sure
-that it won't run out of space. In practice, it is unlikely that even
-half the table will be used at any given moment.
-
-The B<-H> flag limits the number of times a host is allowed to connect to
-the server per the time interval given by B<-X>. The default is C<2>.
-
-The B<-T> flag limits the total number of incoming connections per the
-time interval given by B<-X>. The maximum value is C<128>, and the
-default is C<60>.
-
-=item B<-i> I<count>
-
-B<innd> normally allows a maximum number of concurrent NNTP connections
-given by the value of I<maxconnections> in F<inn.conf>. This option, if
-given, overrides the value of that setting. If I<count> is C<0>, this
-check is suppressed.
-
-=item B<-I> I<address>
-
-Normally if B<innd> itself binds to a port, it lets the operating system
-pick the source IP address (unless I<bindaddress> is set in F<inn.conf>).
-If this option is given, it specifies the IP address that INN should bind
-as. This is only relevant for servers with multiple local IP addresses.
-The IP address must be in dotted quad (C<nnn.nnn.nnn.nnn>) format.
-
-This option is rarely useful since B<innd> should not be binding to a
-port itself. Instead, use inndstart(8) and its analgous B<-I> option.
-
-=item B<-l> I<size>
-
-B<innd> normally rejects any article larger than the value of
-I<maxartsize> in F<inn.conf>. This option, if given, overrides the value
-of that setting and specifies a maximum article size of I<size>. If
-I<size> is C<0>, this check is suppressed.
-
-=item B<-m> I<mode>
-
-Normally B<innd> starts in the C<running> mode. If this option is given,
-it specifies what mode B<innd> should start in. I<mode> should begin with
-one of C<g>, C<p>, or C<t>, and the starting mode will be set to
-C<running>, C<paused>, or C<throttled>, respectively, based on that
-initial letter. (C<g> is short for C<go>.)
-
-=item B<-N>
-
-If this option is given, any filters (Perl, Tcl, or Python) are disabled
-before B<innd> starts (normally, filters default to being enabled). The
-filters can be enabled after B<innd> has started with ctlinnd(8).
-
-=item B<-n> I<flag>
-
-Whether B<innd> allows (and hands off to B<nnrpd>) reader connections
-while paused or throttled is normally determined by the value of
-I<readerswhenstopped> in F<inn.conf>). This option, if given, overrides
-that value. If I<flag> is C<n>, B<innd> will not allow readers if it is
-paused or throttled. If I<flag> is C<y>, readers will be allowed
-regardless of B<innd>'s operating mode.
-
-=item B<-o> I<count>
-
-This flag limits the number of file descriptors that are available for
-outgoing file feeds. The default is the number of available file
-descriptors minus some reserved for internal use (which could potentially
-starve B<innd> of descriptors to use for accepting new connections). If
-B<innd> has more file feeds than I<count>, some of them will be buffered
-and only written out periodically.
-
-Normally you never need to use this option, since the number of outgoing
-feeds is fixed, being the number of file feeds configured in F<newsfeeds>,
-and is generally small (particularly given that innfeed(8) is now used for
-most outgoing feeds at large sites).
-
-=item B<-p> I<fd>
-
-If this flag is given, B<innd> expects the file descriptor given by I<fd>
-to already be open and bound to the appropriate local port and to be
-suitable for listening to for incoming connections. This is how
-B<inndstart> tells B<innd> which open file descriptor is the network
-connection. If this flag is not given, B<innd> will attempt to open its
-network socket itself. B<inndstart> always passes this flag to B<innd>.
-
-=item B<-P> I<port>
-
-The port B<innd> should listen on is normally given by the value of
-I<port> in F<inn.conf>. This option, if given, overrides that value and
-specifies the port that B<innd> should bind to. This option is rarely
-useful since B<innd> normally does not bind itself; instead the analgous
-B<-P> option to inndstart(8) should be used. Since B<innd> should never
-be run as root, I<port> has to be a non-privileged port (one larger than
-1024).
-
-=item B<-r>
-
-Instructs B<innd> to renumber the F<active> file after starting, just as
-if a C<ctlinnd renumber> command were sent.
-
-=item B<-s>
-
-Just check the syntax of the F<newsfeeds> file and exit. B<innd> will
-exit with a non-zero status if any errors are found; the actual errors
-will be reported via syslog(3).
-
-=item B<-t> I<seconds>
-
-Normally, B<innd> will flush any changes to history and the active file
-after 300 seconds of inactivity. This option changes that timeout to
-I<seconds>.
-
-=item B<-u>
-
-The news log (the trace information for every article accepted by B<innd>)
-is normally buffered. This option changes the log to be unbuffered.
-
-=back
-
-=head1 CONTROL MESSAGES
-
-Arriving articles that have a Control: header are called "control
-messages". Except for cancel messages, these messages are handled by
-controlchan(8) via a feed set up in F<newsfeeds>.
-
-(Cancel messages update the history database, so they must be handled
-internally; the cost of syncing, locking, then unlocking would be too high
-given the number of cancel messages that are received. Note that if an
-article is cancelled before it is received by the news server, it will
-be rejected when it arrives since the history database has been updated;
-it is useful for rejecting spam before it arrives.)
-
-The distribution of control messages is different than that of standard
-articles. Control messages are normally filed into the pseudo-newsgroup
-named C<control> regardless of which newsgroup they were actually posted
-to. If, however, a C<control.>I<command> newsgroup exists that matches
-the control command, the control message will be filed into that group
-instead. For example, a newgroup control message will be filed in
-C<control.newgroup> if that group exists; otherwise, it will be filed in
-C<control>.
-
-If you want to specifically feed all control messages to a given site
-regardless of whether the control messages would affect the newsgroups
-you're feeding that site, you can put the appropriate control newsgroup in
-the subscription list. For example, to feed all cancel messages to a
-given remote site (normally a bad idea), add C<control.cancel> to its
-subscription list. Normally it's best to exclude the control newsgroups
-from feeds to keep from sending your peers more control messages than they
-care about. That's why the F<newsfeeds> pattern C<!control,!control.*>
-is as often as not specified (adding this pattern do not prevent control
-messages which affect the newsgroups fed to a site from being sent to it).
-
-checkgroups, newgroup and rmgroup control messages receive additional special
-treatment. If one of these control messages is approved and posted to the
-newsgroup being created or removed (or to the admin group to which the
-checkgroups is posted), the message will be sent to all sites
-whose subscription patterns would cause them to receive articles posted to
-that group. For example, if a newgroup control message for a nonexistent
-newsgroup C<news.admin.meow> is received, it will be sent to any site
-whose subscription pattern would cause it to receive C<news.admin.meow> if
-that newsgroup existed (such as a pattern of C<news.admin.*>). For this
-reason, it is correct to post newgroup messages to the newsgroup that the
-control message would create. It is I<not> generally correct to crosspost
-newgroup messages to some "well-propagated" newsgroup; not only will this
-not actually improve their propagation to sites that want such control
-messages, but it will also cause sites that do not want those control
-messages to receive them. Therefore, assuming that a newgroup control
-message is sent to the group C<news.admin.meow> (specified in the
-Newsgroups: header) in order to create the group C<news.admin.meow>,
-the sites with the following subscription patterns will receive it:
-
- *,@news.*
- news.*
- news.*,!control,!control.*
- control,control.*
-
-but the sites with the following subscription patterns will not receive it:
-
- *,@news.*,!control,!control.*
- comp.*,@news.*
-
-If a control message is posted to a group whose name ends with the four
-characters C<.ctl>, this suffix is stripped off and the control message is
-propagated as if it were posted to the base group. For example, a cancel
-message posted to C<news.admin.ctl> will be sent to all sites that
-subscribe to C<control.cancel> (or C<control> if that newsgroup doesn't
-exist) or C<news.admin>. This behavior is present for historical
-compatibility reasons and should be considered obsolete; support for the
-C<.ctl> suffix may be removed in a future version of INN.
-
-Finally, articles posted to newsgroups beginning with C<to.> are treated
-specially. Provided that either that newsgroup exists in the F<active> file
-or I<mergetogroups> is set in F<inn.conf>, the remainder of the newsgroup
-is taken to be a site name, as configured in F<newsfeeds>, and the article
-is sent to that site. If I<mergetogroups> is set, the article will be
-filed in the group named C<to> (which must exist in the F<active> file). For
-example, with I<mergetogroups> set, an article posted to C<to.uunet> will
-be filed in C<to> and sent to the site C<uunet>.
-
-=head1 PROTOCOL DIFFERENCES
-
-B<innd> implements the NNTP commands defined in RFC 977, with the
-following differences:
-
-=over 4
-
-=item 1.
-
-The LIST command may be followed by an optional ACTIVE, ACTIVE.TIMES, or
-NEWSGROUPS. There is only basic support for LIST in B<innd> since feeding
-peers normally don't need it; see nnrpd(8) for full support.
-
-=item 2.
-
-The AUTHINFO USER and AUTHINFO PASS commands are implemented, although the
-authentication is currently limited to matching a password for a given
-peer specified in F<incoming.conf>. These are based on the reference Unix
-implementation.
-
-=item 3.
-
-A new command, MODE READER, is implemented. This command will cause the
-server to pass the connection to B<nnrpd>.
-
-=item 4.
-
-The streaming extension (MODE STREAM, CHECK, and TAKETHIS) is fully
-supported.
-
-=item 5.
-
-A batch transfer command, XBATCH I<byte-count>, is provided. This command
-will read I<byte-count> bytes and store them for later processing by
-rnews(1) (which must be run separately, probably from cron). See
-innxbatch(8) and F<backends/sendxbatches> for more details on this
-extension.
-
-=item 6.
-
-B<innd> implements a limited subset of the protocol useful for
-transferring news. The only other commands implemented are HEAD, HELP,
-IHAVE, STAT, and QUIT. The remaining commands are mostly only useful for
-readers and are implemented by nnrpd(8).
-
-=back
-
-=head1 HEADER MODIFICATIONS
-
-B<innd> modifies as few article headers as possible, although it could be
-better in this area.
-
-Empty headers and headers that consist of nothing but whitespace are
-dropped.
-
-The local site's name (as set with the I<pathhost> parameter in
-F<inn.conf>) and an exclamation point are prepended to the Path: header,
-provided the first site name in the Path: header is different from the
-local one. In addition, I<pathalias> and I<pathcluster> may be similarly
-respectively prepended and appended to the Path: header; see inn.conf(5)
-for the details.
-
-The Xref: header is removed and a new one created.
-
-A Lines: header will be added if the article was missing one.
-
-B<innd> does not rewrite incorrect headers. For example, it will not
-replace an incorrect Lines header, though it may reject such an article
-depending on the value of I<linecountfuzz> in F<inn.conf>.
-
-=head1 CANCEL FEEDS
-
-In order to efficiently apply a large number of local cancels (such as
-from processing NoCeMs or from some other external source), INN supports a
-special feed mode available only to connections to the local Unix domain
-socket (not to connections to any network sockets).
-
-To enter this mode, connect to the Unix domain socket (I<pathrun>/nntpin)
-and send the command MODE CANCEL. The response will have code C<284>.
-Every subsequent line sent on that connection should consist of a single
-message ID. An attempt will be made to cancel that message ID, and the
-server will reply C<289> for success or C<484> for failure. (Failure can
-occur, for example, if the server is paused or throttled, or the
-Message-ID is corrupt. Failure does I<not> occur if the article to be
-cancelled does not exist.)
-
-=head1 LOGGING
-
-B<innd> reports all incoming articles in its log file (I<pathlog>/news).
-This is a text file with a variable number of space-separated fields in
-one of the following formats:
-
- mon dd hh:mm:ss.mmm + feed <message-id> site ...
- mon dd hh:mm:ss.mmm j feed <message-id> site ...
- mon dd hh:mm:ss.mmm c feed <message-id> Cancelling <message-id>
- mon dd hh:mm:ss.mmm - feed <message-id> reason
- mon dd hh:mm:ss.mmm ? feed <message-id> reason
-
-There may also be hostname and/or size fields after the message ID
-depending on the settings of I<nntplinklog> and I<logartsize> in
-F<inn.conf>.
-
-The first three fields are the date and time to millisecond resolution.
-The fifth field is the site that sent the article (based on the Path
-header) and the sixth field is the article's message ID; they will be a
-question mark if the information is not available.
-
-The fourth field indicates whether the article was accepted or not. If it
-is a plus sign, then the article was accepted. If it is the letter C<j>
-then the article was accepted, but all of the newsgroups to which the
-article was posted were set to mode C<j> in the active file (or not listed
-in the active file and I<wanttrash> was set in F<inn.conf>) so the article
-was filed into the C<junk> newsgroup. In both of these cases, the article
-has been accepted and the C<site ...> field contains the space-separated
-list of sites to which the article is being sent.
-
-If the fourth field is the letter C<c>, then a cancel message was accepted
-before the original article arrived, and a history entry for the cancelled
-message was created so that B<innd> will reject that message if it arrives
-later.
-
-If the fourth field is a minus sign, then the article was rejected. The
-reasons for rejection generated by B<innd> include:
-
- "%s" header too long
- "%s" wants to cancel <%s> by "%s"
- Article exceeds local limit of %s bytes
- Article posted in the future -- "%s"
- Bad "%s" header
- Can't write history
- Duplicate
- Duplicate "%s" header
- EOF in headers
- Linecount %s != %s +- %s
- Missing %s header
- No body
- No colon-space in "%s" header
- No space
- Space before colon in "%s" header
- Too old -- "%s"
- Unapproved for "%s"
- Unwanted newsgroup "%s"
- Unwanted distribution "%s"
- Whitespace in "Newsgroups" header -- "%s"
-
-where C<%s>, above, is replaced by more specific information. (The Perl,
-Python, andr Tcl filters, if used, may reject articles with other
-reasons.)
-
-If the fourth field is the letter C<?>, the article contains strange
-strings, such as CR without LF or LF without CR. (These characters should
-never occur in isolation, only together as CRLF to indicate the end of a
-line.) This log message is just informational, to give an idea of how
-widespread such articles are; B<innd> does not reject such articles.
-
-Note that when I<wanttrash> is set to true in F<inn.conf> and an article
-is received that isn't posted to any valid newsgroups, it will be accepted
-and logged with two lines, a C<j> line and a minus sign line.
-
-B<innd> also makes extensive reports through syslog(3). The first word of
-the log message will be the name of the site if the entry is site-specific
-(such as a "connected" message). The first word will be C<SERVER> if the
-message relates to the server itself, such as when a read error occurs.
-
-If the second word is the four letters C<cant>, then an error is being
-reported. (The absence of an apostrophe is intentional; it makes it
-easier to grep from the command line and easier to find error messages in
-FAQs using a search engine.) In this case, the next two words generally
-name the system call or library routine that failed and the object upon
-which the action was being performed. The rest of the line may contain
-other information.
-
-In other cases, the second word attempts to summarize what change has been
-made, while the rest of the line gives more specific information. The
-word C<internal> generally indicates an internal logic error.
-
-=head1 SIGNALS
-
-B<innd> will catch SIGTERM and SIGHUP and shut down. If B<-d> is used,
-SIGINT will also be caught and will result in an orderly shutdown.
-
-B<innd> will catch the SIGUSR1 signal and recreate the control channel
-used by ctlinnd(8).
-
-=head1 BUGS
-
-B<innd> normally attempts to strip IP options from incoming connections,
-since it uses IP-based authentication and source routing can confuse that.
-However, this doesn't work on all systems, and it doesn't work at all in
-the presence of IPv6 support (and is disabled in that case). Hence, if
-using B<innd> with IPv6 support, make sure that your kernel or router
-disables source routing.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews.
-
-$Id: innd.pod 7748 2008-04-06 13:49:56Z iulius $
-
-=head1 SEE ALSO
-
-active(5), ctlinnd(8), dbz(3), history(5), incoming.conf(5), inn.conf(5),
-newsfeeds(5), nnrpd(8), rnews(1), syslog(3).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-inndf - Report free disk, inodes, and overview information
-
-=head1 SYNOPSIS
-
-B<inndf> [B<-Fhi>] [B<-f> I<filename>] I<directory> [I<directory> ...]
-
-B<inndf> B<-n>
-
-B<inndf> B<-o>
-
-=head1 DESCRIPTION
-
-B<inndf> was originally a replacement for C<df | awk> in innwatch.ctl(5)
-and innstat(8), and now also reports various other usage information about
-INN's storage that df(1) doesn't understand. B<inndf> doesn't sync, forks
-less, and is generally less complicated than df(1).
-
-Its default behavior is to report free kilobytes (not disk blocks), or
-free inodes if B<-i> is used, in the file systems holding the directories
-given on the command line. (A kilobyte in this case is 1024 bytes.) If
-only one directory is given, the output will be a simple number; if more
-than one directory is given, the output will be formatted for human
-readability.
-
-If I<enableoverview> is set to true in F<inn.conf>, B<inndf> can also be
-used to get information about the overview database. With the B<-n>
-option, it reports a count of the total number of overview records stored.
-With B<-o>, it reports the percentage of space used in the overview
-database (for those overview methods where this is meaningful data).
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-f> I<filename>
-
-I<filename> should contain a list of directories to use in addition to
-those given by the arguments, one per line. Blank lines and anything
-after C<#> on any line are ignored.
-
-=item B<-F>
-
-Like B<-f> execpt that the filename is I<pathetc>/filesystems and it is
-not an error if this file doesn't exist. (This option is used primarily
-by such things as innstat(8), so that the news administrator can add
-additional file systems to check to I<pathetc>/filesystems without having
-to modify the script.)
-
-=item B<-h>
-
-Print a usage message and exit.
-
-=item B<-i>
-
-Report the number of free inodes rather than the amount of free disk
-space.
-
-=item B<-n>
-
-Report the total number of records in the overview database. Note that
-crossposted articles will have one overview record for each newsgroup
-they're posted to.
-
-=item B<-o>
-
-Report the percentage usage of the overview database space. This is only
-meaningful for overview methods that pre-allocate a certain amount of
-space rather than grow to accomodate more records. Currently, this flag
-is only useful for the buffindexed overview method.
-
-=back
-
-=head1 EXAMPLES
-
-Print the free kilobytes in /news/spool as a simple number:
-
- inndf /news/spool
-
-Report the free inodes in /usr/local/news and /news/spool in a format
-designed for human readability:
-
- inndf -i /usr/local/news /news/spool
-
-The same, but also add in all file systems in I<pathetc>/filesystems:
-
- inndf -i -F /usr/local/news /news/spool
-
-Print out the number of overview records and the percentage space used by
-a buffindexed overview database:
-
- inndf -no
-
-=head1 HISTORY
-
-B<inndf> was written by Ian Dickinson <idickins@fore.com>. This manual
-page was written by Swa Frantzen <Swa.Frantzen@belgium.eu.net>. Thanks
-also to the following folks for ports, patches, and comments:
-
- Mahesh Ramachandran <rr@eel.ufl.edu>
- Chuck Swiger <chuck@its.com>
- Sang-yong Suh <sysuh@kigam.re.kr>
- Brad Dickey <bdickey@haverford.edu>
- Taso N. Devetzis <devetzis@snet.net>
- Wei-Yeh Lee <weiyeh@columbia.edu>
- Jeff Garzik <jeff.garzik@spinne.com>
-
-and to all the other folks I met and worked with during my 10 years as a
-newsadmin.
-
-Katsuhiro Kondou added the B<-n> and B<-o> options. Russ Allbery added
-reporting of percentage free disk space. Support for B<-f> and B<-F> was
-added by Fabien Tassin <fta@sofaraway.org>.
-
-=head1 SEE ALSO
-
-df(1), innwatch.ctl(5), innstat(8).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-inndstart - Start innd
-
-=head1 SYNOPSIS
-
-B<inndstart> [B<-P> I<port>] [B<-I> I<address>] [I<innd-options>]
-
-=head1 DESCRIPTION
-
-The purpose of B<inndstart> is to raise system file descriptor limits,
-open the privileged news transfer port, and then start innd(8), passing it
-the open file descriptor for the news port. B<inndstart> is used since
-only privileged programs can perform those two operations and since
-B<innd> should not run with elevated privileges. It is installed setuid
-root and drops privileges to the news user (as set at configure time)
-before running B<innd>.
-
-Normally there is no need to run B<inndstart> directly. Instead, run
-rc.news(8) as the news user, and it will handle running B<inndstart>
-appropriately for you.
-
-Since B<inndstart> is setuid root, it is extremely restrictive about who
-can run it and what it is willing to do. See L<"SECURITY"> for the full
-details.
-
-B<inndstart> can only be run by the news user; if run by any other user,
-it will abort. It will also only bind to ports 119, 433, or a port number
-given at configure time with B<--with-innd-port> among those ports below
-1024, although it can bind to any port above 1024. This is to prevent
-various security exploits possible by binding to arbitrary privileged
-ports.
-
-Before running B<innd>, B<inndstart> cleans out the environment and sets
-only those environment variables listed in L<"ENVIRONMENT">.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-P> I<port>
-
-Bind to I<port> instead of whatever is specified by I<port> in
-F<inn.conf>. Note that this is subject to the constraints mentioned
-above.
-
-=item B<-I> I<address>
-
-Bind as I<address> instead of whatever is specified by I<bindaddress> in
-F<inn.conf>. The default behavior is to bind to INADDR_ANY, and that's
-what's desired almost all the time. This option, and the F<inn.conf>
-parameter, may be useful if the machine has multiple interface cards and
-B<innd> should only be listening on a particular one.
-
-=back
-
-All other options given on the command line are passed verbatim to
-B<innd>. In addition, B<inndstart> will give the B<-p> option to B<innd>,
-specifying the file descriptor of the open network socket.
-
-=head1 SECURITY
-
-B<inndstart> is setuid root, and therefore an expected point of attack.
-It has therefore been carefully written with security in mind. In a
-normal INN installation, it is installed setuid root and executable only
-by users in the news group.
-
-Ideally, everything about B<inndstart>'s operations would be hard-coded so
-that it could not be modified. Fighting against this desire, however, is
-the ideal that as much of INN's operation as possible should be
-configurable at run-time using F<inn.conf>, and the news system should be
-able to an alternate inn.conf by setting INNCONF to the path to that file
-before starting any programs. The configuration data therefore can't be
-trusted.
-
-The security model used is:
-
-=over 2
-
-=item *
-
-B<inndstart> can only be executed by the news user and news group, as
-determined at configure time and compiled into B<inndstart> as constants.
-Similarly, B<inndstart> will always setuid() and setgid() to those users
-before running B<innd>. This is to prevent a user other than news but in
-the news group from using B<inndstart> to leverage that access into access
-to the news account.
-
-=item *
-
-As mentioned above, B<inndstart> will only bind to a very limited subset
-of ports below 1024. There are various attacks that can be performed
-using random low-numbered ports, including exploits of the rsh(1) family
-of commands on some systems.
-
-=item *
-
-B<inndstart> does as little as possible as root, dropping privileges
-before performing any operations that do not require elevated privileges.
-
-=back
-
-This program therefore gives the news user the ability to revoke system
-file descriptor limits and bind to the news port, and nothing else.
-
-=head1 DIAGNOSTICS
-
-B<inndstart> may log the following messages to syslog and print them to
-stderr.
-
-=over 4
-
-=item can't bind: %s
-
-(Fatal) Unable to bind to the designated port. This usually means that
-something else is already running on the news port. Check with
-netstat(8) and make sure that inetd(8) doesn't think it's running a
-service on the same port you're trying to run B<innd> on.
-
-=item can't bind to restricted port %d
-
-(Fatal) B<inndstart> was told to bind to a low numbered port (under 1024)
-other than 119, 433, or a port number given at configure time. This is
-not allowed for security reasons. If you're running B<innd> on a port
-other than 119 or 433, you need to give the --with-innd-port flag to
-C<configure> when you compile INN.
-
-=item can't exec %s: %s
-
-(Fatal) B<inndstart> was unable to execute B<innd>. Make sure that
-I<pathbin> is set correctly in inn.conf and that B<innd> is located in
-that directory and is executable by the news user.
-
-=item can't getgrnam(%s)
-
-(Fatal) Unable to determine the GID for the compiled-in news group.
-Perhaps the news group is not listed in F</etc/group>.
-
-=item can't getpwnam(%s)
-
-(Fatal) Unable to determine the UID for the compiled-in news user.
-Perhaps the news user is not listed in F</etc/passwd>.
-
-=item can't open socket: %s
-
-(Fatal) Something went wrong in creating the network socket. Chances are
-your system is out of resources of some kind.
-
-=item can't set file descriptor limit to %d: %s
-
-(Warning) Unable to set the system file descriptor limit to the specified
-value; the limit was left unchanged. Perhaps that value is too high for
-your system. Try changing I<rlimitnofile> in F<inn.conf> to a smaller
-value.
-
-=item can't set SO_REUSEADDR: %s
-
-(Warning) B<inndstart> attempts to set SO_REUSEADDR using setsockopt(2) so
-that if B<innd> exits, it can be restarted again immediately without
-waiting for the port to time out. For some reason, this failed, and that
-option was not set on the port.
-
-=item can't seteuid to %d: %s
-
-(Fatal) Unable to change the effective UID. If B<inndstart> has the
-correct permissions (setuid root) and seteuid to root (UID 0) is failing,
-this may mean that your system has seteuid(2) but doesn't have support for
-POSIX saved UIDs. If this is the case, please report this to the INN
-maintainers.
-
-=item can't setgid to %d: %s
-
-(Fatal) Dropping privileges to the news group failed for some reason.
-
-=item can't setgroups (is inndstart setuid root?): %s
-
-(Warning) Dropping all supplemental groups except the news group failed
-for some reason, and the process group membership was left unchanged.
-This almost always indicates that B<inndstart> isn't setuid root as it has
-to be to do what it does. Make sure that B<inndstart> is setuid root,
-owned by group news, and mode 4710.
-
-=item can't setuid to %d: %s
-
-(Fatal) Dropping privileges to the news user failed for some reason.
-
-=item invalid address %s
-
-(Fatal) B<-I> was specified on the command line, but the argument wasn't a
-valid address. Addresses must be given as numeric IP addresses.
-
-=item invalid bindaddress in inn.conf (%s)
-
-(Fatal) The I<bindaddress> specified in F<inn.conf> could not be converted
-to an IP address. See inn.conf(5) for more information about valid
-values.
-
-=item invalid port %s (must be a number)
-
-(Fatal) B<-P> was specified on the command line, but the argument wasn't a
-valid port. Ports must be port numbers; service names are not allowed.
-
-=item missing address after -I
-
-(Fatal) B<-I> was given on the command line, but no address was given
-after the option.
-
-=item missing port after -P
-
-(Fatal) B<-P> was given on the command line, but no port was given after
-the option.
-
-=item must be run by user %s (%d), not %d
-
-(Fatal) Someone other than the news user attempted to run B<inndstart>.
-B<inndstart> may only be run by the news user for security reasons.
-
-=back
-
-=head1 EXAMPLES
-
-Normally, B<inndstart> is never run directly. However, a simple way to
-just restart B<innd> (if it is not running) without running any other
-auxilliary programs or performing any of the other checks done by
-rc.news(8) is to just run:
-
- inndstart
-
-as the news user.
-
-To start B<innd> on port 433, passing it the C<-c21> option, use:
-
- inndstart -P433 -c21
-
-=head1 ENVIRONMENT
-
-One environment variable affects the operation of B<inndstart> itself:
-
-=over 8
-
-=item INNCONF
-
-The full path to the inn.conf(5) file to read, rather than the default.
-This can be used to run multiple copies of INN on the same machine with
-different settings.
-
-=back
-
-When executing B<innd>, B<inndstart> cleans out the entire environmnent
-and sets only the following variables:
-
-=over 8
-
-=item BIND_INADDR
-
-Passed verbatim from B<inndstart>'s environment. This is used by various
-programs to override the I<bindaddress> parameter in F<inn.conf> and
-therefore must be in B<innd>'s environment for programs like innfeed(8).
-
-=item HOME
-
-Set to I<pathnews> from F<inn.conf>.
-
-=item LOGNAME
-
-Set to the news master, as determined at configure time.
-
-=item PATH
-
-Set to I<pathbin> from F<inn.conf>, I<pathetc> from F<inn.conf>, and then
-F</bin>, F</usr/bin>, and F</usr/ucb> in that order.
-
-=item SHELL
-
-Set to the path to the system Bourne shell as determined by configure
-(probably F</bin/sh>).
-
-=item TMPDIR
-
-Set to I<pathtmp> from inn.conf.
-
-=item TZ
-
-Passed verbatim from B<inndstart>'s environment.
-
-=item USER
-
-Set to the news master, as determined at configure time.
-
-=back
-
-=head1 FILES
-
-=over 4
-
-=item inn.conf
-
-Read for I<pathnews>, I<pathbin>, I<pathtmp>, I<rlimitnofile>,
-I<bindaddress>, and I<port>.
-
-=item I<pathbin>/innd
-
-The binary that is executed as B<innd> and passed the open network socket.
-
-=back
-
-=head1 HISTORY
-
-Written by Russ Allbery E<lt>rra@stanford.eduE<gt> for InterNetNews.
-
-$Id: inndstart.pod 5909 2002-12-03 05:17:18Z vinocur $
-
-=head1 SEE ALSO
-
-inn.conf(5), innd(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-innmail - Simple mail-sending program
-
-=head1 SYNOPSIS
-
-B<innmail> [B<-h>] [B<-s> I<subject>] I<address> [I<address> ...]
-
-=head1 DESCRIPTION
-
-B<innmail> is a Perl script intended to provide the non-interactive
-mail-sending functionality of mail(1) while avoiding nasty security
-problems. It takes the body of a mail message on standard input and sends
-it to the specified addresses by invoking the value of I<mta> in
-F<inn.conf>.
-
-At least one address (formatted for the MTA specified in F<inn.conf>, if it
-matters) is required. B<innmail> will sanitize the addresses so that they
-contain only alphanumerics and the symbols C<@>, C<.>, C<->, C<+>, C<_>,
-and C<%>.
-
-B<innmail> was written to be suitable for the I<mailcmd> setting in
-F<inn.conf>.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-h>
-
-Gives usage information.
-
-=item B<-s> I<subject>
-
-Sets the Subject: header of the message. A warning is issued if this
-option is omitted.
-
-=back
-
-=head1 EXAMPLES
-
-This sends a one-line message to the local user C<joe>:
-
- echo "A one-line message." | innmail -s "Simple message" joe
-
-B<innmail> by default is used by INN for sending nightly reports and
-control message reports.
-
-=head1 BUGS
-
-B<innmail> fails on addresses that begin with C<->, although one might
-hope that the news server will not need to contact any such addresses.
-
-There are many "correct" addresses that will be silently modified by the
-sanitization process. A news administrator should be careful to use
-particularly sane addresses if they may be passed to B<innmail>.
-
-=head1 HISTORY
-
-B<innmail> was written by James Brister <brister@vix.com> for
-InterNetNews. This manual page was originally written by Jeffrey
-M. Vinocur.
-
-=head1 SEE ALSO
-
-inn.conf(5), mail(1).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-innupgrade - Upgrade INN configuration files
-
-=head1 SYNOPSIS
-
-B<innupgrade> I<directory>
-
-B<innupgrade> [B<-t> I<type>] B<-f> I<file>
-
-=head1 DESCRIPTION
-
-B<innupgrade> is intended to be run during a major upgrade of INN to fix
-the configuration files with any required changes. If given a directory,
-it will scan that directory for any files that it has updates defined for,
-try to perform those updates, and replace the files with updated versions
-if applying the updates resulted in any changes. The old versions of the
-files will be saved with a C<.OLD> extension.
-
-If the B<-f> flag is used, only that file will be updated. If the file
-name doesn't match the standard file name of an INN configuration file,
-the optional B<-t> flag may be given to specify the type. See
-L<"EXAMPLES"> for an example of this.
-
-Currently, B<innupgrade> knows how to apply the following updates:
-
-=over 2
-
-=item *
-
-F<inn.conf>: Quote values with whitespace and comment out keys with no
-values, required for the change in configuration parsers introduced in INN
-2.4. The new format is not backward compatible with the previous parser,
-since the previous parser will include the double-quotes in the value of
-the parameter.
-
-=back
-
-Normally, B<innupgrade> should be run on the I<pathetc> directory after
-any upgrade of INN other than a patch release (any upgrade that changes
-the first or second version numbers). This may occur automatically during
-the upgrade process.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-f> I<file>
-
-Only act on I<file> rather than working on an entire directory.
-
-=item B<-t> I<type>
-
-For a file specified with B<-f>, parse it and upgrade it as if it were
-named I<type>. Used for upgrading files with the same syntax as normal
-INN configuration files but with different names. Only makes sense in
-combination with B<-f>.
-
-=back
-
-=head1 EXAMPLES
-
-Upgrade any configuration files found in F</usr/local/news/etc>:
-
- innupgrade /usr/local/news/etc
-
-Upgrade only F</news/etc/inn.conf>:
-
- innupgrade -f /news/etc/inn.conf
-
-Upgrade a file named F<inn-special.conf> that should have the same syntax
-as F<inn.conf>:
-
- innupgrade -t inn.conf -f inn-special.conf
-
-Any upgrade rules that apply to F<inn.conf> will be applied to the
-alternate file.
-
-=head1 HISTORY
-
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-
-$Id: innupgrade.pod 5909 2002-12-03 05:17:18Z vinocur $
-
-=cut
+++ /dev/null
-=head1 Welcome to INN 2.4!
-
-Please read this document thoroughly before trying to install INN. You'll
-be glad you did.
-
-If you are upgrading from a major release of INN prior to 2.3, it is
-recommended that you make copies of your old configuration files and use
-them as guides for doing a clean installation and configuration of 2.4.
-Many config files have changed, some have been added, and some have been
-removed. You'll find it much easier to start with a fresh install than to
-try to update your old installation. This is particularly true if you're
-upgrading from a version of INN prior to 2.0.
-
-If you are upgrading from INN 2.3 or later, you may be able to just update
-the binaries, scripts, and man pages by running:
-
- make update
-
-after building INN and then comparing the new sample configuration files
-with your current ones to see if anything has changed. If you take this
-route, the old binaries, scripts, and man pages will be saved with an
-extension of C<.OLD> so that you can easily back out. Be sure to
-configure INN with the same options that you used previously if you take
-this approach (in particular, INN compiled with B<--enable-largefiles>
-can't read the data structures written by INN compiled without that flag,
-and vice versa). If you don't remember what options you used but you have
-your old build tree, look at the comments at the beginning of
-F<config.status>.
-
-If you made ckpasswd setuid root so that you could use system passwords,
-you'll have to do that again after make update. (It's much better to use
-PAM instead if you can.)
-
-If you use C<make update> to upgrade from INN 2.3, also look at the new
-sample configuration files in F<samples> to see if there are new options
-of interest to you. In particular, F<control.ctl> has been updated and
-F<inn.conf> has various new options.
-
-For more information about recent changes, see F<NEWS>.
-
-=head1 Supported Systems
-
-As much as possible, INN is written in portable C and should work on any
-Unix platform. It does, however, make extensive use of mmap(2) and
-certain other constructs that may be poorly or incompletely implemented,
-particularly on very old operating systems.
-
-INN has been confirmed to work on the following operating systems:
-
- AIX 4.3
- FreeBSD 2.2.x and up
- HP-UX 10.20 and up
- Linux 2.x (tested with libc 5.4, glibc 2.0 and up)
- Mac OS X 10.2 and up
- NetBSD 1.6 and up
- OpenBSD 2.8 and up
- SCO 5.0.4 (tested with gcc 2.8.1, cc)
- Solaris 2.5.x and up
- UnixWare 7.1
- UX/4800 R11 and up
-
-If you have gotten INN working on an operating system other than the ones
-listed above, please let us know at <inn-bugs@isc.org>.
-
-=head1 Before You Begin
-
-INN requires several other packages be installed in order to be fully
-functional (or in some cases, to work at all):
-
-=over 2
-
-=item *
-
-In order to build INN, you will need a C compiler that understands ANSI C.
-If you are trying to install INN on an operating system that doesn't have
-an ANSI C compiler (such as SunOS), installing gcc is recommended. You
-can get it from <ftp://ftp.gnu.org/gnu/gcc/> or its mirrors. INN is
-tested with gcc more thoroughly than with any other compiler, so even if
-you have another compiler available, you may wish to use gcc instead.
-
-=item *
-
-Currently, in order to build INN, you will need an implementation of yacc.
-GNU bison (from <ftp://ftp.gnu.org/gnu/bison/> or its mirrors) will work
-fine. We hope to remove this requirement in the future.
-
-=item *
-
-INN requires at least Perl 5.004_03 to build and to run several
-subsystems. INN is tested primarily with newer versions of Perl, so it's
-generally recommended that you install the latest stable distribution of
-Perl before compiling INN. For instructions on obtaining and installing
-Perl, see <http://www.perl.com/pub/language/info/software.html>. Note
-that you may need to use the same compiler and options (particularly
-largefile support) for Perl and INN.
-
-If you're using a version of Perl prior to 5.6.0, you may need to make
-sure that the Perl versions of your system header files have been
-generated in order for Sys::Syslog to work properly (used by various
-utility programs, including controlchan). To do this, run the following
-two commands:
-
- # cd /usr/include
- # h2ph * sys/*
-
-An even better approach is to install Perl 5.6.1 or later, which have a
-fixed version of Sys::Syslog that doesn't require this (as well as many
-other improvements over earlier versions of Perl).
-
-=item *
-
-The INN Makefiles use the syntax C<include FILE>, rather than the syntax
-expected by some BSDish systems of C<.include E<lt>FILEE<gt>>. If your
-system expects the latter syntax, the recommended solution is to install
-GNU make from <ftp://ftp.gnu.org/make/>. You may have GNU make already
-installed as gmake, in which case using gmake rather than make to build
-INN should be sufficient.
-
-=item *
-
-If you want to enable support for authenticated control messages (this is
-not required, but is highly recommended for systems carrying public Usenet
-hierarchies) then you will need to install some version of PGP. The
-recommended version is GnuPG, since it's actively developed, supports
-OpenPGP, is freely available and free to use for any purpose (in the US
-and elsewhere), and (as of version 1.0.4 at least) supports the RSA
-signatures used by most current control message senders.
-
-Alternately, you can install PGP from <http://www.pgp.com/> or one of the
-international versions of it. Be warned, however, that the licensing
-restrictions on PGP inside the United States are extremely unclear; it's
-possible that if you are installing INN for a company in the U.S., even if
-the news server is not part of the business of that company, you would
-need to purchase a commercial license for PGP. For an educational or
-non-profit organization, this shouldn't be a problem.
-
-=item *
-
-If you want to use either the Python embedded hooks, you'll need to have a
-suitable versions of Python installed. See F<doc/hook-python> for more
-information.
-
-=item *
-
-Many of INN's optional features require other packages (primarily
-libraries) be installed. If you wish to use any of these optional
-features, you will need to install those packages first. Here is a table
-of configure options enabling optional features and the software and
-versions you'll need:
-
- --with-perl Perl 5.004_03 or higher, 5.6.1+ recommended
- --with-python Python 1.5.2 or higher
- --with-berkeleydb BerkeleyDB 2.0 or higher, 4.2+ recommended
- --with-openssl OpenSSL 0.9.6 or higher
- --with-sasl SASL 2.x or higher
- --with-kerberos MIT Kerberos v5 1.2.x or higher
-
-If any of these libraries (other than Perl or Python) are built shared and
-installed in locations where your system doesn't search for shared
-libraries by default, you may need to encode the paths to those shared
-libraries in the INN binaries. For more information on shared library
-paths, see:
-
- <http://www.eyrie.org/~eagle/notes/rpath.html>
-
-For most systems, setting the environment variable LD_RUN_PATH to a
-colon-separated list of additional directories in which to look for shared
-libraries before building INN will be sufficient.
-
-=back
-
-=head1 Unpacking the Distribution
-
-Released versions of INN are available from ftp.isc.org in F</isc/inn>.
-New major releases will be announed on <inn-announce@isc.org> (see
-F<README>) when they're made.
-
-If you want more a more cutting-edge version, you can obtain current
-snapshots from from ftp.isc.org in directory F</isc/inn/snapshots>. These
-are snapshots of the INN CVS tree taken daily; there are two snapshots
-made each night (one of the current development branch, and one of the
-stable branch consisting of bug fixes to the previous major release).
-They are stored in date format; in other words the snapshots from April
-6th, 2000, would be named F<inn-CURRENT-20000406.tar.gz> and
-F<inn-STABLE-20000406.tar.gz>. Choose the newest file of whichever branch
-you prefer. (Note that the downloading, configuring, and compiling steps
-can be done while logged in as any user.)
-
-The distribution is in gzip compressed tar archive format. To extract it,
-execute:
-
- gunzip -c <inn-src-file> | tar -xf -
-
-Extracting the source distribution will create a directory named
-F<< inn-<version> >> or F<< inn-<BRANCH>-<date> >> where the source
-resides.
-
-=head1 Installing INN
-
-Before beginning installation, you should make sure that there is a user
-on your system named C<news>, and that this user's primary group is set to
-a group called C<news>. You can change these with the B<--with-news-user>
-and B<--with-news-group> options to configure (see below). The home
-directory of this user should be set to the directory under which you wish
-to install INN (F</usr/local/news> is the default and is a good choice).
-INN will install itself as this user and group. You can change these if
-you want, but these are the defaults and it's easier to stick with them on
-a new installation.
-
-By default, INN sends reports to the user C<usenet>. This account isn't
-used for any other purposes. You can change it with the
-B<--with-news-master> option to configure (see below).
-
-WARNING: By default, INN installs various configuration files as
-group-writeable, and in general INN is not hardened from a security
-standpoint against an attack by someone who is already in the news group.
-In general, you should consider membership in the news group as equivalent
-to access to the news account. You should not rely on being able to keep
-anyone with access to the news GID from converting that into access to the
-news UID. The recommended configuration is to have the only member of the
-group C<news> be the user C<news>.
-
-Installing INN so that all of its files are under a single directory tree,
-rather than scattering binaries, libraries, and man pages throughout the
-file system, is strongly recommended. It helps keep everything involved
-in the operation of INN together as a unit and will make the installation
-instructions easier to follow.
-
-As a side note, whenever doing anything with a running news server, first
-log in as this user. That way, you can ensure that all files created by
-any commands you run are created with the right ownership to be readable
-by the server. Particularly avoid doing anything in the news spool itself
-as root, and make sure you fix the ownership of any created files if you
-have to. INN doesn't like files in the news spool owned by a user other
-than the news user. However, since certain binaries need to be setuid
-root, indiscriminate use of C<chown news> is not the solution. (If you
-don't like to log in to system accounts, careful use of C<chmod g+s> on
-directories and a umask of C<002> or C<007> may suffice.)
-
-INN uses GNU autoconf and a generated configure script to make
-configuration rather painless. Unless you have a rather abnormal setup,
-configure should be able to completely configure INN for your system. If
-you want to change the defaults, you can invoke the configure script with
-one or more command line options. Type:
-
- ./configure --help
-
-for a full list of supported options. Some of the most commonly used
-options are:
-
-=over 4
-
-=item B<--prefix>=PATH
-
-Sets the installation prefix for INN. The default is F</usr/local/news>.
-All of INN's programs and support files will be installed under this
-directory. This should match the home directory of your news user (it
-will make installation and maintenance easier). It is not recommended to
-set this to F</usr>; if you decide to do that anyway, make sure to point
-INN's temporary directory at a directory that isn't world-writeable (see
-B<--with-tmp-dir> below).
-
-=item B<--with-db-dir>=PATH
-
-Sets the prefix for INN database files. The default is F<PREFIX/db>,
-where PREFIX is F</usr/local/news> unless overridden with the option
-above. The history and active files will be stored in this directory, and
-writes to those files are an appreciable percentage of INN's disk
-activity. The history file can also be quite large (requiring up to 2 GB
-or more during nightly expire), so this is a common portion of INN to move
-to a different file system.
-
-=item B<--with-spool-dir>=PATH
-
-Sets the prefix for the news spool (when using any storage method other
-than CNFS) and the overview spool. The default is F<PREFIX/spool>. This
-is another common portion of INN to move to a different file system (often
-F</news>).
-
-=item B<--with-tmp-dir>=PATH
-
-Sets the directory in which INN will create temporary files. This should
-under no circumstances be the same as the system temporary directory or
-otherwise be set to a world-writeable directory, since INN doesn't take
-care to avoid symlink attacks and other security problems possible with a
-world-writeable directory. This directory should be reserved for the
-exclusive use of INN and only writeable by the news user. Usage is
-generally light, so this is unlikely to need a separate partition.
-
-It's also possible to set the paths for most other sections of the INN
-installation independently; see C<./configure --help> and look for the
-B<--with-*-dir>=PATH options.
-
-=item B<--enable-largefiles>
-
-Enables large file support. This is not enabled by default, even on
-platforms that support it, because it changes the format of INN's on-disk
-databases (making it difficult to upgrade an earlier INN installation) and
-can significantly increase the size of some of the history database files.
-Large file support is not necessary unless your history database is so
-large that it exceeds 2 GB or you want to use CNFS buffers larger than 2
-GB.
-
-The history, tradindexed and buffindexed overview, CNFS, and timecaf
-databases written by an INN built with this option are incompatible with
-those written by an INN without this option.
-
-=item B<--enable-tagged-hash>
-
-Use tagged hash table for the history database. The tagged hash format
-uses much less memory but is somewhat slower. This option is recommended
-if you have less than 256 MB of RAM on your news server. If you install
-INN without tagged hash (the default) and expire takes an excessive amount
-of time, you should make sure the RAM in your system satisfies the
-following formula:
-
- ram > 10 * tablesize
-
- ram: Amount of system RAM (in bytes)
- tablesize: 3rd field on the 1st line of history.dir (bytes)
-
-If you don't have at least that much RAM, try rebuilding INN with tagged
-hash enabled.
-
-NOTE: B<--enable-largefiles> cannot be used with B<--enable-tagged-hash>.
-
-=item B<--with-perl>
-
-Enables support for embedded Perl, allowing you to install filter scripts
-written in Perl. Highly recommended, because many really good spam
-filters are written in Perl. See F<doc/hook-perl> for all the details.
-
-Even if you do not use this option, INN still requires Perl as mentioned
-above.
-
-=item B<--with-python>
-
-Enables support for Python, allowing you to install filter and
-authentication scripts written in Python. You will need Python 1.5.2 or
-later installed on your system to enable this option. See
-F<doc/hook-python> for all the details. Note that there is an
-incompatibility between INN and Python 2.0 when Python is compiled with
-cycle garbage collection; this problem was reported fixed in Python 2.1a1.
-
-=item B<--with-innd-port>=PORT
-
-By default, inndstart(8) refuses to bind to any port under 1024 other than
-119 and 433 for security reasons (to prevent attacks on rsh(1)-based
-commands and replacing standard system daemons). If you want to run innd
-on a different port under 1024, you'll need to tell configure what port
-you intend to use. (You'll also still need to set the port number in
-F<inn.conf> or give it to inndstart on the command line.)
-
-=item B<--with-syslog-facility>=FACILITY
-
-Specifies the syslog facility that INN programs should log to. The
-default is LOG_NEWS unless configure detects that your system doesn't
-understand that facility, in which case it uses LOG_LOCAL1. This flag
-overrides the automatic detection. Be sure to specify a facility not used
-by anything else on your system (one of LOG_LOCAL0 through LOG_LOCAL7, for
-example).
-
-=item B<--enable-libtool>
-
-INN has optional support for libtool to generate shared versions of INN's
-libraries. This can significantly decrease the size of the various
-binaries that come with a complete INN installation. You can also choose
-to use libtool even when only building static libraries; a libtool build
-may be somewhat more portable on weird systems. libtool builds aren't the
-default because they take somewhat longer. See C<./configure --help> for
-the various available options related to libtool builds.
-
-Please note that INN's shared library interface is not stable and may
-change drastically in future releases. For this reason, it's also not
-properly versioned and won't be until some degree of stability is
-guaranteed, and the relevant header files are not installed. Only INN
-should use INN's shared libraries, and you should only use the shared
-libraries corresponding to the version of INN that you're installing.
-
-Also, when updating an existing version of INN, INN tries to save backup
-copies of all files so that you can revert to the previous installed
-version. Unfortunately, when using shared libraries, this confuses
-ldconfig on some systems (such as Linux) and the symbolic links for the
-libraries may point to the .OLD versions. If this happens, you can either
-fix the links by hand or remove the .OLD versions and re-run ldconfig.
-
-=item B<--enable-uucp-rnews>
-
-If this option is given to configure, rnews will be installed setuid news,
-owned by group uucp, and mode 4550. This will allow the UUCP subsystem
-to run rnews to process UUCP batches of news articles. Prior to INN 2.3,
-installing rnews setuid news was standard; since most sites no longer use
-UUCP, it is no longer the default as of INN 2.3 and must be requested at
-configure time. You probably don't want to use this option unless your
-server accepts UUCP news batches.
-
-=item B<--enable-setgid-inews>
-
-If this option is given to configure, inews will be installed setgid news
-and world-executable so that non-privileged users on the news server
-machine can use inews to post articles locally (somewhat faster than
-opening a new network connection). For standalone news servers, by far
-the most common configuration now, there's no need to use this option;
-even if you have regular login accounts on your news server, INN's inews
-can post fine via a network connection to your running news server and
-doesn't need to use the local socket (which is what setgid enables it to
-do). Installing inews setgid was the default prior to INN 2.3.
-
-=item B<--with-berkeleydb=PATH>
-
-Enables support for Berkeley DB (2.x or 3.x), which means that it will
-then be possible to use the ovdb overview method if you wish. Enabling
-this configure option doesn't mean you'll be required to use ovdb, but it
-does require that Berkeley DB be installed on your system (including the
-header files, not just the runtime libraries). If a path is given, it
-sets the installed directory of Berkeley DB (configure will search for it
-in some standard locations, but if you have it installed elsewhere, you
-may need this option).
-
-=item B<--with-openssl=PATH>
-
-Enables support for SSL for news reading, which means it will be possible
-to have SSL or TLS encrypted NNTP connections between your server and
-newsreaders. This option requires OpenSSL be installed on your system
-(including the header files, not just the runtime libraries). If a path
-is given, it sets the installed directory of OpenSSL. After compiling and
-installing INN with this option, you'll still need to make a certificate
-and private key to use SSL. See below for details on how to do that.
-
-=item B<--enable-ipv6>
-
-Enables support for IPv6 in innd, innfeed, nnrpd, and several of the
-supporting programs. This option should be considered developmental at
-present. For more information see F<doc/IPv6-info> (and if you have any
-particularly good or bad news to report, please let us know at
-<inn-bugs@isc.org>).
-
-=back
-
-For the most common installation, a standalone news server, a suggested
-set of options is:
-
- ./configure --with-perl
-
-provided that you have the necessary version of Perl installed.
-(Compiling with an embedded Perl interpretor will allow you to use one of
-the available excellent spam filters if you so choose.)
-
-If the configure program runs successfully, then you are ready to build
-the distribution. From the root of the INN source tree, type:
-
- make
-
-At this point you can step away from the computer for a little while and
-have a quick snack while INN compiles. On a decently fast system it
-should only take five or ten minutes at the most to build.
-
-Once the build has completed successfully, you are ready to install INN
-into its final home. Type:
-
- make install
-
-You will need to run this command as root so that INN can create the
-directories it needs, change ownerships (if you did not compile as the
-news user) and install a couple of setuid wrapper programs needed to raise
-resource limits and allow innd to bind to ports under 1024. This step
-will install INN under the install directory (F</usr/local/news>, unless
-you specified something else to the configure script).
-
-If you are configuring SSL support for newsreaders, you must make a
-certificate and private key at least once. Type:
-
- make cert
-
-as root in order to do this.
-
-You are now ready for the really fun part: configuring your copy of INN!
-
-=head1 Choosing an Article Storage Format
-
-The first thing to decide is how INN should store articles on your system.
-There are four different methods for you to choose from, each of which has
-its own advantages and disadvantages. INN can support all four at the
-same time, so you can store certain newsgroups in one method and other
-newsgroups in another method.
-
-The supported storage formats are:
-
-=over 4
-
-=item tradspool
-
-This is the storage method used by all versions of INN previous to 2.0.
-Articles are stored as individual text files whose names are the same as
-the article number. The articles are divided up into directories based on
-the newsgroup name. For example, article 12345 in news.software.nntp
-would be stored as F<news/software/nntp/12345> relative to the root of the
-article spool.
-
-Advantages: Widely used and well-understood storage mechanism, can read
-article spools written by older versions of INN, compatible with all
-third-party INN add-ons, provides easy and direct access to the articles
-stored on your server and makes writing programs that fiddle with the news
-spool very easy, and gives you fine control over article retention times.
-
-Disadvantages: Takes a very fast file system and I/O system to keep up
-with current Usenet traffic volumes due to file system overhead. Groups
-with heavy traffic tend to create a bottleneck because of inefficiencies
-in storing large numbers of article files in a single directory. Requires
-a nightly expire program to delete old articles out of the news spool, a
-process that can slow down the server for several hours or more.
-
-=item timehash
-
-Articles are stored as individual files as in tradspool, but are divided
-into directories based on the arrival time to ensure that no single
-directory contains so many files as to cause a bottleneck.
-
-Advantages: Heavy traffic groups do not cause bottlenecks, and fine
-control of article retention time is still possible.
-
-Disadvantages: The ability to easily find all articles in a given
-newsgroup and manually fiddle with the article spool is lost, and INN
-still suffers from speed degredation due to file system overhead (creating
-and deleting individual files is a slow operation).
-
-=item timecaf
-
-Similar to timehash, articles are stored by arrival time, but instead of
-writing a separate file for each article, multiple articles are put in the
-same file.
-
-Advantages: Roughly four times faster than timehash for article writes,
-since much of the file system overhead is bypassed, while still retaining
-the same fine control over article retention time.
-
-Disadvantages: Even worse than timehash, and similar to cnfs (below),
-using this method means giving up all but the most careful manually
-fiddling with your article spool. As one of the newer and least widely
-used storage types, timecaf has not been as thoroughly tested as the other
-methods.
-
-=item cnfs
-
-CNFS stores articles sequentially in pre-configured buffer files. When
-the end of the buffer is reached, new articles are stored from the
-beginning of the buffer, overwriting older articles.
-
-Advantages: Blazingly fast because no file creations or deletions are
-necessary to store an article. Unlike all other storage methods, does not
-require manual article expiration; old articles are deleted to make room
-for new ones when the buffers get too full. Also, with CNFS your server
-will never throttle itself due to a full spool disk, and groups are
-restricted to just the buffer files you give them so that they can never
-use more than the amount of disk space you allocate to them.
-
-Disadvantages: Article retention times are more difficult to control
-because old articles are overwritten automatically. Attacks on Usenet,
-such as flooding or massive amounts of spam, can result in wanted articles
-expiring much faster than you intended (with no warning).
-
-=back
-
-Some general recommendations: If you are installing a transit news server
-(one that just accepts news and sends it out again to other servers and
-doesn't support any readers), use CNFS exclusively and don't worry about
-any of the other storage methods. Otherwise, put high-volume groups and
-groups whose articles you don't need to keep around very long (binaries
-groups, *.jobs*, news.lists.filters, etc.) in CNFS buffers, and use
-timehash, timecaf, or tradspool (if you have a fast I/O subsystem or need
-to be able to go through the spool manually) for everything else. You'll
-probably find it most convenient to keep special hierarchies like local
-hierarchies and hierarchies that should never expire in tradspool.
-
-If your news server will be supporting readers, you'll also need to choose
-an overview storage mechanism (by setting I<ovmethod> in F<inn.conf>).
-There are three overview mechanisms to choose from: tradindexed,
-buffindexed, and ovdb. tradindexed is very fast for readers, but it has
-to update two files for each incoming article and can be quite slow to
-write. buffindexed can keep up with a large feed more easily, since it
-uses large buffers to store all overview information, but it's somewhat
-slower for readers (although not as slow as the unified overview in INN
-2.2). ovdb stores overview data in a Berkeley DB database; it's fast and
-very robust, but requires more disk space. See the ovdb(5) man page for
-more information on it.
-
-Note that ovdb has not been as widely tested as the other overview
-mechanisms and should be considered experimental. tradindexed is the best
-tested and most widely used of the overview implementations.
-
-If buffindexed is chosen, you will need to create the buffers for it to
-use (very similar to creating CNFS buffers) and list the available buffers
-in F<buffindexed.conf>. See buffindexed.conf(5) for more information.
-
-=head1 Configuring INN
-
-All documentation from this point on assumes that you have set up the news
-user on your system as suggested in L<Installing INN> so that the root of
-your INN installation is F<~news/>. If you've moved things around by
-using options with C<configure>, you'll need to adjust the instructions to
-account for that.
-
-All of INN's configuration files are located in F<~news/etc>. Unless
-noted otherwise, any files referred to below are in this directory. When
-you first install INN, a sample of each file (containing lots of comments)
-is installed in F<~news/etc>; refer to these for concrete examples of
-everything discussed in this section.
-
-All of INN's configuration files, all of the programs that come with it,
-and some of its library routines have documentation in the form of man
-pages. These man pages were installed in F<~news/man> as part of the INN
-installation process and are the most complete reference to how INN works.
-You're strongly encouraged to refer to the man pages frequently while
-configuring INN, and for quick reference afterwards. Any detailed
-questions about individual configuration files or the behavior of specific
-programs should be answered in them. You may want to add F<~news/man> to
-your MANPATH environment variable; otherwise, you may have to use a
-command like:
-
- man -M ~news/man inn.conf
-
-to see the inn.conf(5) man page (for example).
-
-Before we begin, it is worth mentioning the wildmat pattern matching
-syntax used in many configuration files. These are simple wildcard
-matches using the asterisk (C<*>) as the wildcard character, much like the
-simple wildcard expansion used by Unix shells.
-
-In many cases, wildmat patterns can be specified in a comma-separated list
-to indicate a list of newsgroups. When used in this fashion, each pattern
-is checked in turn to see if it matches, and the last pattern in the line
-that matches the group name is used. Patterns beginning with C<!> mean to
-exclude groups matching that pattern. For example:
-
- *, !comp.*, comp.os.*
-
-In this case, we're saying we match everything (C<*>), except that we
-don't match anything under comp (C<!comp.*>), unless it is actually under
-the comp.os hierarchy (C<comp.os.*>). This is because non-comp groups
-will match only the first pattern (so we want them), comp.os groups will
-match all three patterns (so we want them too, because the third pattern
-counts in this case), and all other comp groups will match the first and
-second patterns and will be excluded by the second pattern.
-
-Some uses of wildmat patterns also support "poison" patterns (patterns
-starting with C<@>). These patterns behave just like C<!> patterns when
-checked against a single newsgroup name. Where they become special is for
-articles crossposted to multiple newsgroups; normally, such an article
-will be considered to match a pattern if any of the newsgroups it is
-posted to matches the pattern. If any newsgroup the article is posted to
-matches an expression beginning with C<@>, however, that article will not
-match the pattern even if other newsgroups to which it was posted match
-other expressions.
-
-See uwildmat(3) for full details on wildmat patterns.
-
-In all INN configuration files, blank lines and lines beginning with a
-C<#> symbol are considered comments and are ignored. Be careful, not all
-files permit comments to begin in the middle of the line.
-
-=head2 inn.conf
-
-The first, and most important file is F<inn.conf>. This file is organized
-as a series of parameter-value pairs, one per line. The parameter is
-first, followed by a colon and one or more whitespace characters, and then
-the value itself. For some parameters the value is a string or a number;
-for others it is true or false. (True values can be written as C<yes>,
-C<true>, or C<on>, whichever you prefer. Similarly, false values can be
-written as C<no>, C<false>, or C<off>.)
-
-F<inn.conf> contains dozens of changeable parameters (see inn.conf(5) for
-full details), but only a few really need to be edited during normal
-operation:
-
-=over 4
-
-=item allownewnews
-
-If set to true then INN will support the NEWNEWS command for news readers.
-While this can be an expensive operation, its speed has been improved
-considerably as of INN 2.3 and it's probably safe to turn on without
-risking excessive server load. The default is true. (Note that the
-I<access:> setting in F<readers.conf> overrides this value; see
-readers.conf(5) for more details.)
-
-=item complaints
-
-Used to set the value of the X-Complaints-To: header, which is added to
-all articles posted locally. The usual value would be something like
-C<abuse@example.com> or C<postmaster@example.com>. If not specified, the
-newsmaster email address will be used.
-
-=item hiscachesize
-
-The amount of memory (in kilobytes) to allocate for a cache of recently
-used history file entries. Setting this to 0 disables history caching.
-History caching can greatly increase the number of articles per second
-that your server is capable of processing. A value of C<256> is a good
-default choice.
-
-=item logipaddr
-
-If set to true (the default), INN will log the IP address (or hostname, if
-the host is listed in F<incoming.conf> with a hostname) of the remote host
-from which it received an article. If set to false, the trailing Path:
-header entry is logged instead. If you are using controlchan (see below)
-and need to process ihave/sendme control messages (this is very, very
-unlikely, so if you don't know what this means, don't worry about it),
-make sure you set this to false, since controlchan needs a site name, not
-an IP address.
-
-=item organization
-
-Set this to the name of your organization as you want it to appear in the
-Organization: header of all articles posted locally and not already
-containing that header. This will be overridden by the value of the
-ORGANIZATION environment variable (if it exists). If neither this
-parameter nor the environment variable or set, no Organization: header
-will be added to posts which lack one.
-
-=item pathhost
-
-This is the name of your news server as you wish it to appear in the Path:
-header of all postings which travel through your server (this includes
-local posts and incoming posts that you forward out to other sites). If
-this parameter is unspecified, the fully-qualified domain name (FQDN) of
-the machine will be used instead. Please use the FQDN of your server or
-an alias for your server unless you have a very good reason not to; a
-future version of the news RFCs may require this.
-
-=item rlimitnofile
-
-If set to a non-negative value (the default is C<-1>), INN (both innd and
-innfeed) will try to raise the maximum number of open file descriptors to
-this value when it starts. This may be needed if you have lots of
-incoming and outgoing feeds. Note that the maximum value for this setting
-is very operating-system-dependent, and you may have to reconfigure your
-system (possibly even recompile your kernel) to increase it. See L<File
-Descriptor Limits> for complete details.
-
-=back
-
-There are tons of other possible settings; you may want to read through
-inn.conf(5) to get a feel for your options. Don't worry if you don't
-understand the purpose of most of them right now. Some of the settings
-are only needed for very obscure things, and with more experience running
-your news server the rest will make more sense.
-
-=head2 newsfeeds
-
-F<newsfeeds> determines how incoming articles are redistributed to your
-peers and to other INN processes. F<newsfeeds> is very versatile and
-contains dozens of options; we will touch on just the basics here.
-The manpage contains more detailed information.
-
-F<newsfeeds> is organized as a series of feed entries. Each feed entry is
-composed of four fields separated by colons. Entries may span multiple
-lines by using a backslash (C<\>) to indicate that the next line is a
-continuation of the current line. (Note that comments don't interact with
-backslashes in the way you might expect. A commented-out line ending in a
-backslash will still be considered continued on the next line, possibly
-resulting in more commented out than you intended or bizarre syntax
-errors. In general, it's best to avoid commenting out lines in the middle
-of continuation lines.)
-
-The first field in an entry is the name of the feed. It must be unique,
-and for feeds to other news servers it is usually set to the actual
-hostname of the remote server (this makes things easier). The name can
-optionally be followed by a slash and a comma-separated exclude list. If
-the feed name or any of the names in the exclude list appear in the Path
-line of an article, then that article will not be forwarded to the feed as
-it is assumed that it has passed through that site once already. The
-exclude list is useful when a news server's hostname is not the same as
-what it puts in the Path header of its articles, or when you don't want a
-feed to receive articles from a certain source.
-
-The second field specifies a set of desired newsgroups and distribution
-lists, given as newsgroup-pattern/distribution-list. The distribution
-list is not described here; see newsfeeds(5) for information (it's not
-used that frequently in practice). The newsgroup pattern is a
-wildmat-style pattern list as described above (supporting C<@>).
-
-The third field is a comma-separated list of flags that determine both the
-type of feed entry and sets certain parameters for the entry. See
-newsfeeds(5) for information on the flag settings; you can do a surprising
-amount with them. The three most common patterns, and the ones mainly
-used for outgoing news feeds to other sites, are C<Tf,Wnm> (to write out a
-batch file of articles to be sent, suitable for processing by nntpsend and
-innxmit), C<Tm> (to send the article to a funnel feed, used with innfeed),
-and C<Tc,Wnm*> (to collect a funnel feed and send it via a channel feed to
-an external program, used to send articles to innfeed).
-
-The fourth field is a multi-purpose parameter whose meaning depends on the
-settings of the flags in the third field. To get a feel for it using the
-examples above, for file feeds (C<Tf>) it's the name of the file to write,
-for funnel feeds (C<Tm>) it's the name of the feed entry to funnel into,
-and for channel feeds (C<Tc>) it's the name of the program to run and feed
-references to articles.
-
-Now that you have a rough idea of the file layout, we'll begin to add the
-actual feed entries. First, we'll set up the special ME entry. This entry
-is required and serves two purposes: the newsgroup pattern specified here
-is prepended to the newsgroup list of all other feeds, and the
-distribution pattern for this entry determines what distributions (from
-the Distribution: header of incoming articles) are accepted from remote
-sites by your server. The example in the sample newsfeeds file is a good
-starting point. If you are going to create a local hierarchy that should
-not be distributed off of your system, it may be useful to exclude it from
-the default subscription pattern, but default subscription patterns are
-somewhat difficult to use right so you may want to just exclude it
-specifically from every feed instead.
-
-The ME entry tends to confuse a lot of people, so this point is worth
-repeating: the newsgroup patterns set the default subscription for
-I<outgoing> feeds, and the distribution patterns set the acceptable
-Distribution: header entries for I<incoming> articles. This is confusing
-enough that it may change in later versions of INN.
-
-There are two basic ways to feed articles to remote sites. The most
-common for large sites and particularly for transit news servers is
-innfeed(8), which sends articles to remote sites in real time (the article
-goes out to all peers that are supposed to receive it immediately after
-your server accepts it). For smaller sites, particularly sites where the
-only outgoing messages will be locally posted articles, it's more common
-to batch outgoing articles and send them every ten minutes or so from cron
-using nntpsend(8) and innxmit(8). Batching gives you more control and
-tends to be extremely stable and reliable, but it's much slower and can't
-handle high volume very well.
-
-Batching outgoing posts is easy to set up; for each peer, add an entry to
-newsfeeds that looks like:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tf,Wnm:
-
-where <newsgroups> is the wildmat pattern for the newsgroups that site
-wants. In this example, the actual name of the remote site is
-"remote.example.com", but it puts "news.example.com" in the Path: header.
-If the remote site puts its actual hostname in the Path: header, you won't
-need the C</news.example.com> part.
-
-This entry will cause innd to write out a file in F<~news/spool/outgoing>
-named F<remote.example.com> and containing the Message-ID and storage
-token of each message to send to that site. (The storage token is INN's
-internal pointer to where an article is stored; to retrieve an article
-given its storage token, use sm(8)). F<innxmit> knows how to read files
-of this format and send those articles to the remote site. For
-information on setting it up to run periodically, see L<Setting Up the
-Cron Jobs> below. You will also need to set up a config file for
-F<nntpsend>; see the man page for nntpsend.ctl(5) for more information.
-
-If instead you want to use F<innfeed> to send outgoing messages
-(recommended for sites with more than a couple of peers), you need some
-slightly more complex magic. You still set up a separate entry for each
-of your peers, but rather than writing out batch files, they all "funnel"
-into a special innfeed entry. That special entry collects all of the
-separate funnel feeds and sends the data through a special sort of feed to
-an external program (F<innfeed> in this case); this is a "channel" feed.
-
-First, the special channel feed entry for F<innfeed> that will collect all
-the funnel feeds:
-
- innfeed!\
- :!*\
- :Tc,Wnm*:/usr/local/news/bin/startinnfeed -y
-
-(adjust the path to startinnfeed(1) if you installed it elsewhere). Note
-that we don't feed this entry any articles directly (its newsgroup pattern
-is C<!*>). Note also that the name of this entry ends in an exclamation
-point. This is a standard convention for all special feeds; since the
-delimiter for the Path: header is C<!>, no site name containing that
-character can ever match the name of a real site.
-
-Next, set up entries for each remote site to which you will be feeding
-articles. All of these entries should be of the form:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tm:innfeed!
-
-specifying that they funnel into the C<innfeed!> feed. As in the previous
-example for batching, "remote.example.com" is the actual name of the
-remote peer, "news.example.com" is what it puts in the Path: header (if
-different than the actual name of the server), and <newsgroups> is the
-wildmat pattern of newsgroups to be sent.
-
-As an alternative to NNTP, INN may also feed news out to an IMAP server,
-by using imapfeed(8), which is almost identical to F<innfeed>. The
-F<startinnfeed> process can be told to start F<imapfeed> instead of
-F<innfeed>. The feed entry for this is as follows:
-
- imapfeed!\
- :!*\
- :Tc,Wnm*,S16384:/usr/local/news/bin/startinnfeed imapfeed
-
-And set up entries for each remote site like:
-
- remote.example.com/news.example.com\
- :<newsgroups>\
- :Tm:imapfeed!
-
-For more information on F<imapfeed>, look at the
-F<innfeed/imap_connection.c>. For more information on IMAP in general,
-see RFC 2060.
-
-Finally, there is a special entry for controlchan(8), which processes
-newsgroup control messages, that should always be in F<newsfeeds> unless
-you never want to honor any control messages. This entry should look
-like:
-
- controlchan!\
- :!*,control,control.*,!control.cancel\
- :Tc,Wnsm:/usr/local/news/bin/controlchan
-
-(modified for the actual path to F<controlchan> if you put it somewhere
-else). See L<Processing Control Messages> for more details.
-
-For those of you upgrading from earlier versions of INN, note that the
-functionality of overchan(8) and F<crosspost> is now incorporated into INN
-and neither of those programs is necessary. Unfortunately, F<crosspost>
-currently will not work even with the tradspool storage method. You can
-still use F<overchan> if you make sure to set I<useoverchan> to true in
-F<inn.conf> so that innd doesn't write overview data itself, but be
-careful: innd may accept articles faster than overchan can process the
-data.
-
-=head2 incoming.conf
-
-F<incoming.conf> file specifies which machines are permitted to connect to
-your host and feed it articles. Remote servers you peer with should be
-listed here. Connections from hosts not listed in this file will (if you
-don't allow readers) be rejected or (if you allow readers) be handed off
-to nnrpd and checked against the access restrictions in F<readers.conf>.
-
-Start with the sample F<incoming.conf> and, for each remote peer, add an
-entry like:
-
- peer remote.example.com { }
-
-This uses the default parameters for that feed and allows incoming
-connections from a machine named "remote.example.com". If that peer could
-be connecting from several different machines, instead use an entry like:
-
- peer remote.example.com {
- hostname: "remote.example.com, news.example.com"
- }
-
-This will allow either "remote.example.com" or "news.example.com" to feed
-articles to you. (In general, you should add new peer lines for each
-separate remote site you peer with, and list multiple host names using the
-I<hostname> key if one particular remote site uses multiple servers.)
-
-You can restrict the newsgroups a remote site is allowed to send you,
-using the same sort of pattern that newsfeeds(5) uses. For example, if
-you want to prevent "example.com" hosts from sending you any articles in
-the C<local.*> hierarchy (even if they're crossposted to other groups),
-change the above to:
-
- peer remote.example.com {
- patterns: "*, @local.*"
- hostname: "remote.example.com, news.example.com"
- }
-
-Note, however, that restricting what a remote side can send you will
-I<not> reduce your incoming bandwidth usage. The remote site will still
-send you the entire article; INN will just reject it rather than saving it
-to disk. To reduce bandwidth, you have to contact your peers and ask them
-not to send you the traffic you don't want.
-
-There are various other things you can set, including the maximum number
-of connections the remote host will be allowed. See incoming.conf(5) for
-all the details.
-
-Note for those familiar with older versions of INN: this file replaces
-the old F<hosts.nntp> configuration file.
-
-=head2 cycbuff.conf
-
-F<cycbuff.conf> is only required if CNFS is used. If you aren't using
-CNFS, skip this section.
-
-CNFS stores articles in logical objects called I<metacycbuffs>. Each
-metacycbuff is in turn composed of one or more physical buffers called
-I<cycbuffs>. As articles are written to the metacycbuff, each article is
-written to the next cycbuff in the list in a round-robin fashion (unless
-C<sequential> mode is specified, in which case each cycbuff is filled
-before moving on to the next). This is so that you can distribute the
-individual cycbuffs across multiple physical disks and balance the load
-between them.
-
-There are two ways to create your cycbuffs:
-
-=over 4
-
-=item 1.
-
-Use a block device directly. This will probably give you the most speed
-since it avoids the file system overhead of large files, but it requires
-your OS support mmap(2) on a block device. Solaris supports this, as do
-late Linux 2.4 kernels. FreeBSD does not at last report. Also on many
-PC-based Unixes it is difficult to create more than eight partitions,
-which may limit your options.
-
-=item 2.
-
-Use a real file on a filesystem. This will probably be a bit slower than
-using a block device directly, but it should work on any Unix system.
-
-=back
-
-If you're having doubts, use option #2; it's easier to set up and should
-work regardless of your operating system.
-
-Now you need to decide on the sizes of your cycbuffs and metacycbuffs.
-You'll probably want to separate the heavy-traffic groups
-(C<alt.binaries.*> and maybe a few other things like C<*.jobs*> and
-C<news.lists.filters>) into their own metacycbuff so that they don't
-overrun the server and push out articles on the more useful groups. If
-you have any local groups that you want to stay around for a while then
-you should put them in their own metacycbuff as well, so that they don't
-get pushed out by other traffic. (Or you might store them in one of the
-other storage methods, such as tradspool.)
-
-For each metacycbuff, you now need to determine how many cycbuffs will
-make up the metacycbuff, the size of those cycbuffs, and where they will
-be stored. Some OSes do not support files larger than 2 GB, which will
-limit the size you can make a single cycbuff, but you can still combine
-many cycbuffs into each metacycbuff. Older versions of Linux are known to
-have this limitation; FreeBSD does not. Some OSes that support large
-files don't support direct access to block devices for large partitions
-(Solaris prior to Solaris 7, or not running in 64-bit mode, is in this
-category); on those OSes, if you want cycbuffs over 2 GB, you'll have to
-use regular files. If in doubt, keep your cycbuffs smaller than 2 GB.
-Also, when laying out your cycbuffs, you will want to try to arrange them
-across as many physical disks as possible (or use a striped disk array and
-put them all on that).
-
-In order to use any cycbuff larger than 2 GB, you need to build INN with
-the B<--enable-largefiles> option. See L<Installing INN> for more
-information and some caveats.
-
-For each cycbuff you will be creating, add a line to F<cycbuff.conf> like
-the following:
-
- cycbuff:NAME:/path/to/buffer:SIZE
-
-NAME must be unique and must be at most seven characters long. Something
-simple like "BUFF00", "BUFF01", etc. is a decent choice, or you may want
-to use something that includes the SCSI target and slice number of the
-partition. SIZE is the buffer size in kilobytes (if you're trying to stay
-under 2 GB, keep your sizes below C<2097152>).
-
-Now, you need to tell INN how to group your cycbuffs into metacycbuffs.
-This is similar to creating cycbuff entries:
-
- metacycbuff:BUFFNAME:CYCBUFF,CYCBUFF,CYCBUFF
-
-BUFFNAME is the name of the metacycbuff and must be unique and at most
-eight characters long. These should be a bit more meaningful than the
-cycbuff names since they will be used in other config files as well. Try
-to name them after what will be stored in them; for example, if this
-metacycbuff will hold alt.binaries postings, "BINARIES" would be a good
-choice. The last part of the entry is a comma-separated list of all of
-the cycbuffs that should be used to build this metacycbuff. Each cycbuff
-should only appear in one metacycbuff line, and all metacycbuff lines must
-occur after all cycbuff lines in the file.
-
-If you want INN to fill each cycbuff before moving on to the next one
-rather than writing to them round-robin, add C<:SEQUENTIAL> to the end of
-the metacycbuff line. This may give noticeably better performance when
-using multiple cycbuffs on the same spindle (such as partitions or slices
-of a larger disk), but will probably give worse performance if your
-cycbuffs are spread out across a lot of spindles.
-
-By default, CNFS data is flushed to disk every 25 articles. If you're
-running a small server with a light article load, this could mean losing
-quite a few articles in a crash. You can change this interval by adding a
-cycbuffupdate line to your F<cycbuff.conf> file; see cycbuff.conf(5) for
-more details.
-
-Finally, you have to create the cycbuffs. See L<Creating the Article
-Spool> for more information on how to do that.
-
-=head2 storage.conf
-
-F<storage.conf> determines where incoming articles will be stored (what
-storage method, and in the case of CNFS, what metacycbuff). Each entry in
-the file defines a storage class for articles. The first matching storage
-class is used to store the article; if no storage class matches, INN will
-reject that article. (This is almost never what you want, so make sure
-this file ends in a catch-all entry that will match everything.)
-
-A storage class definition looks like this:
-
- method <methodname> {
- newsgroups: <wildmat>
- class: <storage_class>
- size: <minsize>[,<maxsize>]
- expires: <mintime>[,<maxtime>]
- options: <options>
- }
-
-<methodname> is the name of the storage method to use to store articles in
-this class ("cnfs", "timehash", "timecaf", "tradspool", or the special
-method "trash" that accepts the article and throws it away).
-
-The first parameter is a wildmat pattern in the same format used by the
-newsfeeds(5) file, and determines what newsgroups are accepted by this
-storage class.
-
-The second parameter is a unique number identifying this storage class and
-should be between 0 and 255. It can be used to control article
-expiration, and for timehash and timecaf will set the top-level directory
-in which articles accepted by this storage class are stored. The easiest
-way to deal with this parameter is to just number all storage classes in
-F<storage.conf> sequentially. The assignment of a particular number to a
-storage class is arbitrary but I<permanent> (since it is used in storage
-tokens).
-
-The third parameter can be used to accept only articles in a certain size
-range into this storage class. A <maxsize> of C<0> (or a missing
-<maxsize>) means no upper limit (and of course a <minsize> of C<0> would
-mean no lower limit, because all articles are more than zero bytes long).
-If you don't want to limit the size of articles accepted by this storage
-class, leave this parameter out entirely.
-
-The fourth parameter you probably don't want to use; it lets you assign
-storage classes based on the Expires: header of incoming articles. The
-exact details are in storage.conf(5). It's very easy to use this
-parameter incorrectly; leave it out entirely unless you've read the man
-page and know what you're doing.
-
-The fifth parameter is the options parameter. Currently only CNFS uses
-this field; it should contain the name of the metacycbuff used to store
-articles in this storage class.
-
-If you're using CNFS exclusively, just create one storage class for each
-metacycbuff that you have defined in F<cycbuff.conf> and set the
-newsgroups pattern according to what newsgroups should be stored in that
-buffer.
-
-If you're using timehash or timecaf, the storage class IDs are used to
-store articles in separate directory trees, which you can take advantage
-of to put particular storage classes on different disks. Also, currently
-storage class is the only way to specify expiration time, so you will need
-to divide up your newsgroups based on how long you want to retain articles
-in those groups and create a storage class for each such collection of
-newsgroups. Make note of the storage class IDs you assign as they will be
-needed when you edit F<expire.ctl> a bit later.
-
-=head2 expire.ctl
-
-F<expire.ctl> sets the expiration policy for articles stored on the
-server. Be careful, since the default configuration will expire most
-articles after 10 days; in most circumstances this deletion is
-I<permanent>, so read this whole section carefully if you want to keep
-local hierarchies forever. (See archive(8) for a way to automate backups
-of important articles.)
-
-Only one entry is required for all storage classes; it looks like:
-
- /remember/:10
-
-This entry says how long to keep the Message-IDs for articles that have
-already expired in the history file so that the server doesn't accept them
-again. Occasionally, fairly old articles will get regurgitated somewhere
-and offered to you again, so even after you've expired articles from your
-spool, you want to keep them around in your history file for a little
-while to ensure you don't get duplicates.
-
-INN will reject any articles more than a certain number of days old (the
-I<artcutoff> parameter in F<inn.conf>, defaulting to C<10>); the number on
-the C</remember/> line should match that.
-
-CNFS makes no further use of F<expire.ctl>, since articles stored in CNFS
-buffers expire automatically when the buffer runs out of free space (but
-see the C<-N> option in expireover(8) if you really want to expire them
-earlier). For other storage methods, there are two different syntaxes of
-this file, depending on I<groupbaseexpiry> in F<inn.conf>. If it is set
-to false, F<expire.ctl> takes entries of the form:
-
- <storage_class>:<keep>:<default>:<purge>
-
-<storage_class> is the number assigned to a storage class in
-F<storage.conf>. <default> is the number of days to keep normal articles
-in that storage class (decimal values are allowed). For articles that
-don't have an Expires: header, those are the only two values that matter.
-For articles with an Expires: header, the other two values come into play;
-the date given in the Expires: header of an article will be honored,
-subject to the contraints set by <keep> and <purge>. All articles in this
-storage class will be kept for at least <keep> days, regardless of their
-Expires: headers, and all articles in this storage class will be expired
-after <purge> days, even if their Expires: headers specify a longer life.
-
-All three of these fields can also contain the special keyword C<never>.
-If <default> is C<never>, only articles with explicit Expires: headers
-will ever be expired. If <keep> is C<never>, articles with explicit
-Expires: headers will be kept forever. Setting <purge> to C<never> says
-to honor Expires: headers even if they specify dates far into the future.
-(Note that if <keep> is set to C<never>, all articles with Expires:
-headers are kept forever and the value of <purge> is not used.)
-
-If the value of C<groupbaseexpiry> is true, F<expire.ctl> takes entries of
-the form:
-
- <wildmat>:<flag>:<keep>:<default>:<purge>
-
-<wildmat> is a wildmat expression (C<!> and C<@> not permitted, and only a
-single expression, not a comma-separated set of them). Each expiration
-line applies to groups matching the wildmat expression. <flag> is C<M>
-for moderated groups, C<U> for unmoderated groups, and C<A> for groups
-with any moderation status; the line only matches groups with the
-indicated expiration status. All of the other fields have the same
-meaning as above.
-
-=head2 readers.conf
-
-Provided that I<noreader> is set to false in F<inn.conf>, any connection
-from a host that doesn't match an entry in F<incoming.conf> (as well as
-any connection from a host that does match such an entry, but has issued a
-MODE READER command) will be handed off to nnrpd(8), the part of INN that
-supports newsreading clients. nnrpd uses F<readers.conf> to determine
-whether a given connection is allowed to read news, and if so what
-newsgroups the client can read and post to.
-
-There are a variety of fairly complicated things that one can do with
-F<readers.conf>, things like run external authentication programs that can
-query RADIUS servers. See readers.conf(5) and the example file for all
-the gory details. Here's an example of probably the simplest reasonable
-configuration, one that only allows clients in the example.com domain to
-read from the server and allows any host in that domain to read and post
-to all groups:
-
- auth "example.com" {
- hosts: "example.com, *.example.com"
- default: "<user>"
- default-domain: "example.com"
- }
-
- access "all" {
- users: "*@example.com"
- newsgroups: "*"
- }
-
-If you're running a server for one particular domain, want to allow all
-hosts within that domain to read and post to any group on the server, and
-want to deny access to anyone outside that domain, just use the above and
-change C<example.com> in the above to your domain and you're all set.
-Lots of examples of more complicated things are in the sample file.
-
-=head1 Creating the Article Spool (CNFS only)
-
-If you are using actual files as your CNFS buffers, you will need to
-pre-create those files, ensuring they're the right size. The easiest way
-to do this is with dd. For each cycbuff in F<cycbuff.conf>, create the
-buffer with the following commands (as the news user):
-
- dd if=/dev/zero of=/path/to/buffer bs=1k count=BUFFERSIZE
- chmod 664 /path/to/buffer
-
-Substitute the correct path to the buffer and the size of the buffer as
-specified in F<cycbuff.conf>. This will create a zero-filled file of the
-correct size; it may take a while, so be prepared to wait.
-
-Here's a command that will print out the dd(1) commands that you should
-run:
-
- awk -F: \
- '/^cy/ { printf "dd if=/dev/zero of=%s bs=1k count=%s\n", $3, $4 }' \
- ~news/etc/cycbuff.conf
-
-If you are using block devices, you don't technically have to do anything
-at all (since INN is capable of using the devices in F</dev>), but you
-probably want to create special device files for those devices somewhere
-for INN's private use. It s more convenient to keep all of INN's stuff
-together, but more importantly, the device files used by INN really should
-be owned by the news user and group, and you may not want to do that with
-the files in F</dev>.
-
-To create the device files for INN, use mknod(8) with a type of C<b>,
-getting the major and minor device numbers from the existing devices in
-F</dev>. There's a small shell script in cycbuff.conf(5) that may help
-with this. Make sure to create the device files in the location INN
-expects them (specified in F<cycbuff.conf>).
-
-Solaris users please note: on Solaris, do not use block devices that
-include the first cylinder of the disk. Solaris doesn't protect the
-superblock from being overwritten by an application writing to block
-devices and includes it in the first cylinder of the disk, so unless you
-use a slice that starts with cylinder 1 instead of 0, INN will invalidate
-the partition table when it tries to initialize the cycbuff and all
-further accesses will fail until you repartition.
-
-=head1 Creating the Database Files
-
-At this point, you need to set up the news database directory
-(F<~news/db>). This directory will hold the active(5) file (the list of
-newsgroups you carry), the active.times(5) file (the creator and creation
-time of newsgroups created since the server was initialized), the
-newsgroups(5) file (descriptions for all the newsgroups you carry), and
-the history(5) file (a record of every article the server currently has or
-has seen in the past few days, used to decide whether to accept or refuse
-new incoming messages).
-
-Before starting to work on this, make sure you're logged on as the news
-user, since all of these files need to be owned by that user. This is a
-good policy to always follow; if you are doing any maintenance work on
-your news server, log on as the news user. Don't do maintenance work as
-root. Also make sure that F<~news/bin> is in the default path of the news
-user (and while you're at it, make sure F<~news/man> is in the default
-MANPATH) so that you can run INN maintenance commands without having to
-type the full path.
-
-If you already have a server set up (if you're upgrading, or setting up a
-new server based on an existing server), copy F<active> and F<newsgroups>
-from that server into F<~news/db>. Otherwise, you'll need to figure out
-what newsgroups you want to carry and create new active and newsgroups
-files for them. If you plan to carry a full feed, or something close to
-that, go to <ftp://ftp.isc.org/pub/usenet/CONFIG/> and download F<active>
-and F<newsgroups> from there; that will start you off with reasonably
-complete files. If you plan to only carry a small set of groups, the
-default minimal F<active> file installed by INN is a good place to start;
-you can create additional groups after the server is running by using
-C<ctlinnd newgroup>. (Another option is to use actsync(8) to synchronize
-your newsgroup list to that of another server.)
-
-C<control> and C<junk> must exist as newsgroups in your active file for
-INN to start, and creating pseudogroups for the major types of control
-messages is strongly encouraged for all servers that aren't standalone.
-If you don't want these groups to be visible to clients, do I<not> delete
-them; simply hide them in F<readers.conf>. C<to> must also exist as a
-newsgroup if you have mergetogroups set in F<inn.conf>.
-
-Next, you need to create an empty history database. To do this, type:
-
- cd ~news/db
- touch history
- makedbz -i
-
-When it finishes, rename the files it created to remove the C<.n> in the
-file names and then make sure the file permissions are correct on all the
-files you've just created:
-
- chmod 644 *
-
-Your news database files are now ready to go.
-
-=head1 Configuring syslog
-
-While some logs are handled internally, INN also logs a wide variety of
-information via syslog. INN's nightly report programs know how to roll
-and summarize those syslog log files, but when you first install INN you
-need to set them up.
-
-If your system understands the C<news> syslog facility, INN will use it;
-otherwise, it will log to C<local1>. Nearly every modern system has a
-C<news> syslog facility so you can safely assume that yours does, but if
-in doubt take a look at the output from running C<configure>. You should
-see a line that looks like:
-
- checking log level for news... LOG_NEWS
-
-If that says LOG_LOCAL1 instead, change the below instructions to use
-C<local1> instead of C<news>.
-
-Edit F</etc/syslog.conf> on your system and add lines that look like the
-following:
-
- news.crit /usr/local/news/log/news.crit
- news.err /usr/local/news/log/news.err
- news.notice /usr/local/news/log/news.notice
-
-(Change the path names as necessary if you installed INN in a different
-location than F</usr/local/news>.) These lines I<must> be tab-delimited,
-so don't copy and paste from these instructions. Type it in by hand and
-make sure you use a tab, or you'll get mysterious failures. You'll also
-want to make sure that news log messages don't fill your other log files
-(INN generates a lot of log traffic); so for every entry in
-F</etc/syslog.conf> that starts with C<*>, add C<;news.none> to the end of
-the first column. For example, if you have a line like:
-
- *.err /dev/console
-
-change it to:
-
- *.err;news.none /dev/console
-
-(You can choose not to do this for the higher priority log messages, if
-you want to make sure they go to your normal high-priority log files as
-well as INN's. Don't bother with anything lower priority than C<crit>,
-though. C<news.err> isn't interesting enough to want to see all the
-time.) Now, make sure that the news log files exist; syslog generally
-won't create files automatically. Enter the following commands:
-
- touch /usr/local/news/log/news.crit
- touch /usr/local/news/log/news.err
- touch /usr/local/news/log/news.notice
- chown news /usr/local/news/log/news.*
- chgrp news /usr/local/news/log/news.*
-
-(again adjusting the paths if necessary for your installation). Finally,
-send a HUP signal to syslogd to make it re-read its configuration file.
-
-=head1 Setting Up the Cron Jobs
-
-INN requires a special cron job to be set up on your system to run
-news.daily(8) which performs daily server maintenance tasks such as
-article expiration and the processing and rotation of the server logs.
-Since it will slow the server down while it is running, it should be run
-during periods of low server usage, such as in the middle of the night.
-To run it at 3am, for example, add the following entry to the news user's
-crontab file:
-
- 0 3 * * * /usr/local/news/bin/news.daily expireover lowmark
-
-or, if your system does not have per-user crontabs, put the following line
-into your system crontab instead:
-
- 0 3 * * * su -c "/usr/local/news/bin/news.daily expireover lowmark" news
-
-If you're using any non-CNFS storage methods, add C<delayrm> to the above
-option list for news.daily.
-
-The news user obviously must be able to run cron jobs. On Solaris, this
-means that it must have a valid F</etc/shadow> entry and must not be
-locked (although it may be a non-login account). There may be similar
-restrictions with other operating systems.
-
-If you use the batching method to send news, also set up a cron job to run
-nntpsend(8) every ten minutes. nntpsend will run innxmit for all
-non-empty pending batch files to send pending news to your peers. That
-cron entry should look something like:
-
- 0,10,20,30,40,50 * * * * /usr/local/news/bin/nntpsend
-
-The pathnames and user ID used above are the installation defaults; change
-them to match your installation if you used something other than the
-defaults.
-
-The parameters passed to news.daily in the above example are the most
-common (and usually the most efficient) ones to use. More information on
-what these parameters do can be found in the news.daily(8) man page.
-
-=head1 File Descriptor Limits
-
-INN likes to use a lot of file descriptors, particularly if you have a lot
-of peers. Depending on what your system defaults are, you may need to
-make sure the default limit is increased for INN (particularly for innd
-and innfeed). This is vital on Solaris, which defaults (at least as of
-2.6) to an absurdly low limit of 64 file descriptors per process.
-
-One way to increase the number of file descriptors is to set
-I<rlimitnofile> in F<inn.conf> to a higher value. This will cause both
-startinnfeed and inndstart (the setuid root wrapper scripts that start
-innfeed and innd, respectively) to increase the file descriptor limits
-before they run the regular INN programs. Note, however, that INN won't
-be able to increase the limits above the hard limits set by your operating
-system; on some systems, that hard limit is normally 256 file descriptors
-(Linux, for example). On others, like Solaris, it's 1024. Increasing the
-limit beyond that value may require serious system configuration work.
-(On some operating systems, it requires patching and recompiling the
-kernel. On Solaris it can be changed in F</etc/system>, but for 2.6 or
-earlier the limit cannot be increased beyond 1024 without breaking
-select(2) and thereby breaking all of INN. For current versions of Linux,
-you may be able to change the maximum by writing to
-F</proc/sys/fs/file-max>.)
-
-256 file descriptors will probably be enough for all but the largest
-sites. There is no harm in setting the limits higher than you actually
-need (provided they're set to something lower than or equal to your system
-hard limit). C<256> is therefore a reasonable value to try.
-
-If you're installing INN on a Solaris system, particularly if you're
-installing it on a dedicated news server machine, it may be easier to just
-increase the default file descriptor limit across the board for all
-processes. You can do that by putting the line:
-
- set rlim_fd_cur = 256
-
-in F</etc/system> and rebooting. You can increase it all the way to
-C<1024> (and may need to if you have a particularly large site), but that
-can cause RPC and some stdio applications to break. It therefore probably
-isn't a good idea on a machine that isn't dedicated to INN.
-
-=head1 Starting and Stopping the System
-
-INN is started via the shell script F<rc.news>. This must be run as the
-news user and not as root. To start INN on system boot, you therefore
-want to put something like:
-
- su - news -c /usr/local/news/bin/rc.news
-
-in the system boot scripts. If innd is stopped or killed, you can restart
-it by running rc.news by hand as the news user.
-
-The rc.news script may also be used to shut down INN, with the C<stop>
-option:
-
- su - news -c '/usr/local/news/bin/rc.news stop'
-
-In the F<contrib> directory of this source tree is a sample init script
-for people using System V-style init.d directories.
-
-=head1 Processing Newsgroup Control Messages
-
-Control messages are specially-formatted messages that tell news servers
-to take various actions. Cancels (commands to delete messages) are
-handled internally by INN, and all other control messages are processed by
-controlchan. controlchan should be run out of F<newsfeeds> if you want
-your news server to process any control messages; see L<Configuring INN>
-for specific instructions.
-
-The actions of controlchan are determined by F<control.ctl>, which lists
-who can perform what actions. The primary control messages to be
-concerned with are C<newgroup> (to create a newsgroup), C<rmgroup> (to
-remove a newsgroup), and C<checkgroups> (to compare the list of groups
-carried in a hierarchy to a canonical list). INN comes with a
-F<control.ctl> file that processes control messages in most major public
-hierarchies; if you don't want to act on all those control messages, you
-should remove from that file all entries for hierarchies you don't want to
-carry.
-
-You can tell INN to just authenticate control messages based on the From
-header of the message, but this is obviously perilous and control messages
-are widely forged. Many hierarchies sign all of their control messages
-with PGP, allowing news servers to verify their authenticity, and checking
-those signatures for hierarchies that use them is highly recommended.
-controlchan knows how to do this (using pgpverify) without additional
-configuration, but you do have to provide it with a public key ring
-containing the public keys of all of the hierarchy administrators whose
-control messages you want to check.
-
-INN expects the public key ring to either be in the default location for a
-PGP public key ring for the news user (generally ~news/.gnupg for GnuPG
-and ~news/.pgp for old PGP implementations), or in pathetc/pgp
-(/usr/local/news/etc/pgp by default). The latter is the recommended path.
-To add a key to that key ring, use:
-
- gpg --import --homedir=/usr/local/news/etc/pgp <file>
-
-where <file> is a file containing the hierarchy key. Change the homedir
-setting to point to pathetc/pgp if you have INN installed in a non-default
-location. If you're using the old-style PGP program, an equivalent
-command is:
-
- env PGPPATH=/usr/local/news/etc/pgp pgp <file>
-
-You can safely answer "no" to questions about whether you want to sign,
-trust, or certify keys.
-
-The URLs from which you can get hierarchy keys are noted in comments in
-F<control.ctl>. L<ftp://ftp.isc.org/pub/pgpcontrol/PGPKEYS> tries to
-collect the major hierarchy keys.
-
-If you are using GnuPG, please note that the first user ID on the key will
-be the one that's used by INN for verification and must match the key
-listed in F<control.ctl>. If a hierarchy key has multiple user IDs, you
-may have to remove all the user IDs except the one that matches the
-F<control.ctl> entry using C<gpg --edit-key> and the C<delkey> command.
+++ /dev/null
-=head1 NAME
-
-libauth - routines for writing nnrpd resolvers and authenticators
-
-=head1 SYNOPSIS
-
- #include "libauth.h"
-
- struct res_info {
- struct sockaddr *client;
- struct sockaddr *local;
- char *clienthostname;
- };
-
- struct auth_info {
- char *username;
- char *password;
- };
-
- struct auth_info *get_auth_info(FILE *);
- struct res_info *get_res_info (FILE *);
-
- void free_auth_info(struct auth_info*);
- void free_res_info (struct res_info*);
-
-=head1 DESCRIPTION
-
-These functions provide a convenient C frontend to the nnrpd external
-authentication interface documented in F<doc/external-auth>. Use of
-this library is B<not> required; in particular, external resolvers and
-authenticators written in languages other than C will need to implement
-the necessary functionality themselves.
-
-The get_auth_info() and get_res_info() functions allocate sufficient
-memory for a B<struct auth_info> or B<struct res_info> and any necessary
-fields, and return a pointer to the struct with the fields filled in
-from information supplied by nnrpd (the B<FILE*> parameter generally
-should be C<stdin>). Both functions return NULL on error. The caller
-is responsible for deallocating the memory by using the functions below.
-
-The string fields of both structs are straightforward. The B<client>
-and B<local> fields of B<struct res_info> actually point to instances of
-B<struct sockaddr_in> (or B<struct sockaddr_in6> if IPv6 support is
-compiled in).
-
-The free_auth_info() and free_res_info() functions free the struct
-passed in as argument and all necessary fields.
-
-=head1 BUGS
-
-In many cases, nnrpd provides more information than is normally useful
-(for example, even when calling an authenticator, the resolver
-information is often provided.) On the other hand, in certain cases it
-provides less information than might be expected (for example, if nnrpd
-is reading from stdin rather than a socket). The implementation is
-capable of handling at least the first of these issues, but that
-functionality is not exposed in the interface.
-
-At present, F<libauth.h> and its implementation are located in
-F<authprogs/>; perhaps they should be moved to F<include/> and F<lib/>,
-respectively?
-
-=head1 HISTORY
-
-Written by Jeffrey M. Vinocur <jeff@litech.org> for InterNetNews.
-
-$Id: libauth.pod 5988 2002-12-12 23:02:14Z vinocur $
-
-=head1 SEE ALSO
-
-nnrpd(8), readers.conf(5), F<doc/external-auth>
-
-=cut
+++ /dev/null
-=head1 NAME
-
-his - routines for managing INN history
-
-=head1 SYNOPSIS
-
-B<#include E<lt>inn/history.hE<gt>>
-
-B<struct history;>
-
-B<struct histstats {>
-B< int hitpos;>
-B< int hitneg;>
-B< int misses;>
-B< int dne;>
-B<};>
-
-B<#define HIS_RDONLY ...>
-B<#define HIS_RDWR ...>
-B<#define HIS_CREAT ...>
-B<#define HIS_ONDISK ...>
-B<#define HIS_INCORE ...>
-B<#define HIS_MMAP ...>
-
-B<enum {>
-B< HISCTLG_PATH,>
-B< HISCTLS_PATH,>
-B< HISCTLS_SYNCCOUNT,>
-B< HISCTLS_NPAIRS,>
-B< HISCTLS_IGNOREOLD,>
-B< HISCTLS_STATINTERVAL>
-B<};>
-
-B<struct history *HISopen(const char *>I<path>B<, const char *>I<method>B<, int >I<flags>B<);>
-
-B<bool HISclose(struct history *>I<history>B<);>
-
-B<bool HISsync(struct history *>I<history>B<);>
-
-B<void HISsetcache(struct history *>I<history>B<, size_t >I<size>B<);>
-
-B<bool HISlookup(struct history *>I<history>B<, const char *>I<key>B<, time_t *>I<arrived>B<, time_t *>I<posted>B<, time_t *>I<expires>B<, TOKEN *>I<token>B<);>
-
-B<bool HIScheck(struct history *>I<history>B<, const char *>I<key>B<);>
-
-B<bool HISwrite(struct history *>I<history>B<, const char *>I<key>B<, time_t >I<arrived>B<, time_t >I<posted>B<, time_t >I<expires>B<, const TOKEN *>I<token>B<);>
-
-B<bool HISremember(struct history *>I<history>B<, const char *>I<key>B<, time_t >I<arrived>B<);>
-
-B<bool HISreplace(struct history *>I<history>B<, const char *>I<key>B<, time_t >I<arrived>B<, time_t >I<posted>B<, time_t >I<expires>B<, const TOKEN *>I<token>B<);>
-
-B<bool HISexpire(struct history *>I<history>B<, const char *>I<path>B<, const char *>I<reason>B<, bool >I<writing>B<, void *>I<cookie>B<, time_t >I<threshold>B<, bool (*>I<exists>B<)(void *cookie, time_t arrived, time_t posted, time_t expires, const TOKEN *token));>
-
-B<bool HISwalk(struct history *>I<history>B<, const char *>I<reason>B<, void *>I<cookie>B<, bool (*>I<callback>B<)(void *cookie, time_t arrived, time_t posted, time_t expires, const TOKEN *token));>
-
-B<struct histstats HISstats(struct history *>I<history>B<);>
-
-B<const char *HISerror(struct history *>I<history>B<);>
-
-B<bool HISctl(struct history *>I<history>B<, int >I<request>B<, void *>I<val>B<);>
-
-=head1 DESCRIPTION
-
-These functions provide provide access to the INN history
-database. They maintain key/value pairs in an opaque database whilst
-providing for expiry of outdated information.
-
-The history structure is an opaque handle returned from HISopen.
-
-The B<HISopen> function opens the history file designated by I<path>
-using the mode I<flags> using the specified I<method>. I<flags> may be
-B<HIS_RDONLY> to indicate that read-only access to the history
-database is desired, or B<HIS_RDWR> for read/write access. History
-methods are defined at build time; the history method currently
-available is "hisv6". On success a newly initialised history handle is
-returned, or B<NULL> on failure.
-
-B<HIS_ONDISK>, B<HIS_INCORE> and B<HIS_MMAP> may be logically ORed
-into I<flags> to provide a hint to the underlying history manager as
-to how it should handle its data files; B<HIS_ONDISK> indicates that
-the caller would like as much of the data to be kept on disk (and out
-of memory), B<HIS_INCORE> indicates that the data files should be kept
-in main memory where possible and B<HIS_MMAP> that the files should be
-mmap()ed into the processes address space. B<HIS_INCORE> is typically
-used where a mass rebuild of the history database is being performed;
-the underlying history manager may assume that the caller will call
-B<HISsync>() to sync the data files to disk.
-
-The B<HIS_CREAT> flag indicates that the history database should be
-initialised as new; if any options which affect creation of the
-database need to be set an anonymous history handle should be created
-by calling B<HISopen> with I<path> set to B<NULL>, any options set
-using B<HISctl>, then the database opened by calling B<HISctl> with
-B<HISCTLS_PATH>.
-
-The B<HISclose> function closes the handle I<history> and deallocates
-any resources associated with it. It returns B<false> on failure or
-B<true> on success.
-
-The B<HISsync> function synchronises any outstanding transactions
-associated with I<history> to disk.
-
-B<HISsetcache> associates a cache used for speeding up HIScheck with
-I<history>. The cache will occupy approximately I<size> bytes.
-
-B<HISlookup> retrieves a token from I<history> based on the passed
-I<key> (normally the Message-ID). If no entry with an associated token
-can be found, B<HISlookup> will return B<false>. If a token is found
-I<arrived>, I<expires>, and I<posted> are filled in with the message
-arrival, expiry, and posting times respectively (or zero, if the time
-component is not available), in addition to I<token> being set to the
-retrieved token and a function return value of B<true>. Any of
-arrived, expires, posted, or token may be B<NULL> in which case that
-component is not returned to the caller, without affecting the return
-value.
-
-B<HIScheck> checks the database I<history> for I<key> (normally the
-Message-ID); if I<key> has previously been set via B<HISwrite>,
-B<HIScheck> returns B<true>, else B<false>.
-
-B<HISwrite> writes a new entry to the database I<history> associated
-with I<key>. I<arrived>, I<posted>, and I<expired> specify the arrival,
-posting, and expiry time respectively; I<posted> and I<expired> may be
-specifed as <= 0 in which case that component shall be treated as
-absent in the database. I<token> is associated with the specified
-I<key>. B<HISwrite> returns B<true> on success, or B<false> on
-failure. The behaviour when I<key> is not unique with respect to the
-existing entries in I<history> is unspecified.
-
-B<HISremember> writes a new entry to the database I<history>
-associated with I<key>, merely remembering that this I<key> has been
-seen, together with its arrival time I<arrived>. B<HISremember>
-returns B<true> on success, or B<false> on failure. The behaviour when
-I<key> is not unique with respect to the existing entries in
-I<history> is unspecified.
-
-B<HISreplace> replaces an existing entry in the database I<history>,
-associated with I<key>. I<arrived>, I<posted>, I<expired> specify the
-arrival, posting and expiry time respectively; I<posted> and
-I<expired> may be specifed as <= 0 in which case that component shall
-be treated as absent in the database. I<token> is associated with the
-specified I<key>; if B<NULL> then the history database merely
-remembers that this I<key> has been seen, together with its arrival
-time. B<HISreplace> returns B<true> on success, or B<false> on
-failure.
-
-B<HISexpire> expires the history database associated with I<history>,
-creating a new, replacement, database in the same location if I<path>
-is B<NULL>, or in I<path> if not B<NULL>; if I<path> is not B<NULL>
-then the replacement of the old history database with the new one is
-assumed to be performed out of band by the caller. The I<writing> flag
-is normally passed as B<true>, if you wish to inhibit writing of the
-new database (and so merely see the callbacks), I<writing> may be set
-B<false>.
-
-If the underlying history mechanism needs to pause the server, the
-I<reason> string is used as the argument to the `ctlinnd pause'
-command, and as such the server should be reserved by the caller prior
-to calling B<HISexpire>; if the caller wishes to inhibit pausing of
-the server, passing B<NULL> will achieve this. If I<reason> is not
-B<NULL>, then on successful return from B<HISexpire> the server will
-be left paused and the caller should unpause it.
-
-The history database is scanned and entries with an associated storage
-token are passed to the discrimination function I<exists>.
-
-If I<exists>() returns B<false> it indicates that stored entity
-associated with token is no longer available (or no longer required),
-and therefore the associated history entry may be expired once it
-meets the I<threshold> constraint. If I<exists>() returns B<true> the
-entry is kept as-is in the newly expired history database.
-
-The I<exists> function is passed the arrival, posting and expiry
-times, in addition to the token associated with the entry. Note that
-posting and/or expiry may be zero, but that the token will never be
-B<NULL> (such entries are handled solely via the threshold
-mechanism). The storage token passed to the discrimination function
-may updated if required (for example, as might be needed by a
-hierachical storage management implementation).
-
-Entries in the database with an arrival time less than I<threshold>
-with no token associated with them are deleted from the database.
-
-The parameter I<cookie> is passed to the discrimination function, and
-may be used for any purpose required by the caller.
-
-If the discrimination function attempts to access the underlying
-database (for read or write) during the callback, the behaviour is
-unspecified.
-
-B<HISwalk> provides an iteration function for the specified I<history>
-database. For every entry in the history database, I<callback> is
-invoked, passing the I<cookie>, arrival, posting, and expiry times, in
-addition to the token associated with the entry. If the I<callback>()
-returns B<false> the iteration is aborted and B<HISwalk> returns
-B<false> to the caller.
-
-To process the entire database in the presence of a running server,
-I<reason> may be passed; if this argument is not B<NULL>, it is used
-as an an argument to the `ctlinnd (reserve|pause|go)' commands. If
-I<reason> is B<NULL> and the server is running, the behaviour of
-B<HISwalk> is undefined.
-
-If the callback function attempts to access the underlying database
-during the callback, the behaviour is unspecified.
-
-B<HISstats> returns statistics on the history cache mechanism; given a
-handle I<history>, the return value is a I<struct histstats>
-detailing:
-
-=over 4
-
-=item C<hitpos>
-
-The number of times an item was found directly in the cache and known
-to exist in the underlying history manager.
-
-=item C<hitneg>
-
-The number of times an item was found directly in the cache and known
-not to exist in the underlying history manager.
-
-=item C<misses>
-
-The number of times an item was not found directly in the cache, but
-on retrieval from the underlying history manager was found to exist.
-
-=item C<dne>
-
-The number of times an item was not found directly in the cache, but
-on retrieval from the underlying history manager was found not to exist.
-
-=back
-
-Note that the history cache is only checked by B<HIScheck> and only
-affected by B<HIScheck>, B<HISwrite>, B<HISremember> and
-B<HISreplace>. Following a call to B<HISstats> the history statistics
-associated with I<history> are cleared.
-
-B<HISerror> returns a string describing the most recent error
-associated with I<history>; the format and content of these strings is
-history manager dependent. Note that on setting an error, the history
-API will call the B<warn> function from libinn(3).
-
-B<HISctl> provides a control interface to the underlying history
-manager. The I<request> argument determines the type of the request
-and the meaning of the I<val> argument. The values for I<request> are:
-
-=over 4
-
-=item C<HISCTLG_PATH> (const char **)
-
-Get the base file path which the history handle represents. I<val>
-should be a pointer to a location of type B<const char *>. The
-result must not later be passed to free(3).
-
-
-=item C<HISCTLS_PATH> (const char *)
-
-Set the base file path which this history handle should use; typically
-this is used after an anonymous handle has been created using
-B<HISopen(NULL, ...)>. I<val> should be a value of type B<const char
-*> and will be copied before being stored internally.
-
-=item C<HISCTLS_SYNCCOUNT> (size_t *)
-
-Set an upper bound on how many history operations may be pending in
-core before being synced to permanent storage; B<0> indicates
-unlimited. I<val> should be a pointer to a value of type B<size_t> and
-will not be modified by the call.
-
-=item C<HISCTLS_NPAIRS> (size_t *)
-
-Set a hint to the to the underlying history manager as to how many
-entries there are expected to be in the history database; B<0>
-indicates that an automatic or default sizing should be made. I<val>
-should be a pointer to a value of type B<size_t> and will not be
-modified by the call.
-
-=item C<HISCTLS_IGNOREOLD> (bool *)
-
-Instruct the underlying history manager to ignore existing database
-when creating new ones; typically this option may be set to B<true> if
-the administrator believes that the existing history database is
-corrupt and that ignoring it may help. I<val> should be a pointer to a
-value of type B<bool> and will not be modified by the call.
-
-=item C<HISCTLS_STATINTERVAL> (time_t *)
-
-For the history v6 and tagged hash managers, set the interval, in
-seconds, between stat(2)s of the history files checking for replaced
-files (as happens during expire); this option is typically used by
-nnrpd(8) like applications. I<val> should be a pointer to a value of
-type B<time_t> and will not be modified by the call.
-
-=head1 HISTORY
-
-Written by Alex Kiernan <alexk@demon.net> for InterNetNews 2.4.0.
-
-$Id: libinnhist.pod 5909 2002-12-03 05:17:18Z vinocur $
+++ /dev/null
-=head1 NAME
-
-list - list routines
-
-=head1 SYNOPSIS
-
-B<#include E<lt>inn/list.hE<gt>>
-
-struct node {
- struct node *succ;
- struct node *pred;
-};
-
-struct list {
- struct node *head;
- struct node *tail;
- struct node *tailpred;
-};
-
-B<void list_new(struct list *>I<list>B<);>
-
-B<struct node *list_addhead(struct list *>I<list>B<, struct node *>I<node>B<);>
-
-B<struct node *list_addtail(struct list *>I<list>B<, struct node *>I<node>B<);>
-
-B<struct node *list_head(struct list *>I<list>B<);>
-
-B<struct node *list_tail(struct list *>I<list>B<);>
-
-B<struct node *list_succ(struct node *>I<node>B<);>
-
-B<struct node *list_pred(struct node *>I<node>B<);>
-
-B<struct node *list_remhead(struct list *>I<list>B<);>
-
-B<struct node *list_remtail(struct list *>I<list>B<);>
-
-B<struct node *list_remove(struct node *>I<node>B<);>
-
-B<struct node *list_insert(struct list *>I<list>B<, struct node *>I<node>B<, struct node *>I<pred>B<);>
-
-B<bool list_isempty(struct list *>I<list>B<);>
-
-=head1 DESCRIPTION
-
-B<list_new> initialises the list header I<list> so as to create an
-empty list.
-
-B<list_addhead> adds I<node> to the head of I<list>, returning the node
-just added.
-
-B<list_addtail> adds I<node> to the tail of I<list>, returning the node
-just added.
-
-B<list_head> returns a pointer to the the node at the head of I<list>
-or B<NULL> if the list is empty.
-
-B<list_tail> returns a pointer to the the node at the tail of I<list>
-or B<NULL> if the list is empty.
-
-B<list_succ> returns the next (successor) node on the list after
-I<node> or B<NULL> if I<node> was the final node.
-
-B<list_pred> returns the previous (predecessor) node on the list before
-I<node> or B<NULL> if I<node> was the first node.
-
-B<list_remhead> removes the first node from I<list> and returns it to
-the caller. If the list is empty B<NULL> is returned.
-
-B<list_remtail> removes the last node from I<list> and returns it to
-the caller. If the list is empty B<NULL> is returned.
-
-B<list_remove> removes I<node> from the list it is on and returns it
-to the caller.
-
-B<list_insert> inserts I<node> onto I<list> after the node I<pred>. If
-I<pred> is B<NULL> then I<node> is added to the head of I<list>.
-
-=head1 HISTORY
-
-Written by Alex Kiernan <alex.kiernan@thus.net> for InterNetNews 2.4.0.
-
-$Id: list.pod 6168 2003-01-21 06:27:32Z alexk $
+++ /dev/null
-=head1 NAME
-
-mailpost - Feed an e-mail message into a newsgroup
-
-=head1 SYNOPSIS
-
-B<mailpost> [B<-hn>] [B<-a> I<addr>] [B<-b> I<database>] [B<-c> I<wait-time>]
-[B<-d> I<distribution>] [B<-f> I<addr>] [B<-m> I<mailing-list>]
-[B<-o> I<output-command>] [B<-p> I<port>] [B<-r> I<addr>]
-[B<-x> I<header>[B<:>I<header>...]] I<newsgroups>
-
-=head1 DESCRIPTION
-
-The B<mailpost> program reads a properly formatted e-mail message from stdin
-and feeds it to B<inews> for posting to a news server. I<newsgroups> is a
-whitespace-separated list of group names to which to post the article
-(at least one newsgroup must be specified).
-
-Before feeding the article to B<inews>, it checks that the article has not
-been seen before, and it changes some headers (cleans up some address
-headers, removes X-Trace: and X-Complaints-To:, and puts C<X-> in front
-of unknown headers).
-
-If the article has been seen before (B<mailpost> records the Message-ID of
-each article it handles), then the article will be silently dropped. Other
-errors will cause the article to be mailed to the newsmaster (selected
-at configure time and defaulting to C<usenet>).
-
-Normally, B<mailpost> is run by sendmail(8) via an alias entry:
-
- local-mail-wreck-bikes: "|<pathbin in inn.conf>/mailpost
- -b /var/tmp -d local local.mail.rec.bicycles.racing"
-
-Instead of F</var/tmp>, the mail spool directory can be specified,
-or any other directory where the B<mailpost> process has write access.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-a> I<addr>
-
-If the B<-a> flag is used, the value given is added to the article
-as an Approved: header.
-
-=item B<-b> I<database>
-
-If the B<-b> flag is used, then it defines the location of the database
-used to store the Message-IDs of articles sent on. This is to prevent articles
-looping around if a news-to-mail gateway sends them back here. This option may
-be required if the B<mailpost> process does not have write access to the news
-temporary directory. The default value is I<pathtmp> as set in F<inn.conf>.
-
-=item B<-c> I<wait-time>
-
-The B<-c> flag indicates a length of time to sleep before posting. If
-duplicate messages are received in this interval (by any instance of
-B<mailpost> using the same database), the article is only posted once, but
-with Newsgroups: header modified to crosspost the article to all indicated
-groups. The units for I<wait-time> are seconds; a reasonable value may be
-anywhere from tens to hundreds of seconds, or even higher, depending on how
-long mail can be delayed on its way to your system.
-
-=item B<-d> I<distribution>
-
-If the B<-d> flag is used, the value given is added to the article as a
-Distribution: header.
-
-=item B<-f> I<addr>
-
-The B<-f> flag is a synonym for the B<-r> flag.
-
-=item B<-h>
-
-Print usage information and exit.
-
-=item B<-m> I<mailing-list>
-
-If the B<-m> flag is used, the value given is added to the article in a
-Mailing-List: header, if such a header doesn't already exist.
-
-=item B<-n>
-
-If the B<-n> flag is used, neither an article is posted nor a mail is sent
-in case an error occurs. Everything is written to the standard output.
-
-=item B<-o> I<output-command>
-
-Specifies the program to which the resulting article processed by B<mailpost>
-should be sent. For debugging purpose, C<-o cat> can be used. The default
-value is C<inews -S -h>.
-
-=item B<-p> I<port>
-
-Specifies the port on which B<nnrpd> is listening, used for article posting.
-If given, B<-p> is passed along to B<inews>.
-
-=item B<-r> I<addr>
-
-A heuristic is used to determine a reasonable value for the Path: header.
-The B<-r> flag indicates what to use if no other value can be determined.
-
-=item B<-x> I<header>[B<:>I<header>...]
-
-A colon-separated list of additional headers which should be treated as
-known headers; these headers will be passed through to B<inews> without
-having C<X-> prepended.
-
-Known headers are:
-
- Approved
- Content-*
- Date
- Distribution
- From
- Mailing-List
- Message-ID
- MIME-*
- References
- Return-Path
- Sender
- Subject
-
-=back
-
-=head1 FILES
-
-=over 4
-
-=item I<pathbin>/mailpost
-
-The Perl script itself used to feed an e-mail message to a newsgroup.
-
-=item I<pathtmp>/mailpost-msgid.dir and I<pathtmp>/mailpost-msgid.pag
-
-The default database files which record previously seen Message-IDs.
-
-=back
-
-=head1 HISTORY
-
-Written by Paul Vixie long ago and then hacked up by James Brister for INN
-integration.
-
-$Id: mailpost.pod 7795 2008-04-26 08:28:08Z iulius $
-
-=head1 SEE ALSO
-
-active(5), inews(1), inn.conf(5), nnrpd(8), uwildmat(3).
-
-=cut
-
+++ /dev/null
-=head1 NAME
-
-makehistory - Initialize or rebuild INN history database
-
-=head1 SYNOPSIS
-
-B<makehistory> [B<-abeFIOx>] [B<-f> I<filename>] [B<-l> I<count>]
-[B<-T> I<tmpdir>] [B<-s> I<size>]
-
-=head1 DESCRIPTION
-
-B<makehistory> rebuilds the history(5) text file, which contains a list of
-Message-IDs of articles already seen by the server. It can also be used
-to rebuild the overview database. Note that the dbz(3) indexes for the
-history file are rebuilt by makedbz(8), not by B<makehistory> as in
-earlier versions of INN.
-
-The default location of the history text file is I<pathdb>/history; to
-specify an alternate location, use the B<-f> flag.
-
-By default, B<makehistory> will scan the entire spool, using the storage
-manager, and write a history line for every article. To also generate
-overview information, use the B<-O> flag.
-
-WARNING: If you're trying to rebuild the overview database, be sure to
-stop innd(8) and delete or zero out the existing database before you start
-for the best results. An overview rebuild should not be done while the
-server is running. Unless the existing overview is deleted, you may end
-up with problems like out-of-order overview entries, excessively large
-overview buffers, and the like.
-
-If I<ovmethod> in F<inn.conf> is C<ovdb>, you must have the ovdb processes
-running while rebuilding overview. ovdb needs them available while
-writing overview entries. You can start them by hand separate from the
-rest of the server by running B<ovdb_init>; see ovdb_init(8) for more
-details.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-a>
-
-Append to the history file rather than generating a new one. If you
-append to the main history file, make sure innd(8) is throttled or not
-running, or you can corrupt the history.
-
-=item B<-b>
-
-Delete any messages found in the spool that do not have valid Message-ID
-headers in them.
-
-=item B<-e>
-
-Compute Bytes headers which is used for overview data. This option is valid
-only if B<-O> flag is specified and F<overview.fmt> includes C<Bytes:>.
-
-=item B<-f> I<filename>
-
-Rather than writing directly to I<pathdb>/history, instead write to
-I<filename>.
-
-=item B<-F>
-
-Fork a separate process to flush overview data to disk rather than doing
-it directly. The advantage of this is that it allows B<makehistory> to
-continue to collect more data from the spool while the first batch of data
-is being written to the overview database. The disadvantage is that up to
-twice as much temporary disk space will be used for the generated overview
-data. This option only makes sense in combination with B<-O>. With
-C<buffindexed>, the C<overchan> program is invoked to write overview.
-
-=item B<-I>
-
-Don't store overview data for articles numbered lower than the lowest
-article number in F<active>. This is useful if there are for whatever
-reason old articles on disk that shouldn't be available to readers or put
-into the overview database.
-
-=item B<-l> I<count>
-
-This option specifies how many articles to process before writing the
-accumulated overview information out to the overview database. The
-default is C<10000>. Since overview write performance is faster with
-sorted data, each "batch" gets sorted. Increasing the batch size
-with this option may further improve write performance, at the cost
-of longer sort times. Also, temporary space will be needed to store
-the overview batches. At a rough estimate, about 300 * I<count> bytes
-of temporary space will be required (not counting temp files created
-by sort(1)). See the description of the B<-T> option for how to
-specify the temporary storage location. This option has no effect
-with C<buffindexed>, because C<buffindexed> does not need sorted
-overview and no batching is done.
-
-=item B<-s> I<size>
-
-Size the history database for approximately I<size> pairs. Accurately
-specifying the size is an optimization that will create a more
-efficient database. (The size should be the estimated eventual size
-of the F<history> file, typically the size of the old file, in lines.)
-
-=item B<-O>
-
-Create the overview database as well as the history file. Overview
-information is only required if the server supports readers; it is not
-needed for a transit-only server (see I<enableoverview> in inn.conf(5)).
-If you are using the C<buffindexed> overview storage method, erase all of
-your overview buffers before running B<makehistory> with B<-O>.
-
-=item B<-T> I<tmpdir>
-
-If B<-O> is given, B<makehistory> needs a location to write temporary
-overview data. By default, it uses I<pathtmp>, set in F<inn.conf>, but if
-this option is given, the provided I<tmpdir> is used instead. This is
-also used for temporary files created by sort(1) (which is invoked in the
-process of writing overview information since sorted overview information
-writes faster). By default, sort usually uses your system temporary
-directory; see the sort(1) man page on your system to be sure.
-
-=item B<-x>
-
-If this option is given, B<makehistory> won't write out history file
-entries. This is useful mostly for building overview without generating
-a new history file.
-
-=back
-
-=head1 EXAMPLES
-
-Here's a typical example of rebuilding the entire history and overview
-database, removing broken articles in the news spool. This uses the
-default temporary file locations and should be done while innd isn't
-running (or is throttled).
-
- makehistory -b -f history.n -O -l 30000 -I
-
-This will rebuild the overview (if using C<buffindexed>, erase the
-existing overview buffers before running this command) and leave a new
-history file as C<history.n> in I<pathdb>. To preserve all of the history
-entries from the old history file that correspond to rejected articles or
-expired articles, follow the above command with:
-
- cd /usr/local/news/db
- awk 'NF == 2 { print }' < history >> history.n
-
-(replacing the path with your I<pathdb>, if it isn't the default). Then
-look over the new history file for problems and run:
-
- makedbz -s `wc -l < history` -f history.n
-
-Then rename all of the files matching C<history.n.*> to C<history.*>,
-replacing the current history database and indexes. After that, it's safe
-to unthrottle innd.
-
-For a simpler example:
-
- makehistory -b -f history.n -I -O
-
-will scan the spool, removing broken articles and generating history and
-overview entries for articles missing from history.
-
-To just rebuild overview:
-
- makehistory -O -x -F
-
-=head1 FILES
-
-=over 4
-
-=item inn.conf
-
-Read for I<pathdb>, I<pathtmp>, and other settings.
-
-=item I<pathdb>/history
-
-This is the default output file for B<makehistory>.
-
-=item I<pathtmp>
-
-Where temporary files are written unless B<-T> is given.
-
-=back
-
-=head1 HISTORY
-
-Originally written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews and
-updated by various other people since.
-
-$Id: makehistory.pod 6400 2003-07-12 19:26:58Z rra $
-
-=head1 SEE ALSO
-
-dbz(3), active(5), history(5), inn.conf(5), ctlinnd(8), innd(8),
-makedbz(8), ovdb_init(8), overview.fmt(5).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-motd.news - Message of the day information for readers
-
-=head1 DESCRIPTION
-
-This file, found in I<pathetc>/motd.news, contains local information for
-news readers in a free-form format. The entire file is returned verbatim
-to any client that issues the LIST MOTD command. This might be used for
-new information, notification of upcoming downtime, or similar purposes.
-
-Be aware that use of the LIST MOTD command is not widespread and most news
-clients will never ask for this file.
-
-If this file is missing, it is not an error. The server will just send
-the client an empty response.
-
-=head1 HISTORY
-
-Rewritten in POD by Russ Allbery <rra@stanford.edu> for InterNetNews.
-
-$Id: motd.news.pod 6574 2003-12-27 06:25:05Z rra $
-
-=head1 SEE ALSO
-
-inn.conf(5)
+++ /dev/null
-=head1 Changes in 2.4.5
-
-=over 2
-
-=item *
-
-Fixed the "alarm signal" around C<SSL_read> in B<nnrpd>: it allows
-a proper disconnection of news clients which were previously hanging
-when posting an article through a SSL connection. Moreover, the
-I<clienttimeout> parameter now works on SSL connections. Thanks to
-Matija Nalis for the patch.
-
-=item *
-
-SO_KEEPALIVE is now implemented for SSL TCP connections on systems
-which support it, allowing system detection and closing the dead
-TCP SSL connections automatically after system-specified time. Thanks
-to Matija Nalis for the patch.
-
-=item *
-
-Fixed a segmentation fault when an article of a size greater than remaining
-stack is retrieved via SSL. Thanks to Chris Caputo for this patch.
-
-=item *
-
-Fixed a few segfaults and bugs which affected both Python B<innd> and B<nnrpd>
-hooks. They no longer check the existence of methods not used by the hooked
-script. An issue with Python exception handling was also fixed, as well as
-a segfault fixed by Russ Allbery which happened whenever one closes and then
-reopens Python in the same process. Julien Elie also fixed a bug when reloading
-Python filters (they were not always correctly reloaded) and a segfault when
-generating access groups with embedded Python filters for B<nnrpd>.
-Many thanks to David Hlacik for its bug reports.
-
-=item *
-
-The F<nnrpd.py> stub file in order to test Python B<nnrpd> hooks, as
-mentioned in their documentation, is now installed; only F<INN.py> was
-previously installed in I<pathfilter>. Also fixed a bug in F<INN.py>
-and add missing methods to it.
-
-=item *
-
-Fixed a long-standing bug in B<innreport> which prevented it from
-correctly reporting B<nnrpd> and B<innfeed> log messages.
-
-=item *
-
-Fixed a hang in Perl hooks on (at least) HP/PA since S<Perl 5.10>.
-
-=item *
-
-Fixed a compilation problem on some platforms because of AF_INET6 which
-was not inside a HAVE_INET6 block in B<innfeed>.
-
-=item *
-
-Fixed a bug in B<innfeed> which contained thrice the same IPs for each
-peer; it unnecessarily slowed the peer IP rotation for B<innfeed>. Thanks,
-S<D. Stussy>, for having seen that. Miquel van Smoorenburg provided the patch.
-
-=item *
-
-A new I<heavily> improved version of B<pullnews> is shipped with this
-INN release. This new version is provided by Geraint Edwards. He added
-no more than S<16 flags>, fixed some bugs and integrated the B<backupfeed>
-contrib script by Kai Henningsen, adding again S<6 other> flags. A
-long-standing but very minor bug in the B<-g> option was especially fixed
-and items from the to-do list implemented. Many thanks again to Geraint Edwards.
-
-=item *
-
-New headers are accessible through Perl and Python B<innd> filtering
-hooks. You will find the exact list in the INN Python Filtering and
-Authentication Hooks documentation (F<doc/hook-python>) and in Python
-samples. Thanks to Matija Nalis for this addition of new useful headers.
-
-=item *
-
-New samples for Python B<nnrpd> hooks are shipped with INN: F<nnrpd_access.py>
-for access control and F<nnrpd_dynamic.py> for dynamic access control. The
-F<nnrpd_auth.py> script is now only used for authorization control. See the
-F<readers.conf> man page for more information (especially the I<python_auth>,
-I<python_access> and I<python_dynamic> parameters). The documention about
-INN Python Filtering and Authentication Hooks has also been improved by
-Julien Elie.
-
-=back
-
-=head1 Changes in 2.4.4
-
-=over 2
-
-=item *
-
-Fixed incomplete checking of packet sizes in the B<ctlinnd> interface in
-the no-Unix-domain-sockets case. This is a potential buffer overflow in
-dead code since basically all systems INN builds on support Unix domain
-sockets these days. Also track the buffer size more correctly in the
-client side of this interface for the Unix domain socket case.
-
-=item *
-
-Group blocks in F<incoming.conf> are now correctly parsed and no longer
-cause segfaults when loading this file.
-
-=item *
-
-Fixed a problem with B<innfeed> continuously segfaulting on amd64 hardware
-(and possibly on lots of 64-bit platforms). Many thanks to Ollivier Robert
-for his patch and also to Kai Gallasch for having reported the problem and
-provided the FreeBSD server to debug it.
-
-=item *
-
-B<scanlogs> now rotates B<innfeed>'s log file, which prevents B<innfeed>
-from silently dying when its log file reaches S<2 GB>.
-
-=item *
-
-S<Perl 5.10> support has been added to INN thanks to Jakub Bogusz.
-
-=item *
-
-Some news clients hang when posting an article through a SSL connection:
-it seems that B<nnrpd>'s SSL routines make it wrongly wait for data
-completion. In order to fix the problem, the select() wait is now
-just bypassed. However, the IDLE timer stat is currently not collected
-for such connections. Thanks to Kachun Lee for this workaround.
-
-=item *
-
-Fixed a bug in the display of the used compressor (C<cunbatch> was used
-if arguments were passed to B<gzip> or B<bzip2>).
-
-=item *
-
-Fixed a bug in B<mailpost> and B<pullnews> which prevented useful error
-messages to be seen. Also add the B<-x> flag to B<pullnews> in order
-to insert Xref: headers in articles which lack one.
-
-=item *
-
-If compiling with S<Berkeley DB>, use its ndbm compatibility layer for
-B<ckpasswd> in preference to searching for a traditional dbm library.
-INN also supports S<Berkeley DB 4.4>, 4.5 and 4.6 thanks to Marco d'Itri.
-
-=item *
-
-B<ovdb_init> now properly closes stdin/out/err when it becomes a daemon.
-The issue was reported by Viktor Pilpenok and fixed by Marco d'Itri.
-
-=item *
-
-Added support for Diablo quickhash and hashfeed algorithms.
-It allows to distribute the messages among several peers (new B<Q> flag
-for F<newsfeeds>). Thanks to Miquel van Smoorenburg for this
-implementation in INN.
-
-=item *
-
-B<innd> now listen on separate sockets for IPv4 and IPv6 connections
-if the IPV6_V6ONLY socket option is available. There might also be
-operating systems that still have separate IPv4 and IPv6 TCP implementations,
-and advanced features like TCP SACK might not be available on v6 sockets.
-Thanks to Miquel van Smoorenburg for this patch.
-
-=item *
-
-The two configuration options I<bindaddress> and I<bindaddress6> can now
-be set on a per-peer basis for B<innfeed>. Setting I<bindaddress6>
-to C<none> tells B<innfeed> to never attempt an IPv6 connection to that
-host. Thanks to Miquel van Smoorenburg for this patch.
-
-=item *
-
-Added a I<nnrpdflags> parameter to F<inn.conf> (modeled on the concept of
-I<innflags>) to permit passing of command line arguments to instances of
-B<nnrpd> spawned from B<innd>.
-
-=item *
-
-A new F<inn.conf> parameter called I<pathcluster> has been added:
-it allows to append a common name to the Path: header
-on all incoming articles. I<pathhost> and I<pathalias> (if set)
-are still appended to the path as usual, but I<pathcluster>
-is always appended as the last element (e.g. on the leftmost
-side of the Path: header). Thanks to Miquel van Smoorenburg for
-this feature.
-
-=item *
-
-B<simpleftp> has been rewritten to use C<Net::FTP>. Indeed, F<ftp.pl>
-is no longer shipped with S<Perl 5> and the script did not work.
-
-=item *
-
-B<perl-nocem> will now check for a timeout and re-open the socket
-if required. Additionally, B<perl-nocem> will switch to
-cancel_ctlinnd in case cancel_nntp fails after sending
-the Message-ID. Thanks to Christoph Biedl for the patch. A more
-detailed documentation has also been written for perl-nocem(8).
-
-=item *
-
-The RADIUS configuration is now wrapped in a C<server {}> block in
-F<radius.conf>.
-
-=item *
-
-Checkgroups when there is nothing to change no longer result in sending
-a blank mail to administrators. Besides, no mail is sent by B<controlchan>
-for the creation of a newsgroup when the action is C<no change>.
-
-=item *
-
-Checkgroups are now properly propagated even though the news server
-does not carry the groups they are posted to.
-
-=item *
-
-B<controlchan> and B<docheckgroups> now handle wire format messages
-so that articles from the spool can be directly fed to them.
-
-=item *
-
-Newgroup control messages for existing groups now change their description.
-If a mail is sent to administrators, it reminds them to update their
-F<newsgroups> file. It also warns when there are missing or obsolete
-descriptions. Furthermore, the F<newsgroups> file is now written prettier
-(from one to three tabulations between the name of the group and its
-short description) and to.* groups cannot be created.
-
-=item *
-
-The sample F<control.ctl> file has been extensively updated.
-
-=item *
-
-Fixed empty LISTGROUP replies which were not terminated. Thanks to
-David Canzi for the patch.
-
-=item *
-
-In response to a LIST [file] command, if the file does not exist,
-we assume it is not maintained and return C<503> instead of C<215> and
-an empty file. Moreover, capability to LIST ACTIVE.TIMES for a wildmat
-pattern as its third argument has been added in order to select wanted
-newsgroups.
-
-=item *
-
-B<inews> now tries to authenticate if it does not receive a C<200> return
-code after MODE READER. Indeed, it might be able to post even with
-a C<201> return code and also with another codes like C<440> or C<480>.
-
-=item *
-
-If creating a new F<history> file, set the ownership and mode appropriately.
-B<inncheck> also expects fewer things to be private to the news user. Most
-of the configuration files will never contain private information like
-passwords.
-
-=item *
-
-Other minor bug fixes and documentation improvements.
-
-=back
-
-=head1 Changes in 2.4.3
-
-=over 2
-
-=item *
-
-Previous versions of INN had an optimization for handling XHDR Newsgroups
-that used the Xref: header from overview. While this does make the command
-much faster, it doesn't produce accurate results and breaks the NNTP
-protocol, so this optimization has been removed.
-
-=item *
-
-Fixed a bug in B<innd> that allowed it to accept articles with duplicated
-headers if the header occurred an odd number of times. Modified the
-programs for rebuilding overview to use the last Xref: header if there
-are multiple ones to avoid problems with spools that contain such invalid
-articles.
-
-=item *
-
-Fixed yet another problem with verifying that a user has permissions to
-approve posts to a moderated group. Thanks, Jens Schlegel.
-
-=item *
-
-Increase the send and receive buffer on the Unix domain socket used by
-B<ctlinnd>. This should allow longer replies (particularly for B<innstat>) on
-platforms with very low default Unix domain socket buffer sizes.
-
-=item *
-
-B<rnews>'s handling of articles with nul characters, NNTP errors, header
-problems, and deferrals has been significantly improved.
-
-=item *
-
-Thomas Parmelan added support to B<send-uucp> for specifying the funnel or
-exploder site to flush for feeds managed through one and fixed a problem
-with picking up old stranded work files.
-
-=item *
-
-Many other more minor bug fixes, optimization improvements, and
-documentation fixes.
-
-=back
-
-=head1 Changes in 2.4.2
-
-=over 2
-
-=item *
-
-INN is now licensed under a less restrictive license (about as minimally
-restrictive as possible shy of public domain), and the clause similar to
-the old BSD advertising clause has been dropped.
-
-=item *
-
-C<make install> and C<make update> now always install the newly built binaries,
-rather than only installing them if the modification times are newer.
-This is the behavior that people expect. C<make install> now also
-automatically builds a new (empty) history database if one doesn't already
-exist.
-
-=item *
-
-The embedded Tcl filter code has been disabled (and will be removed
-entirely in the next major release of INN). It hasn't worked for some
-time and causes B<innd> crashes if compiled in (even if not used). If
-someone wants to step forward and maintain it, I recommend starting from
-scratch and emulating the Perl and Python filters.
-
-=item *
-
-B<ctlinnd> should now successfully handle messages from INN up to the maximum
-allowable packet size in the protocol, fixing problems sites with many
-active peers were having with B<innstat> output.
-
-=item *
-
-Overview generation has been fixed in both B<makehistory> and B<innd> to follow
-the rules in the latest NNTP draft rather than just replacing special
-characters with spaces. This means that the unfolding of folded header
-lines will not introduce additional, incorrect whitespace in the overview
-data.
-
-=item *
-
-B<nnrpd> now uniformly responds with a C<480> or C<502> status code to attempts
-to read a newsgroup to which the user does not have access, depending on
-whether the user has authenticated. Previously, it returned a C<411> status
-code, claiming the group didn't exist, which confuses the reactive
-authentication capability of news readers.
-
-=item *
-
-If a user is not authorized to approve articles (using the C<A> I<access>
-control in F<readers.conf>), articles that include Approved: headers will be
-rejected even if posted to unmoderated groups. Some other site may
-consider that group to be moderated.
-
-=item *
-
-The configuration parser used for F<readers.conf> and others now correctly
-handles C<#> inside quoted strings and is more robust against unmatched
-double quotes.
-
-=item *
-
-Messages mailed to moderators had two spaces after the colons in the
-headers, rather than one. This bug has been fixed.
-
-=item *
-
-A bug that could cause heap corruption and random crashes in B<innd> if INN
-were compiled with Python support has been fixed.
-
-=item *
-
-Some problems with B<innd>'s tracking of article size and enforcement of the
-configured maximum article size have been fixed.
-
-=item *
-
-B<pgpverify> will now correctly verify signatures generated by GnuPG and
-better supports GnuPG as the PGP implementation.
-
-=item *
-
-INN's code should now be more 64-bit clean in its handling of size_t,
-pointer differences, and casting of pointers, correcting problems that
-showed up on 64-bit platforms like AMD64.
-
-=item *
-
-Improved the error reporting in the history database code, in B<inews>, in
-B<controlchan>, and in B<expire>.
-
-=item *
-
-Many other, more minor bugs have also been fixed.
-
-=back
-
-=head1 Changes in 2.4.1
-
-=over 2
-
-=item *
-
-SECURITY: Handle the special filing of control messages into per-type
-newsgroups more robustly. This closes a potentially exploitable buffer
-overflow. Thanks to Dan Riley for his excellent bug report.
-
-=item *
-
-Fixed article handling in B<innd> so that articles without a Path: header
-(arising from peers sending malformatted articles or injecting
-malformatted articles through rnews) would not cause B<innd> to crash. (This
-was not exploitable.)
-
-=item *
-
-Fixed a serious bug in XPAT handling, thanks to Tommy van Leeuwen.
-
-=item *
-
-C<configure> now looks for B<sendmail> only in F</usr/sbin> and F</usr/lib>, not on
-the user's path. This should reduce the need for B<--with-sendmail> if your
-preferred sendmail is in a standard location.
-
-=item *
-
-The robustness of the tradindexed overview method has been further
-increased, handling more edge cases arising from corrupted databases and
-oddly-named newsgroups.
-
-=item *
-
-B<innd> now never decreases the high water mark of a newsgroup when
-renumbering, which should help ameliorate overview and F<active> file
-synchronization problems.
-
-=item *
-
-Do not close and reopen the F<history> file on B<ctlinnd> reload when the server
-is paused or throttled. This was breaking B<ctlinnd> reload all during a
-server pause.
-
-=item *
-
-Various minor portability and compilation issues fixed. Substantial
-numbers of compiler warnings have been cleaned up, thanks largely to work
-by Ilya Kovalenko.
-
-=item *
-
-Multiple other more minor bugs have been fixed.
-
-=item *
-
-Documentation and man pages have been clarified and updated.
-
-=back
-
-=head1 Upgrading from 2.3 to 2.4
-
-The F<inn.conf> parser has changed between S<INN 2.3> and 2.4. Due to that
-change, options in F<inn.conf> that contain whitespace or a few other
-special characters must be quoted with double quotes, and empty parameters
-(parameters with no value) are not allowed. S<INN 2.4> comes with a script,
-B<innupgrade>, run automatically during C<make update>, that will attempt
-to fix any problems that it finds with your F<inn.conf> file, saving the
-original as F<inn.conf.OLD>.
-
-This change is the beginning of standardization of parsing and syntax
-across all of INN's configuration files.
-
-The history subsystem now has a standard API that allows other backends to
-be used. Because of this, you now need to specify the history method in
-F<inn.conf>. Adding:
-
- hismethod: hisv6
-
-will tell INN to use the same history backend as was used in previous
-versions. B<innupgrade> should take care of this for you.
-
-ovdb is known to have some locking and timing issues related to how B<nnrpd>
-shuts down (or fails to shut down) the overview databases. If you have
-stability problems with ovdb, try setting I<readserver> to C<true> in
-F<ovdb.conf>. This will funnel all ovdb reads through a single process
-with a cleaner interface to the underlying S<Berkeley DB> database.
-
-If you use Perl authentication for B<nnrpd> (if I<nnrpdperlauth> in
-F<inn.conf> is C<true>), there have been major changes. See "Changes to
-Perl Authentication Support for nnrpd" in F<doc/hook-perl> for details.
-
-Similarly, if you use Python authentication for B<nnrpd> (if
-I<nnrpdpythonauth> in F<inn.conf> is C<true>), there have been major changes.
-See "Changes to Python Authentication and Access Control Support for
-nnrpd" in F<doc/hook-python> for details.
-
-If you use B<send-uucp>, it has been completely rewritten and now takes a
-configuration file to specify its behavior. See its man page for more
-information. If you use B<sendbatch>, it is no longer included in INN
-since the new B<send-uucp> can handle all of the same functionality.
-
-The wildmat API has been renamed (to uwildmat and friends; see uwildmat(3)
-for the interfaces) to distinguish it from Rich $alz's original version,
-since it now supports UTF-8. This may require changes in other software
-packages that link against INN's libraries.
-
-If you are upgrading from a version prior to S<INN 2.3>, see L<Upgrading
-from 2.2 to 2.3>.
-
-=head1 Changes in 2.4.0
-
-=over 2
-
-=item *
-
-IPv6 support has been added, disabled by default. If you have IPv6
-connectivity, build with B<--enable-ipv6> to try it. There are no known
-bugs, but please report any problems you find (or even successes, if you
-use an unusual platform). There are a few changes of interest; further
-information is available in F<doc/IPv6-info>.
-
-=item *
-
-The tradindexed overview method has been completely rewritten and should
-be considerably more robust in the face of system crashes. A new utility,
-B<tdx-util>, is provided to examine the contents of the overview database,
-repair inconsistencies, and rebuild the overview for particular groups
-from a tradspool news spool. See tdx-util(8) for more details.
-
-=item *
-
-The Perl and Python authentication hooks for readers have been extensively
-overhauled and integrated better with F<readers.conf>. See the Changes
-sections in F<doc/hook-perl> and F<doc/hook-python> for more details.
-
-=item *
-
-B<nnrpd> now optionally supports article injection via IHAVE, see
-readers.conf(5). Any articles injected this way must have Date, From,
-Message-ID, Newsgroups, Path, and Subject headers. X-Trace and
-X-Complaints-To headers will be added if the appropriate options are set
-in F<readers.conf>, but other headers will not be modified/inserted (e.g.
-NNTP-Posting-Host, NNTP-Posting-Date, Organization, Lines, Cc, Bcc, and To
-headers).
-
-=item *
-
-B<nnrpd> now handles arbitrarily long lines in POST and IHAVE; administrators
-who want to limit the length of lines in locally posted articles will need
-to add this to their local filters instead.
-
-=item *
-
-B<nnrpd> no longer handles the poorly-specified S<RFC 977> optional fourth
-argument to the NEWGROUPS command specifying the "distributions" that the
-command was supposed to apply to.
-
-Clients that use that argument will break. There are not believed to be
-any such clients, and it's easy enough to just filter the returned list of
-newsgroups (which is generally fairly short) to achieve the same results.
-
-=item *
-
-B<nnrpd> no longer accepts UTC as a synonym for GMT for NEWGROUPS or NEWNEWS.
-This usage was never portable, and was rejected by the NNTP working group.
-It is being removed now in the hope that it will be caught before anyone
-starts to rely on it.
-
-=item *
-
-B<innfeed> supports a new peer parameter, I<backlog-feed-first>, that if set
-to C<true> feeds any backlog to a peer before new articles, see
-innfeed.conf(5). When used in combination with I<max-connections> set to C<1>,
-this can be used to enforce in-order delivery of messages to a peer that
-is doing Xref slaving, avoiding cases where a higher-numbered message is
-received before a lower-numbered message in the same group.
-
-=item *
-
-Several other, more minor protocol issues have been fixed: connections
-rejected due to the connection rate limiting in B<innd> receive C<400> replies
-instead of C<504> or C<505>, and ARTICLE without an argument will always either
-retrieve the current article or return a C<423> error, never advance the
-current article number to the next valid article.
-
-See F<doc/compliance-nntp> for all of the known issues with INN's
-compliance with the current NNTP draft.
-
-=item *
-
-All accesses to the F<history> file for all parts of INN now go through a
-generic API like the storage and overview subsystems do. This will
-eventually allow new history implementations to be dropped in without
-affecting the rest of INN, and will significantly improve the
-encapsulation of the history subsystem. See the libinnhist(3) man page
-for the details of the interface.
-
-=item *
-
-INN now uses a new parser for the F<inn.conf> file. This means that
-parameters containing whitespace or other special characters must now be
-quoted; see inn.conf(5). It fixes the long-standing bug that certain
-values must be included in F<inn.conf> even if using the defaults for the
-use of shell or Perl scripts, and it will serve as the basis for
-standardizing and cleaning up the configuration file parsing in other
-parts of INN. B<innupgrade> is run during C<make update> and should convert
-an existing F<inn.conf> file for you.
-
-=item *
-
-B<send-uucp> has been replaced by a completely rewritten version from
-Marco d'Itri, Edvard Tuinder, and Miquel van Smoorenburg, which uses a
-configuration file that specifies batch sizes, compression methods, and
-hours during which batches should be generated. The old B<sendbatch>
-script has been retired, since B<send-uucp> can now handle everything
-that it did.
-
-=item *
-
-Two C<configure> options have changed names: B<--with-tmp-path> is now
-B<--with-tmp-dir>, and B<--with-largefiles> is now B<--enable-largefiles>, to
-improve consistency and better match the C<autoconf> option guidelines.
-
-=item *
-
-Variables can now be used in the F<newsfeeds> file to make it easier to
-specify many similar feeds or feed patterns. See the newsfeeds(5) man
-page for details.
-
-=item *
-
-Local connections to INN support a new special mode, MODE CANCEL, that
-allows efficient batch cancellation of messages. This is intended to be
-the preferred interface for external spam and abuse filters like NoCeM.
-See "CANCEL FEEDS" in innd(8) for details.
-
-=item *
-
-Two new options, I<nfsreader> and I<nfswriter>, have been added to
-F<inn.conf> to aid in building NFS based shared reader/writer platforms.
-On the writer server configure I<nfswriter> to C<true> and on all of the readers
-configure I<nfsreader> to C<true>; these options add calls to force data out to
-the NFS server and force it to be read directly from the NFS server at the
-appropriate moments. Note that it has only been tested on S<Solaris 8>,
-using CNFS as the storage mechanism and tradindexed as the overview
-method.
-
-=item *
-
-A new option, I<tradindexedmmap>, has been added to F<inn.conf>. If set
-to C<true> (the default), then the tradindexed overview method will use
-mmap() to access its overview data (in 2.3 you couldn't control this; it
-always used mmap).
-
-=item *
-
-Thanks to code contributed by CMU, B<innfeed> can now feed an IMAP server as
-well as other NNTP servers. See the man page for innfeed(8) for more
-information.
-
-=item *
-
-An authenticator, B<auth_smb>, that checks a username and password against
-a remote Samba server is now included. See auth_smb(8) for details.
-
-=item *
-
-The wildmat functions in INN now support UTF-8, in a way that should allow
-them to still work with most simple 8-bit character sets in widespread
-use. As part of this change, some additional wildmat interfaces are now
-available and the names have changed (to uwildmat, where C<u> is for
-Unicode). See uwildmat(3) for the details.
-
-=item *
-
-The interface between external authenticators and B<nnrpd> is now properly
-documented, in F<doc/external-auth>. A library implementing this
-interface in C is provided, which should make it easier to write
-additional authenticators resolvers. See libauth(3) for details, and any
-of the existing programs in F<authprogs/> for examples.
-
-=item *
-
-Most (if not all) of the temporary file creation in INN now uses functions
-that create temporary files properly and safely.
-
-=back
-
-=head1 Changes in 2.3.5
-
-=over 2
-
-=item *
-
-Clients using POST are no longer permitted to provide an Injector-Info:
-header.
-
-=item *
-
-Fixed a bug causing posts with Followup-To: set to a moderated group to be
-rejected if the posting user didn't have permission to approve postings.
-
-=item *
-
-Fixed bugs in B<inncheck> with setuid rnews or setgid inews, in I<innconfval>
-with F<inn.conf> parameters containing shell metacharacters but no spaces,
-and in F<parsedate.y> with some versions of B<yacc>. Fixed a variety of
-size-related printf format warnings (e.g., C<%d> vs. C<%ld>) thanks to the work
-of Winfried Szukalski.
-
-=back
-
-=head1 Changes in 2.3.4
-
-=over 2
-
-=item *
-
-LIST ACTIVE no longer returns data when given a single group argument if
-the client is not authorized to read that group.
-
-=item *
-
-XHDR and XPAT weren't correctly parsing article headers, resulting in
-searches for the header "newsgroup" matching the header "newsgroups".
-
-=item *
-
-Made CNFS more robust against crashes by actually syncing the cycbuff
-headers to disk as was originally intended. Fixed a memory leak in the
-tradspool code.
-
-=item *
-
-Two bugs in B<pgpverify> when using GnuPG were fixed: it now correctly checks
-for B<gpgv> (rather than B<pgp>) when told to use GnuPG and expects the keyring
-to be F<pubring.gpg> (not F<pubring.pgp>).
-
-=item *
-
-Substantial updates to the sample provided F<control.ctl> file.
-
-=item *
-
-Compilation fixes with S<Perl 5.8.0>, S<Berkeley DB 4.x>, current versions of
-Linux (including with large file support), and Tru64. B<inndf> fixes for
-ReiserFS.
-
-=item *
-
-Various bugs in the header handling in B<nnrpd> have been fixed, including
-hangs when using virtual domains and improper processing of folded headers
-under certain circumstances.
-
-=item *
-
-Other minor bug fixes and documentation improvements.
-
-=back
-
-=head1 Changes in 2.3.3
-
-=over 2
-
-=item *
-
-B<pgpverify> now supports using GnuPG to check signatures (rather than PGP)
-without the B<pgpgpg> wrapper. GnuPG can check both old-style RSA signatures
-and new OpenPGP signatures and is recommended over S<PGP 2.6>. If you have
-GnuPG installed, B<pgpverify> will use it rather than PGP, which means that
-you may have to create a new key ring for GnuPG to use to verify signatures
-if you were previously using PGP.
-
-=item *
-
-Users can no longer post articles containing Approved: headers to
-moderated groups by default; they must be specifically given that
-permission with the I<access> parameter in F<readers.conf>. See the man page
-for more details.
-
-=item *
-
-Two bugs in repacking overview index files and a reliability bug with
-writing overview data were all fixed in the tradindexed overview method,
-hopefully making it somewhat more reliable, particularly for B<makehistory>.
-
-=item *
-
-If F<rc.news.local> exists in the INN binary directory, it will be run with
-the start or stop argument whenever B<rc.news> is run. This is available
-as a hook for local startup and shutdown code.
-
-=item *
-
-The default history table hash sizes were increased because a too-small
-value can cause serious performance problems (whereas a too-large hash
-just wastes a bit of disk space).
-
-=item *
-
-The sample F<control.ctl> file has been extensively updated.
-
-=item *
-
-Wildmat exclusions (C<@> and C<!>) should now work properly in F<storage.conf>
-newsgroup patterns.
-
-=item *
-
-The implementation of the B<-w> flag for B<expireover> was fixed; previously,
-the value given to B<-w> to change B<expireover>'s notion of the current time
-was scaled by too much.
-
-=item *
-
-Various other more minor bug fixes, standards compliance fixes, and
-documentation improvements.
-
-=back
-
-=head1 Changes in 2.3.2
-
-=over 2
-
-=item *
-
-B<innxmit> can again handle regular filenames as input as well as storage API
-tokens (allowing it to be used to import an old traditional spool).
-
-=item *
-
-Several problems with tagged-hash history files have been fixed thanks to
-the debugging efforts of Andrew Gierth and Sang-yong Suh.
-
-=item *
-
-A very long-standing (since S<INN 1.0>!) NNTP protocol bug in B<nnrpd> was
-fixed. The response to an ARTICLE command retrieving a message by Message-ID
-should have the Message-ID as the third word of the response, not the
-fourth. Fixing this is reported to I<possibly> cause problems with some
-Netscape browsers, but other news servers correctly follow the protocol.
-
-=item *
-
-Some serious performance problems with expiration of tradspool should now
-be at least somewhat alleviated. tradspool and timehash now know how to
-output file names for removal rather than tokens, and B<fastrm>'s ability to
-remove regular files has been restored. This should bring expiration
-times for tradspool back to within a factor of two of pre-storage-API
-expiration times.
-
-=item *
-
-Added a sample F<subscriptions> file and documentation for it and B<innmail>.
-
-=back
-
-=head1 Changes in 2.3.1
-
-=over 2
-
-=item *
-
-B<inews> no longer downloads the F<active> file, no longer tries to send
-postings to moderated groups to the moderator directly, and in general
-duplicates less of the functionality of B<nnrpd>, instead letting B<nnrpd>
-handle it. This fixes the problem of B<inews> not working properly for users
-other than news without being setgid.
-
-=item *
-
-Added a man page for B<ckpasswd>.
-
-=item *
-
-A serious bug in the embedded Perl authentication hooks was fixed, thanks
-to Jan Rychter.
-
-=item *
-
-The annoying compilation problem with embedded Perl filtering on Linux
-systems without libgdbm installed should be fixed.
-
-=item *
-
-INN now complains loudly at C<configure> time if the configured path for
-temporary files is world-writeable, since this configuration can be a
-security hole.
-
-=item *
-
-Many other varied bug fixes and documentation fixes of all sorts.
-
-=back
-
-=head1 Upgrading from 2.2 to 2.3
-
-There may be additional things to watch out for not listed here; if you
-run across any, please let <inn-bugs@isc.org> know about them.
-
-Simply doing a C<make update> is not sufficient to upgrade; the history and
-overview information will also have to be regenerated, since the formats
-of both files have changed between 2.2 and 2.3. Regardless of whether you
-were using the storage API or traditional spool under 2.2, you'll need to
-rebuild your overview and history files. You will also need to add a
-F<storage.conf> file, if you weren't using the storage API under S<INN 2.2>. A
-good default F<storage.conf> file for 2.2 users would be:
-
- method tradspool {
- newsgroups: *
- class: 0
- }
-
-Create this F<storage.conf> file before rebuilding history or overview.
-
-If you want to allow readers, or if you want to expire based on newsgroup
-name, you need to tell INN to generate overview data and pick an overview
-method by setting I<ovmethod> in F<inn.conf>. See F<INSTALL> and inn.conf(5)
-for more details.
-
-The code that generates the dbz index files has been split into a separate
-program, B<makedbz>. B<makehistory> still generates the base F<history> file
-and the overview information, but some of its options have been changed.
-To rebuild the history and overview files, use something like:
-
- makehistory -b -f history.n -O -T /usr/local/news/tmp -l 600000
-
-(change the F</usr/local/news/tmp> path to some directory that has plenty of
-temporary space, and leave off B<-O> if you're running a transit-only server
-and don't intend to expire based on group name, and therefore don't need
-overview.) Or if your overview is buffindexed, use:
-
- makehistory -b -f history.n -O -F
-
-Both will generate a new history file as F<history.n> and rebuild overview
-at the same time. If you want to preseve a record of expired Message-IDs
-in the history file, run:
-
- awk 'NF==2 { print; }' < history >> history.n
-
-to append them to the new history file you created above. Look over the
-new history file and make sure it looks right, then generate the new index
-files and move them into place:
-
- makedbz -s `wc -l < history.n` -f history.n
- mv history.n history
- mv history.n.dir history.dir
- mv history.n.hash history.hash
- mv history.n.index history.index
-
-(Rather than F<.hash> and F<.index> files, you may have a F<.pag> file if you're
-using tagged hash.)
-
-For reader machines, F<nnrp.access> has been replaced by F<readers.conf>.
-There currently isn't a program to convert between the old format and the
-new format (if you'd like to contribute one, it would be welcomed
-gratefully). The new file is unfortunately considerably more complex as
-a result of its new capabilities; please carefully read the example
-F<readers.conf> provided and the man page when setting up your initial
-configuration. The provided commented-out examples cover the most common
-installation (IP-based authentication for all machines on the local
-network).
-
-INN makes extensive use of mmap(2) for the new overview mechanisms, so at
-the present time NFS-mounting the spool and overview on multiple reader
-machines from one central server probably isn't feasible in this version.
-mmap tends to interact poorly with NFS (at the least, NFS clients won't
-see updates to the mapped files in situations where they should). (The
-preferred way to fix this would, rather than backing out the use of mmap
-or making it optional, to add support for Diablo-style header feeds and
-pull-on-demand of articles from a master server.)
-
-The flags for B<overchan> have changed, plus you probably don't want to
-run B<overchan> at all any more. Letting B<innd> write overview data itself
-results in somewhat slower performance, but is more reliable and has a
-better failure mode under high loads. Writing overview data directly is
-the default, so in a normal upgrade from 2.2 to 2.3 you'll want to comment
-out or remove your B<overchan> entry in F<newsfeeds> and set I<useoverchan> to
-C<false> in F<inn.conf>.
-
-B<crosspost> is no longer installed, and no longer works (even with
-traditional spool). If you have an entry for B<crosspost> in F<newsfeeds>,
-remove it.
-
-If you're importing a traditional spool from a pre-storage API INN server,
-it's strongly recommended that you use NNTP to feed the articles to your
-new server rather than trying to build overview and history directly from
-the old spool. It's more reliable and ensures that everything gets put
-into the right place. The easiest way to do this is to generate, on your
-old server, a list of all of your existing article files and then feed
-that list to B<innxmit>. Further details can be found in the FAQ at
-L<http://www.eyrie.org/~eagle/faqs/inn.html>.
-
-If you are using a version of Cleanfeed that still has a line in it like:
-
- $lines = $hdr{'__BODY__'} =~ tr/\n/\n/;
-
-you will need to change this line to:
-
- $lines = $hdr{'__LINES__'};
-
-to work with S<INN 2.3> or later. This is due to an internal optimization of
-the interface to embedded filters that's new in S<INN 2.3>.
-
-=head1 Changes in 2.3.0
-
-=over 2
-
-=item *
-
-New F<readers.conf> file (replaces F<nnrp.access>) which allows more
-flexible specification of access restrictions. Included in the sample
-implementations is a RADIUS-based authenticator.
-
-=item *
-
-Unified overview has been replaced with an overview API, and there are now
-three separate overview implementations to choose from. One (tradindexed)
-is very like traditional overview but uses an additional index file. The
-second (buffindexed) uses large buffers rather than separate files for
-each group and can handle a higher incoming article rate while still being
-fast for readers. The third (ovdb) uses S<Berkeley DB> to store overview
-information (so you need to have S<Berkeley DB> installed to use it). The
-I<ovmethod> key in F<inn.conf> chooses the overview method to use.
-
-Note that ovdb has not been as widely tested as the other overview
-mechanisms and should be considered experimental.
-
-=item *
-
-All article storage and retrieval is now done via the storage API.
-Traditional spool is now available as a storage type under the storage
-API. (Note that the current traditional spool implementation causes
-nightly expire to be extremely slow for a large number of articles, so
-it's not recommended that you use the tradspool storage method for the
-majority of a large spool.)
-
-=item *
-
-The timecaf storage method has been added, similar to timehash but storing
-multiple articles in a single file. See F<INSTALL> for details on it.
-
-=item *
-
-INN now supports embedded Python filters as well as Perl and Tcl filters,
-and supports Python authentication hooks.
-
-=item *
-
-There is preliminary support for news reading over SSL, using OpenSSL.
-
-=item *
-
-To simplify anti-abuse filtering, and to be more compliant with news
-standards and proposed standards, INN now treats as control messages only
-articles containing a Control: header. A Subject: line beginning with
-C<cmsg > is no longer sufficient for a message to be considered a control
-message, and the Also-Control: header is no longer supported.
-
-=item *
-
-The INN build system no longer uses subst. (This will be transparent to
-most users; it's an improvement and modernization of how INN is
-configured.)
-
-=item *
-
-The build and installation system has been substantially overhauled.
-C<make update> now updates scripts as well as binaries and documentation,
-there is better support for parallel builds (C<make -j>), there is less
-C<make> recursion, and far more of the system-dependent configuration is
-handled directly by C<autoconf>. libtool build support (including shared
-library support) should be better than previous releases.
-
-=back
-
-=head1 Changes in 2.2.3
-
-=over 2
-
-=item *
-
-B<inews> is not installed setgid news and B<rnews> is not installed setuid root
-by default any more. If you need the old permissions, you have to give a
-flag to configure. See F<INSTALL> for more details.
-
-=item *
-
-Fixed a security hole when I<verifycancels> was enabled in F<inn.conf> (not the
-default).
-
-=item *
-
-Message-IDs are now limited to 250 octets to prevent interoperability
-problems with other servers.
-
-=item *
-
-Embedded Perl filters now work with S<Perl 5.6.0>.
-
-=item *
-
-Lots of bug fixes and changes for security paranoia.
-
-=back
-
-=head1 Changes in 2.2.2
-
-=over 2
-
-=item *
-
-Various minor bug fixes and a Y2K bug fix. The Y2K bug is in version
-version 2.2.1 only and will show up after S<Jan 1st>, 2000 when a news reader
-issues a NEWNEWS command for a date prior to the year 2000.
-
-=back
-
-=head1 Changes in 2.2.1
-
-=over 2
-
-=item *
-
-Various bug fixes, mostly notably fixes for potential buffer overflow
-security vulnerabilities.
-
-=back
-
-=head1 Changes in 2.2.0
-
-=over 2
-
-=item *
-
-New F<storage.conf> file (replaces F<storage.ctl>).
-
-=item *
-
-New (optional) way of handling non-cancel control messages (B<controlchan>)
-that serializes them and prevents server overload from control message
-storms.
-
-=item *
-
-Support for B<actsyncd> to fetch F<active> file with B<ftp>; configured by default
-to use L<ftp://ftp.isc.org/pub/usenet/CONFIG/active.Z> if you run B<actsyncd>.
-Be sure to read the manual page for B<actsync> to configure an F<actsync.ign>
-file for your site, and test B<simpleftp> if you do not C<configure> with B<wget>
-or B<ncftp>. Also see L<ftp://ftp.isc.org/pub/usenet/CONFIG/README>.
-
-=item *
-
-Some options to C<configure> are now moved to F<inn.conf> (I<merge-to-groups> and
-I<pgp-verify>, without the hyphen).
-
-=item *
-
-B<inndf>, a portable version of df(1), is supplied.
-
-=item *
-
-New B<cnfsstat> program to show stats of CNFS buffers.
-
-=item *
-
-B<news2mail> and B<mailpost> programs for gatewaying news to mail and mail to
-news are supplied.
-
-=item *
-
-B<pullnews> program for doing a sucking feed is provided (not meant for large
-feeds).
-
-=item *
-
-The B<innshellvars.csh.in> script is obsolete (and lives in the F<obsolete>
-directory, for now).
-
-=back
-
-=cut
+++ /dev/null
-=head1 NAME
-
-newsfeeds - Determine where Usenet articles are sent
-
-=head1 DESCRIPTION
-
-The file I<pathetc>/newsfeeds specifies how incoming articles should be
-distributed to other programs and files on the server. It is parsed by
-the InterNetNews server innd(8) when it starts up, or when directed to by
-ctlinnd(8). B<innd> doesn't send articles to remote sites itself, so
-F<newsfeeds> doesn't directly determine which remote news servers articles
-are sent to. Instead, it specifies what batch files should be created or
-which programs should be run (and what information should be sent to
-them), and then this information is used by programs like innxmit(8) and
-innfeed(8) to feed articles to remote sites.
-
-The F<newsfeeds> file isn't used solely to set up feeding accepted
-articles to remote sites but also to pass them (or bits of information
-about them) to any local programs or files that want that data. For
-example, controlchan(8), a daemon that processes incoming control
-messages, runs out of F<newsfeeds>, as could a news to mail gateway.
-
-The file is interpreted as a set of lines, parsed according to the
-following rules: If a line ends with a backslash, the backslash, the
-newline, and any whitespace at the start of the next line is deleted.
-This is repeated until the entire "logical" line is collected. If the
-logical line is blank or starts with a number sign (C<#>), it is ignored.
-
-All other lines are interpreted as feed entries. An entry should consist
-of four colon-separated fields; two of the fields may have optional
-sub-fields, marked off by a slash. Fields or sub-fields that take
-multiple parameters should be separated by a comma. Extra whitespace can
-cause problems and should be avoided. Except for the site names, case is
-significant. The format of an entry is:
-
- sitename[/exclude,exclude,...]\
- :pattern,pattern...[/distribution,distribution...]\
- :flag,flag...\
- :parameter
-
-Each field is described below.
-
-The I<sitename> is the name of the site to which a news article can be
-sent. It is used for writing log entries and for determining if an
-article should be forwarded to a site. (A "site" is the generic term for
-some destination of newsfeed data; it often corresponds to a remote news
-peer, but doesn't have to. For example, a local archiving program run
-from F<newsfeeds> is also a "site.") If I<sitename> already appears in
-the article's Path: header, then the article will not be sent to the site.
-The name is usually whatever the remote site uses to identify itself in
-the Path: header, but can be almost any word.
-
-Be careful, though, to avoid having the I<sitename> accidentally match a
-Path: header entry unintentionally. For this reason, special local
-entries (such as archivers or gateways) should probably end with an
-exclamation point to make sure that they do not have the same name as any
-real site. For example, C<gateway> is an obvious name for the local entry
-that forwards articles out to a mailing list. If a site with the name
-C<gateway> posts an article, when the local site receives the article it
-will see the name in the Path and not send the article to its own
-C<gateway> entry. Since C<gateway!> can't appear as an individual Path:
-entry since C<!> is a delimiter in the Path: header, that would be a
-better thing to use for I<sitename>.
-
-(Another way to avoid this problem is with the C<Ap> flag; see the
-description below.)
-
-If an entry has an exclusion sub-field, the article will not be sent to
-that site if any of I<exclude> appear in the Path: header. (It's
-sometimes convenient to have the I<sitename> be an abbreviated form of the
-name of the remote site, since all the I<sitename>s to which an article
-is sent are written to the log and using shorter I<sitename>s can
-therefore improve performance for large servers. In this case, the Path:
-header entries of those sites should be given as I<exclude> entries and
-the C<Ap> flag used so that the abbreviated I<sitename> doesn't
-accidentally match some other Path: header entry.)
-
-The same I<sitename> can be used more than once and the appropriate action
-will be taken for each entry that should receive the article, but this is
-recommended only for program feeds to avoid confusion. Case is not
-significant in site names.
-
-The comma-separated I<pattern> specifies which groups to send to the site;
-it is interpreted to build a "subscription list" for the site. The
-default subscription is to get all groups carried by the server. It is a
-uwildmat(3) pattern supporting poison (C<@>) wildcards; see the uwildmat(3)
-man page for full details on the pattern matching language. I<pattern>
-will be matched against every newsgroup carried by the server and all
-newsgroups that match will be added to the subscription list for the site.
-
-Normally, a given article (or information about it) is sent to a site if
-any of the newsgroups to which the article was posted are in that site's
-subscription list. If a newsgroup matches a C<@> pattern in I<pattern>,
-then not only is it not added to the subscription list, but any articles
-crossposted to that newsgroup also will not be sent to that site even if
-other newsgroups to which it was crossposted are in that site's
-subscription list. This is called a poison pattern (because matching
-groups are "poisoned").
-
-For example, to receive all comp.* groups, but only comp.sources.unix
-within the sources newsgroups, the following I<pattern> can be used:
-
- comp.*,!comp.sources.*,comp.sources.unix
-
-Note that the trailing C<.*> is required; the pattern has to match the
-whole newsgroup name. C<comp.sources.*> could be written C<comp.sources*>
-and would exclude the newsgroup comp.sources (if it exists) as well as the
-groups in the comp.sources.* hierarchy, but note that this would also
-exclude a newsgroup named comp.sources-only (whereas the above pattern
-would add that group to the site subscription list since it matches
-C<comp.*> and none of the other patterns.
-
-For another example, to feed alt.* and misc.* to a given site but not any
-articles posted to alt.binaries.warez (even if they're also crossposted to
-other alt.* or misc.* groups), the following pattern can be used:
-
- alt.*,@alt.binaries.warez,misc.*
-
-Note, however, that if you reversed the C<alt.*> and <@alt.binaries.warez>
-entries, this pattern would be equivalent to C<alt.*,misc.*>, since the
-last matching pattern determines whether a given newsgroup matches and the
-poison logic only applies if the poison entry is the last matching entry.
-
-Control messages follow slightly different propagation rules than normal
-articles; see innd(8) for the details. Note that most subscriptions
-should have C<!junk,!control,!control.*> in their pattern list due to those
-propagation rules (and since junk is a special internal newsgroup; see
-I<wanttrash> in inn.conf(5) for more details on what it's used for) and
-that the best way to keep control messages local to a site is with a
-distribution.
-
-A subscription can be further modified by specifying distributions that
-the site should or should not receive. The default is to send all
-articles to all sites that subscribe to any of the groups where it has
-been posted, but if an article has a Distribution: header and any
-I<distribution>s are specified, then they are checked according to the
-following rules:
-
-=over 4
-
-=item 1.
-
-If the Distribution: header matches any of the values in the sub-field,
-the article is sent.
-
-=item 2.
-
-If a I<distribution> starts with an exclamation point, and it matches the
-Distribution: header, the article is not sent.
-
-=item 3.
-
-If the Distribution: header does not match any I<distribution> in the
-site's entry and no negations were used, the article is not sent.
-
-=item 4.
-
-If the Distribution: header does not match any I<distribution> in the
-site's entry and any I<distribution> started with an exclamation point,
-the article is sent.
-
-=back
-
-If an article has more than one distribution specified, then each one is
-handled according according to the above rules. If any of the specified
-distributions indicate that the article should be sent, it is; if none do,
-it is not sent. In other words, the rules are used as a logical or.
-
-It is almost definitely a mistake to have a single feed that specifies
-distributions that start with an exclamation point along with some that
-don't.
-
-Distributions are text words, not patterns; entries like C<*> or C<all>
-have no special meaning.
-
-The I<flag> field is described in L<"FLAG VALUES">. The interpretation of
-the I<parameter> field depends on the type of feed and is explained in
-more detail in L<"FEED TYPES">. It can be omitted for some types of
-feeds.
-
-The site named C<ME> is special. There must be exactly one such entry,
-and it should be the first entry in the file. If the C<ME> entry has an
-exclusion sub-field, incoming articles are rejected completely if any of
-the names specified in that exclusion sub-field appear in their Path:
-headers. If the C<ME> entry has a subscription list, that list is
-prepended to the subscription list of all other entries. For example,
-C<*,!control,!control.*,!junk,!foo.*> could be used to set the default subscription
-list for all other feeds so that local postings are not propagated unless
-C<foo.*> explicitly appears in the site's subscription list. This feature
-tends to be somewhat confusing since the default subscription is prepended
-and can be overridden by other patterns.
-
-If the C<ME> entry has a distribution sub-field, only articles that match
-that distribution list are accepted and all other articles are rejected.
-A common use for this is to put something like C</!local> in the C<ME>
-entry to reject local postings from other misconfigured sites.
-
-Finally, it is also possible to set variables in F<newsfeeds> and use them
-later in the file. A line starting with C<$> sets a variable. For
-example:
-
- $LOCALGROUPS=local.*,example.*
-
-This sets the variable C<LOCALGROUPS> to C<local.*,example.*>. This
-variable can later be used elsewhere in the file, such as in a site entry
-like:
-
- news.example.com:$LOCALGROUPS:Tf,Wnm:
-
-which is then completely equivalent to:
-
- news.example.com:local.*,example.*:Tf,Wnm:
-
-Variables aren't solely simple substitution. If either C<!> or C<@>
-immediately preceeds the variable and the value of the variable contains
-commas, that character will be duplicated before each comma. This
-somewhat odd-sounding behavior is designed to make it easier to use
-variables to construct feed patterns. The utility becomes more obvious
-when you observe that the line:
-
- news.example.net:*,@$LOCALGROUPS:Tf,Wnm:
-
-is therefore equivalent to:
-
- news.example.net:*,@local.*,@example.*:Tf,Wnm:
-
-which (as explained below) excludes all of the groups in $LOCALGROUPS from
-the feed to that site.
-
-=head1 FLAG VALUES
-
-The I<flags> parameter specifies miscellaneous parameters, including the
-type of feed, what information should be sent to it, and various
-limitations on what articles should be sent to a site. They may be
-specified in any order and should be separated by commas. Flags that take
-values should have the value immediately after the flag letter with no
-whitespace. The valid flags are:
-
-=over 4
-
-=item B<E<lt>> I<size>
-
-An article will only be sent to this site if it is less than I<size> bytes
-long. The default is no limit.
-
-=item B<E<gt>> I<size>
-
-An article will only be sent to this site if it is greater than I<size>
-bytes long. The default is no limit.
-
-=item B<A> I<checks>
-
-An article will only be sent to this site if it meets the requirements
-specified in I<checks>, which should be chosen from the following set.
-I<checks> can be multiple letters if appropriate.
-
-=over 3
-
-=item c
-
-Exclude all kinds of control messages.
-
-=item C
-
-Only send control messages, not regular articles.
-
-=item d
-
-Only send articles with a Distribution header. Combined with a particular
-distribution value in the I<distribution> part of the site entry, this can
-be used to limit articles sent to a site to just those with a particuliar
-distribution.
-
-=item e
-
-Only send articles where every newsgroup listed in the Newsgroups: header
-exists in the active file.
-
-=item f
-
-Don't send articles rejected by filters. This is only useful when
-I<dontrejectfiltered> is set in F<inn.conf>. With that variable set, this
-lets one accept all articles but not propagate filtered ones to some
-sites.
-
-=item o
-
-Only send articles for which overview data was stored.
-
-=item O
-
-Send articles to this site that don't have an X-Trace: header, even if the
-C<O> flag is also given.
-
-=item p
-
-Only check the exclusions against the Path: header of articles; don't
-check the site name. This is useful if your site names aren't the same as
-the Path: entries added by those remote sites, or for program feeds where
-the site name is arbitrary and unrelated to the Path: header.
-
-=back
-
-If both C<c> and C<C> are given, the last specified one takes precedence.
-
-=item B<B> I<high>/I<low>
-
-If a site is being fed by a file, channel, or exploder (see below), the
-server will normally start trying to write the information as soon as
-possible. Providing a buffer may give better system performance and help
-smooth out overall load if a large batch of news comes in. The value of
-the this flag should be two numbers separated by a slash. I<high>
-specifies the point at which the server can start draining the feed's I/O
-buffer, and I<low> specifies when to stop writing and begin buffering
-again; the units are bytes. The default is to do no buffering, sending
-output as soon as it is possible to do so.
-
-=item B<C> I<count>
-
-If this flag is specified, an article will only be sent to this site if
-the number of groups it is posted to, plus the square of the number of
-groups followups would appear in, is no more than I<count>. C<30> is a
-good value for this flag, allowing crossposts to up to 29 groups when
-followups are set to a single group or poster and only allowing crossposts
-to 5 groups when followups aren't set.
-
-=item B<F> I<name>
-
-Specifies the name of the file that should be used if it's necessary to
-begin spooling for the site (see below). If I<name> is not an absolute
-path, it is taken to be relative to I<pathoutgoing> in F<inn.conf>. If
-I<name> is a directory, the file F<togo> in that directory will be used as
-the file name.
-
-=item B<G> I<count>
-
-If this flag is specified, an article will only be sent to this site if it
-is posted to no more than I<count> newsgroups. This has the problem of
-filtering out many FAQs, as well as newsgroup creation postings and
-similar administrative announcements. Either the B<C> flag or the B<U>
-flag is a better solution.
-
-=item B<H> I<count>
-
-If this flag is specified, an article will only be sent to this site if it
-has I<count> or fewer sites in its Path: line. This flag should only be
-used as a rough guide because of the loose interpretation of the Path:
-header; some sites put the poster's name in the header, and some sites
-that might logically be considered to be one hop become two because they
-put the posting workstation's name in the header. The default value for
-I<count> if not specified is one. (Also see the B<O> flag, which is
-sometimes more appropriate for some uses of this flag.)
-
-=item B<I> I<size>
-
-The flag specifies the size of the internal buffer for a file feed. If
-there are more file feeds than allowed by the system, they will be
-buffered internally in least-recently-used order. If the internal buffer
-grows bigger then I<size> bytes, however, the data will be written out to
-the appropriate file. The default value is 16 KB.
-
-=item B<N> I<status>
-
-Restricts the articles sent to this site to those in newsgroups with the
-moderation status given by I<status>. If I<status> is C<m>, only articles
-in moderated groups are sent; if I<status> is C<u>, only articles in
-unmoderated groups are sent.
-
-=item B<O> I<originator>
-
-If this flag is specified, an article will only be sent to this site if it
-contains an X-Trace: header and the first field of this header matches
-I<originator>. I<originator> is a uwildmat(3) expression without commas or
-a list of such expressions, separated by C</>. The article is never sent
-if the first character of the pattern begins with C<@> and the rest of the
-pattern matches. One use of this flag is to restrict the feed to locally
-generated posts by using an I<originator> pattern that matches the
-X-Trace: header added by the local server.
-
-=item B<P> I<priority>
-
-The nice priority that this channel or program feed should receive. This
-should be a positive number between 0 and 20 and is the priority that the
-new process will run with. This flag can be used to raise the priority to
-normal if you're using the I<nicekids> parameter in F<inn.conf>.
-
-=item B<Q> I<hashfeed>
-
-Specifies the I<hashfeed> match expression for this site. It must be in
-the form C<value/mod> or C<start-end/mod>. The Message-ID of the article
-is hashed using MD5, which results in a 128-bit hash. The lowest
-S<32 bits> are then taken by default as the hashfeed value (which is an
-integer). If the hashfeed value modulus C<mod> plus one equals C<value> or
-is between C<start> and C<end>, the article will be fed to this site. All
-these numbers must be integers.
-
-It is a deterministic way to control the flow of articles and to split a feed.
-For instance:
-
- Q1/2 Feeds about 50% of all articles to this site.
- Q2/2 Feeds the other 50% of all articles.
-
-Another example with three sites:
-
- Q1-3/10 Feeds about 30% of all articles.
- Q4-5/10 Feeds about 20% of all articles.
- Q6-10/10 Feeds about 50% of all articles.
-
-If this flag is specified multiple times, the contents will be
-logically C<OR>ed together (just one match is needed).
-
-You can use an extended syntax of the form C<value/mod_offset> or
-C<start-end/mod_offset>. As MD5 generates a 128-bit return value,
-it is possible to specify from which byte-offset the 32-bit integer
-used by hashfeed starts. The default value for C<offset> is C<_0>
-and thirteen overlapping values from C<_0> to C<_12> can be used.
-Only up to four totally independent values exist: C<_0>, C<_4>,
-C<_8> and C<_12>.
-
-Therefore, it allows to a generate a second level of deterministic
-distribution. Indeed, if a news server is fed C<Q1/2>, it can go on
-splitting thanks to C<Q1-3/9_4> for instance.
-
-The algorithm is compatible with the one used by S<Diablo 5.1> and up.
-If you want to use the legacy quickhashing method used by Diablo
-before 5.1, you can put an C<@> sign just after the B<Q> flag (for
-instance C<Q@1-3/10>, but the distribution of the messages is not
-perfect with this legacy method whose use is discouraged and for
-which offsets cannot be used).
-
-=item B<S> I<size>
-
-If the amount of data queued for the site gets to be larger than I<size>
-bytes, the server will switch to spooling, appending to a file specified
-by the B<F> flag, or I<pathoutgoing>/I<sitename> if B<F> is not specified.
-Spooling usually happens only for channel or exploder feeds, when the
-spawned program isn't keeping up with its input.
-
-=item B<T> I<type>
-
-This flag specifies the type of feed for this site. I<type> should be a
-letter chosen from the following set:
-
- c Channel
- f File
- l Log entry only
- m Funnel (multiple entries feed into one)
- p Program
- x Exploder
-
-Each feed is described below in L<"FEED TYPES">. The default is B<Tf>,
-for a file feed.
-
-=item B<U> I<count>
-
-If this flag is specified, an article will only be sent to this site if
-followups to this article would be posted to no more than I<count>
-newsgroups. (Also see B<C> for a more complex way of handling this.)
-
-=item B<W> I<items>
-
-For a file, channel, or exploder feed, this flag controls what information
-will be sent to this site. For a program feed, only the asterisk (C<*>)
-has any effect. I<items> should be chosen from the following set:
-
-=over 3
-
-=item b
-
-Size of the article (in wire format, meaning with CRLF at the end of each
-line, periods doubled at the beginning of lines, and ending in a line with
-a single period) in bytes.
-
-=item e
-
-The time the article will expire as seconds since epoch if it has an
-Expires: header, C<0> otherwise.
-
-=item f
-
-The storage API token of the article (the same as C<n>). The article can
-be retrieved given the storage API token by using sm(8).
-
-=item g
-
-The newsgroup the article is in; if cross-posted, then the first of the
-groups to which the article was posted that this site gets. (The
-difference from C<G> is that this sends the newsgroup to which the article
-was posted even if it is a control message.)
-
-=item h
-
-The history hash key of the article (derived from the message ID).
-
-=item m
-
-The message ID of the article.
-
-=item n
-
-The storage API token of the article. The article can be retrieved given
-the storage API token by using sm(8).
-
-=item p
-
-The time the article was posted a seconds since epoch.
-
-=item s
-
-The site that fed the article to the server. This is taken from either
-the Path: header or the IP address of the sending site depending on the
-value of I<logipaddr> in F<inn.conf>. If I<logipaddr> is true and the IP
-address is C<0.0.0.0> (meaning that the article was fed from localhost by
-a program like rnews(8)), the Path: header value will be sent instead.
-
-=item t
-
-The time the article was received as seconds since epoch.
-
-=item Z<>*
-
-The names of the appropriate funnel entries, or all sites that get the
-article (see below for more details).
-
-=item D
-
-The value of the Distribution: header of the article, or C<?> if there is
-no such header in the article.
-
-=item G
-
-Where the article is stored. If the newsgroup is crossposted, this is
-generally the first of the groups to which it was posted that this site
-receives; however, control messages are filed in control or control.*
-(which is the difference between this item and C<g>).
-
-=item H
-
-All of the headers, followed by a blank line. The Xref header will
-already be present, and a Bytes header containing the article's size in
-bytes as in the C<b> item will be added to the headers. If used, this
-should be the only item in the list.
-
-=item N
-
-The value of the Newsgroups: header.
-
-=item P
-
-The value of the Path: header.
-
-=item O
-
-Overview data for the article.
-
-=item R
-
-Information needed for replication (the Xref header without the site
-name).
-
-=back
-
-More than one letter can be given. If multiple items are specified, they
-will be written in the order specified separated by spaces. (C<H> should
-be the only item if given, but if it's not a newline will be sent before
-the beginning of the headers.) The default is B<Wn>.
-
-The C<H> and C<O> items are intended for use by programs that create news
-overview databases or require similar information. B<WnteO> is the flag
-to generate input needed by the overchan(8) program.
-
-The asterisk (C<*>) has special meaning. Normally it expands to a
-space-separated list of all sites that received the current article. If,
-however, this site is a target of a funnel feed (in other words, if it is
-named by other sites which have the B<Tm> flag), then the asterisk expands
-to the names of the funnel feeds that received the article. Similarly, if
-the site is a program feed, an asterisk in the I<parameter> field will be
-expanded into the list of funnel feeds that received the article. A
-program feed cannot get the site list unless it is the target of other
-B<Tm> feeds.
-
-=back
-
-=head1 FEED TYPES
-
-B<innd> provides four basic types of feeds: log, file, program, and
-channel. An exploder is a special type of channel. In addition, several
-entries can feed into the same feed; these are funnel feeds, which refer
-to an entry that is one of the other types. Funnel feeds are partially
-described above with the description of the B<W*> flag. A funnel feed
-gets every article that would be sent to any of the feeds that funnel into
-it and normally include the B<W*> flag in their flags so that the program
-processing that feed knows which sites received which articles. The most
-common funnel feed is innfeed(8).
-
-Note that the term "feed" is technically a misnomer, since the server
-doesn't transfer articles itself and only writes data to a file, program,
-or log telling another program to transfer the articles.
-
-The simplest feed is a log feed (B<Tl>). Other than a mention in the news
-log file, I<pathlog>/news, no data is written out. This is equivalent to
-a B<Tf> entry writing to F</dev/null>, except that no file is ever opened.
-Flushing a log feed does nothing.
-
-A file feed (B<Tf>) is the next simplest type of feed. When the site
-should receive an article, the specified data is written out to the file
-named by the I<parameter> field. If I<parameter> is not an absolute path,
-it is taken to be relative to I<pathoutgoing> in F<inn.conf>. If
-I<parameter> is not given, it defaults to I<pathoutgoing>/I<sitename>.
-The file name should be unique (two file feeds should not ever point to
-the same file).
-
-File feeds are designed for use by external programs that periodically
-process the written data. To cooperate with B<innd> properly, such
-external programs should first rename the batch file and then send a flush
-command for that site to B<innd> using ctlinnd(8). B<innd> will then
-write out any buffered data, close the file, and reopen it (under the
-original name), and the program can process the data in the renamed file
-at its leisure. File feeds are most frequently used in combination with
-nntpsend(8).
-
-A program feed (B<Tp>) spawns a given program for every article that the
-site receives. The I<paramter> field must be the command line to execute,
-and should contain one instance of C<%s>, which will be replaced by the
-storage API token of the article (the actual article can be retrieved by
-the program using sm(8)). The program will not receive anything on
-standard input (unlike earlier versions of INN, where the article is sent
-to the program on stdin), and standard output and error from the program
-will be set to the error log (I<pathlog>/errlog). B<innd> will try to
-avoid spawning a shell if the command has no shell meta-characters; this
-feature can be defeated if necessary for some reason by appending a
-semi-colon to the end of the command. The full path name of the program
-to be run must be specified unless the command will be run by the shell
-(and it is strongly recommended that the full path name always be
-specified regardless).
-
-If a program feed is the target of a funnel, and if B<W*> appears in the
-flags of the site, a single asterisk may be present in the I<parameter>
-and will be replaced by a space-separated list of names of the sites
-feeding into the funnel which received the relevant article. If the site
-is not the target of a funnel, or if the B<W*> flag is not used, the
-asterisk has no special meaning.
-
-Flushing a program feed does nothing.
-
-For a channel (B<Tc>) or exploder (B<Tx>) feed, the I<parameter> field
-again names the process to start. As with program feeds, the full path to
-the program must be specified. However, rather than spawning the program
-for every article, it is spawned once and then whenever the site receives
-an article, the data specified by the site flags is written to the
-standard input of the spawned program. Standard output and error are set
-as with program feeds. If the process exits, it will be restarted
-automatically. If the process cannot be started, the server will spool
-input to a file named I<pathoutgoing>/I<sitename> and will try to start
-the process again later.
-
-When a channel or exploder feed is flushed, the server closes its end of
-the pipe to the program's standard input. Any pending data that has not
-been written will be spooled; see the description of the B<S> flag above.
-The server will then spawn a new instance of the program. No signal is
-sent to the program; it is up to the program handling a channel or
-exploder feed to notice end of file on its standard input and exit
-appropriately.
-
-Exploders are a special type of channel feed. In addition to the channel
-feed behavior described above, exploders can also be sent command lines.
-These lines start with an exclamation point and their interpretation is up
-to the exploder. The following commands are generated automatically by
-the server:
-
- !newgroup group
- !rmgroup group
- !flush
- !flush site
-
-These commands are sent whenever the ctlinnd(8) command of the same name
-is received by the server. In addition, the ctlinnd(8) C<send> command
-can be used to send an arbitrary command line to an exploder. The primary
-exploder is buffchan(8).
-
-Finally, B<Tm> feeds are the input to a funnel. The I<parameter> field of
-the site should name the site handling articles for all of the funnel
-inputs.
-
-=head1 EXAMPLES
-
-All of the following examples assume that INN was installed with a prefix
-of F</usr/local/news>; if you installed it somewhere else, modify the
-paths as appropriate.
-
-The syntax of the F<newsfeeds> file is so complex because you can specify
-a staggering variety of feeds. INN is capable of interacting with a wide
-variety of programs that do various things with news articles. Far and
-away the most common two entries in F<newsfeeds>, however, are file feeds
-for nntpsend(8) and funnel feeds for innfeed(8).
-
-The former look like this:
-
- feed.example.com:*,!control,!control.*,!junk:Tf,Wnm:
-
-which generates a file named I<pathoutgoing>/feed.example.com containing
-one line per article consisting of the storage API token, a space, and the
-message ID.
-
-The latter look like this:
-
- feed.example.com:*,!control,!control.*,!junk:Tm:innfeed!
-
-Very similar, except that this is the input to a funnel feed named
-C<innfeed!>. One could also write this as:
-
- example/feed.example.com:*,!control,!control.*,!junk:Ap,Tm:innfeed!
-
-(note the B<Ap> so that articles that contain just C<example> in the Path:
-header will still be sent), which is completely equivalent except that
-this will be logged in I<pathlog>/news as going to the site C<example>
-rather than C<feed.example.com>.
-
-The typical feed entry for innfeed(8) is a good example of a channel feed
-that's the target of various funnel feeds:
-
- innfeed!:!*:Tc,Wnm*:/usr/local/news/bin/startinnfeed -y
-
-Note that the I<pattern> for this feed is just C<!*> so that it won't
-receive any articles directly. The feed should only receive those
-articles that would go to one of the funnel feeds that are feeding into
-it. innfeed(8) (spawned by B<startinnfeed>) will receive one line per
-article on its standard input containing the storage API token, the
-message ID, and a space-separated list of sites that should receive that
-article.
-
-Here's a more esoteric example of a channel feed:
-
- watcher!:*:Tc,Wbnm\
- :exec awk '$1 > 1000000 { print "BIG", $2, $3 }' > /dev/console
-
-This receives the byte size of each article along with the storage API
-token and message ID, and prints to the console a line for every article
-that's over a million bytes. This is actually rather a strange way to
-write this since INN can do the size check itself; the following is
-equivalent:
-
- watcher!:*:Tc,>1000000,Wbnm\
- :exec awk '{ print "BIG", $2, $3}' > /dev/console
-
-Here's a cute, really simple news to mail gateway that also serves as an
-example of a fairly fancy program feed:
-
- mailer!:!*:W*,Tp\
- :sm %s | innmail -s "News article" *
-
-Remember that C<%s> is replaced by the storage API token, so this
-retrieves the article and pipes it into B<innmail> (which is safer than
-programs like Mail(1) because it doesn't parse the body for tilde
-commands) with a given subject line. Note the use of C<*> in the command
-line and B<W*> in the flags; this entry is designed to be used as the
-target of funnel feeds such as:
-
- peter@example.com:news.software.nntp:Tm:mailer!
- sue@example.com:news.admin.misc:Tm:mailer!
-
-Suppose that the server receives an article crossposted between
-news.admin.misc and news.software.nntp. The server will notice that the
-article should be sent to the site C<peter@example.com> and the site
-C<bob@example.com>, both of which funnel into C<mailer!>, so it will look
-at the C<mailer!> site and end up executing the command line:
-
- sm @...@ | innmail -s "News article" peter@example.com sue@example.com
-
-which will mail the article to both Peter and Sue.
-
-Finally, another very useful example of a channel feed: the standard
-entry for controlchan(8).
-
- controlchan!\
- :!*,control,control.*,!control.cancel/!collabra-internal\
- :Tc,Wnsm:/usr/local/news/bin/controlchan
-
-This program only wants information about articles posted to a control
-newsgroup other than control.cancel, which due to the sorting of control
-messages described in innd(8) will send it all control messages except for
-cancel messages. In this case, we also exclude any article with a
-distribution of C<collabra-internal>. B<controlchan> gets the storage
-API token, the name of the sending site (for processing old-style ihave
-and sendme control messages, be sure to read about I<logipaddr> in
-controlchan(8)), and the message ID for each article.
-
-For many other examples, including examples of the special C<ME> site
-entry, see the example F<newsfeeds> file distributed with INN. Also see the
-install documentation that comes with INN for information about setting up
-the standard newsfeeds entries used by most sites.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Reformatted
-and rewritten in POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: newsfeeds.pod 7741 2008-04-06 09:51:47Z iulius $
-
-=head1 SEE ALSO
-
-active(5), buffchan(8), controlchan(8), ctlinnd(8), inn.conf(5), innd(8),
-innfeed(8), innxmit(8), nntpsend(8), uwildmat(3).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ninpaths - Report Usenet Path statistics (new inpaths)
-
-=head1 SYNOPSIS
-
-B<ninpaths> B<-p> B<-d> I<dumpfile>
-
-B<ninpaths> B<-r> I<site> B<-u> I<dumpfile> [B<-u> I<dumpfile> ...] B<-v>
-I<level>
-
-=head1 DESCRIPTION
-
-This is an efficient and space-saving inpaths reporting program. It works
-as follows: you feed it the Path lines via an INN channel feed or some
-other similar method, and from time to time the program writes all its
-internal counters accumulated so far to a dump file. Another instance of
-the program picks up all the dump files, adds them up and formats them
-into the report. The purpose of the final report is to summarize the
-frequency of occurrence of sites in the Path headers of articles.
-
-Some central sites accumulate the Path data from many news servers running
-this program or one like it, and then report statistics on the most
-frequently seen news servers in Usenet article Path lines. The
-B<sendinpaths> shell script can be run once a month to mail the
-accumulated statistics to such a site and remove the old dump files.
-
-You can get a working setup by doing the following:
-
-=over 4
-
-=item 1.
-
-Create a directory at I<pathlog>/path (replacing I<pathlog> here and in
-all steps that follow with the full path to your INN log directory).
-
-=item 2.
-
-Set up a channel feed using an entry like:
-
- inpaths!:*:Tc,WP:ninpaths -p -d <pathlog>/path/inpaths.%d
-
-if your version of INN supports WP (2.0 and later all do). Replace
-<pathlog> with the full path to your INN log directory.
-
-=item 3.
-
-Enter into your news user crontab something like:
-
- 6 6 * * * ctlinnd flush inpaths!
-
-(the actual time doesn't matter). This will force B<ninpaths> to generate
-a dump file once a day.
-
-=item 4.
-
-Once per month, run the B<sendinpaths> script, which collects the dumps,
-makes a report, and then deletes the old dumps. (You can generate a
-report without mailing it and without deleting it with C<sendinpaths -n>.)
-
-=back
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-d> I<dumpfile>
-
-Save dumps in I<dumpfile>. Any C<%d> in I<dumpfile> will be replaced with
-the current system time when the dump is made. This option should be used
-with B<-p>.
-
-=item B<-p>
-
-Read Path lines from standard input.
-
-=item B<-r> I<site>
-
-Generate a report for I<site>. Generally I<site> should be the value of
-I<pathhost> from F<inn.conf>.
-
-=item B<-u> I<dumpfile>
-
-Read data from I<dumpfile>. This option can be repeated to read data from
-multiple dump files.
-
-=item B<-v> I<level>
-
-Set the verbosity level of the report. Valid values for I<level> are 0,
-1, and 2, with 2 being the default.
-
-=back
-
-=head1 NOTES
-
-If your INN doesn't have the WP feed flag (1.5 does not, 1.6 does, 1.7 I
-don't know, 2.0 and later all do), use the following newsfeeds entry:
-
- inpaths!:*:Tc,WH:ginpaths
-
-where B<ginpaths> is the following script:
-
- #!/bin/sh
- exec egrep '^Path: ' | ninpaths -p -d <pathlog>/path/inpaths.%d
-
-replacing <pathlog> as above.
-
-=head1 SEE ALSO
-
-newsfeeds(5), sendinpaths(8)
-
-This is a slightly modified version of Olaf Titz's original ninpaths
-program, which is posted to alt.sources and kept on his WWW archive under
-L<http://sites.inka.de/~bigred/sw/>.
-
-=head1 HISTORY
-
-B<ninpaths> was written by Olaf Titz <olaf@bigred.inka.de>.
-
-The idea and some implementation details for ninpaths come from the
-original inpaths program, but most of the code has been rewritten for
-clarity. This program is in the public domain.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-nnrpd - NNTP server for reader clients
-
-=head1 SYNOPSIS
-
-B<nnrpd> [B<-DfnoSt>] [B<-b> I<address>] [B<-c> I<configfile>]
-[B<-g> I<shadowgroup>>] [B<-i> I<initial>] [B<-I> I<instance>] [B<-p> I<port>]
-[B<-P> I<prefork>] [B<-r> I<reason>] [B<-s> I<padding>]
-
-=head1 DESCRIPTION
-
-B<nnrpd> is an NNTP server for newsreaders. It accepts commands on its
-standard input and responds on its standard output. It is normally
-invoked by innd(8) with those descriptors attached to a remote client
-connection. B<nnrpd> also supports running as a standalone daemon.
-
-Unlike innd(8) B<nnrpd> supports all NNTP commands for user-oriented
-reading and posting. B<nnrpd> uses the F<readers.conf> file to control
-who is authorized to access the Usenet database.
-
-On exit, B<nnrpd> will report usage statistics through syslog(3).
-
-B<nnrpd> only reads config files (both F<readers.conf> and F<inn.conf>)
-when it is spawned. You can therefore never change the behavior of a
-client that's already connected. If B<nnrpd> is run from B<innd> (the
-default) or from inetd(8), xinetd(8), or some equivalent, a new B<nnrpd>
-process is spawned for every connection and therefore any changes to
-configuration files will be immediately effective for all new
-connections. If you are instead running B<nnrpd> with the B<-D> option,
-any configuration changes won't take effect until B<nnrpd> is restarted.
-
-The F<inn.conf> setting I<nnrpdflags> can be used to pass any of the
-options below to instances of B<nnrpd> that are spawned directly from
-B<innd>. Many options only make sense when B<-D> is used, so these
-options should not be used with I<nnrpdflags>. See also the discussion
-of I<nnrpdflags> in inn.conf(5).
-
-When I<nnrpdloadlimit> in F<inn.conf> is not 0, it will also reject
-connections if the load average is greater than that value (typically 16).
-B<nnrpd> can also prevent high-volume posters from abusing your
-resources. See the discussion of exponential backoff in inn.conf(5).
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-b> I<address>
-
-The B<-b> parameter instructs B<nnrpd> to bind to the specified IP
-address when started as a standalone daemon using the B<-D> flag. This
-has to be a valid IPv4 or IPv6 address belonging to an interface of
-the local host. It can also be ::0 (although the default is 0.0.0.0
-if unspecified).
-
-=item B<-c> I<configfile>
-
-By default, B<nnrpd> reads the F<readers.conf> to determine how to
-authenticate connections. The B<-c> flag specifies an alternate file
-for this purpose. If the file name isn't fully qualified, it is taken
-to be relative to I<pathetc> in F<inn.conf> (this is useful to have
-several instances of B<nnrpd> running on different ports or IP
-addresses with different settings.)
-
-=item B<-D>
-
-If specified, this parameter causes B<nnrpd> to operate as a
-daemon. That is, it detaches itself and runs in the background,
-forking a process for every connection. By default B<nnrpd> listens on
-the NNTP port (119), so either innd(8) has to be started on another
-port or B<nnrpd> B<-p> parameter. Note that with this parameter,
-B<nnrpd> continues running until killed. This means that it reads
-F<inn.conf> once on startup and never again until restarted. B<nnrpd>
-should therefore be restarted if inn.conf is changed.
-
-When started in daemon mode, B<nnrpd> will write its PID into a file in
-the I<pathrun> directory. The file will be named F<nnrpd-%d.pid>, where
-C<%d> is replaced with the port that B<nnrpd> is configured to listen on
-(119 unless the B<-p> option is given).
-
-=item B<-f>
-
-If specified, B<nnrpd> does not detach itself and runs in the
-foreground when started as a standalone daemon using the B<-D> flag.
-
-=item B<-g> I<shadowgroup>
-
-On systems that have a shadow password file, B<nnrpd> tries to add the
-group I<shadow> as a supplementary group if it is running in
-standalone mode. On many systems, members of that group have read
-permission for the shadow password file. The B<-g> parameter instructs
-B<nnrpd> to try to add the named group as a supplementary group on
-shadow systems instead of I<shadow>. This only works if
-C<HAVE_GETSPNAM> in F<include/config.h> is defined and B<nnrpd> is
-running in standalone mode since this call only works when B<nnrpd> is
-started as root.
-
-=item B<-i> I<initial>
-
-Specify an initial command to B<nnrpd>. When used, I<initial> is taken
-as if it were the first command received by B<nnrpd>.
-
-=item B<-I> I<instance>
-
-If specified I<instance> is used as an additional static portion
-within MessageIDs generated by B<nnrpd>; typically this option would
-be used where a cluster of machines exist with the same virtual
-hostname and must be disambiguated during posts.
-
-=item B<-n>
-
-The B<-n> flag turns off resolution of IP addresses to names. If you
-only use IP-based restrictions in F<readers.conf> and can handle IP
-addresses in your logs, using this flag may result in some additional
-speed.
-
-=item B<-o>
-
-The B<-o> flag causes all articles to be spooled instead of sending
-them to innd(8). B<rnews> with the B<-U> flag should be invoked from
-cron on a regular basis to take care of these articles. This flag is
-useful if innd(8) in accepting articles and B<nnrpd> is started
-standalone or using inetd(8).
-
-=item B<-p> I<port>
-
-The B<-p> parameter instructs B<nnrpd> to listen on I<port> when
-started as a standalone daemon using the B<-D> flag.
-
-=item B<-P> I<prefork>
-
-The B<-P> parameter instructs B<nnrpd> to prefork I<prefork> children
-awaiting connections when started as a standalone daemon using the
-B<-D> flag.
-
-=item B<-r> I<reason>
-
-If the B<-r> flag is used, then B<nnrpd> will reject the incoming
-connection giving I<reason> as the text. This flag is used by innd(8)
-when it is paused or throttled.
-
-=item B<-s> I<padding>
-
-As each command is received, B<nnrpd> tries to change its C<argv>
-array so that ps(1) will print out the command being executed. To get
-a full display, the B<-s> flag may be used with a long string as its
-argument, which will be overwritten when the program changes its
-title.
-
-=item B<-S>
-
-If specified, B<nnrpd> will start a negotiation for SSL session as
-soon as connected. To use this flag, C<--with-openssl> must have been
-specified at C<configure> time.
-
-=item B<-t>
-
-If the B<-t> flag is used then all client commands and initial
-responses will be traced by reporting them in syslog. This flag is set
-by innd(8) under the control of the ctlinnd(8) C<trace> command, and
-is toggled upon receipt of a C<SIGHUP>; see signal(2).
-
-=back
-
-=head1 SSL SUPPORT
-
-If INN is built with C<--with-openssl>, B<nnrpd> will support news reading
-over TLS (also known as SSL). For clients that use the STARTTLS command,
-no special configuration is needed beyond creating a TLS/SSL certificate
-for the server. You should do this in exactly the same way that you would
-generate a certificate for a web server.
-
-If you're happy with a self-signed certificate (which will generate
-warnings with some news reader clients), you can create and install one in
-the default path by running C<make cert> after C<make install> when
-installing INN, or by running the following commands:
-
- openssl req -new -x509 -nodes -out /usr/local/news/lib/cert.pem \
- -days 366 -keyout /usr/local/news/lib/key.pem
- chown news:news /usr/local/news/lib/cert.pem
- chmod 640 /usr/local/news/lib/cert.pem
- chown news:news /usr/local/news/lib/key.pem
- chmod 600 /usr/local/news/lib/key.pem
-
-Replace the paths with something appropriate to your INN installation.
-This will create a self-signed certificate that will expire in a year.
-The B<openssl> program will ask you a variety of questions about your
-organization. Enter the fully qualified domain name of the server as the
-name the certificate is for.
-
-Most news clients currently do not use the STARTTLS command, however, and
-instead expect to connect to a separate port (563) and start an SSL
-negotiation immediately. B<innd> does not, however, know how to listen
-for connections to that port and then spawn B<nnrpd> the way that it does
-for regular reader connections. You will therefore need to arrange for
-B<nnrpd> to listen on that port through some other means. This can be
-done with the B<-D> flag (and C<-P 563>), but the easiest way is probably
-to add a line like:
-
- nntps stream tcp nowait news /usr/lib/news/bin/nnrpd nnrpd -S
-
-to F</etc/inetd.conf> or the equivalent on your system and let B<inetd>
-run B<nnrpd>. (Change the path to B<nnrpd> to match your installation if
-needed.) You may need to replace C<nntps> with C<563> if C<nntps> isn't
-defined in F</etc/services> on your system.
-
-=head1 PROTOCOL DIFFERENCES
-
-B<nnrpd> implements the NNTP commands defined in RFC 977, with the
-following differences:
-
-=over 4
-
-=item 1.
-
-The C<slave> command is not implemented. This command has never been
-fully defined.
-
-=item 2.
-
-The C<list> command may be followed by the optional word C<active.times>,
-C<distributions>, C<distrib.pats>, C<moderators>, C<newsgroups>,
-C<subscriptions>, or C<Ioverview.fmt> to get a list of when newsgroups
-where created, a list of valid distributions, a file specifying default
-distribution patterns, moderators list, a one-per-line description of the
-current set of newsgroups, a list of the automatic group subscriptions, or
-a listing of the F<overview.fmt> file.
-
-The command C<list active> is equivalent to the C<list> command. This
-is a common extension.
-
-=item 3.
-
-The C<xhdr>, C<authinfo user> and C<authinfo pass> commands are
-implemented. These are based on the reference Unix implementation. See
-RFC 2980.
-
-=item 4.
-
-A new command, C<xpat header range|MessageID pat [morepat...]>, is
-provided. The first argument is the case-insensitive name of the header
-to be searched. The second argument is either an article range or a
-single Message-ID, as specified in RFC 977. The third argument is a
-C<uwildmat>(3)-style pattern; if there are additional arguments they are
-joined together separated by a single space to form the complete pattern.
-This command is similar to the C<xhdr> command. It returns a C<221>
-response code, followed by the text response of all article numbers that
-match the pattern.
-
-=item 5.
-
-The C<listgroup group> command is provided. This is a comment extension.
-It is equivalent to the C<group> command, except that the reply is a
-multi-line response containing the list of all article numbers in the
-group.
-
-=item 6.
-
-The C<xgtitle [group]> command is provided. This extension is used by
-ANU-News. It returns a C<282> reply code, followed by a one-line
-description of all newsgroups thatmatch the pattern. The default is the
-current group.
-
-=item 7.
-
-The C<xover [range]> command is provided. It returns a C<224> reply code,
-followed by the overview data for the specified range; the default is to
-return the data for the current article.
-
-=item 8.
-
-The C<xpath MessageID> command is provided; see innd(8).
-
-=item 9.
-
-The C<date> command is provided; this is based on the draft NNTP protocol
-revision (draft-ietf-nntpext-imp-04.txt). It returns a one-line response
-code of C<111> followed by the GMT date and time on the server in the form
-C<YYYYMMDDhhmmss>.
-
-=back
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Overview
-support added by Rob Robertston <rob@violet.berkeley.edu> and Rich in
-January, 1993. Exponential backoff (for posting) added by Dave Hayes in
-Febuary 1998.
-
-$Id: nnrpd.pod 7751 2008-04-06 14:35:40Z iulius $
-
-=head1 SEE ALSO
-
-ctlinnd(8), innd(8), inn.conf(5), signal(2), uwildmat(3).
+++ /dev/null
-=head1 NAME
-
-ovdb - Overview storage method for INN
-
-=head1 DESCRIPTION
-
-Ovdb is a storage method that uses the BerkeleyDB library to store
-overview data. It requires version 2.6.x or later of the BerkeleyDB
-library, but has mostly been tested with version 3 and 4.
-
-Ovdb makes use of the full transaction/logging/locking functionality of
-the BerkeleyDB environment. BerkeleyDB may be downloaded from
-L<http://www.sleepycat.com> and is needed to build the ovdb backend.
-
-=head1 UPGRADING
-
-This is version 2 of ovdb. If you have a database created with a previous
-version of ovdb (such as the one shipped with INN 2.3.0) your database
-will need to be upgraded using ovdb_init(8). See the man page
-ovdb_init(8) for upgrade instructions.
-
-=head1 INSTALLATION
-
-To build ovdb support into INN, specify the option C<--with-berkeleydb>
-when running the configure script. By default, configure will search for
-a BerkeleyDB tree in several likely locations, and choose the highest
-version (based on the name of the directory, e.g., F<BerkeleyDB.3.0>) that
-it finds. There will be a message in the configure output indicating the
-chosen pathname.
-
-You can override this pathname by adding a path to the option, e.g.,
-C<--with-berkeleydb=/usr/BerkeleyDB.3.1>. This directory is expected to
-have subdirectories F<include> and F<lib>, containing F<db.h>, and the
-library itself, respectively.
-
-The ovdb database will take up more disk space for a given spool than the
-other overview methods. Plan on needing at least 1.1 KB for every article
-in your spool (not counting crossposts). So, if you have 5 million
-articles, you'll need at least 5.5 GB of disk space for ovdb. With
-BerkeleyDB 2.x, the db files are 'grow only'; the library will not shrink
-them, even if data is removed. So, reserving extra space above the
-estimate is a good idea. Plus, you'll need additional space for
-transaction logs: at least 100 MB. By default the transaction logs go in
-the same directory as the database. To improve performance, they can be
-placed on a different disk -- see the DB_CONFIG section.
-
-=head1 CONFIGURATION
-
-To enable ovdb, set the I<ovmethod> parameter in F<inn.conf> to C<ovdb>.
-The ovdb database is stored in the directory specified by the
-I<pathoverview> paramter in F<inn.conf>. This is the "DB_HOME" directory.
-To start out, this directory should be empty (other than an optional
-F<DB_CONFIG> file; see L<DB_CONFIG> for details) and B<innd> (or
-B<makehistory>) will create the files as necessary in that directory.
-Make sure the directory is owned by the news user.
-
-Other parameters for configuring ovdb are in the ovdb.conf(5)
-configuration file. See also the sample F<ovdb.conf>.
-
-=over 4
-
-=item cachesize
-
-Size of the memory pool cache, in kilobytes. The cache will have a
-backing store file in the DB directory which will be at least as big. In
-general, the bigger the cache, the better. Use C<ovdb_stat -m> to see
-cache hit percentages. To make a change of this parameter take effect,
-shut down and restart INN (be sure to kill all of the nnrpds when shutting
-down). Default is 8000, which is adequate for small to medium sized
-servers. Large servers will probably need at least 20000.
-
-=item numdbfiles
-
-Overview data is split between this many files. Currently, B<innd> will
-keep all of the files open, so don't set this too high or B<innd> may run
-out of file descriptors. B<nnrpd> only opens one at a time, regardless.
-May be set to one, or just a few, but only do that if your OS supports
-large (>2G) files. Changing this parameter has no effect on an
-already-established database. Default is 32.
-
-=item txn_nosync
-
-If txn_nosync is set to false, BerkeleyDB flushes the log after every
-transaction. This minimizes the number of transactions that may be lost
-in the event of a crash, but results in significantly degraded
-performance. Default is true.
-
-=item useshm
-
-If useshm is set to true, BerkeleyDB will use shared memory instead of
-mmap for its environment regions (cache, lock, etc). With some platforms,
-this may improve performance. Default is false. This parameter is
-ignored if you have BerkeleyDB 2.x
-
-=item shmkey
-
-Sets the shared memory key used by BerkeleyDB when 'useshm' is true.
-BerkeleyDB will create several (usually 5) shared memory segments, using
-sequentially numbered keys starting with 'shmkey'. Choose a key that does
-not conflict with any existing shared memory segments on your system.
-Default is 6400. This parameter is only used with BerkeleyDB 3.1 or
-newer.
-
-=item pagesize
-
-Sets the page size for the DB files (in bytes). Must be a power of 2.
-Best choices are 4096 or 8192. The default is 8192. Changing this
-parameter has no effect on an already-established database.
-
-=item minkey
-
-Sets the minimum number of keys per page. See the BerkeleyDB
-documentation for more info. Default is based on page size:
-
- default_minkey = MAX(2, pagesize / 2048 - 1)
-
-The lowest allowed minkey is 2. Setting minkey higher than the default is
-not recommended, as it will cause the databases to have a lot of overflow
-pages. Changing this parameter has no effect on an already-established
-database.
-
-=item maxlocks
-
-Sets the BerkeleyDB "lk_max" parameter, which is the maxmium number of
-locks that can exist in the database at the same time. Default is 4000.
-
-=item nocompact
-
-The nocompact parameter affects expireover's behavior. The expireover
-function in ovdb can do its job in one of two ways: by simply deleting
-expired records from the database, or by re-writing the overview records
-into a different location leaving out the expired records. The first
-method is faster, but it leaves 'holes' that result in space that can not
-immediately be reused. The second method 'compacts' the records by
-rewriting them.
-
-If this parameter is set to 0, expireover will compact all newsgroups; if
-set to 1, expireover will not compact any newsgroups; and if set to a
-value greater than one, expireover will only compact groups that have less
-than that number of articles.
-
-Experience has shown that compacting has minimal effect (other than
-making expireover take longer) so the default is now 1. This parameter
-will probably be removed in the future.
-
-=item readserver
-
-Normally, each nnrpd process directly accesses the BerkeleyDB environment.
-The process of attaching to the database (and detaching when finished) is
-fairly expensive, and can result in high loads in situations when there
-are lots of reader connections of relatively short duration.
-
-When the readserver parameter is "true", the nnrpds will access overview
-via a helper server (B<ovdb_server> -- which is started by B<ovdb_init>).
-This can also result in cleaner shutdowns for the database, improving
-stability and avoiding deadlocks and corrupted databases. If you are
-experiencing any instability in ovdb, try setting this parameter to true.
-Default is false.
-
-=item numrsprocs
-
-This parameter is only used when I<readserver> is true. It sets the
-number of ovdb_server processes. As each ovdb_server can process only one
-transaction at a time, running more servers can improve reader response
-times. Default is 5.
-
-=item maxrsconn
-
-This parameter is only used when I<readserver> is true. It sets a maximum
-number of readers that a given ovdb_server process will serve at one time.
-This means the maximum number of readers for all of the ovdb_server
-processes is (numrsprocs * maxrsconn). Default is 0, which means an
-umlimited number of connections is allowed.
-
-=back
-
-=head1 DB_CONFIG
-
-A file called F<DB_CONFIG> may be placed in the database directory to
-customize where the various database files and transaction logs are
-written. By default, all of the files are written in the "DB_HOME"
-directory. One way to improve performance is to put the transaction logs
-on a different disk. To do this, put:
-
- DB_LOG_DIR /path/to/logs
-
-in the F<DB_CONFIG> file. If the pathname you give starts with a /, it is
-treated as an absolute path; otherwise, it is relative to the "DB_HOME"
-directory. Make sure that any directories you specify exist and have
-proper ownership/mode before starting INN, because they won't be created
-automatically. Also, don't change the DB_CONFIG file while anything that
-uses ovdb is running.
-
-Another thing that you can do with this file is to split the overview
-database across multiple disks. In the F<DB_CONFIG> file, you can list
-directories that BerkeleyDB will search when it goes to open a database.
-
-For example, let's say that you have I<pathoverview> set to
-F</mnt/overview> and you have four additional file systems created on
-F</mnt/ov?>. You would create a file "/mnt/overview/DB_CONFIG" containing
-the following lines:
-
- set_data_dir /mnt/overview
- set_data_dir /mnt/ov1
- set_data_dir /mnt/ov2
- set_data_dir /mnt/ov3
- set_data_dir /mnt/ov4
-
-(For BerkeleyDB 2.x, replace C<set_data_dir> with C<DB_DATA_DIR>.)
-
-Distribute your ovNNNNN files into the four filesystems. (say, 8 each).
-When called upon to open a database file, the db library will look for it
-in each of the specified directories (in order). If said file is not
-found, one will be created in the first of those directories.
-
-Whenever you change DB_CONFIG or move database files around, make sure all
-news processes that use the database are shut down first (including
-nnrpds).
-
-The DB_CONFIG functionality is part of BerkeleyDB itself, rather than
-something provided by ovdb. See the BerkeleyDB documentation for complete
-details for the version of BerkeleyDB that you're running.
-
-=head1 RUNNING
-
-When starting the news system, B<rc.news> will invoke B<ovdb_init>.
-B<ovdb_init> must be run before using the database. It performs the
-following tasks:
-
-=over 4
-
-=item *
-
-Creates the database environment, if necessary.
-
-=item *
-
-If the database is idle, it performs a normal recovery. The recovery will
-remove stale locks, recreate the memory pool cache, and repair any damage
-caused by a system crash or improper shutdown.
-
-=item *
-
-Starts the DB housekeeping processes (B<ovdb_monitor>) if they're not
-already running.
-
-=back
-
-And when stopping INN, B<rc.news> kills the ovdb_monitor processes after
-the other INN processes have been shut down.
-
-=head1 DIAGNOSTICS
-
-Problems relating to ovdb are logged to news.err with "OVDB" in the error
-message.
-
-INN programs that use overview will fail to start up if the ovdb_monitor
-processes aren't running. Be sure to run B<ovdb_init> before running
-anything that accesses overview.
-
-Also, INN programs that use overview will fail to start up if the user
-running them is not the "news" user.
-
-If a program accessing the database crashes, or otherwise exits uncleanly,
-it might leave a stale lock in the database. This lock could cause other
-processes to deadlock on that stale lock. To fix this, shut down all news
-processes (using C<kill -9> if necessary) and then restart. B<ovdb_init>
-should perform a recovery operation which will remove the locks and repair
-damage caused by killing the deadlocked processes.
-
-=head1 FILES
-
-=over 4
-
-=item inn.conf
-
-The I<ovmethod> and I<pathoverview> parameters are relevant to ovdb.
-
-=item ovdb.conf
-
-Optional configuration file for tuning. See L<CONFIGURATION> above.
-
-=item I<pathoverview>
-
-Directory where the database goes. BerkeleyDB calls it the 'DB_HOME'
-directory.
-
-=item I<pathoverview>/DB_CONFIG
-
-Optional file to configure the layout of the database files.
-
-=item I<pathrun>/ovdb.sem
-
-A file that gets locked by every process that is accessing the database.
-This is used by B<ovdb_init> to determine whether the database is active
-or quiescent.
-
-=item I<pathrun>/ovdb_monitor.pid
-
-Contains the process ID of B<ovdb_monitor>.
-
-=back
-
-=head1 TO DO
-
-Implement a way to limit how many databases can be open at once (to reduce
-file descriptor usage); maybe using something similar to the cache code in
-ov3.c
-
-=head1 HISTORY
-
-Written by Heath Kehoe <hakehoe@avalon.net> for InterNetNews
-
-=head1 SEE ALSO
-
-inn.conf(5), innd(8), nnrpd(8), ovdb_init(8), ovdb_monitor(8),
-ovdb_stat(8)
-
-BerkeleyDB documentation: in the F<docs> directory of the BerkeleyDB
-source distribution, or on the Sleepycat web page:
-L<http://www.sleepycat.com/>.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ovdb_init - Prepare ovdb database for use
-
-=head1 SYNOPSYS
-
-ovdb_init [C<-u>|C<-r>]
-
-=head1 DESCRIPTION
-
-This command must be run before any other process can access the
-overview database. It performs the following steps:
-
-=over 4
-
-=item 1
-
-Creates the database environment, if necessary
-
-=item 2
-
-If the database is idle (and if the C<-u> option is not specified),
-it performs a normal recovery. The recovery will remove stale locks,
-recreate the memory pool cache, and repair any damage caused by a system
-crash or improper shutdown.
-
-=item 3
-
-If the C<-u> option is specified, it performs any necessary upgrades
-to the database. See the UPGRADING section below.
-
-=item 4
-
-Starts the DB housekeeping processes (ovdb_monitor) if they're not
-already running. (Unless the C<-r> option is specified).
-
-=item 5
-
-Starts the ovdb readserver (ovdb_server) processes if C<readserver>
-in F<ovdb.conf> is C<true>, and if they're not
-already running. (Unless the C<-r> option is specified).
-
-=back
-
-Returns exit status of 0 if all steps were completed successfully.
-In the event of an error, messages are written to syslog and/or stderr.
-
-If a recovery was attempted but it failed, the database may be
-damaged beyond repair, requiring a rebuild with makehistory(8).
-
-This command is normally invoked automatically by rc.news(8).
-
-It is OK to run this command multiple times.
-
-=head1 OPTIONS
-
-=over 4
-
-=item C<-r>
-
-Perform recovery only. C<ovdb_monitor> is not started.
-
-=item C<-u>
-
-Perform any needed upgrades. Recovery is not attempted.
-C<ovdb_monitor> is started if the upgrade succeeded.
-
-=back
-
-=head1 UPGRADING
-
-There are two situations in which the database will need to be
-upgraded:
-
-=over 4
-
-=item *
-
-You upgrade the BerkeleyDB library to a newer version, for example
-from 2.7.7 to 3.1.17. In this case, the BerkeleyDB db->upgrade()
-method is used.
-
-=item *
-
-You upgrade ovdb to a newer major version; i.e., ovdb-1.0 to ovdb-2.0.
-
-=back
-
-In both of these cases, the database is upgraded in-place; and the
-upgrade can not be undone. Do not interrupt the upgrade process once
-it has started, because there is a risk of irrepairable corruption.
-The upgrade may take several minutes to complete.
-If an upgrade does get interrupted, try running the upgrade again.
-
-Here's an example procedure to upgrade a database created with BerkeleyDB
-2.7.7 to use BerkeleyDB 3.1.17:
-
-=over 4
-
-=item 1
-
-Build and install the BerkeleyDB 3.1.17
-
-=item 2
-
-Run configure in the INN source tree and make sure it picks up the
-right BerkeleyDB directory (e.g., /usr/local/BerkeleyDB.3.1)
-
-=item 3
-
-Do a C<make>
-
-=item 4
-
-Shut down INN (e.g., with C<rc.news stop>). Be sure to kill all nnrpds as
-well.
-
-=item 5
-
-Do a C<make update> to install the new binaries.
-
-=item 6
-
-Run C<ovdb_init -u> as the news user.
-
-=item 7
-
-Start INN with C<rc.news>
-
-=back
-
-It is OK to specify C<-u> even if no upgrades are needed.
-
-=head1 HISTORY
-
-Written by Heath Kehoe E<lt>hakehoe@avalon.netE<gt> for InterNetNews.
-
-=head1 SEE ALSO
-
-ovdb(5), makehistory(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ovdb_monitor - Database maintenance
-
-=head1 SYNOPSYS
-
-Use C<ovdb_init> to start ovdb_monitor
-
-=head1 DESCRIPTION
-
-When started (by C<ovdb_init>), C<ovdb_monitor> forks three processes
-that perform routine database maintenance tasks. These are:
-transaction checkpointing, deadlock detection, and transaction log
-removal. The process ID of the parent is written to
-F<I<pathrun>/ovdb_monitor.pid>. This PID is used by other INN
-commands to verify that ovdb_monitor is running.
-
-To shut down ovdb_monitor, send a TERM signal to the process ID
-in F<I<pathrun>/ovdb_monitor.pid> . The parent process will shut
-down the three children and wait for their exit before exiting itself.
-
-=head1 HISTORY
-
-Written by Heath Kehoe E<lt>hakehoe@avalon.netE<gt> for InterNetNews.
-
-=head1 SEE ALSO
-
-ovdb(5), ovdb_init(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ovdb_server - overview 'helper' server
-
-=head1 SYNOPSYS
-
-Use C<ovdb_init> to start ovdb_server
-
-=head1 DESCRIPTION
-
-If the C<readserver> parameter in F<ovdb.conf> is true,
-C<ovdb_init> will start C<ovdb_server>.
-
-C<ovdb_server> opens the overview database, and accesses it
-on behalf of the nnrpd reader processes.
-
-To shut down ovdb_server, send a TERM signal to the process ID
-in F<I<pathrun>/ovdb_server.pid> . The parent process will shut
-down its children and wait for their exit before exiting itself.
-
-=head1 HISTORY
-
-Written by Heath Kehoe E<lt>hakehoe@avalon.netE<gt> for InterNetNews.
-
-=head1 SEE ALSO
-
-ovdb(5), ovdb_init(8)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-ovdb_stat - Display information from the ovdb database
-
-=head1 SYNOPSYS
-
-B<ovdb_stat> B<-Hgci> [B<-r> I<artnumrange>] newsgroup [newsgroup ...]
-
-B<ovdb_stat> B<-Hklmtv> [B<-d> I<database>]
-
-=head1 DESCRIPTION
-
-B<ovdb_stat> displays information from the ovdb database: BerkeleyDB
-statistics, newsgroup data, and overview records; and optionally
-outputs in HTML format.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-g>
-
-Newsgroup himark, lowmark, article count, and flag for the given newsgroups
-(as stored in the ovdb "groupinfo" database) are displayed.
-
-=item B<-c>
-
-Similar to B<-g>, except the himark, lowmark, and count are calculated
-by actually scanning the overview records and counting them.
-This can be a lengthy operation on groups with lots of articles.
-
-=item B<-i>
-
-Internal data regarding the given newsgroups are displayed.
-
-=item B<-r> I<artnumrange>
-
-Overview records are retrieved. The I<artnumrange> parameter may be
-a single article number, or a range of articles in the format C<low-hi>.
-
-=item B<-H>
-
-Output is presented in HTML format.
-
-=item B<-k>
-
-Displays lock region statistics, as returned by the BerkeleyDB lock_stat()
-call.
-
-=item B<-l>
-
-Displays log region statistics, as returned by the BerkeleyDB log_stat()
-call.
-
-=item B<-m>
-
-Displays global memory pool statistics, as returned by the
-BerkeleyDB memp_stat() call.
-
-=item B<-M>
-
-Same as B<-m>, and also displays memory pool statistics for each
-database file.
-
-=item B<-t>
-
-Displays log region statistics, as returned by the BerkeleyDB txn_stat()
-call.
-
-=item B<-v>
-
-Displays ovdb version, and BerkeleyDB version.
-
-=item B<-d> I<database>
-
-Displays information about the given database, as returned by the
-BerkeleyDB db->stat() call. This operation may take a long time
-on busy systems (several minutes or more).
-
-=back
-
-=head1 WARNINGS
-
-ovdb_stat may be safely killed with the INT, TERM, or HUP signals.
-It catches those signals and exits cleanly.
-Do not kill ovdb_stat with other signals, unless absolutely necessary,
-because it may leave stale locks in the DB environment.
-
-=head1 HISTORY
-
-Written by Heath Kehoe E<lt>hakehoe@avalon.netE<gt> for InterNetNews.
-
-=head1 SEE ALSO
-
-ovdb(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-passwd.nntp - passwords for connecting to remote NNTP servers
-
-=head1 DESCRIPTION
-
-The file F<passwd.nntp> in I<pathetc> contains host / name / password
-triplets for use when authenticating client programs to NNTP servers.
-This file is normally interpreted by NNTPsendpassword() in libinn(3).
-Blank lines and lines beginning with a number sign (C<#>) are ignored.
-All other lines should consist of three or four fields separated by
-colons:
-
- host:name:password
- host:name:password:style
-
-The first field is the name of a host, and is matched in a
-case-insensitive manner. (No detailed matching, such as comparing IP
-addresses, is done.)
-
-The second field is a user name, and the third is a password. If either
-the username or password is empty, then that portion of the
-authentication will not occur. (For example, when connecting to a
-remote INN for peering, only the password is needed.)
-
-The optional fourth field specifies the type of authentication to use.
-At present, the only recognized "authentication style" is C<authinfo>;
-this is also the default. It means that NNTP "authinfo" commands are
-used to authenticate to the remote host. (The C<authinfo> command is a
-common extension to RFC 977.)
-
-For example:
-
- ## UUNET needs a password, MIT doesn't.
- mit.edu:bbn::authinfo
- uunet.uu.net:bbn:yoyoma:authinfo
-
-This file should not be world-readable.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. This is
-revision $Revision: 5089 $, dated $Date: 2002-02-03 11:03:41 -0800 (Sun, 03 Feb 2002) $.
-
-$Id: passwd.nntp.pod 5089 2002-02-03 19:03:41Z vinocur $
-
-=head1 SEE ALSO
-
-inn.conf(5), innd(8), libinn(3).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-pullnews - Pull news from multiple news servers and feed it to another
-
-=head1 SYNOPSIS
-
-B<pullnews> [B<-hnqRx>] [B<-b> I<fraction>] [B<-c> I<config>] [B<-C> I<width>]
-[B<-d> I<level>] [B<-f> I<fraction>] [B<-F> I<fakehop>] [B<-g> I<groups>]
-[B<-G> I<newsgroups>] [B<-H> I<headers>] [B<-k> I<checkpt>] [B<-l> I<logfile>]
-[B<-m> I<header_pats>] [B<-M> I<num>] [B<-N> I<timeout>] [B<-p> I<port>]
-[B<-P> I<hop_limit>] [B<-Q> I<level>] [B<-r> I<file>] [B<-s> I<to-server>[:I<port>]]
-[B<-S> I<max-run>] [B<-t> I<retries>] [B<-T> I<connect-pause>] [B<-w> I<num>]
-[B<-z> I<article-pause>] [B<-Z> I<group-pause>] [I<from-server> ...]
-
-=head1 REQUIREMENTS
-
-The C<Net::NNTP> module must be installed. This module is available as part
-of the libnet distribution and comes with recent versions of Perl. For
-older versions of Perl, you can download it from L<http://www.cpan.org/>.
-
-=head1 DESCRIPTION
-
-B<pullnews> reads a config file in the running user's home directory
-(normally called F<~/.pullnews>) and connects to the upstream servers
-given there as a reader client. By default, it connects to all servers
-listed in the configuration file, but you can limit B<pullnews> to
-specific servers by listing them on the command line: a whitespace-separated
-list of server names can be specified, like I<from-server> for one of them.
-For each server it connects to, it pulls over articles and feeds them to the
-destination server via the IHAVE or POST commands. This means that the system
-B<pullnews> is run on must have feeding access to the destination news server.
-
-B<pullnews> is designed for very small sites that do not want to bother
-setting up traditional peering and is not meant for handling large feeds.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-b> I<fraction>
-
-Backtrack on server numbering reset. Specify the proportion (C<0.0> to C<1.0>)
-of a group's articles to pull when the server's article number is less than
-our high for that group. When I<fraction> is C<1.0>, pull all the articles on
-a renumbered server. The default is to do nothing.
-
-=item B<-c> I<config>
-
-Normally, the config file is stored in F<~/.pullnews> for the user running
-B<pullnews>. If B<-c> is given, I<config> will be used as the config file
-instead. This is useful if you're running B<pullnews> as a system user on
-an automated basis out of cron rather than as an individual user.
-
-See L<CONFIG FILE> below for the format of this file.
-
-=item B<-C> I<width>
-
-Use I<width> characters per line for the progress table. The default value
-is C<50>.
-
-=item B<-d> I<level>
-
-Set the debugging level to the integer I<level>; more debugging output
-will be logged as this increases. The default value is C<0>.
-
-=item B<-f> I<fraction>
-
-This changes the proportion of articles to get from each group to
-I<fraction> and should be in the range C<0.0> to C<1.0> (C<1.0> being
-the default).
-
-=item B<-F> I<fakehop>
-
-Prepend I<fakehop> as a host to the Path: header of articles fed.
-
-=item B<-g> I<groups>
-
-Specify a collection of groups to get. I<groups> is a list of
-newsgroups separated by commas (only commas, no spaces). Each group must
-be defined in the config file, and only the remote hosts that carry those
-groups will be contacted. Note that this is a simple list of groups, not
-a wildmat expression, and wildcards are not supported.
-
-=item B<-G> I<newsgroups>
-
-Add the comma-separated list of groups I<newsgroups> to each server in the
-configuration file (see also B<-g> and B<-w>).
-
-=item B<-h>
-
-Print a usage message and exit.
-
-=item B<-H> I<headers>
-
-Remove these named headers (colon-separated list) from fed articles.
-
-=item B<-k> I<checkpt>
-
-Checkpoint (save) the config file every I<checkpt> articles
-(default is C<0>, that is to say at the end of the session).
-
-=item B<-l> I<logfile>
-
-Log progress/stats to I<logfile> (default is C<stdout>).
-
-=item B<-m> I<header_pats>
-
-Feed an article based on header matching. The argument is a number of
-whitespace-separated tuples (each tuple being a colon-separated header and
-regular expression). For instance:
-
- Hdr1:regexp1 !Hdr2:regexp2
-
-specifies that the article will be passed only if the C<Hdr1:> header
-matches C<regexp1> and the C<Hdr2:> header does not match C<regexp2>.
-
-=item B<-M> I<num>
-
-Specify the maximum number of articles (per group) to process.
-The default is to process all new articles. See also B<-f>.
-
-=item B<-n>
-
-Do nothing but read articles S<-- does> not feed articles downstream,
-writes no B<rnews> file, does not update the config file.
-
-=item B<-N> I<timeout>
-
-Specify the timeout length, as I<timeout> seconds,
-when establishing an NNTP connection.
-
-=item B<-p> I<port>
-
-Connect to the destination news server on a port other than the default of
-C<119>. This option does not change the port used to connect to the source
-news servers.
-
-=item B<-P> I<hop_limit>
-
-Restrict feeding an article based on the number of hops it has already made.
-Count the hops in the Path: header (I<hop_count>), feeding the article only
-when I<hop_limit> is C<+num> and I<hop_count> is more than I<num>;
-or I<hop_limit> is C<-num> and I<hop_count> is less than I<num>.
-
-=item B<-q>
-
-Print out less status information while running.
-
-=item B<-Q> I<level>
-
-Set the quietness level (C<-Q 2> is equivalent to C<-q>). The higher this
-value, the less gets logged. The default is C<0>.
-
-=item B<-r> I<file>
-
-Rather than feeding the downloaded articles to a destination server, instead
-create a batch file that can later be fed to a server using B<rnews>. See
-rnews(1) for more information about the batch file format.
-
-=item B<-R>
-
-Be a reader (use MODE READER and POST commands) to the downstream
-server. The default is to use the IHAVE command.
-
-=item B<-s> I<to-server>[:I<port>]
-
-Normally, B<pullnews> will feed the articles it retrieves to the news
-server running on localhost. To connect to a different host, specify a
-server with the B<-s> flag. You can also specify the port with this same
-flag or use B<-p>.
-
-=item B<-S> I<max-run>
-
-Specify the maximum time I<max-run> in seconds for B<pullnews> to run.
-
-=item B<-t> I<retries>
-
-The maximum number (I<retries>) of attempts to connect to a server
-(see also B<-T>). The default is C<0>.
-
-=item B<-T> I<connect-pause>
-
-Pause I<connect-pause> seconds between connection retries (see also B<-t>).
-The default is C<1>.
-
-=item B<-w> I<num>
-
-Set each group's high watermark (last received article number) to I<num>.
-If I<num> is negative, calculate S<I<Current>+I<num>> instead (i.e. get the last
-I<num> articles). Therefore, a I<num> of C<0> will re-get all articles on the
-server; whereas a I<num> of C<-0> will get no old articles, setting the
-watermark to I<Current> (the most recent article on the server).
-
-=item B<-x>
-
-If the B<-x> flag is used, an Xref: header is added to any article
-that lacks one. It can be useful for instance if articles are fed
-to a news server which has I<xrefslave> set in F<inn.conf>.
-
-=item B<-z> I<article-pause>
-
-Sleep I<article-pause> seconds between articles. The default is C<0>.
-
-=item B<-Z> I<group-pause>
-
-Sleep I<group-pause> seconds between groups. The default is C<0>.
-
-=back
-
-=head1 CONFIG FILE
-
-The config file for B<pullnews> is divided into blocks, one block for each
-remote server to connect to. A block begins with the host line, which
-must have no leading whitespace and contains just the hostname of the
-remote server, optionally followed by authentication details (username
-and password for that server).
-
-Following the host line should be one or more newsgroup lines which start
-with whitespace followed by the name of a newsgroup to retrieve. Only one
-newsgroup should be listed on each line.
-
-B<pullnews> will update the config file to include the time the group was
-last checked and the highest numbered article successfully retrieved and
-transferred to the destination server. It uses this data to avoid doing
-duplicate work the next time it runs.
-
-The full syntax is:
-
- <host> [<username> <password>]
- <group> [<time> <high>]
- <group> [<time> <high>]
-
-where the <host> line must not have leading whitespace and the <group>
-lines must.
-
-A typical configuration file would be:
-
- # Format group date high
- data.pa.vix.com
- rec.bicycles.racing 908086612 783
- rec.humor.funny 908086613 18
- comp.programming.threads
- nnrp.vix.com pull sekret
- comp.std.lisp
-
-Note that an earlier run of B<pullnews> has filled in details about the
-last article downloads from the two rec.* groups. The two comp.* groups
-were just added by the user and have not yet been checked.
-
-The nnrp.vix.com server requires authentication, and B<pullnews> will use
-the username C<pull> and the password C<sekret>.
-
-=head1 FILES
-
-=over 4
-
-=item I<pathbin>/pullnews
-
-The Perl script itself used to pull news from upstream servers and feed
-it to another news server.
-
-=item I<$HOME>/.pullnews
-
-The default config file. It is in the running user's home directory
-(normally called F<~/.pullnews>).
-
-=back
-
-=head1 HISTORY
-
-B<pullnews> was written by James Brister for INN. The documentation was
-rewritten in POD by Russ Allbery <rra@stanford.edu>.
-
-Geraint A. Edwards greatly improved B<pullnews>, adding no more than S<16 new>
-recognized flags, fixing some bugs and integrating the B<backupfeed>
-contrib script by Kai Henningsen, adding again S<6 other> flags.
-
-$Id: pullnews.pod 7853 2008-05-27 19:07:45Z iulius $
-
-=head1 SEE ALSO
-
-incoming.conf(5), rnews(1).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-qio - Quick I/O routines for reading files
-
-=head1 SYNOPSIS
-
-B<#include E<lt>inn/qio.hE<gt>>
-
-B<QIOSTATE *QIOopen(const char *>I<name>B<);>
-
-B<QIOSTATE *QIOfdopen(int> I<fd>B<);>
-
-B<void QIOclose(QIOSTATE *>I<qp>B<);>
-
-B<char *QIOread(QIOSTATE *>I<qp>B<);>
-
-B<int QIOfileno(QIOSTATE *>I<qp>B<);>
-
-B<size_t QIOlength(QIOSTATE *>I<qp>B<);>
-
-B<int QIOrewind(QIOSTATE *>I<qp>B<);>
-
-B<off_t QIOtell(QIOSTATE *>I<qp>B<);>
-
-B<bool QIOerror(QIOSTATE *>I<qp>B<);>
-
-B<bool QIOtoolong(QIOSTATE *>I<qp>B<);>
-
-=head1 DESCRIPTION
-
-The routines described in this manual page are part of libinn(3). They
-are used to provide quick read access to files; the QIO routines use
-buffering adapted to the block size of the device, similar to stdio, but
-with a more convenient syntax for reading newline-terminated lines. QIO
-is short for "Quick I/O" (a bit of a misnomer, as QIO provides read-only
-access to files only).
-
-The QIOSTATE structure returned by B<QIOopen> and B<QIOfdopen> is the
-analog to stdio's FILE structure and should be treated as a black box by
-all users of these routines. Only the above API should be used.
-
-B<QIOopen> opens the given file for reading. For regular files, if your
-system provides that information and the size is reasonable, QIO will use
-the block size of the underlying file system as its buffer size;
-otherwise, it will default to a buffer of 8 KB. Returns a pointer to use
-for subsequent calls, or NULL on error. B<QIOfdopen> performs the same
-operation except on an already-open file descriptor (I<fd> must designate
-a file open for reading).
-
-B<QIOclose> closes the open file and releases any resources used by the
-QIOSTATE structure. The QIOSTATE pointer should not be used again after
-it has been passed to this function.
-
-B<QIOread> reads the next newline-terminated line in the file and returns
-a pointer to it, with the trailing newline replaced by nul. The returned
-pointer is a pointer into a buffer in the QIOSTATE object and therefore
-will remain valid until B<QIOclose> is called on that object. If EOF is
-reached, an error occurs, or if the line is longer than the buffer size,
-NULL is returned instead. To distinguish between the error cases, use
-B<QIOerror> and B<QIOtoolong>.
-
-B<QIOfileno> returns the descriptor of the open file.
-
-B<QIOlength> returns the length in bytes of the last line returned by
-B<QIOread>. Its return value is only defined after a successful call to
-B<QIOread>.
-
-B<QIOrewind> sets the read pointer back to the beginning of the file and
-reads the first block of the file in anticipation of future reads. It
-returns 0 if successful and -1 on error.
-
-B<QIOtell> returns the current value of the read pointer (the lseek(2)
-offset at which the next line will start).
-
-B<QIOerror> returns true if there was an error in the last call to
-B<QIOread>, false otherwise. B<QIOtoolong> returns true if there was an
-error and the error was that the line was too long. If B<QIOread> returns
-NULL, these functions should be called to determine what happened. If
-B<QIOread> returned NULL and B<QIOerror> is false, EOF was reached. Note
-that if B<QIOtoolong> returns true, the next call to B<QIOread> will try
-to read the remainder of the line and will likely return a partial line;
-users of this library should in general treat long lines as fatal errors.
-
-=head1 EXAMPLES
-
-This block of code opens F</etc/motd> and reads it a line at a time,
-printing out each line preceeded by its offset in the file.
-
- QIOSTATE *qp;
- off_t offset;
- char *p;
-
- qp = QIOopen("/etc/motd");
- if (qp == NULL) {
- perror("Open error");
- exit(1);
- }
- for (p = QIOread(qp); p != NULL; p = QIOread(qp))
- printf("%ld: %s\n", (unsigned long) QIOtell(qp), p);
- if (QIOerror(qp)) {
- perror("Read error");
- exit(1);
- }
- QIOclose(qp);
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> for InterNetNews. Updated by
-Russ Allbery <rra@stanford.edu>.
-
-$Id: qio.pod 5909 2002-12-03 05:17:18Z vinocur $
+++ /dev/null
-=head1 NAME
-
-radius.conf - Configuration for nnrpd RADIUS authenticator
-
-=head1 DESCRIPTION
-
-This describes the format and attributes of the configuration file for the
-nnrpd RADIUS authenticator. See radius(1) for more information about the
-authenticator program. The default location for this file is
-F<radius.conf> in I<pathetc>.
-
-Blank lines and lines beginning with C<#> are ignored, as is anything
-after a C<#> on a line. All other lines should begin with a parameter
-name followed by a colon and the value of that key, except that each
-section of configuration for a particular server should be enclosed in:
-
- server <name> {
- # parameters...
- }
-
-where <name> is just some convenient label for that server.
-
-The available parameters are:
-
-=over 4
-
-=item I<radhost>
-
-The hostname of the RADIUS server to use for authentication. This
-parameter must be set.
-
-=item I<radport>
-
-The port to query on the RADIUS server. Defaults to 1645 if not set.
-
-=item I<lochost>
-
-The hostname or IP address making the request. The RADIUS server expects
-an IP address; a hostname will be translated into an IP address with
-gethostbyname(). If not given, this information isn't included in the
-request (not all RADIUS setups require this information).
-
-=item I<locport>
-
-The port the client being authenticated is connecting to. If not given,
-defaults to 119. This doesn't need to be set unless readers are
-connecting to a non-standard port.
-
-=item I<secret>
-
-The shared secret with the RADIUS server. If your secret includes spaces,
-tabs, or C<#>, be sure to include it in double quotes. This parameter
-must be set.
-
-=item I<prefix>
-
-Prepend the value of this parameter to all usernames before passing them
-to the RADIUS server. Can be used to prepend something like C<news-> to
-all usernames in order to put news users into a different namespace from
-other accounts served by the same server. If not set, nothing is
-prepended.
-
-=item I<suffix>
-
-Append the value of this parameter to all usernames before passing them to
-the RADIUS server. This is often something like C<@example.com>,
-depending on how your RADIUS server is set up. If not set, nothing is
-appended.
-
-=item I<ignore-source>
-
-Can be set to C<true> or C<false>. If set to false, the RADIUS
-authenticator will check to ensure that the response it receives is from
-the same IP address as it sent the request to (for some added security).
-If set to true, it will skip this verification check (if your RADIUS
-server has multiple IP addresses or if other odd things are going on, it
-may be perfectly normal for the response to come from a different IP
-address).
-
-=back
-
-=head1 EXAMPLE
-
-Here is a configuration for a news server named news.example.com,
-authenticating users against radius.example.com and appending
-C<@example.com> to all client-supplied usernames before passing them to
-the RADIUS server:
-
- server example {
- radhost: radius.example.com
- lochost: news.example.com
- secret: IamARADIUSsecRET
- suffix: @example.com
- }
-
-The shared secret with the RADIUS server is C<IamARADIUSsecRET>.
-
-=head1 HISTORY
-
-This documentation was written by Russ Allbery <rra@stanford.edu> based on
-the comments in the sample radius.conf file by Yury B. Razbegin.
-
-$Id: radius.conf.pod 6736 2004-05-16 23:06:08Z rra $
-
-=head1 SEE ALSO
-
-radius(1)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-radius - nnrpd RADIUS password authenticator
-
-=head1 SYNOPSIS
-
-B<radius> [B<-h>] [B<-f> I<config>]
-
-=head1 DESCRIPTION
-
-B<radius> is an nnrpd authenticator, accepting a username and password
-from nnrpd (given to nnrpd by a reader connection) and attempting to
-authenticate that username and password against a RADIUS server. See
-readers.conf(5) for more information on how to configure an nnrpd
-authenticator. It is useful for a site that already does user
-authentication via RADIUS and wants to authenticate news reading
-connections as well.
-
-By default, B<radius> reads I<pathetc>/radius.conf for configuration
-information, but a different configuration file can be specified with
-B<-f>. See radius.conf(5) for a description of the configuration file.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-f> I<config>
-
-Read I<config> instead of I<pathetc>/radius.conf for configuration
-information.
-
-=item B<-h>
-
-Print out a usage message and exit.
-
-=back
-
-=head1 EXAMPLE
-
-The following readers.conf(5) fragment tells nnrpd to authenticate all
-connections using this authenticator:
-
- auth radius {
- auth: radius
- default: <FAIL>
- default-domain: example.com
- }
-
-C<@example.com> will be appended to the user-supplied identity, and if
-RADIUS authentication failes, the user will be assigned an identity of
-C<E<lt>FAILE<gt>@example.com>.
-
-=head1 BUGS
-
-It has been reported that this authenticator doesn't work with Ascend
-RADIUS servers, but does work with Cistron RADIUS servers. It's also
-believed to work with Livingston's RADIUS server. Contributions to make
-it work better with different types of RADIUS servers would be gratefully
-accepted.
-
-This code has not been audited against the RADIUS protocol and may not
-implement it correctly.
-
-=head1 HISTORY
-
-The RADIUS authenticator was originally written by Aidan Cully. This
-documentation was written by Russ Allbery <rra@stanford.edu>.
-
-$Id: radius.pod 5894 2002-12-01 19:44:18Z rra $
-
-=head1 SEE ALSO
-
-nnrpd(8), radius.conf(5), readers.conf(5)
-
-RFC 2865, Remote Authentication Dial In User Service.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-rc.news - Start or stop INN daemons
-
-=head1 SYNOPSIS
-
-B<rc.news> [start | stop]
-
-=head1 DESCRIPTION
-
-B<rc.news> can be used to start or stop B<innd> and supporting programs.
-It checks to make sure INN is not already running, handles cases of
-unclean shutdown, finishes up tasks which might have been interrupted by
-the preceeding shutdown, emails certain boot-time warnings to
-I<newsmaster> (as set in F<inn.conf>), and is generally safer and easier
-than starting and stopping everything directly. It needs to be run as the
-news user so that files in I<pathrun> are created with the right ownership
-(though this is less important for C<rc.news stop>), and therefore
-requires that F<inndstart> be setuid root, see inndstart(8) for
-discussion.
-
-Programs run and stopped by this script include:
-
-=over 4
-
-=item *
-
-Always: B<inndstart> is run, and B<innd> is stopped.
-
-=item *
-
-If I<doinnwatch> is true in F<inn.conf>: B<innwatch> is started and
-stopped.
-
-=item *
-
-If I<docnfsstat> is true in F<inn.conf>: B<ovdb_init> is run;
-B<ovdb_server> and B<ovdb_monitor> are stopped.
-
-=item *
-
-If F<rc.news.local> exists in I<pathbin>: B<rc.news.local> is run with
-argument C<start> or C<stop> (to perform site-specific startup or shutdown
-tasks).
-
-=back
-
-=head1 OPTIONS
-
-=over 4
-
-=item C<start>
-
-If the first argument is C<start>, or no first argument is given,
-B<rc.news> initiates INN startup.
-
-=item C<stop>
-
-If the first argument is C<stop>, B<rc.news> initiates INN shutdown. It
-is recommended to throttle the server first as described in ctlinnd(8).
-
-=back
-
-=head1 EXAMPLES
-
-To start INN and leave certain error messages going to the terminal:
-
- su - news -c ~news/bin/rc.news
-
-To run INN at startup time from appropriate system boot scripts:
-
- su - news -c ~news/bin/rc.news >/dev/console
-
-To stop INN (throttling first):
-
- ~news/bin/ctlinnd throttle reason
- su - news -c '~news/bin/rc.news stop'
-
-=head1 BUGS
-
-Running C<rc.news start> as root is never the right thing to do, so we
-should at minimum check for this and error, or perhaps change effective
-user ID.
-
-=head1 HISTORY
-
-// FIXME: any attribution for rc.news itself?
-
-This manual page written by Jeffrey M. Vinocur <jeff@litech.org> for
-InterNetNews.
-
-$Id: rc.news.pod 5908 2002-12-03 04:41:36Z vinocur $
-
-=head1 SEE ALSO
-
-ctlinnd(8),
-cnfsstat(8),
-inn.conf(5),
-inndstart(8),
-innwatch(8),
-ovdb(5).
-
-=cut
-
+++ /dev/null
-=head1 NAME
-
-readers.conf - Access control and configuration for nnrpd
-
-=head1 DESCRIPTION
-
-F<readers.conf> in I<pathetc> specifies access control for nnrpd(8). It
-controls who is allowed to connect as a news reader and what they're
-allowed to do after they connect. nnrpd reads this file when it starts
-up. This generally means that any changes take effect immediately on all
-subsequent connections, but B<nnrpd> may have to be restarted if you use
-the B<-D> option. (The location I<pathetc>/readers.conf is only the
-default; the same format applies to any file specified with C<nnrpd -c>.)
-
-There are two types of entries in F<readers.conf>: parameter/value pairs
-and configuration groups. Blank lines and anything after a number sign
-(C<#>) are ignored, unless the character C<#> is escaped with C<\>. The
-maximum number of characters on each line is 8,191.
-
-Parameter/value pairs consist of a keyword immediately followed by a
-colon, at least one whitespace character, and a value. The case of the
-parameter is significant (parameter should generally be in all lowercase),
-and a parameter may contain any characters except colon, C<#>, and
-whitespace. An example:
-
- hosts: *.example.com
-
-Values that contain whitespace should be quoted with double quotes, as in:
-
- hosts: "*.example.com, *.example.net"
-
-If the parameter does not contain whitespace, such as:
-
- hosts: *.example.com,*.example.net
-
-it's not necessary to quote it, although you may wish to anyway for
-clarity.
-
-There is no way to continue a line on the next line, and therefore no way
-to have a single parameter with a value longer than about 8,180
-characters.
-
-Many parameters take a boolean value. For all such parameters, the value
-may be specified as C<true>, C<yes>, or C<on> to turn it on and may be any
-of C<false>, C<no>, or C<off> to turn it off. The case of these values is
-not significant.
-
-There are two basic types of configuration groups, auth and access. The
-auth group provides mechanisms to establish the identity of the user, who
-they are. The access group determines, given the user's identity, what
-that user is permitted to do. Writing a F<readers.conf> file for your
-setup is a two-step process: first assigning an identity to each incoming
-connection using auth groups, and then giving each identity appropriate
-privileges with access group. We recommend I<not> intermingling auth
-groups and access groups in the config file; it is often more sensible (in
-the absence of the I<key> parameter) to put all of the auth groups first,
-and all of the access groups below.
-
-A user identity, as established by an auth group, looks like an e-mail
-address; in other words, it's in the form "<username>@<domain>" (or
-sometimes just "<username>" if no domain is specified.
-
-If I<nnrpdauthsender> is set in F<inn.conf>, the user identity is also put
-into the Sender: header of posts made by that user. See the documentation
-of that option in inn.conf(5) for more details.
-
-An auth group definition looks like:
-
- auth <name> {
- hosts: <host-wildmat>
- auth: <auth-program>
- res: <res-program>
- default: <defuser>
- default-domain: <defdomain>
- # ...possibly other settings
- }
-
-The <name> is used as a label for the group and is only for documentation
-purposes. (If your syslog configuration records the C<news.debug>
-facility, the <name> will appear in the debugging output of nnrpd.
-Examining that output can be very helpful in understanding why your
-configuration doesn't do what you expect it to.)
-
-A given auth group applies only to hosts whose name or IP address matches
-the wildmat expression given with the hosts: parameter (comma-separated
-wildmat expressions allowed, but C<@> is not supported). Rather than
-wildmat expressions, you may also use CIDR notation to match any IP
-address in a netblock; for example, "10.10.10.0/24" will match any IP
-address between 10.10.10.0 and 10.10.10.255 inclusive.
-
-If compiled against the SSL libraries, an auth group with the require_ssl:
-parameter set to true only applies if the incoming connection is using
-SSL.
-
-For any connection from a host that matches that wildmat expression or
-netblock, each <res-program> (multiple res: lines may be present in a
-block; they are run in sequence until one succeeds), if any, is run to
-determine the identity of the user just from the connection information.
-If all the resolvers fail, or if the res: parameter isn't present, the
-user is assigned an identity of "<defuser>@<defdomain>"; in other words,
-the values of the default: and default-domain: parameters are used. If
-<res-program> only returns a username, <defdomain> is used as the
-domain.
-
-If the user later authenticates via the AUTHINFO USER/PASS commands, the
-provided username and password are passed to each <auth-program> (multiple
-auth, perl_auth, or python_auth lines may be present in a block; they are
-run in sequence until one succeeds), if any. If one succeeds and returns
-a different identity than the one assigned at the time of the connection,
-it is matched against the available access groups again and the actions
-the user is authorized to do may change. The most common <auth-program>
-to use is B<ckpasswd>, which supports several ways of checking passwords
-including using PAM. See the ckpasswd(8) man page for more details.
-
-When matching auth groups, the last auth group in the file that matches a
-given connection and username/password combination is used.
-
-An access group definition usually looks like:
-
- access <name> {
- users: <identity-wildmat>
- newsgroups: <group-wildmat>
- # ...possibly other settings
- }
-
-Again, <name> is just for documentation purposes. This says that all
-users whose identity matches <identity-wildmat> can read and post to all
-newsgroups matching <group-wildmat> (as before, comma-separated wildmat
-expressions are allowed, but C<@> is not supported). Alternately, you can
-use the form:
-
- access <name> {
- users: <identity-wildmat>
- read: <read-wildmat>
- post: <post-wildmat>
- }
-
-and matching users will be able to read any group that matches
-<read-wildmat> and post to any group that matches <post-wildmat>. You can
-also set several other things in the access group as well as override
-various inn.conf(5) parameters for just a particular group of users.
-
-Just like with auth groups, when matching access groups the last matching
-one in the file is used to determine the user's permissions. There is
-an exception to this rule: if the auth group which matched the client
-contains a perl_access: or python_access: parameter, then the script
-given as argument is used to dynamically generate an access group.
-This new access group is then used to determine the access rights of
-the client; the access groups in the file are ignored.
-
-There is one additional special case to be aware of. When forming
-particularly complex authentication and authorization rules, it is
-sometimes useful for the identities provided by a given auth group to only
-apply to particular access groups; in other words, rather than checking
-the identity against the users: parameter of every access group, it's
-checked against the users: parameter of only some specific access groups.
-This is done with the key: parameter. For example:
-
- auth example {
- key: special
- hosts: *.example.com
- default: <SPECIAL>
- }
-
- access example {
- key: special
- users: <SPECIAL>
- newsgroups: *
- }
-
-In this case, the two key: parameters bind this auth group with this
-access group. For any incoming connection matching "*.example.com"
-(assuming there isn't any later auth group that also matches such hosts),
-no access group that doesn't have "key: special" will even be considered.
-Similarly, the above access group will only be checked if the user was
-authenticated with an auth group containing "key: special". This
-mechanism normally isn't useful; there is almost always a better way to
-achieve the same result.
-
-Also note in the example that there's no default-domain: parameter, which
-means that no domain is appended to the default username and the identity
-for such connections is just "<SPECIAL>". Note that some additional
-add-ons to INN may prefer that authenticated identities always return a
-full e-mail address (including a domain), so you may want to set up your
-system that way.
-
-Below is the full list of allowable parameters for auth groups and access
-groups, and after that are some examples that may make this somewhat
-clearer.
-
-=head1 AUTH GROUP PARAMETERS
-
-An access group without at least one of the res:, auth:, perl_auth:,
-python_auth:, or default: parameters makes no sense (and in practice will
-just be ignored).
-
-=over 4
-
-=item B<hosts:>
-
-A comma-separated list of remote hosts, wildmat patterns matching either
-hostnames or IP addresses, or IP netblocks specified in CIDR notation. If
-a user connects from a host that doesn't match this parameter, this auth
-group will not match the connection and is ignored.
-
-Note that if you have a large number of patterns that can't be merged into
-broader patterns (such as a large number of individual systems scattered
-around the net that should have access), the hosts: parameter may exceed
-the maximum line length of 8,192 characters. In that case, you'll need to
-break that auth group into multiple auth groups, each with a portion of
-the hosts listed in its hosts: parameter, and each assigning the same user
-identity.
-
-All hosts match if this parameter is not given.
-
-=item B<localaddress:>
-
-A comma-separated list of local host or address patterns with the same
-syntax as the same as with the hosts: parameter. If this parameter is
-specified, its auth group will only match connections made to a matching
-local interface. (Obviously, this is only useful for servers with
-multiple interfaces.)
-
-All local addresses match if this parameter is not given.
-
-=item B<res:>
-
-A simple command line for a user resolver (shell metacharacters are not
-supported). If a full path is not given, the program executed must be in
-the I<pathbin>/auth/resolv directory. A resolver is an authentication
-program which attempts to figure out the identity of the connecting user
-using nothing but the connection information (in other words, the user
-has not provided a username and password). An examples of a resolver
-would be a program that assigns an identity from an ident callback or
-from the user's hostname.
-
-One auth group can have multiple res: parameters, and they will be tried
-in the order they're listed. The results of the first successful one
-will be used.
-
-=item B<auth:>
-
-A simple command line for a user authenticator (shell metacharacters are
-not supported). If a full path is not given, the program executed must be
-located in the I<pathbin>/auth/passwd directory. An authenticator is a
-program used to handle a user-supplied username and password, via a
-mechanism such as AUTHINFO USER/PASS. Like with res:, one auth group can
-have multiple auth: parameters; they will be tried in order and the
-results of the first successful one will be used. See also perl_auth:
-below.
-
-The most common authenticator to use is ckpasswd(8); see its man page for
-more information.
-
-=item B<perl_auth:>
-
-A path to a perl script for authentication. The perl_auth: parameter
-works exactly like auth:, except that it calls the named script using
-the perl hook rather then an external program. Multiple/mixed use of
-the auth, perl_auth, and python_auth parameters is permitted within any
-auth group; each line is tried in the order it appears. perl_auth:
-has more power than auth: in that it provides the authentication
-program with additional information about the client and the ability
-to return an error string and a username. This parameter is only
-valid if INN is compiled with Perl support (B<--with-perl> passed to
-configure). More information may be found in F<doc/hook-perl>.
-
-=item B<python_auth:>
-
-A Python script for authentication. The I<python_auth> parameter works
-exactly like I<auth>, except that it calls the named script (without its
-C<.py> extension) using the Python hook rather then an external program.
-Multiple/mixed use of the I<auth>, I<perl_auth>, and I<python_auth>
-parameters is permitted within any auth group; each line is tried
-in the order it appears. I<python_auth> has more power than I<auth>
-in that it provides the authentication program with additional information
-about the client and the ability to return an error string and a username.
-This parameter is only valid if INN is compiled with Python support
-(B<--with-python> passed to B<configure>). More information may be
-found in F<doc/hook-python>.
-
-=item B<default:>
-
-The default username for connections matching this auth group. This is
-the username assigned to the user at connection time if all resolvers fail
-or if there are no res: parameters. Note that it can be either a bare
-username, in which case default-domain: (if present) is appended after
-an C<@>, or a full identity string containing an C<@>, in which case it
-will be used verbatim.
-
-=item B<default-domain:>
-
-The default domain string for this auth group. If a user resolver or
-authenticator doesn't provide a domain, or if the default username is used
-and it doesn't contain a C<@>, this domain is used to form the user
-identity. (Note that for a lot of setups, it's not really necessary for
-user identities to be qualified with a domain name, in which case there's
-no need to use this parameter.)
-
-=item B<key:>
-
-If this parameter is present, any connection matching this auth group will
-have its privileges determined only by the subset of access groups
-containing a matching key parameter.
-
-=item B<require_ssl:>
-
-If set to true, an incoming connection only matches this auth group if
-it is encrypted using SSL. This parameter is only valid if INN is
-compiled with SSL support (B<--with-openssl> passed to configure).
-
-=item B<perl_access:>
-
-A path to a perl script for dynamically generating an access group. If
-an auth group matches successfully and contains a perl_access parameter,
-then the argument perl script will be used to create an access group.
-This group will then determine the access rights of the client,
-overriding any access groups in F<readers.conf>. If and only if a
-sucessful auth group contains the perl_access parameter, F<readers.conf>
-access groups are ignored and the client's rights are instead determined
-dynamically. This parameter is only valid if INN is compiled with Perl
-support (B<--with-perl> passed to configure). More information may be
-found in the file F<doc/hook-perl>.
-
-=item B<python_access:>
-
-A Python script for dynamically generating an access group. If
-an auth group matches successfully and contains a I<python_access> parameter,
-then the argument script (without its C<.py> extension) will be used to
-create an access group. This group will then determine the access rights
-of the client, overriding any access groups in F<readers.conf>. If and only
-if a successful auth group contains the I<python_access> parameter, F<readers.conf>
-access groups are ignored and the client's rights are instead determined
-dynamically. This parameter is only valid if INN is compiled with Python
-support (B<--with-python> passed to B<configure>). More information may be
-found in the file F<doc/hook-python>.
-
-=item B<python_dynamic:>
-
-A Python script for applying access control dynamically on a per newsgroup
-basis. If an auth group matches successfully and contains a
-I<python_dynamic> parameter, then the argument script (without its
-C<.py> extension) will be used to determine the clients rights each time
-the user attempts to view a newsgroup, or read or post an article. Access
-rights as determined by I<python_dynamic> override the values of access
-group parameters such as I<newsgroups>, I<read> and I<post>. This parameter
-is only valid if INN is compiled with Python support (B<--with-python>
-passed to B<configure>). More information may be found in the file
-F<doc/hook-python>.
-
-=back
-
-=head1 ACCESS GROUP PARAMETERS
-
-=over 4
-
-=item B<users:>
-
-The privileges given by this access group apply to any user identity which
-matches this comma-separated list of wildmat patterns. If this parameter
-isn't given, the access group applies to all users (and is essentially
-equivalent to C<users: *>).
-
-=item B<newsgroups:>
-
-Users that match this access group are allowed to read and post to all
-newsgroups matching this comma-separated list of wildmat patterns. The
-empty string is equivalent to C<newsgroups: *>; if this parameter is
-missing, the connection will be rejected (unless read: and/or post: are
-used instead, see below).
-
-=item B<read:>
-
-Like the newsgroups: parameter, but the client is only given permission to
-read the matching newsgroups. This parameter is often used with post:
-(below) to specify some read-only groups; it cannot be used in the same
-access group with a newsgroups: parameter. (If read: is used and post:
-is missing, the client will have only read-only access.)
-
-=item B<post:>
-
-Like the newsgroups: parameter, but the client is only given permission to
-post to the matching newsgroups. This parameter is often used with read:
-(above) to define the patterns for reading and posting separately (usually
-to give the user permission to read more newsgroups than they're permitted
-to post to). It cannot be used in the same access group with a
-newsgroups: parameter.
-
-=item B<access:>
-
-A set of letters specifying the permissions granted to the client. The
-letters are chosen from the following set:
-
-=over 3
-
-=item R
-
-The client may read articles.
-
-=item P
-
-The client may post articles.
-
-=item I
-
-The client may inject articles with IHAVE. Note that in order to
-inject articles with the IHAVE the user must also have POST permission
-(the C<P> option).
-
-=item A
-
-The client may post articles with Approved: headers (in other words, may
-approve articles for moderated newsgroups). By default, this is not
-allowed.
-
-=item N
-
-The client may use the NEWNEWS command, overriding the global setting.
-
-=item L
-
-The client may post to newsgroups that are set to disallow local posting
-(mode C<n> in the active(5) file).
-
-=back
-
-Note that if this parameter is given, I<allownewnews> in F<inn.conf> is
-ignored for connections matching this access group and the ability of the
-client to use NEWNEWS is entirely determined by the presence of C<N> in
-the access string. If you want to support NEWNEWS, make sure to include
-C<N> in the access string when you use this parameter.
-
-Note that if this parameter is given and C<R> isn't present in the access
-string, the client cannot read regardless of newsgroups: or read:
-parameters. Similarly, if this parameter is given and C<P> isn't present,
-the client cannot post. This use of access: is deprecated and confusing;
-it's strongly recommended that if the access: parameter is used, C<R> and
-C<P> always be included in the access string and newsgroups:, read:, and
-post: be used to control access. (To grant read access but no posting
-access, one can have just a read: parameter and no post: parameter.)
-
-=item B<key:>
-
-If this parameter is present, this access group is only considered when
-finding privileges for users matching auth groups with this same key:
-parameter.
-
-=item B<reject_with:>
-
-If this parameter is present, a client matching this block will be
-disconnected with a "Permission denied" message containing the contents
-(a "reason" string) of this parameter. Some newsreaders will then
-display the reason to the user.
-
-=item B<max_rate:>
-
-If this parameter is present (and nonzero), it is used for B<nnrpd>'s
-rate-limiting code. The client will only be able to download at this
-speed (in bytes/second). Note that if SSL is being used, limiting
-is applied to the pre-encryption datastream.
-
-=item B<localtime:>
-
-If a Date: header is not included in a posted article, nnrpd(8) normally
-adds a new Date: header in UTC. If this is set to true, the Date: header
-will be formatted in local time instead. This is a boolean value and the
-default is false.
-
-=item B<newsmaster:>
-
-Used as the contact address in the help message returned by nnrpd(8), if
-the virtualhost: parameter is set to true.
-
-=item B<strippath:>
-
-If set to true, any Path: header provided by a user in a post is stripped
-rather than used as the beginning of the Path: header of the article.
-This is a boolean value and the default is false.
-
-=item B<perlfilter:>
-
-If set to false, posts made by these users do not pass through the Perl
-filter even if it is otherwise enabled. This is a boolean value and the
-default is true.
-
-=item B<pythonfilter:>
-
-If set to false, posts made by these users do not pass through the Python
-filter even if it is otherwise enabled. This is a boolean value and the
-default is true.
-
-=item B<virtualhost:>
-
-Set this parameter to true in order to make B<nnrpd> behave as if it is
-running on a server with a different name than it actually is. If you
-set this parameter to true, you must also set either pathhost: or domain:
-in the relevant access group in F<readers.conf> to something different
-than is set in F<inn.conf>. All articles displayed to clients will then have
-their Path: and Xref: headers altered to appear to be from the server
-named in pathhost: or domain: (whichever is set), and posted articles will
-use that server name in the Path:, Message-ID:, and X-Trace: headers.
-
-Note that setting this parameter requires the server modify all posts
-before presenting them to the client and therefore may decrease
-performance slightly.
-
-=back
-
-In addition, all of the following parameters are valid in access groups
-and override the global setting in F<inn.conf>. See inn.conf(5) for the
-descriptions of these parameters:
-
- addnntppostingdate, addnntppostinghost, backoff_auth, backoff_db,
- backoff_k, backoff_postfast, backoff_postslow, backoff_trigger,
- checkincludedtext, clienttimeout, complaints, domain,
- fromhost, localmaxartsize, moderatormailer, nnrpdauthsender,
- nnrpdcheckart, nnrpdoverstats, nnrpdposthost, nnrpdpostport, organization,
- pathhost, readertrack, spoolfirst, strippostcc.
-
-=head1 SUMMARY
-
-Here's a basic summary of what happens when a client connects:
-
-=over 2
-
-=item *
-
-All auth groups are scanned and the ones that don't match the client
-(due to hosts:, localaddress:, require_ssl:, etc) are eliminated.
-
-=item *
-
-The remaining auth groups are scanned from the last to the first, and an
-attempt is made to apply it to the current connection. This means running
-res: programs, if any, and otherwise applying default:. The first auth
-group (starting from the bottom) to return a valid user is kept as the
-active auth group.
-
-=item *
-
-If no auth groups yield a valid user (none have default: parameters or
-successful res: programs) but some of the auth groups have auth: lines
-(indicating a possibility that the user can authenticate and then obtain
-permissions), the connection is considered to have no valid auth group
-(which means that the access groups are ignored completely) but the
-connection isn't closed. Instead, 480 is returned for everything until
-the user authenticates.
-
-=item *
-
-When the user authenticates, the auth groups are rescanned, and only the
-matching ones which contain at least one auth, perl_auth, or
-python_auth line are considered. These auth groups are scanned from
-the last to the first, running auth: programs and perl_auth: or
-python_auth: scripts. The first auth group (starting from the bottom)
-to return a valid user is kept as the active auth group.
-
-=item *
-
-Regardless of how an auth group is established, as soon as one is, that
-auth group is used to assign a user identity by taking the result of the
-successful res, auth, perl_auth, or python_auth line (or the
-default: if necessary), and appending the default-domain if
-necessary. (If the perl_access: or python_access: parameter is
-present, see below.)
-
-=item *
-
-Finally, an access group is selected by scanning the access groups from
-bottom up and finding the first match. (If the established auth group
-contained a perl_access: or python_access line, the dynamically
-generated access group returned by the script is used instead.)
-User permissions are granted based on the established access group.
-
-=back
-
-=head1 EXAMPLES
-
-Probably the simplest useful example of a complete F<readers.conf>,
-this gives permissions to read and post to all groups to any connections
-from the "example.com" domain, and no privileges for anyone connecting
-elsewhere:
-
- auth example.com {
- hosts: "*.example.com, example.com"
- default: <LOCAL>
- }
-
- access full {
- newsgroups: *
- }
-
-Note that the access realm has no users: key and therefore applies to any
-user identity. The only available auth realm only matches hosts in the
-"example.com" domain, though, so any connections from other hosts will be
-rejected immediately.
-
-If you have some systems that should only have read-only access to the
-server, you can modify the example above slightly by adding an additional
-auth and access group:
-
- auth lab {
- hosts: "*.lab.example.com"
- default: <LAB>
- }
-
- access lab {
- users: <LAB>
- read: *
- }
-
-If those are put in the file after the above example, they'll take
-precedence (because they're later in the file) for any user coming from a
-machine in the lab.example.com domain, everyone will only have read
-access, not posting access.
-
-Here's a similar example for a news server that accepts connections from
-anywhere but requires the user to specify a username and password. The
-username and password are first checked against an external database of
-usernames and passwords, and then against the system shadow password file:
-
- auth all {
- auth: "ckpasswd -d <pathdb in inn.conf>/newsusers"
- auth: "ckpasswd -s"
- }
-
- access full {
- users: *
- newsgroups: *
- }
-
-When the user first connects, there are no res: keys and no default, so
-they don't receive any valid identity and the connection won't match any
-access groups (even ones with C<users: *>). Such users receive nothing
-but authentication-required responses from nnrpd until they authenticate.
-
-If they then later authenticate, the username and password are checked
-first by running B<ckpasswd> with the B<-d> option for an external dbm
-file of encrypted passwords, and then with the B<-s> option to check the
-shadow password database (note that this option may require ckpasswd to
-be setgid to a shadow group, and there are security considerations; see
-ckpasswd(8) for details). If both of those fail, the user will continue
-to have no identity; otherwise, an identity will be assigned (usually
-the supplied username, perhaps with a domain appended, although an
-authenticator technically can provide a completely different username
-for the identity), and the access group will match, giving full access.
-
-It may be educational to consider how to combine the above examples;
-general groups always go first. The order of the auth groups actually
-doesn't matter, since the "hosts: example.com" one only matches
-connections before username/password is sent, and the "auth: ckpasswd"
-one only matches after; order would matter if either group applied to
-both cases. The order of the access groups in this case does matter,
-provided the newsgroups: lines differ; the access group with no users:
-line needs to be first, with the "users: <LOCAL>" group after.
-
-Here's a very complicated example. This is for an organization that has
-an internal hierarchy "example.*" only available to local shell users, who
-are on machines where identd can be trusted. Dialup users must provide a
-username and password, which is then checked against RADIUS. Remote users
-have to use a username and password that's checked against a database on
-the news server. Finally, the admin staff (users "joe" and "jane") can
-post anywhere (including the "example.admin.*" groups that are read-only
-for everyone else), and are exempted from the Perl filter. For an
-additional twist, posts from dialup users have their Sender: header
-replaced by their authenticated identity.
-
-Since this organization has some internal moderated newsgroups, the admin
-staff can also post messages with Approved: headers, but other users
-cannot.
-
- auth default {
- auth: "ckpasswd -f <pathdb in inn.conf>/newsusers"
- default: <FAIL>
- default-domain: example.com
- }
-
- auth shell {
- hosts: *.shell.example.com
- res: ident
- auth: "ckpasswd -s"
- default: <FAIL>
- default-domain: shell.example.com
- }
-
- auth dialup {
- hosts: *.dialup.example.com
- auth: radius
- default: <FAIL>
- default-domain: dialup.example.com
- }
-
- access shell {
- users: *@shell.example.com
- read: *
- post: "*, !example.admin.*"
- }
-
- access dialup {
- users: *@dialup.example.com
- newsgroups: *,!example.*
- nnrpdauthsender: true
- }
-
- access other {
- users: "*@example.com, !<FAIL>@example.com"
- newsgroups: *,!example.*
- }
-
- access fail {
- users: "<FAIL>@*"
- newsgroups: !*
- }
-
- access admin {
- users: "joe@*,jane@*"
- newsgroups: *
- access: "RPA"
- perlfilter: false
- }
-
-Note the use of different domains to separate dialup from shell users
-easily. Another way to do that would be with key: parameters, but this
-way provides slightly more intuitive identity strings. Note also that the
-fail access group catches not only failing connections from external users
-but also failed authentication of shell and dialup users and dialup users
-before they've authenticated. The identity string given for, say, dialup
-users before RADIUS authentication has been attempted matches both the
-dialup access group and the fail access group, since it's
-"<FAIL>@dialup.example.com", but the fail group is last so it takes
-precedence.
-
-The shell auth group has an auth: parameter so that users joe and jane
-can, if they choose, use username and password authentication to gain
-their special privileges even if they're logged on as a different user on
-the shell machines (or if ident isn't working). When they first connect,
-they'd have the default access for that user, but they could then send
-AUTHINFO USER and AUTHINFO PASS (or AUTHINFO SIMPLE) and get their
-extended access.
-
-Also note that if the users joe and jane are using their own accounts,
-they get their special privileges regardless of how they connect, whether
-the dialups, the shell machines, or even externally with a username and
-password.
-
-Finally, here's a very simple example of a configuration for a public
-server for a particular hierarchy.
-
- auth default {
- hosts: *
- default: <PUBLIC>
- }
-
- access default {
- users: <PUBLIC>
- newsgroups: example.*
- }
-
-Notice that clients aren't allowed to read any other groups; this keeps
-them from getting access to administrative groups or reading control
-messages, just as a precaution. When running a public server like this,
-be aware that many public hierarchies will later be pulled down and
-reinjected into the main Usenet, so it's highly recommended that you also
-run a Perl or Python filter to reject any messages crossposted out of your
-local hierarchy and any messages containing a Supersedes: header. This
-will keep messages posted to your public hierarchy from hurting any of the
-rest of Usenet if they leak out.
-
-=head1 SECURITY CONSIDERATIONS
-
-In general, separate passwords should be used for NNTP wherever
-possible; the NNTP protocol itself does not protect passwords from
-casual interception, and many implementations (including this one) do
-not "lock out" accounts or otherwise discourage password-guessing
-attacks. So it is best to ensure that a compromised password has
-minimal effects.
-
-Authentication using the AUTHINFO USER/PASS commands passes unencrypted
-over the network. Extreme caution should therefore be used especially
-with system passwords (e.g. C<auth: ckpasswd -s>). Passwords can be
-protected by using NNTP over SSL or through ssh tunnels, and this usage
-can be enforced by a well-considered server configuration that only
-permits certain auth groups to be applied in certain cases. Here are
-some ideas:
-
-=over 4
-
-=item *
-
-To restrict connections on the standard nntp port (119) to use SSL for
-some (or all) of the auth groups to match, use the require_ssl:
-parameter.
-
-=item *
-
-If you consider your local network (but not the internet) secure, have
-some auth groups with a restrictive hosts: parameter; they would go
-above, with ones having global applicability below.
-
-=item *
-
-Consider running a C<nnrpd -S> (with C<-D>, or out of "super-server"
-like B<inetd>) on the NNTPS port (563) for clients that support SSL. See
-nnrpd(8) for more details about how to configure that. You
-can use the require_ssl: parameter, or C<-c> to specify an alternate
-F<readers.conf> if you want a substantially different configuration for
-this case.
-
-=item *
-
-If you want to restrict an auth group to only match loopback connections
-(for users running newsreaders on localhost or connecting via an ssh
-tunnel), use the localaddress: parameter.
-
-=back
-
-=head1 HISTORY
-
-Written by Aidan Cully <aidan@panix.com> for InterNetNews. Substantially
-expanded by Russ Allbery <rra@stanford.edu>.
-
-$Id: readers.conf.pod 7895 2008-06-22 17:54:10Z iulius $
-
-=head1 SEE ALSO
-
-auth_krb5(8), auth_smb(8), ckpasswd(8), inn.conf(5), innd(8), newsfeeds(5),
-nnrpd(8), uwildmat(3).
-
-=cut
+++ /dev/null
-=head1 Welcome to INN 2.4!
-
-This work is sponsored by Internet Systems Consortium.
-
-Please see F<INSTALL> for installation instructions, F<NEWS> for what's
-changed from the previous release, and F<LICENSE> for the copyright,
-license, and distribution terms.
-
-=head1 What is INN?
-
-INN (InterNetNews), originally written by Rich Salz, is an extremely
-flexible and configurable Usenet / netnews news server. For a complete
-description of the protocols behind Usenet and netnews, see RFC 1036 and
-RFC 977 (or their replacements). In brief, netnews is a set of protocols
-for exchanging messages between a decentralized network of news servers.
-News articles are organized into newsgroups, which are themselves
-organized into hierarchies. Each individual news server stores locally
-all articles it has received for a given newsgroup, making access to
-stored articles extremely fast. Netnews does not require any central
-server; instead, each news server passes along articles it receives to all
-of the news servers it peers with, those servers pass the articles along
-to their peers, and so on, resulting in "flood fill" propagation of news
-articles.
-
-A news server performs three basic functions: it accepts articles from
-other servers and stores them on disk, sends articles it has received out
-to other servers, and offers stored news articles to readers on demand.
-It additionally has to perform some periodic maintenance tasks, such as
-deleting older articles to make room for new ones.
-
-Originally, a news server would just store all of the news articles it had
-received in a file system. Users could then read news by reading the
-article files on disk (or more commonly using news reading software that
-did this efficiently). These days, news servers are almost always
-stand-alone systems and news reading is supported via network connections.
-A user who wants to read a newsgroup opens that newsgroup in their
-newsreader software, which opens a network connection to the news server
-and sends requests for articles and related information. The protocol
-that a newsreader uses to talk to a news server and that a news server
-uses to talk to another news server over TCP/IP is called NNTP (Network
-News Transport Protocol).
-
-INN supports accepting articles via either NNTP connections or via UUCP.
-B<innd>, the heart of INN, handles NNTP feeding connections directly;
-UUCP newsfeeds use B<rnews> (included in INN) to hand articles off to
-innd. Other parts of INN handle feeding articles out to other news
-servers, most commonly B<innfeed> (for real-time outgoing feeds) or
-B<nntpsend> and B<innxmit> (used to send batches of news created by innd
-to a remote site via TCP/IP). INN can also handle outgoing UUCP feeds.
-
-The part of INN that handles connections from newsreaders is nnrpd.
-
-Also included in INN are a wide variety of supporting programs to handle
-periodic maintenance and recovery from crashes, process special control
-messages, maintain the list of active newsgroups, and generate and record
-a staggering variety of statistics and summary information on the usage
-and performance of the server.
-
-INN also supports an extremely powerful filtering system that allows the
-server administrator to reject unwanted articles (such as spam and other
-abuses of Usenet).
-
-INN is free software, supported by Internet Systems Consortium and
-volunteers around the world. See L<"Supporting the INN Effort"> below.
-
-=head1 Prerequisites
-
-Compiling INN requires an ANSI C compiler (gcc is recommended). INN was
-originally written in K&R C, but supporting pre-ANSI compilers has become
-enough of a headache that a lot of the newer parts of INN will no longer
-compile with a non-ANSI compiler. gcc itself will compile with most
-vendor non-ANSI compilers, however, so if you're stuck with one,
-installing gcc is highly recommended. Not only will it let you build INN,
-it will make installing lots of other software much easier. You may also
-need GNU make (particularly if your system make is BSD-derived), although
-most SysV make programs should work fine. Compiling INN also currently
-requires a yacc implementation (bison will do fine).
-
-INN uses GNU autoconf to probe the capabilities of your system, and
-therefore should compile on nearly any Unix system. It does, however,
-make extensive use of mmap(), which can cause problems on some older
-operating systems. See F<INSTALL> for a list of systems it is known to
-work on. If you encounter problems compiling or running INN, or if you
-successfully run INN on a platform that isn't listed in F<INSTALL>, please
-let us know (see L<"Reporting Bugs"> below).
-
-Perl 5.003 or later is required to build INN. Perl 5.004 is required if
-you want the embedded Perl filter support (which is highly recommended;
-some excellent spam filters have been written for INN). Since all
-versions of Perl previous to 5.004 are buggy (including security problems)
-and have fewer features, installing Perl 5.004 or later is recommended.
-
-If you want to enable PGP verification of control messages (highly
-recommended), you will need to have a PGP implementation installed. See
-F<INSTALL> for more details.
-
-=head1 Getting Started
-
-A news server can be a fairly complicated piece of software to set up just
-because of the wide variety of pieces that have to be configured (who is
-authorized to read from the server, what newsgroups it carries, and how
-the articles are stored on disk at a bare minimum, and if the server isn't
-completely stand-alone -- and very few servers are -- both incoming and
-outgoing feeds have to be set up and tested). Be prepared to take some
-time to understand what's going on and how all the pieces fit together.
-If you have any specific suggestions for documentation, or comments about
-things that are unclear, please send them to the INN maintainers (see
-L<"Reporting Bugs"> below).
-
-See F<INSTALL> for step-by-step instructions for setting up and
-configuring a news server.
-
-INN also comes with a very complete set of man pages; there is a man page
-for every configuration file and program that comes with INN. (If you
-find one that doesn't have a man page, that's a bug. Please do report
-it.) When trying to figure out some specific problem, reading the man
-pages for all of the configuration files involved is a very good start.
-
-=head1 Reporting Bugs
-
-We're interested in all bug reports. Not just on the programs, but on the
-documentation too. Please send I<all> such reports to
-
- inn-bugs@isc.org
-
-(patches are certainly welcome, see below). Even if you post to Usenet,
-please CC the above address. All other INN mail should go to
-
- inn@isc.org
-
-(please do I<not> send bug reports to this address).
-
-If you have general "how do I do this" questions or problems configuring
-your server that you don't believe are due to a bug in INN, you should
-post them to news.software.nntp. A lot of experienced INN users,
-including several of the INN maintainers, read that newsgroup regularly.
-Please don't send general questions to the above addresses; those
-addresses are specifically for INN, and the INN maintainers usually won't
-have time to answer general questions.
-
-=head1 Contributing Code
-
-If you have a patch or a utility that you'd like to be considered for
-inclusion into INN, please mail it to
-
- inn-patches@isc.org
-
-in the body of the message (not as an attachment), or put it on a
-webpage and send a link. Patches included with a bug report as
-described above should follow the same procedure, but need not be sent
-to both addresses (either will do).
-
-Have fun!
-
-=head1 Mailing Lists
-
-There are various INN-related mailing lists you can join or send messages
-to if you like. Some of them you must be a member of before you can send
-mail to them (thank the spammers for that policy), and one of them is
-read-only (no postings allowed).
-
-=over 24
-
-=item inn-announce@isc.org
-
-Where announcements about INN are set (only maintainers may post).
-
-=item inn-workers@isc.org
-
-Discussion of INN development (postings by members only).
-
-=item inn-patches@isc.org
-
-Where to send patches for consideration for inclusion into INN (open
-posting).
-
-=item inn-committers@isc.org
-
-CVS commit messages for INN are sent to this list (only the automated
-messages are sent here, no regular posting).
-
-=item inn-bugs@isc.org
-
-Where to send bug reports (open posting). If you're an INN expert and
-have the time to help out other users, we encourage you to join this
-mailing list to answer questions. (You may also want to read the
-newsgroup news.software.nntp, which gets a lot of INN-related questions.)
-
-=back
-
-To join these lists, send a subscription request to the C<-request>
-address. The addresses for the above lists are:
-
- inn-announce-request@isc.org
- inn-workers-request@isc.org
- inn-patches-request@isc.org
- inn-committers-request@isc.org
- inn-bugs-request@isc.org
-
-=head1 Who's Responsible / Who to Thank
-
-See F<CONTRIBUTORS> for a long list of past contributors as well as people
-from the inn-workers mailing list who have dedicated a lot of time and
-effort to getting this new version together. They deserve a big round of
-applause. They've certainly got our thanks.
-
-This product includes software developed by UUNET Technologies, Inc. and
-by the University of California, Berkeley and its contributors.
-
-Last, but certainly not least, Rich Salz, the original author of INN
-deserves a lion's share of the credit for writing INN in the first place
-and making it the most popular news server software on the planet (no NNTP
-yet to the moon, but we plan to be there first).
-
-=head1 Related Packages
-
-INN users may also be interested in the following software packages that
-work with INN or are based on it. Please note that none of this software
-is developed or maintained by ISC; we don't support it and generally can't
-answer questions about it.
-
-=over 4
-
-=item CleanFeed
-
-URL: <http://www.bofh.it/~md/cleanfeed/>
-
-CleanFeed is an extremely powerful spam filter, probably the most widely
-used spam filter on Usenet currently. It catches excessive multiposting
-and a host of other things, and is highly configurable. Note that it
-requires that INN be built with Perl support (the B<--with-perl> option to
-configure).
-
-=item GUP (Group Update Program)
-
-URL: <ftp://ftp.debian.org/debian/pool/main/g/gup/>
-
-GUP provides a way for your peers to update their newsfeeds entries as
-they want without having to ask you to edit the configuration file all the
-time. It's useful when feeding peers who take limited and very specific
-feeds that change periodically.
-
-=item inflow
-
-URL: <http://www.switch.ch/netnews/wg/netnews-wg.html>
-
-inflow generates graphs of news flow statistics in real time from INN's
-logs (things like articles accepted per peer, volume accepted per peer,
-and the like).
-
-=item News-Portal
-
-URL: <http://floh.gartenhaus.net/newsportal/>
-
-A PHP-based web news reader that works as a front-end to a regular news
-server such as INN and lets people read and post without learning a news
-reader.
-
-=item PersonalINN
-
-URL: <http://www.ritual.org/summer/pinn/>
-
-PersonalINN is a version of INN modified for personal use and with a
-friendly GUI built on top of it. It is available for NeXTSTEP or OPENSTEP
-only, unfortunately.
-
-=item suck
-
-URL: <http://home.comcast.net/~bobyetman/index.html>
-
-suck is a separate package for downloading a news feed via a reading
-connection (rather than via a direct NNTP or UUCP feed) and sending
-outgoing local posts via POST. It's intended primarily for personal or
-small-organization news servers who get their news via an ISP and are too
-small to warrant setting up a regular news feed.
-
-=item newsx
-
-URL: <http://www.kvaleberg.com/newsx.html>
-
-Serving the same purpose as suck, newsx is a separate package for
-downloading a news feed via a reading connectino and sending outgoing
-local posts via POST. Some people find suck easier to configure and use,
-and some people find newsx easier. If you have problems with one, try the
-other.
-
-=back
-
-=head1 Supporting the INN Effort
-
-Note that INN is supported by Internet Systems Consortium, and although it
-is free for use and redistribution and incorporation into vendor products
-and export and anything else you can think of, it costs money to produce.
-That money comes from ISPs, hardware and software vendors, companies who
-make extensive use of the software, and generally kind-hearted folk such
-as yourself.
-
-Internet Systems Consortium has also commissioned a DHCP server
-implementation and handles the official support/release of BIND. You can
-learn more about the ISC's goals and accomplishments from the web page at
-<http://www.isc.org/>.
-
- Russ Allbery
- Katsuhiro Kondou
- <inn@isc.org>
+++ /dev/null
-=head1 NAME
-
-sasl.conf - SASL Configuration file for nnrpd.
-
-=head1 DESCRIPTION
-
-The file F<sasl.conf> in I<pathetc> specifies Simple Authentication
-and Security Layer (SASL), defined in RFC 2222, for nnrpd.
-Now nnrpd implements only Security Layer support, which is an extension
-of RFC 2595. This means you can get SSL or TLS encrypted NNRP between
-your server and newsreaders. It requires OpenSSL 0.9.3 or newer from
-http://www.openssl.org/; it has been tested with versions 0.9.4 and 0.9.5.
-
-=head1 INSTALLATION
-
-To use SSL, a certificate and private key are needed that you can
-create using the openssl binary.
-Make certain that each keys are owned by your news user, news group,
-and are mode 0640 or 0660.
-
-=head2 EXAMPLE
-
- openssl req -new -x509 -nodes -out /usr/local/news/lib/cert.pem\
- -days 366 -keyout /usr/local/news/lib/cert.pem
- chown news:news /usr/local/news/lib/cert.pem
- chmod 640 /usr/local/news/lib/cert.pem
-
-You also can make the keys as the root user with C<make cert>.
-
-=head1 CONFIGURATION
-
-Comments begin with a number sign (C<#>) and continue through the
-end of the line. Blank lines and comments are ignored.
-All other lines specify parameters, and should be of the form
-
- <option>: <value>
-
-where <option> is the name of the configuration option being set and
-<value> is the value that the configuration option is being set to.
-
-Blank lines and lines beginning with (C<#>) are ignored.
-For boolean options, the values C<yes>, C<on>, C<t>,
-and C<1> turn the option on; the values C<no>, C<off>,
-C<f>, and C<0> turn the option off.
-
-=over 4
-
-=item tls_cert_file
-
-The path to a file containing the server's certificate.
-
-=item tls_key_file
-
-The path to a file containing the server's private key.
-
-=item tls_ca_path
-
-The path to a directory containing the CA's certificate.
-
-=item tls_ca_file
-
-The path to a file containing the CA's certificate.
-
-=back
-
-=head1 TO DO
-
-Implement methods of the authentication protocols of SASL.
-
-=head1 HISTORY
-
-Written by Kenichi OKADA E<lt>okada@opaopa.orgE<gt> for InterNetNews.
-
-=head1 SEE ALSO
-
-inn.conf(5), innd(8), nnrpd(8), readers.conf(5)
-
-=cut
+++ /dev/null
-=head1 NAME
-
-sendinpaths - Send Usenet Path statistics via e-mail
-
-=head1 SYNOPSIS
-
-B<sendinpaths> [B<-n>]
-
-=head1 DESCRIPTION
-
-B<sendinpaths> checks I<pathlog>/path for B<ninpaths> dump files, finds
-dump files generated in the past 30 days, makes sure they are valid by
-running B<ninpaths> on each one and making sure the exit status is zero,
-and passes them to B<ninpaths> to generate a cumulative report. That
-report is mailed to the e-mail addresses configured at the beginning of
-this script (by default "pathsurvey@top1000.org" and
-"top1000@anthologeek.net").
-
-When finished, B<sendinpaths> deletes all dump files in I<pathlog>/path
-that are older than 14 days (configurable at the beginning of the script).
-
-For more information on how to set up B<ninpaths>, see ninpaths(8).
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-n>
-
-Don't e-mail the report; instead, just print it to standard output. Don't
-delete old dump files.
-
-=back
-
-=head1 SEE ALSO
-
-ninpaths(8)
-
-=head1 HISTORY
-
-B<sendinpaths> was written by Olaf Titz <olaf@bigred.inka.de>.
-
-=cut
+++ /dev/null
-=head1 NAME
-
-simpleftp - Rudimentary FTP client
-
-=head1 SYNOPSIS
-
-B<simpleftp> I<url> [...]
-
-=head1 DESCRIPTION
-
-B<simpleftp> is a Perl script that provides basic support for
-fetching files with FTP in a batch oriented fashion. It takes one or more
-FTP URLs on the command line. The file(s) will be retrieved from the
-remote server and placed in the current directory with the same basename
-as on the remote; e.g., L<ftp://ftp.isc.org/pub/usenet/CONFIG/active.gz>
-is stored as F<active.gz> in the current directory.
-
-The script properly understands usernames, passwords and ports specified
-as follows:
-
- ftp://user:password@host:port/path/file
-
-=head1 BUGS
-
-B<simpleftp> is an extremely poor substitute for more complete programs
-like the freely available B<wget> or B<ncftp> utilities. It was written
-only to provide elementary support in INN for non-interactive fetching of
-the files in L<ftp://ftp.isc.org/pub/pgpcontrol/> or
-L<ftp://ftp.isc.org/pub/usenet/CONFIG/> without requiring
-administrators to install yet another package. Its shortcomings as a
-general purpose program are too numerous to mention, but one that stands
-out is that downloaded files by B<simpleftp> override existing files
-with the same name in the local directory.
-
-=head1 HISTORY
-
-Tossed off by David C Lawrence <tale@isc.org> for InterNetNews.
-Rewritten to use Net::FTP by Julien Elie <julien@trigofacile.com>.
-
-$Id: simpleftp.pod 7739 2008-04-06 09:38:31Z iulius $
-
-=head1 SEE ALSO
-
-actsync(8).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-sm - Command-line interface to the INN storage manager
-
-=head1 SYNOPSIS
-
-B<sm> [B<-dHiqRrS>] [I<token> ...]
-
-=head1 DESCRIPTION
-
-The INN storage manager is the subsystesm that stores and keeps track of
-all of the articles and what storage backend they're in. All stored
-articles are assigned a storage API token. B<sm> is a command-line
-interface to that storage manager, primarily used to retrieve articles by
-those tokens but also to perform other operations on the storage
-subsystem.
-
-I<token> is the token of an article (the same thing that's returned by
-B<grephistory> or stored in the history file). It looks something like:
-
- @0502000005A4000000010000000000000000@
-
-Any number of tokens can be given on the command line. If none are, B<sm>
-reads tokens from standard input, one per line. The default operation is
-to retrieve and write to standard output the corresponding article for
-each token given.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-d>, B<-r>
-
-Rather than retrieving the specified article, remove the article. This
-will delete the article out of the news spool and it will not subsequently
-be retrievable by any part of INN. It's equivalent to C<ctlinnd cancel>
-except it takes a storage API token instead of a message ID.
-
-=item B<-H>
-
-Retrieve only the header of the article rather than the entire article.
-This option cannot be used with B<-d>, B<-r>, B<-i>, or B<-S>.
-
-=item B<-i>
-
-Show the newsgroup name and article number associated with the token
-rather than the article itself. Note that for crossposted articles, only
-the first newsgroup and article number to which the article is associated
-will be returned.
-
-=item B<-q>
-
-Suppress all error messages except usage errors.
-
-=item B<-R>
-
-Display the raw article. This means that line endings won't be converted
-to native line endings and will be left as CRLF sequences, leading periods
-will still be escaped for sending over NNTP, and the article will end in
-a CRLF.CRLF sequence.
-
-=item B<-S>
-
-Write the article to standard output in the format used by rnews spool
-files. Multiple articles can be written in this format, and the resulting
-output can be fed to rnews (on another system, for example) to inject
-those articles into INN. This option cannot be used with B<-d>, B<-r>,
-B<-H>, B<-i>, or B<-R>.
-
-=back
-
-=head1 EXIT STATUS
-
-If all operations were successful, B<sm> exits with status 0. If an
-operation on any of the provided tokens fails, B<sm> will exit with status
-1, even if the operations on other tokens were successful. In other
-words, if twenty tokens are fed to C<sm -r> on stdin, 19 articles were
-successfully removed, but the sixth article couldn't be found, B<sm> will
-still exit with status 1.
-
-This means that if you need to be sure whether a particular operation
-succeeded, you should run sm on one token at a time.
-
-=head1 HISTORY
-
-Written by Katsuhiro Kondou <kondou@nec.co.jp> for InterNetNews.
-Rewritten in POD by Russ Allbery <rra@stanford.edu>.
-
-$Id: sm.pod 6683 2004-03-06 18:31:58Z rra $
-
-=head1 SEE ALSO
-
-ctlinnd(8), grephistory(1), history(5), rnews(1), storage.conf(5).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-subscriptions - Default recommended subscriptions
-
-=head1 DESCRIPTION
-
-The I<pathetc>/F<subscriptions> file contains a list of newsgroups that is
-returned by the NNTP command LIST SUBSCRIPTIONS.
-
-Clients that support this command and send it the first time they connect
-to a new news server use the returned list to initialize the list of
-subscribed newsgroups. The F<subscriptions> file therefore should contain
-groups intented for new users, for testing, or that contain FAQs and other
-useful information for first-time Usenet users.
-
-The syntax of the F<subscriptions> file is trivial; it is a simple list of
-newsgroup names, one per line. The order of newsgroups may be
-significant; the news reading client may present the groups in that order
-to the user.
-
-=head1 EXAMPLE
-
-A typical F<subscriptions> file may look like:
-
- news.announce.newusers
- news.newusers.questions
- local.test
- local.general
- local.talk
- misc.test
- misc.test.moderated
- news.answers
- news.announce.newgroups
-
-This gives the client the FAQs and question newsgroup for new users first,
-then a local newsgroup for testing and various commonly-read local
-discussion groups, followed by the world-wide test groups, all the FAQs,
-and announcements of new world-wide newsgroups. If there is a local new
-users group, one might want to list it first.
-
-=head1 HISTORY
-
-Written by Bettina Fink <laura@hydrophil.de> for InterNetNews.
-
-=head1 SEE ALSO
-
-nnrpd(8).
-
-=cut
+++ /dev/null
-=head1 NAME
-
-tdx-util - Tradindexed overview manipulation utility
-
-=head1 SYNOPSIS
-
-B<tdx-util> [B<-AFgio>] [B<-a> I<article>] [B<-n> I<newsgroup>]
-[B<-p> I<path>] [B<-R> I<path>]
-
-=head1 DESCRIPTION
-
-B<tdx-util> is an administrative interface to the tradindexed overview
-method for INN. It only works on tradindexed overview databases, not on
-any other type of INN overview. It allows the administrator to dump
-various information about the internal state of the overview, audit it for
-errors, and rebuild portions of the overview database.
-
-The tradindexed overview method should lock properly and therefore it
-should be safe to run this utility and perform any operation it performs,
-including full repairs or per-group overview rebuilds, while the server is
-running. However, note that some of the operations performed by this
-utility can take an extended period of time and will hold locks in the
-overview database during that period, which depending on what the server
-is doing may cause the server to stall until B<tdx-util> completes its
-operation.
-
-The dump operations are B<-i>, which dumps the master index for the
-overview database, B<-g>, which dumps the index for an individual group,
-and B<-o>, which dumps the overview information for a particular group
-(including the additional metadata stored in the index). For B<-g> and
-B<-o>, the B<-n> option must also be given to specify a newsgroup to
-operate on.
-
-To audit the entire overview database for problems, use B<-A>. Any
-problems found will be reported to standard error. There is not (yet) a
-corresponding option to correct the errors found.
-
-To rebuild the database for a particular newsgroup, use B<-R>. The B<-R>
-option takes a path to a directory which contains all of the articles for
-that newsgroup, one per file. The names of the files must be the numbers
-of the articles in that group. (In other words, this directory must be a
-traditional spool directory for that group.) The B<-n> option must also
-be given to specify the newsgroup for which the overview is being rebuilt.
-
-For all operations performed by B<tdx-util>, a different overview database
-than the one specified in F<inn.conf> may be specified using the B<-p>
-option.
-
-=head1 OPTIONS
-
-=over 4
-
-=item B<-A>
-
-Audit the entire overview database for problems. This runs the internal
-consistency checks built into the tradindexed overview implementation,
-checking such things as the validity and reachability of all group index
-entries, the format of the individual overview entries, the correspondance
-of index entries to overview data, and similar such things. No changes
-will be made to the database, but problems will be reported to standard
-error.
-
-=item B<-a> I<article>
-
-The article number to act on. Only useful in combination with the B<-o>
-option to dump overview information.
-
-=item B<-F>
-
-Audit the entire overview database for problems, fixing them as they're
-detected where possible. This runs the internal consistency checks built
-into the tradindexed overview implementation, checking such things as the
-validity and reachability of all group index entries, the format of the
-individual overview entries, the correspondance of index entries to
-overview data, and similar such things. The strategy used when fixing
-problems is to throw away data that's unrecoverable, so be warned that
-using this option may result in inaccessible articles if their overview
-data has been corrupted.
-
-To see what would be changed by B<-F>, run B<tdx-util> with B<-A> first.
-
-=item B<-g>
-
-Dump the master index of the overview database. This contains similar
-information to the server active file, such as high and low water marks
-and moderation status, and is the information that nnrpd hands out to
-clients.
-
-The fields are, in order, the newsgroup name, the high water mark, the low
-water mark, the base article number (the point at which the group index
-begins), the count of articles in the group, the group status flag, the
-time (in seconds since epoch) when that newsgroup was deleted or 0 if it
-hasn't been, and the inode of the index file for that group.
-
-=item B<-i>
-
-Dump the index of a particular group. The fields are, in order, the
-article number, the offset of the data for that article in the overview
-data file for that group, the length of the overview data, the time (in
-seconds since epoch) when the article arrived on the server, the time (in
-seconds since epoch) when the article should expire based on its Expires
-header (or 0 if there is no Expires header), and the storage API token of
-the article.
-
-If this option is given, the B<-n> option must also be given to specify
-the newsgroup on which to act.
-
-=item B<-n> I<newsgroup>
-
-Specify the newsgroup on which to act, required for the B<-i>, B<-o>, and
-B<-R> options.
-
-=item B<-o>
-
-Dump the overview information for a newsgroup, in the same format as it
-would be returned to clients but with one modification. Appended to the
-end of each entry will be four additional pieces of data: the article
-number according to the index file for that group, the storage API token
-for that article, the arrival date for that article on the server in RFC
-822 date format, and the expiration date for that article (from the
-Expires header) in RFC 822 date format if there is any.
-
-If this option is given, the B<-n> option must also be given to specify
-the newsgroup on which to act. By default, all of the overview
-information for that newsgroup is dumped, but the B<-a> option may be
-given to restrict the dump to the information for a single article.
-
-=item B<-p> I<path>
-
-Act on the overview database rooted in I<path>, overriding the overview
-path specified in F<inn.conf>.
-
-=item B<-R> I<path>
-
-Rebuild the overview for a given group from the articles stored in
-I<path>. The articles must be in the form of a traditional spool
-directory; in other words, each article must be in a separate file and the
-name of the file must match the article number of the article.
-
-If this option is given, the B<-n> option must also be given to specify
-the newsgroup on which to act.
-
-=back
-
-=head1 EXAMPLES
-
-Dump the master index for the overview database in F</news/overview>,
-regardless of the overview path specified in F<inn.conf>:
-
- tdx-util -i -p /news/overview
-
-Dump the group index for example.test:
-
- tdx-util -g -n example.test
-
-Dump the complete overview information for example.test:
-
- tdx-util -o -n example.test
-
-Audit the entire overview database for any problems:
-
- tdx-util -A
-
-Rebuild the overview information for example.test from a traditional spool
-directory:
-
- tdx-util -R /news/spool/articles/example/test -n example.test
-
-The last command may be useful for recovering from a bad crash or
-corrupted overview information for a particular group, if you are also
-using the tradspool article storage method.
-
-=head1 HISTORY
-
-Written by Russ Allbery <rra@stanford.edu> for InterNetNews.
-
-$Id: tdx-util.pod 7047 2004-12-19 19:41:49Z rra $
-
-=head1 SEE ALSO
-
-makehistory(8)
-
-=cut
-
+++ /dev/null
-=head1 NAME
-
-tst - ternary search trie functions
-
-=head1 SYNOPSIS
-
-B<#include E<lt>inn/tst.hE<gt>>
-
-B<struct tst;>
-
-B<struct tst *tst_init(int >I<node_line_width>B<);>
-
-B<void tst_cleanup(struct tst *>I<tst>B<);>
-
-B<int tst_insert(struct tst *>I<tst>B<, const unsigned char *>I<key>B<, void *>I<data>B<, int >I<option>B<, void **>I<exist_ptr>B<);>
-
-B<void *tst_search(struct tst *>I<tst>B<, const unsigned char *>I<key>B<);>
-
-B<void *tst_delete(struct tst *>I<tst>B<, const unsigned char *>I<key>B<);>
-
-=head1 DESCRIPTION
-
-B<tst_init> allocates memory for members of I<struct tst>, and
-allocates the first I<node_line_width> nodes. A NULL pointer is
-returned by B<tst_init> if any part of the memory allocation fails. On
-success, a pointer to a I<struct tst> is returned.
-
-The value for I<node_line_width> must be chosen very carefully. One
-node is required for every character in the tree. If you choose a
-value that is too small, your application will spend too much time
-calling malloc(3) and your node space will be too spread out. Too large
-a value is just a waste of space.
-
-B<tst_cleanup> frees all memory allocated to nodes, internal structures,
-as well as I<tst> itself.
-
-B<tst_insert> inserts the string I<key> into the tree. Behavior when a
-duplicate key is inserted is controlled by I<option>. If I<key> is
-already in the tree then B<TST_DUPLICATE_KEY> is returned, and the
-data pointer for the existing key is placed in I<exist_ptr>. If
-I<option> is set to B<TST_REPLACE> then the existing data pointer for
-the existing key is replaced by I<data>. Note that the old data
-pointer will still be placed in I<exist_ptr>.
-
-If a duplicate key is encountered and I<option> is not set to
-B<TST_REPLACE> then B<TST_DUPLICATE_KEY> is returned. If I<key> is
-zero length then B<TST_NULL_KEY> is returned. A successful insert or
-replace returns B<TST_OK>. A return value of B<TST_ERROR> indicates
-that a memory allocation error occurred while trying to grow the node
-free.
-
-Note that the I<data> argument must never be B<NULL>. If it is, then
-calls to B<tst_search> will fail for a key that exists because the
-data value was set to B<NULL>, which is what B<tst_search> returns. If
-you just want a simple existence tree, use the B<tst> pointer as the
-data pointer.
-
-B<tst_search> finds the string I<key> in the tree if it exists and
-returns the data pointer associated with that key.
-
-If I<key> is not found then B<NULL> is returned, otherwise the data pointer
-associated with I<key> is returned.
-
-B<tst_delete> deletes the string I<key> from the tree if it exists and
-returns the data pointer assocaited with that key.
-
-If I<key> is not found then B<NULL> is returned, otherwise the data
-pointer associated with I<key> is returned.
-
-=head1 HISTORY
-
-Converted to POD from Peter A. Friend's ternary search trie
-documentation by Alex Kiernan <alex.kiernan@thus.net> for InterNetNews
-2.4.0.
-
-$Id: tst.pod 6104 2003-01-02 09:16:09Z alexk $
+++ /dev/null
-=head1 NAME
-
-uwildmat, uwildmat_simple, uwildmat_poison - Perform wildmat matching
-
-=head1 SYNOPSIS
-
-B<#include E<lt>libinn.hE<gt>>
-
-B<bool uwildmat(const char *>I<text>B<, const char *>I<pattern>B<);>
-
-B<bool uwildmat_simple(const char *>I<text>B<, const char *>I<pattern>B<);>
-
-B<enum uwildmat uwildmat_poison(const char *>I<text>B<,
-const char *>I<pattern>B<);>
-
-=head1 DESCRIPTION
-
-B<uwildmat> compares I<text> against the wildmat expression I<pattern>,
-returning true if and only if the expression matches the text. C<@> has
-no special meaning in I<pattern> when passed to B<uwildmat>. Both I<text>
-and I<pattern> are assumed to be in the UTF-8 character encoding, although
-malformed UTF-8 sequences are treated in a way that attempts to be mostly
-compatible with single-octet character sets like ISO 8859-1. (In other
-words, if you try to match ISO 8859-1 text with these routines everything
-should work as expected unless the ISO 8859-1 text contains valid UTF-8
-sequences, which thankfully is somewhat rare.)
-
-B<uwildmat_simple> is identical to B<uwildmat> except that neither C<!>
-nor C<,> have any special meaning and I<pattern> is always treated as a
-single pattern. This function exists solely to support legacy interfaces
-like NNTP's XPAT command, and should be avoided when implementing new
-features.
-
-B<uwildmat_poison> works similarly to B<uwildmat>, except that C<@> as the
-first character of one of the patterns in the expression (see below)
-"poisons" the match if it matches. B<uwildmat_poison> returns
-B<UWILDMAT_MATCH> if the expression matches the text, B<UWILDMAT_FAIL> if
-it doesn't, and B<UWILDMAT_POISON> if the expression doesn't match because
-a poisoned pattern matched the text. These enumeration constants are
-defined in the B<libinn.h> header.
-
-=head1 WILDMAT EXPRESSIONS
-
-A wildmat expression follows rules similar to those of shell filename
-wildcards but with some additions and changes. A wildmat I<expression> is
-composed of one or more wildmat I<patterns> separated by commas. Each
-character in the wildmat pattern matches a literal occurance of that same
-character in the text, with the exception of the following metacharacters:
-
-=over 8
-
-=item ?
-
-Matches any single character (including a single UTF-8 multibyte
-character, so C<?> can match more than one byte).
-
-=item *Z<>
-
-Matches any sequence of zero or more characters.
-
-=item \
-
-Turns off any special meaning of the following character; the following
-character will match itself in the text. C<\> will escape any character,
-including another backslash or a comma that otherwise would separate a
-pattern from the next pattern in an expression. Note that C<\> is not
-special inside a character range (no metacharacters are).
-
-=item [...]
-
-A character set, which matches any single character that falls within that
-set. The presence of a character between the brackets adds that character
-to the set; for example, C<[amv]> specifies the set containing the
-characters C<a>, C<m>, and C<v>. A range of characters may be specified
-using C<->; for example, C<[0-5abc]> is equivalent to C<[012345abc]>. The
-order of characters is as defined in the UTF-8 character set, and if the
-start character of such a range falls after the ending character of the
-range in that ranking the results of attempting a match with that pattern
-are undefined.
-
-In order to include a literal C<]> character in the set, it must be the
-first character of the set (possibly following C<^>); for example, C<[]a]>
-matches either C<]> or C<a>. To include a literal C<-> character in the
-set, it must be either the first or the last character of the set.
-Backslashes have no special meaning inside a character set, nor do any
-other of the wildmat metacharacters.
-
-=item [^...]
-
-A negated character set. Follows the same rules as a character set above,
-but matches any character B<not> contained in the set. So, for example,
-C<[^]-]> matches any character except C<]> and C<->.
-
-=back
-
-In addition, C<!> (and possibly C<@>) have special meaning as the first
-character of a pattern; see below.
-
-When matching a wildmat expression against some text, each comma-separated
-pattern is matched in order from left to right. In order to match, the
-pattern must match the whole text; in regular expression terminology, it's
-implicitly anchored at both the beginning and the end. For example, the
-pattern C<a> matches only the text C<a>; it doesn't match C<ab> or C<ba>
-or even C<aa>. If none of the patterns match, the whole expression
-doesn't match. Otherwise, whether the expression matches is determined
-entirely by the rightmost matching pattern; the expression matches the
-text if and only if the rightmost matching pattern is not negated.
-
-For example, consider the text C<news.misc>. The expression C<*> matches
-this text, of course, as does C<comp.*,news.*> (because the second pattern
-matches). C<news.*,!news.misc> does not match this text because both
-patterns match, meaning that the rightmost takes precedence, and the
-rightmost matching pattern is negated. C<news.*,!news.misc,*.misc> does
-match this text, since the rightmost matching pattern is not negated.
-
-Note that the expression C<!news.misc> can't match anything. Either the
-pattern doesn't match, in which case no patterns match and the expression
-doesn't match, or the pattern does match, in which case because it's
-negated the expression doesn't match. C<*,!news.misc>, on the other hand,
-is a useful pattern that matches anything except C<news.misc>.
-
-C<!> has significance only as the first character of a pattern; anywhere
-else in the pattern, it matches a literal C<!> in the text like any other
-non-metacharacter.
-
-If the B<uwildmat_poison> interface is used, then C<@> behaves the same as
-C<!> except that if an expression fails to match because the rightmost
-matching pattern began with C<@>, B<UWILDMAT_POISON> is returned instead of
-B<UWILDMAT_FAIL>.
-
-If the B<uwildmat_simple> interface is used, the matching rules are the
-same as above except that none of C<!>, C<@>, or C<,> have any special
-meaning at all and only match those literal characters.
-
-=head1 BUGS
-
-All of these functions internally convert the passed arguments to const
-unsigned char pointers. The only reason why they take regular char
-pointers instead of unsigned char is for the convenience of INN and other
-callers that may not be using unsigned char everywhere they should. In a
-future revision, the public interface should be changed to just take
-unsigned char pointers.
-
-=head1 HISTORY
-
-Written by Rich $alz <rsalz@uunet.uu.net> in 1986, and posted to Usenet
-several times since then, most notably in comp.sources.misc in
-March, 1991.
-
-Lars Mathiesen <thorinn@diku.dk> enhanced the multi-asterisk failure
-mode in early 1991.
-
-Rich and Lars increased the efficiency of star patterns and reposted it to
-comp.sources.misc in April, 1991.
-
-Robert Elz <kre@munnari.oz.au> added minus sign and close bracket handling
-in June, 1991.
-
-Russ Allbery <rra@stanford.edu> added support for comma-separated patterns
-and the C<!> and C<@> metacharacters to the core wildmat routines in July,
-2000. He also added support for UTF-8 characters, changed the default
-behavior to assume that both the text and the pattern are in UTF-8, and
-largely rewrote this documentation to expand and clarify the description
-of how a wildmat expression matches.
-
-Please note that the interfaces to these functions are named B<uwildmat>
-and the like rather than B<wildmat> to distinguish them from the
-B<wildmat> function provided by Rich $alz's original implementation.
-While this code is heavily based on Rich's original code, it has
-substantial differences, including the extension to support UTF-8
-characters, and has noticable functionality changes. Any bugs present in
-it aren't Rich's fault.
-
-$Id: uwildmat.pod 5533 2002-08-10 18:51:37Z rra $
-
-=head1 SEE ALSO
-
-grep(1), fnmatch(3), regex(3), regexp(3).
-
-=cut
+++ /dev/null
-Path: bounce-back
-From: group-admin@isc.org (David C Lawrence)
-Newsgroups: news.announce.newusers
-Subject: cmsg newgroup news.announce.newusers moderated
-Control: newgroup news.announce.newusers moderated
-Approved: newgroups-request@isc.org
-Message-ID: <868485430.2655@isc.org>
-Date: Wed, 09 Jul 1997 21:57:10 GMT
-Lines: 8
-X-Info: ftp://ftp.isc.org/pub/pgpcontrol/README.html
- ftp://ftp.isc.org/pub/pgpcontrol/README
-X-PGP-Sig: 2.6.2 Subject,Control,Message-ID,Date,From,Sender
- iQCVAwUBM8QJNsJdOtO4janBAQGkUAP6AlzO065jDQFrG20/b3/SaOm4WGQBly5D
- pXlVJdYBqPAG3HvxVqAdKM7y6ixM7Mml4OdfK0JeVCH03nqeGuBc51sTDIZ6kyAx
- +YHlNSnp/JJnpDuJCfXZjwNl4kWImucGgwI5BxrQco8re949Cg5m5TFXiwYMiR/+
- AjKZCTtmV1Y=
- =uSbd
-
-news.announce.newusers is a moderated newsgroup which has existed
-since the mid-1980s.
-
-Group submission address: netannounce@deshaw.com
-Moderator contact address: netannounce@deshaw.com (Mark Moraes)
-
-For your newsgroups file:
-news.announce.newusers Explanatory postings for new users. (Moderated)
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS)
-
-ALL = convdate expire expireover expirerm fastrm grephistory \
- makedbz makehistory prunehistory
-
-SOURCES = convdate.c expire.c expireover.c fastrm.c grephistory.c \
- makedbz.c makehistory.c prunehistory.c
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- for F in convdate fastrm grephistory ; do \
- $(LI_XPUB) $$F $D$(PATHBIN)/$$F ; \
- done
- for F in expire expireover makedbz makehistory prunehistory ; do \
- $(LI_XPRI) $$F $D$(PATHBIN)/$$F ; \
- done
- $(CP_XPRI) expirerm $D$(PATHBIN)/expirerm
-
-clean:
- rm -f *.o $(ALL)
- rm -f profiled expirep
- rm -rf .libs
-
-clobber distclean: clean
- rm -f tags
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES)
-
-
-## Compilation rules.
-
-BOTH = $(LIBHIST) $(LIBSTORAGE) $(LIBINN)
-
-LINK = $(LIBLD) $(LDFLAGS) -o $@
-INNLIBS = $(LIBINN) $(LIBS)
-STORELIBS = $(BOTH) $(EXTSTORAGELIBS) $(LIBS)
-
-FIX = $(FIXSCRIPT)
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-convdate: convdate.o $(LIBINN) ; $(LINK) convdate.o $(INNLIBS)
-expire: expire.o $(BOTH) ; $(LINK) expire.o $(STORELIBS)
-expireover: expireover.o $(BOTH) ; $(LINK) expireover.o $(STORELIBS)
-fastrm: fastrm.o $(BOTH) ; $(LINK) fastrm.o $(STORELIBS)
-grephistory: grephistory.o $(BOTH) ; $(LINK) grephistory.o $(STORELIBS)
-makedbz: makedbz.o $(LIBINN) ; $(LINK) makedbz.o $(INNLIBS)
-makehistory: makehistory.o $(BOTH) ; $(LINK) makehistory.o $(STORELIBS)
-prunehistory: prunehistory.o $(BOTH) ; $(LINK) prunehistory.o $(STORELIBS)
-
-expirerm: expirerm.in $(FIX) ; $(FIX) expirerm.in
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSTORAGE): ; (cd ../storage ; $(MAKE))
-$(LIBHIST): ; (cd ../history ; $(MAKE))
-
-
-## Profiling. These rules have not been checked for a while and may need
-## some work.
-
-profiled: expirep
- date >$@
-
-expirep: expire.c
- rm -f expire.o
- $(MAKEPROFILING) expire
- mv expire expirep
- rm -f expire.o
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-convdate.o: convdate.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h
-expire.o: expire.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/history.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h \
- ../include/inndcomm.h ../include/libinn.h ../include/paths.h \
- ../include/storage.h
-expireover.o: expireover.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/qio.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ../include/paths.h ../include/storage.h
-fastrm.o: fastrm.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/qio.h ../include/libinn.h \
- ../include/storage.h
-grephistory.o: grephistory.c ../include/clibrary.h ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h \
- ../include/inn/history.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h ../include/libinn.h \
- ../include/paths.h ../include/storage.h
-makedbz.o: makedbz.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/dbz.h ../include/libinn.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/messages.h ../include/inn/qio.h \
- ../include/libinn.h ../include/paths.h ../include/storage.h
-makehistory.o: makehistory.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/wait.h ../include/config.h ../include/inn/buffer.h \
- ../include/inn/defines.h ../include/inn/history.h \
- ../include/inn/innconf.h ../include/inn/messages.h ../include/inn/qio.h \
- ../include/inn/wire.h ../include/libinn.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ../include/paths.h \
- ../include/storage.h
-prunehistory.o: prunehistory.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/history.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h ../include/libinn.h \
- ../include/paths.h
+++ /dev/null
-/* $Id: convdate.c 6372 2003-05-31 19:48:28Z rra $
-**
-** Convert date strings and numbers to numbers and strings.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <time.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-static const char usage[] = "\
-Usage: convdate -n [date ...]\n\
- convdate [-dl] -c [time ...]\n\
- convdate [-dl] [-s] [date ...]\n\
-\n\
-convdate -n converts a date (in any format parseable by parsedate) to the\n\
-number of seconds since epoch. convdate -s does the same, but converts\n\
-to a date string. convdate -c converts seconds since epoch to a date\n\
-string. The default output is the output of ctime (normally the same format\n\
-as returned by the date command). If -d is given, the output is formatted\n\
-as a valid Usenet article Date header. If -l is given with -d, format the\n\
-time in local time rather than UTC. If no options are given, the -s\n\
-behavior is the default; if no dates are given, the current time is used.\n";
-
-/* Whether to format the output as a Date header. */
-static bool date_format = false;
-
-/* Whether to use local time instead of UTC. */
-static bool date_local = false;
-
-
-/*
-** Return true if the given string is entirely digits.
-*/
-static bool
-isdigits(const char *p)
-{
- for (; *p; p++)
- if (!CTYPE(isdigit, *p))
- return false;
- return true;
-}
-
-
-/*
-** Print date corresponding to the provided time_t. By default, the output
-** of ctime is printed, but if date_format is true, makedate is used
-** instead. If date_local is true, format in local time; otherwise, use
-** UTC. Returns success.
-*/
-static bool
-print_date(time_t date)
-{
- char date_buffer[128];
- char *result;
-
- if (date_format) {
- if (!makedate(date, date_local, date_buffer, sizeof(date_buffer))) {
- warn("can't format %ld", (long) date);
- return false;
- } else {
- printf("%s\n", date_buffer);
- }
- } else {
- result = ctime(&date);
- if (result == NULL) {
- warn("can't format %ld", (long) date);
- return false;
- } else {
- printf("%s", result);
- }
- }
- return true;
-}
-
-
-/*
-** The core function. Given a string representing a date (in some format
-** given by the mode) and a mode ('s', 'n', or 'c', corresponding to the
-** basic three options to the program), convert the date and print the
-** output. date may be NULL, in which case the current date is used.
-** Returns true if conversion was successful, false otherwise.
-*/
-static bool
-convdate(const char *date, char mode)
-{
- time_t seconds;
-
- /* Convert the given date to seconds or obtain the current time. */
- if (date == NULL) {
- seconds = time(NULL);
- } else if (mode == 'c') {
- if (!isdigits(date)) {
- warn("\"%s\" doesn't look like a number", date);
- return false;
- } else {
- seconds = (time_t) atol(date);
- }
- } else {
- seconds = parsedate((char *) date, NULL);
- if (seconds == (time_t) -1) {
- warn("can't convert \"%s\"", date);
- return false;
- }
- }
-
- /* Output the resulting date. */
- if (mode == 'n') {
- printf("%ld\n", (long) seconds);
- return true;
- } else {
- return print_date(seconds);
- }
-}
-
-
-int
-main(int argc, char *argv[])
-{
- int option, status;
- char *date;
- char mode = '\0';
-
- message_program_name = "convdate";
-
- /* Parse options. */
- while ((option = getopt(argc, argv, "cdhlns")) != EOF) {
- switch (option) {
- case 'h':
- printf("%s\n", usage);
- exit(0);
- break;
- case 'd':
- date_format = true;
- break;
- case 'l':
- date_local = true;
- break;
- case 'c':
- case 'n':
- case 's':
- if (mode != 0) die("only one of -c, -n, or -s is allowed");
- mode = option;
- break;
- default:
- fprintf(stderr, "%s", usage);
- exit(1);
- break;
- }
- }
- if (mode == '\0')
- mode = 's';
- argc -= optind;
- argv += optind;
-
- /* Perform the desired action for each provided argument. */
- if (argc == 0) {
- exit(convdate(NULL, mode) ? 0 : 1);
- } else {
- for (date = *argv, status = 0; date != NULL; date = *++argv)
- status += (convdate(date, mode) ? 0 : 1);
- exit(status);
- }
-}
+++ /dev/null
-/* $Id: expire.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Expire news articles.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <pwd.h>
-#include <sys/stat.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inndcomm.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-
-typedef struct _EXPIRECLASS {
- time_t Keep;
- time_t Default;
- time_t Purge;
- bool Missing;
- bool ReportedMissing;
-} EXPIRECLASS;
-
-/*
-** Expire-specific stuff.
-*/
-#define MAGIC_TIME 49710.
-
-static bool EXPtracing;
-static bool EXPusepost;
-static bool Ignoreselfexpire = false;
-static FILE *EXPunlinkfile;
-static EXPIRECLASS EXPclasses[NUM_STORAGE_CLASSES+1];
-static char *EXPreason;
-static time_t EXPremember;
-static time_t Now;
-static time_t RealNow;
-
-/* Statistics; for -v flag. */
-static char *EXPgraph;
-static int EXPverbose;
-static long EXPprocessed;
-static long EXPunlinked;
-static long EXPallgone;
-static long EXPstillhere;
-static struct history *History;
-static char *NHistory;
-
-static void CleanupAndExit(bool Server, bool Paused, int x);
-
-static int EXPsplit(char *p, char sep, char **argv, int count);
-
-enum KR {Keep, Remove};
-
-\f
-
-/*
-** Open a file or give up.
-*/
-static FILE *
-EXPfopen(bool Unlink, const char *Name, const char *Mode, bool Needclean,
- bool Server, bool Paused)
-{
- FILE *F;
-
- if (Unlink && unlink(Name) < 0 && errno != ENOENT)
- syswarn("cannot remove %s", Name);
- if ((F = fopen(Name, Mode)) == NULL) {
- syswarn("cannot open %s in %s mode", Name, Mode);
- if (Needclean)
- CleanupAndExit(Server, Paused, 1);
- else
- exit(1);
- }
- return F;
-}
-
-
-/*
-** Split a line at a specified field separator into a vector and return
-** the number of fields found, or -1 on error.
-*/
-static int EXPsplit(char *p, char sep, char **argv, int count)
-{
- int i;
-
- if (!p)
- return 0;
-
- while (*p == sep)
- ++p;
-
- if (!*p)
- return 0;
-
- if (!p)
- return 0;
-
- while (*p == sep)
- ++p;
-
- if (!*p)
- return 0;
-
- for (i = 1, *argv++ = p; *p; )
- if (*p++ == sep) {
- p[-1] = '\0';
- for (; *p == sep; p++)
- ;
- if (!*p)
- return i;
- if (++i == count)
- /* Overflow. */
- return -1;
- *argv++ = p;
- }
- return i;
-}
-
-
-/*
-** Parse a number field converting it into a "when did this start?".
-** This makes the "keep it" tests fast, but inverts the logic of
-** just about everything you expect. Print a message and return false
-** on error.
-*/
-static bool EXPgetnum(int line, char *word, time_t *v, const char *name)
-{
- char *p;
- bool SawDot;
- double d;
-
- if (strcasecmp(word, "never") == 0) {
- *v = (time_t)0;
- return true;
- }
-
- /* Check the number. We don't have strtod yet. */
- for (p = word; ISWHITE(*p); p++)
- ;
- if (*p == '+' || *p == '-')
- p++;
- for (SawDot = false; *p; p++)
- if (*p == '.') {
- if (SawDot)
- break;
- SawDot = true;
- }
- else if (!CTYPE(isdigit, (int)*p))
- break;
- if (*p) {
- warn("bad '%c' character in %s field on line %d", *p, name, line);
- return false;
- }
- d = atof(word);
- if (d > MAGIC_TIME)
- *v = (time_t)0;
- else
- *v = Now - (time_t)(d * 86400.);
- return true;
-}
-
-
-/*
-** Parse the expiration control file. Return true if okay.
-*/
-static bool EXPreadfile(FILE *F)
-{
- char *p;
- int i;
- int j;
- bool SawDefault;
- char buff[BUFSIZ];
- char *fields[7];
-
- /* Scan all lines. */
- EXPremember = -1;
- SawDefault = false;
-
- for (i = 0; i <= NUM_STORAGE_CLASSES; i++) {
- EXPclasses[i].ReportedMissing = false;
- EXPclasses[i].Missing = true;
- }
-
- for (i = 1; fgets(buff, sizeof buff, F) != NULL; i++) {
- if ((p = strchr(buff, '\n')) == NULL) {
- warn("line %d too long", i);
- return false;
- }
- *p = '\0';
- p = strchr(buff, '#');
- if (p)
- *p = '\0';
- else
- p = buff + strlen(buff);
- while (--p >= buff) {
- if (isspace((int)*p))
- *p = '\0';
- else
- break;
- }
- if (buff[0] == '\0')
- continue;
- if ((j = EXPsplit(buff, ':', fields, ARRAY_SIZE(fields))) == -1) {
- warn("too many fields on line %d", i);
- return false;
- }
-
- /* Expired-article remember line? */
- if (strcmp(fields[0], "/remember/") == 0) {
- if (j != 2) {
- warn("invalid format on line %d", i);
- return false;
- }
- if (EXPremember != -1) {
- warn("duplicate /remember/ on line %d", i);
- return false;
- }
- if (!EXPgetnum(i, fields[1], &EXPremember, "remember"))
- return false;
- continue;
- }
-
- /* Storage class line? */
- if (j == 4) {
- /* Is this the default line? */
- if (fields[0][0] == '*' && fields[0][1] == '\0') {
- if (SawDefault) {
- warn("duplicate default on line %d", i);
- return false;
- }
- j = NUM_STORAGE_CLASSES;
- SawDefault = true;
- } else {
- j = atoi(fields[0]);
- if ((j < 0) || (j >= NUM_STORAGE_CLASSES))
- warn("bad storage class %d on line %d", j, i);
- }
-
- if (!EXPgetnum(i, fields[1], &EXPclasses[j].Keep, "keep")
- || !EXPgetnum(i, fields[2], &EXPclasses[j].Default, "default")
- || !EXPgetnum(i, fields[3], &EXPclasses[j].Purge, "purge"))
- return false;
- /* These were turned into offsets, so the test is the opposite
- * of what you think it should be. If Purge isn't forever,
- * make sure it's greater then the other two fields. */
- if (EXPclasses[j].Purge) {
- /* Some value not forever; make sure other values are in range. */
- if (EXPclasses[j].Keep && EXPclasses[j].Keep < EXPclasses[j].Purge) {
- warn("keep time longer than purge time on line %d", i);
- return false;
- }
- if (EXPclasses[j].Default && EXPclasses[j].Default < EXPclasses[j].Purge) {
- warn("default time longer than purge time on line %d", i);
- return false;
- }
- }
- EXPclasses[j].Missing = false;
- continue;
- }
-
- /* Regular expiration line -- right number of fields? */
- if (j != 5) {
- warn("bad format on line %d", i);
- return false;
- }
- continue; /* don't process this line--per-group expiry is done by expireover */
- }
-
- return true;
-}
-
-/*
-** Should we keep the specified article?
-*/
-static enum KR EXPkeepit(const TOKEN *token, time_t when, time_t Expires)
-{
- EXPIRECLASS class;
-
- class = EXPclasses[token->class];
- if (class.Missing) {
- if (EXPclasses[NUM_STORAGE_CLASSES].Missing) {
- /* no default */
- if (!class.ReportedMissing) {
- warn("class definition for %d missing from control file,"
- " assuming it should never expire", token->class);
- EXPclasses[token->class].ReportedMissing = true;
- }
- return Keep;
- } else {
- /* use the default */
- class = EXPclasses[NUM_STORAGE_CLASSES];
- EXPclasses[token->class] = class;
- }
- }
- /* Bad posting date? */
- if (when > (RealNow + 86400)) {
- /* Yes -- force the article to go to right now */
- when = Expires ? class.Purge : class.Default;
- }
- if (EXPverbose > 2) {
- if (EXPverbose > 3)
- printf("%s age = %0.2f\n", TokenToText(*token), (Now - when) / 86400.);
- if (Expires == 0) {
- if (when <= class.Default)
- printf("%s too old (no exp)\n", TokenToText(*token));
- } else {
- if (when <= class.Purge)
- printf("%s later than purge\n", TokenToText(*token));
- if (when >= class.Keep)
- printf("%s earlier than min\n", TokenToText(*token));
- if (Now >= Expires)
- printf("%s later than header\n", TokenToText(*token));
- }
- }
-
- /* If no expiration, make sure it wasn't posted before the default. */
- if (Expires == 0) {
- if (when >= class.Default)
- return Keep;
-
- /* Make sure it's not posted before the purge cut-off and
- * that it's not due to expire. */
- } else {
- if (when >= class.Purge && (Expires >= Now || when >= class.Keep))
- return Keep;
- }
- return Remove;
-
-}
-
-
-/*
-** An article can be removed. Either print a note, or actually remove it.
-** Also fill in the article size.
-*/
-static void
-EXPremove(const TOKEN *token)
-{
- /* Turn into a filename and get the size if we need it. */
- if (EXPverbose > 1)
- printf("\tunlink %s\n", TokenToText(*token));
-
- if (EXPtracing) {
- EXPunlinked++;
- printf("%s\n", TokenToText(*token));
- return;
- }
-
- EXPunlinked++;
- if (EXPunlinkfile) {
- fprintf(EXPunlinkfile, "%s\n", TokenToText(*token));
- if (!ferror(EXPunlinkfile))
- return;
- syswarn("cannot write to -z file (will ignore it for rest of run)");
- fclose(EXPunlinkfile);
- EXPunlinkfile = NULL;
- }
- if (!SMcancel(*token) && SMerrno != SMERR_NOENT && SMerrno != SMERR_UNINIT)
- warn("cannot unlink %s", TokenToText(*token));
-}
-
-/*
-** Do the work of expiring one line.
-*/
-static bool
-EXPdoline(void *cookie UNUSED, time_t arrived, time_t posted, time_t expires,
- TOKEN *token)
-{
- time_t when;
- bool HasSelfexpire = false;
- bool Selfexpired = false;
- ARTHANDLE *article;
- enum KR kr;
- bool r;
-
- if (innconf->groupbaseexpiry || SMprobe(SELFEXPIRE, token, NULL)) {
- if ((article = SMretrieve(*token, RETR_STAT)) == (ARTHANDLE *)NULL) {
- HasSelfexpire = true;
- Selfexpired = true;
- } else {
- /* the article is still alive */
- SMfreearticle(article);
- if (innconf->groupbaseexpiry || !Ignoreselfexpire)
- HasSelfexpire = true;
- }
- }
- if (EXPusepost && posted != 0)
- when = posted;
- else
- when = arrived;
- EXPprocessed++;
-
- if (HasSelfexpire) {
- if (Selfexpired || token->type == TOKEN_EMPTY) {
- EXPallgone++;
- r = false;
- } else {
- EXPstillhere++;
- r = true;
- }
- } else {
- kr = EXPkeepit(token, when, expires);
- if (kr == Remove) {
- EXPremove(token);
- EXPallgone++;
- r = false;
- } else {
- EXPstillhere++;
- r = true;
- }
- }
-
- return r;
-}
-
-\f
-
-/*
-** Clean up link with the server and exit.
-*/
-static void
-CleanupAndExit(bool Server, bool Paused, int x)
-{
- FILE *F;
-
- if (Server) {
- ICCreserve("");
- if (Paused && ICCgo(EXPreason) != 0) {
- syswarn("cannot unpause server");
- x = 1;
- }
- }
- if (Server && ICCclose() < 0) {
- syswarn("cannot close communication link to server");
- x = 1;
- }
- if (EXPunlinkfile && fclose(EXPunlinkfile) == EOF) {
- syswarn("cannot close -z file");
- x = 1;
- }
-
- /* Report stats. */
- if (EXPverbose) {
- printf("Article lines processed %8ld\n", EXPprocessed);
- printf("Articles retained %8ld\n", EXPstillhere);
- printf("Entries expired %8ld\n", EXPallgone);
- if (!innconf->groupbaseexpiry)
- printf("Articles dropped %8ld\n", EXPunlinked);
- }
-
- /* Append statistics to a summary file */
- if (EXPgraph) {
- F = EXPfopen(false, EXPgraph, "a", false, false, false);
- fprintf(F, "%ld %ld %ld %ld %ld\n",
- (long)Now, EXPprocessed, EXPstillhere, EXPallgone,
- EXPunlinked);
- fclose(F);
- }
-
- SMshutdown();
- HISclose(History);
- if (EXPreason != NULL)
- free(EXPreason);
-
- if (NHistory != NULL)
- free(NHistory);
- closelog();
- exit(x);
-}
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: expire [flags] [expire.ctl]\n");
- exit(1);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may create new database files so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-int
-main(int ac, char *av[])
-{
- int i;
- char *p;
- FILE *F;
- char *HistoryText;
- const char *NHistoryPath = NULL;
- const char *NHistoryText = NULL;
- char *EXPhistdir;
- char buff[SMBUF];
- bool Server;
- bool Bad;
- bool IgnoreOld;
- bool Writing;
- bool UnlinkFile;
- bool val;
- time_t TimeWarp;
- size_t Size = 0;
-
- /* First thing, set up logging and our identity. */
- openlog("expire", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "expire";
-
- /* Set defaults. */
- Server = true;
- IgnoreOld = false;
- Writing = true;
- TimeWarp = 0;
- UnlinkFile = false;
-
- if (!innconf_read(NULL))
- exit(1);
-
- HistoryText = concatpath(innconf->pathdb, _PATH_HISTORY);
-
- umask(NEWSUMASK);
-
- /* find the default history file directory */
- EXPhistdir = xstrdup(HistoryText);
- p = strrchr(EXPhistdir, '/');
- if (p != NULL) {
- *p = '\0';
- }
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "f:h:d:g:iNnpr:s:tv:w:xz:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'd':
- NHistoryPath = optarg;
- break;
- case 'f':
- NHistoryText = optarg;
- break;
- case 'g':
- EXPgraph = optarg;
- break;
- case 'h':
- HistoryText = optarg;
- break;
- case 'i':
- IgnoreOld = true;
- break;
- case 'N':
- Ignoreselfexpire = true;
- break;
- case 'n':
- Server = false;
- break;
- case 'p':
- EXPusepost = true;
- break;
- case 'r':
- EXPreason = xstrdup(optarg);
- break;
- case 's':
- Size = atoi(optarg);
- break;
- case 't':
- EXPtracing = true;
- break;
- case 'v':
- EXPverbose = atoi(optarg);
- break;
- case 'w':
- TimeWarp = (time_t)(atof(optarg) * 86400.);
- break;
- case 'x':
- Writing = false;
- break;
- case 'z':
- EXPunlinkfile = EXPfopen(true, optarg, "a", false, false, false);
- UnlinkFile = true;
- break;
- }
- ac -= optind;
- av += optind;
- if ((ac != 0 && ac != 1))
- Usage();
-
- /* if EXPtracing is set, then pass in a path, this ensures we
- * don't replace the existing history files */
- if (EXPtracing || NHistoryText || NHistoryPath) {
- if (NHistoryPath == NULL)
- NHistoryPath = innconf->pathdb;
- if (NHistoryText == NULL)
- NHistoryText = _PATH_HISTORY;
- NHistory = concatpath(NHistoryPath, NHistoryText);
- }
- else {
- NHistory = NULL;
- }
-
- time(&Now);
- RealNow = Now;
- Now += TimeWarp;
-
- /* Change users if necessary. */
- setuid_news();
-
- /* Parse the control file. */
- if (av[0]) {
- if (strcmp(av[0], "-") == 0)
- F = stdin;
- else
- F = EXPfopen(false, av[0], "r", false, false, false);
- } else {
- char *path;
-
- path = concatpath(innconf->pathetc, _PATH_EXPIRECTL);
- F = EXPfopen(false, path, "r", false, false, false);
- free(path);
- }
- if (!EXPreadfile(F)) {
- fclose(F);
- die("format error in expire.ctl");
- }
- fclose(F);
-
- /* Set up the link, reserve the lock. */
- if (Server) {
- if (EXPreason == NULL) {
- snprintf(buff, sizeof(buff), "Expiring process %ld",
- (long) getpid());
- EXPreason = xstrdup(buff);
- }
- }
- else {
- EXPreason = NULL;
- }
-
- if (Server) {
- /* If we fail, leave evidence behind. */
- if (ICCopen() < 0) {
- syswarn("cannot open channel to server");
- CleanupAndExit(false, false, 1);
- }
- if (ICCreserve((char *)EXPreason) != 0) {
- warn("cannot reserve server");
- CleanupAndExit(false, false, 1);
- }
- }
-
- History = HISopen(HistoryText, innconf->hismethod, HIS_RDONLY);
- if (!History) {
- warn("cannot open history");
- CleanupAndExit(Server, false, 1);
- }
-
- /* Ignore failure on the HISctl()s, if the underlying history
- * manager doesn't implement them its not a disaster */
- HISctl(History, HISCTLS_IGNOREOLD, &IgnoreOld);
- if (Size != 0) {
- HISctl(History, HISCTLS_NPAIRS, &Size);
- }
-
- val = true;
- if (!SMsetup(SM_RDWR, (void *)&val) || !SMsetup(SM_PREOPEN, (void *)&val)) {
- warn("cannot set up storage manager");
- CleanupAndExit(Server, false, 1);
- }
- if (!SMinit()) {
- warn("cannot initialize storage manager: %s", SMerrorstr);
- CleanupAndExit(Server, false, 1);
- }
- if (chdir(EXPhistdir) < 0) {
- syswarn("cannot chdir to %s", EXPhistdir);
- CleanupAndExit(Server, false, 1);
- }
-
- Bad = HISexpire(History, NHistory, EXPreason, Writing, NULL,
- EXPremember, EXPdoline) == false;
-
- if (UnlinkFile && EXPunlinkfile == NULL)
- /* Got -z but file was closed; oops. */
- Bad = true;
-
- /* If we're done okay, and we're not tracing, slip in the new files. */
- if (EXPverbose) {
- if (Bad)
- printf("Expire errors: history files not updated.\n");
- if (EXPtracing)
- printf("Expire tracing: history files not updated.\n");
- }
-
- if (!Bad && NHistory != NULL) {
- snprintf(buff, sizeof(buff), "%s.n.done", NHistory);
- fclose(EXPfopen(false, buff, "w", true, Server, false));
- CleanupAndExit(Server, false, Bad ? 1 : 0);
- }
-
- CleanupAndExit(Server, !Bad, Bad ? 1 : 0);
- /* NOTREACHED */
- abort();
-}
+++ /dev/null
-/* $Id: expireover.c 6708 2004-05-16 19:59:26Z rra $
-**
-** Expire the overview database.
-**
-** This program handles the nightly expiration of overview information. If
-** groupbaseexpiry is true, this program also handles the removal of
-** articles that have expired. It's separate from the process that scans
-** and expires the history file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <pwd.h>
-#include <signal.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-#include "storage.h"
-
-static const char usage[] = "\
-Usage: expireover [-ekNpqs] [-w offset] [-z rmfile] [-Z lowmarkfile]\n";
-
-/* Set to 1 if we've received a signal; expireover then terminates after
- finishing the newsgroup that it's working on (this prevents corruption of
- the overview by killing expireover). */
-static volatile sig_atomic_t signalled = 0;
-
-
-/*
-** Handle a fatal signal and set signalled. Restore the default signal
-** behavior after receiving a signal so that repeating the signal will kill
-** the program immediately.
-*/
-static RETSIGTYPE
-fatal_signal(int sig)
-{
- signalled = 1;
- xsignal(sig, SIG_DFL);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may create new database files so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-int
-main(int argc, char *argv[])
-{
- int option, low;
- char *line, *p;
- QIOSTATE *qp;
- bool value;
- OVGE ovge;
- char *active_path = NULL;
- char *lowmark_path = NULL;
- char *path;
- FILE *lowmark = NULL;
- bool purge_deleted = false;
- bool always_stat = false;
- struct history *history;
-
- /* First thing, set up logging and our identity. */
- openlog("expireover", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "expireover";
-
- /* Set up some default options for group-based expiration, although none
- of these will be used if groupbaseexpiry isn't true. */
- ovge.earliest = false;
- ovge.keep = false;
- ovge.ignoreselfexpire = false;
- ovge.usepost = false;
- ovge.quiet = false;
- ovge.timewarp = 0;
- ovge.filename = NULL;
- ovge.delayrm = false;
-
- /* Parse the command-line options. */
- while ((option = getopt(argc, argv, "ef:kNpqsw:z:Z:")) != EOF) {
- switch (option) {
- case 'e':
- ovge.earliest = true;
- break;
- case 'f':
- active_path = xstrdup(optarg);
- break;
- case 'k':
- ovge.keep = true;
- break;
- case 'N':
- ovge.ignoreselfexpire = true;
- break;
- case 'p':
- ovge.usepost = true;
- break;
- case 'q':
- ovge.quiet = true;
- break;
- case 's':
- always_stat = true;
- break;
- case 'w':
- ovge.timewarp = (time_t) (atof(optarg) * 86400.);
- break;
- case 'z':
- ovge.filename = optarg;
- ovge.delayrm = true;
- break;
- case 'Z':
- lowmark_path = optarg;
- break;
- default:
- fprintf(stderr, "%s", usage);
- exit(1);
- }
- }
- if (ovge.earliest && ovge.keep)
- die("-e and -k cannot be specified at the same time");
-
- /* Initialize innconf. */
- if (!innconf_read(NULL))
- exit(1);
-
- /* Change to the news user if necessary. */
- setuid_news();
-
- /* Initialize the lowmark file, if one was requested. */
- if (lowmark_path != NULL) {
- if (unlink(lowmark_path) < 0 && errno != ENOENT)
- syswarn("can't remove %s", lowmark_path);
- lowmark = fopen(lowmark_path, "a");
- if (lowmark == NULL)
- sysdie("can't open %s", lowmark_path);
- }
-
- /* Set up the path to the list of newsgroups we're going to use and open
- that file. This could be stdin. */
- if (active_path == NULL) {
- active_path = concatpath(innconf->pathdb, _PATH_ACTIVE);
- purge_deleted = true;
- }
- if (strcmp(active_path, "-") == 0) {
- qp = QIOfdopen(fileno(stdin));
- if (qp == NULL)
- sysdie("can't reopen stdin");
- } else {
- qp = QIOopen(active_path);
- if (qp == NULL)
- sysdie("can't open active file (%s)", active_path);
- }
- free(active_path);
-
- /* open up the history manager */
- path = concatpath(innconf->pathdb, _PATH_HISTORY);
- history = HISopen(path, innconf->hismethod, HIS_RDONLY);
- free(path);
-
- /* Initialize the storage manager. We only need to initialize it in
- read/write mode if we're not going to be writing a separate file for
- the use of fastrm. */
- if (!ovge.delayrm) {
- value = true;
- if (!SMsetup(SM_RDWR, &value))
- die("can't setup storage manager read/write");
- }
- value = true;
- if (!SMsetup(SM_PREOPEN, &value))
- die("can't setup storage manager");
- if (!SMinit())
- die("can't initialize storage manager: %s", SMerrorstr);
-
- /* Initialize and configure the overview subsystem. */
- if (!OVopen(OV_READ | OV_WRITE))
- die("can't open overview database");
- if (innconf->groupbaseexpiry) {
- time(&ovge.now);
- if (!OVctl(OVGROUPBASEDEXPIRE, &ovge))
- die("can't configure group-based expire");
- }
- if (!OVctl(OVSTATALL, &always_stat))
- die("can't configure overview stat behavior");
-
- /* We want to be careful about being interrupted from this point on, so
- set up our signal handlers. */
- xsignal(SIGTERM, fatal_signal);
- xsignal(SIGINT, fatal_signal);
- xsignal(SIGHUP, fatal_signal);
-
- /* Loop through each line of the input file and process each group,
- writing data to the lowmark file if desired. */
- line = QIOread(qp);
- while (line != NULL && !signalled) {
- p = strchr(line, ' ');
- if (p != NULL)
- *p = '\0';
- p = strchr(line, '\t');
- if (p != NULL)
- *p = '\0';
- if (!OVexpiregroup(line, &low, history))
- warn("can't expire %s", line);
- else if (lowmark != NULL && low != 0)
- fprintf(lowmark, "%s %u\n", line, low);
- line = QIOread(qp);
- }
- if (signalled)
- warn("received signal, exiting");
-
- /* If desired, purge all deleted newsgroups. */
- if (!signalled && purge_deleted)
- if (!OVexpiregroup(NULL, NULL, history))
- warn("can't expire deleted newsgroups");
-
- /* Close everything down in an orderly fashion. */
- QIOclose(qp);
- OVclose();
- SMshutdown();
- HISclose(history);
- if (lowmark != NULL)
- if (fclose(lowmark) == EOF)
- syswarn("can't close %s", lowmark_path);
-
- return 0;
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## Remove articles listed by expire -z.
-## Remove all files specified in the input file.
-
-MAIL="${MAILCMD} -s 'Problem removing expired files' ${NEWSMASTER}"
-
-#RMPROC="xargs rm"
-RMPROC="fastrm -e ${SPOOL}"
-
-if [ -z "$1" ] ; then
- echo "Expire called with zero list of files on `hostname`" \
- | eval ${MAIL}
- exit 0
-fi
-if [ ! -f $1 ] ; then
- echo "Expire called with no files to expire on `hostname`" \
- | eval ${MAIL}
- exit 0
-fi
-
-eval "cd ${SPOOL} \
- && ${RMPROC} <$1 \
- && mv $1 ${MOST_LOGS}/expire.list"
-if [ -f $1 ] ; then
- echo "Expire had problems removing articles on `hostname`" \
- | eval ${MAIL}
- exit 1
-fi
+++ /dev/null
-/* $Id: fastrm.c 6155 2003-01-19 19:58:25Z rra $
-**
-** Delete a list of filenames or tokens from stdin.
-**
-** Originally written by <kre@munnari.oz.au> (to only handle files)
-**
-** Files that can't be unlinked because they didn't exist are considered
-** okay. Any error condition results in exiting with non-zero exit
-** status. Input lines in the form @...@ are taken to be storage API
-** tokens. Input filenames should be fully qualified. For maximum
-** efficiency, input filenames should be sorted; fastrm will cd into each
-** directory to avoid additional directory lookups when removing a lot of
-** files in a single directory.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "storage.h"
-
-/* We reject any path names longer than this. */
-#define MAX_DIR_LEN 2048
-
-/* Data structure for a list of files in a single directory. */
-typedef struct filelist {
- int count;
- int size;
- char *dir;
- char **files;
-} filelist;
-
-/* All relative paths are relative to this directory. */
-static char *base_dir = NULL;
-
-/* The absolute path of the current working directory. */
-static char current_dir[MAX_DIR_LEN];
-
-/* The prefix for the files that we're currently working with. We sometimes
- also use this as working space for forming file names to remove, so give
- ourselves a bit of additional leeway just in case. */
-static char prefix_dir[MAX_DIR_LEN * 2];
-static int prefix_len;
-
-/* Some threshold values that govern the optimizations that we are willing
- to perform. chdir_threshold determines how many files to be removed we
- want in a directory before we chdir to that directory. sort_threshold
- determines how many files must be in a directory before we use readdir to
- remove them in order. relative_threshold determines how many levels of
- "../" we're willing to try to use to move to the next directory rather
- than just calling chdir with the new absolute path. */
-static int chdir_threshold = 3;
-static int relative_threshold = 0;
-static int sort_threshold = 0;
-
-/* True if we should only print what we would do, not actually do it. */
-static bool debug_only = false;
-
-/* A string used for constructing relative paths. */
-static const char dotdots[] = "../../../../";
-
-/* The number of errors encountered, used to determine exit status. */
-static int error_count = 0;
-
-/* Whether the storage manager has been initialized. */
-static bool sm_initialized = false;
-
-/* True if unlink may be able to remove directories. */
-static bool unlink_dangerous = false;
-
-
-
-/*
-** Sorting predicate for qsort and bsearch.
-*/
-static int
-file_compare(const void *a, const void *b)
-{
- const char *f1, *f2;
-
- f1 = *((const char **) a);
- f2 = *((const char **) b);
- return strcmp(f1, f2);
-}
-
-
-/*
-** Create a new filelist.
-*/
-static filelist *
-filelist_new(char *dir)
-{
- filelist *new;
-
- new = xmalloc(sizeof(filelist));
- new->count = 0;
- new->size = 0;
- new->dir = dir;
- new->files = NULL;
- return new;
-}
-
-
-/*
-** Insert a file name into a list of files (unsorted).
-*/
-static void
-filelist_insert(filelist *list, char *name)
-{
- if (list->count == list->size) {
- list->size = (list->size == 0) ? 16 : list->size * 2;
- list->files = xrealloc(list->files, list->size * sizeof(char *));
- }
- list->files[list->count++] = xstrdup(name);
-}
-
-
-/*
-** Find a file name in a sorted list of files.
-*/
-static char *
-filelist_lookup(filelist *list, const char *name)
-{
- char **p;
-
- p = bsearch(&name, list->files, list->count, sizeof(char *),
- file_compare);
- return (p == NULL ? NULL : *p);
-}
-
-
-/*
-** Empty a list of files, freeing all of the names but keeping the
-** structure intact.
-*/
-static void
-filelist_empty(filelist *list)
-{
- int i;
-
- for (i = 0; i < list->count; i++)
- free(list->files[i]);
- list->count = 0;
-}
-
-
-/*
-** Free a list of files.
-*/
-static void
-filelist_free(filelist *list)
-{
- filelist_empty(list);
- if (list->files != NULL)
- free(list->files);
- if (list->dir != NULL)
- free(list->dir);
- free(list);
-}
-
-
-/*
-** Exit handler for die. Shut down the storage manager before exiting.
-*/
-static int
-sm_cleanup(void)
-{
- SMshutdown();
- return 1;
-}
-
-
-/*
-** Initialize the storage manager. This includes parsing inn.conf, which
-** fastrm doesn't need for any other purpose.
-*/
-static void
-sm_initialize(void)
-{
- bool value;
-
- if (!innconf_read(NULL))
- exit(1);
- value = true;
- if (!SMsetup(SM_RDWR, &value) || !SMsetup(SM_PREOPEN, &value))
- die("can't set up storage manager");
- if (!SMinit())
- die("can't initialize storage manager: %s", SMerrorstr);
- sm_initialized = true;
- message_fatal_cleanup = sm_cleanup;
-}
-
-
-/*
-** Get a line from a given QIO stream, returning a pointer to it. Warn
-** about and then skip lines that are too long. Returns NULL at EOF or on
-** an error.
-*/
-static char *
-get_line(QIOSTATE *qp)
-{
- static int count;
- char *p;
-
- p = QIOread(qp);
- count++;
- while (QIOtoolong(qp) || (p != NULL && strlen(p) >= MAX_DIR_LEN)) {
- warn("line %d too long", count);
- error_count++;
- while (p == NULL && QIOtoolong(qp))
- p = QIOread(qp);
- p = QIOread(qp);
- }
- if (p == NULL) {
- if (QIOerror(qp)) {
- syswarn("read error");
- error_count++;
- }
- return NULL;
- }
- return p;
-}
-
-
-/*
-** Read lines from stdin (including the first that may have been there
-** from our last time in) until we reach EOF or until we get a line that
-** names a file not in the same directory as the previous lot. Remember
-** the file names in the directory we're examining and return the list.
-*/
-static filelist *
-process_line(QIOSTATE *qp, int *queued, int *deleted)
-{
- static char *line = NULL;
- filelist *list = NULL;
- char *p;
- char *dir = NULL;
- int dlen = -1;
-
- *queued = 0;
- *deleted = 0;
-
- if (line == NULL)
- line = get_line(qp);
-
- for (; line != NULL; line = get_line(qp)) {
- if (IsToken(line)) {
- (*deleted)++;
- if (debug_only) {
- printf("Token %s\n", line);
- continue;
- }
- if (!sm_initialized)
- sm_initialize();
- if (!SMcancel(TextToToken(line)))
- if (SMerrno != SMERR_NOENT && SMerrno != SMERR_UNINIT) {
- warn("can't cancel %s", line);
- error_count++;
- }
- } else {
- if (list == NULL) {
- p = strrchr(line, '/');
- if (p != NULL) {
- *p++ = '\0';
- dlen = strlen(line);
- dir = xstrdup(line);
- } else {
- p = line;
- dlen = -1;
- dir = NULL;
- }
- list = filelist_new(dir);
- } else {
- if ((dlen < 0 && strchr(line, '/'))
- || (dlen >= 0 && (line[dlen] != '/'
- || strchr(line + dlen + 1, '/')
- || strncmp(dir, line, dlen))))
- return list;
- }
- filelist_insert(list, line + dlen + 1);
- (*queued)++;
- }
- }
- return list;
-}
-
-
-/*
-** Copy n leading segments of a path.
-*/
-static void
-copy_segments(char *to, const char *from, int n)
-{
- char c;
-
- for (c = *from++; c != '\0'; c = *from++) {
- if (c == '/' && --n <= 0)
- break;
- *to++ = c;
- }
- *to = '\0';
-}
-
-
-/*
-** Return the count of path segments in a file name (the number of
-** slashes).
-*/
-static int
-slashcount(char *name)
-{
- int i;
-
- for (i = 0; *name != '\0'; name++)
- if (*name == '/')
- i++;
- return i;
-}
-
-
-/*
-** Unlink a file, reporting errors if the unlink fails for a reason other
-** than the file not existing doesn't exist. Be careful to avoid unlinking
-** a directory if unlink_dangerous is true.
-*/
-static void
-unlink_file(const char *file)
-{
- struct stat st;
-
- /* On some systems, unlink will remove directories if used by root. If
- we're running as root, unlink_dangerous will be set, and we need to
- make sure that the file isn't a directory first. */
- if (unlink_dangerous) {
- if (stat(file, &st) < 0) {
- if (errno != ENOENT) {
- if (*file == '/')
- syswarn("can't stat %s", file);
- else
- syswarn("can't stat %s in %s", file, current_dir);
- error_count++;
- }
- return;
- }
- if (S_ISDIR(st.st_mode)) {
- if (*file == '/')
- syswarn("%s is a directory", file);
- else
- syswarn("%s in %s is a directory", file, current_dir);
- error_count++;
- return;
- }
- }
-
- if (debug_only) {
- if (*file != '/')
- printf("%s / ", current_dir);
- printf("%s\n", file);
- return;
- }
-
- if (unlink(file) < 0 && errno != ENOENT) {
- if (*file == '/')
- syswarn("can't unlink %s", file);
- else
- syswarn("can't unlink %s in %s", file, current_dir);
- }
-}
-
-
-/*
-** A wrapper around chdir that dies if chdir fails for a reason other than
-** the directory not existing, returns false if the directory doesn't
-** exist (reporting an error), and otherwise returns true. It also checks
-** to make sure that filecount is larger than chdir_threshold, and if it
-** isn't it instead just sets prefix_dir and prefix_len to point to the new
-** directory without changing the working directory.
-*/
-static bool
-chdir_checked(const char *path, int filecount)
-{
- if (filecount < chdir_threshold) {
- strlcpy(prefix_dir, path, sizeof(prefix_dir));
- prefix_len = strlen(path);
- } else {
- prefix_len = 0;
- if (chdir(path) < 0) {
- if (errno != ENOENT)
- sysdie("can't chdir from %s to %s", current_dir, path);
- else {
- syswarn("can't chdir from %s to %s", current_dir, path);
- return false;
- }
- }
- }
- return true;
-}
-
-
-/*
-** Set our environment (process working directory, and global vars) to
-** reflect a change of directory to dir (relative to base_dir if dir is not
-** an absolute path). We're likely to want to do different things
-** depending on the amount of work to do in dir, so we also take the number
-** of files to remove in dir as the second argument. Return false if the
-** directory doesn't exist (and therefore all files in it have already been
-** removed; otherwise, return true.
-*/
-static bool
-setup_dir(char *dir, int filecount)
-{
- char *p, *q, *absolute;
- char path[MAX_DIR_LEN];
- int base_depth, depth;
-
- /* Set absolute to the absolute path to the new directory. */
- if (dir == NULL)
- absolute = base_dir;
- else if (*dir == '/')
- absolute = dir;
- else if (*dir == '\0') {
- strlcpy(path, "/", sizeof(path));
- absolute = path;
- } else {
- /* Strip off leading "./". */
- while (dir[0] == '.' && dir[1] == '/')
- for (dir += 2; *dir == '/'; dir++)
- ;
-
- /* Handle any leading "../", but only up to the number of segments
- in base_dir. */
- base_depth = slashcount(base_dir);
- while (base_depth > 0 && strncmp(dir, "../", 3) == 0)
- for (base_depth--, dir += 3; *dir == '/'; dir++)
- ;
- if (base_depth <= 0)
- die("too many ../'s in path %s", dir);
- copy_segments(path, base_dir, base_depth + 1);
- if (strlen(path) + strlen(dir) + 2 > MAX_DIR_LEN)
- die("path %s too long", dir);
- strlcat(path, "/", sizeof(path));
- strlcat(path, dir, sizeof(path));
- absolute = path;
- }
-
- /* Find the first point of difference between absolute and current_dir.
- If there is no difference, we're done; we're changing to the same
- directory we were in (this is probably some sort of error, but can
- happen with odd relative paths). */
- for (p = absolute, q = current_dir; *p == *q; p++, q++)
- if (*p == '\0')
- return true;
-
- /* If we reached the end of current_dir and there's more left of
- absolute, we're changing to a subdirectory of where we were. */
- if (*q == '\0' && *p == '/') {
- p++;
- if (!chdir_checked(p, filecount))
- return false;
- if (prefix_len == 0)
- strlcpy(current_dir, absolute, sizeof(current_dir));
- return true;
- }
-
- /* Otherwise, if we were promised that we have a pure tree (in other
- words, no symbolic links to directories), see if it's worth going up
- the tree with ".." and then down again rather than chdir to the
- absolute path. relative_threshold determines how many levels of ".."
- we're willing to use; the default of 1 seems fractionally faster than
- 2 and 0 indicates to always use absolute paths. Values larger than 3
- would require extending the dotdots string, but are unlikely to be
- worth it.
-
- FIXME: It's too hard to figure out what this code does. It needs to be
- rewritten. */
- if (p != '\0' && relative_threshold > 0) {
- depth = slashcount(q);
- if (depth <= relative_threshold) {
- while (p > absolute && *--p != '/')
- ;
- p++;
- strlcpy(prefix_dir, dotdots + 9 - depth * 3, sizeof(prefix_dir));
- strlcat(prefix_dir, p, sizeof(prefix_dir));
- if (!chdir_checked(prefix_dir, filecount))
- return false;
-
- /* Now patch up current_dir to reflect where we are. */
- if (prefix_len == 0) {
- while (q > current_dir && *--q != '/')
- ;
- q[1] = '\0';
- strlcat(current_dir, p, sizeof(current_dir));
- }
- return true;
- }
- }
-
- /* All else has failed; just use the absolute path. This includes the
- case where current_dir is a subdirectory of absolute, in which case
- it may be somewhat faster to use chdir("../..") or the like rather
- than the absolute path, but this case rarely happens when the user
- cares about speed (it usually doesn't happen with sorted input). So
- we don't bother. */
- if (!chdir_checked(absolute, filecount))
- return false;
- if (prefix_len == 0)
- strlcpy(current_dir, absolute, sizeof(current_dir));
- return true;
-}
-
-
-/*
-** Process a filelist of files to be deleted, all in the same directory.
-*/
-static void
-unlink_filelist(filelist *list, int filecount)
-{
- bool sorted;
- DIR *dir;
- struct dirent *entry;
- char *file;
- int i;
-
- /* If setup_dir returns false, the directory doesn't exist and we're
- already all done. */
- if (!setup_dir(list->dir, filecount)) {
- filelist_free(list);
- return;
- }
-
- /* We'll use prefix_dir as a buffer to write each file name into as we
- go, so get it set up. */
- if (prefix_len == 0)
- file = prefix_dir;
- else {
- prefix_dir[prefix_len++] = '/';
- file = prefix_dir + prefix_len;
- *file = '\0';
- }
-
- /* If we're not sorting directories or if the number of files is under
- the threshold, just remove the files. */
- if (sort_threshold == 0 || filecount < sort_threshold) {
- for (i = 0; i < list->count; i++) {
- strlcpy(file, list->files[i], sizeof(prefix_dir) - prefix_len);
- unlink_file(prefix_dir);
- }
- filelist_free(list);
- return;
- }
-
- /* We have enough files to remove in this directory that it's worth
- optimizing. First, make sure the list of files is sorted. It's not
- uncommon for the files to already be sorted, so check first. */
- for (sorted = true, i = 1; sorted && i < list->count; i++)
- sorted = (strcmp(list->files[i - 1], list->files[i]) <= 0);
- if (!sorted)
- qsort(list->files, list->count, sizeof(char *), file_compare);
-
- /* Now, begin doing our optimized unlinks. The technique we use is to
- open the directory containing the files and read through it, checking
- each file in the directory to see if it's one of the files we should
- be removing. The theory is that we want to minimize the amount of
- time the operating system spends doing string compares trying to find
- the file to be removed in the directory. This is often an O(n)
- operation. Note that this optimization may slightly slow more
- effecient operating systems. */
- dir = opendir(prefix_len == 0 ? "." : prefix_dir);
- if (dir == NULL) {
- if (prefix_len > 0 && prefix_dir[0] == '/')
- warn("can't open directory %s", prefix_dir);
- else
- warn("can't open directory %s in %s",
- (prefix_len == 0) ? "." : prefix_dir, current_dir);
- error_count++;
- filelist_free(list);
- return;
- }
- for (i = 0, entry = readdir(dir); entry != NULL; entry = readdir(dir))
- if (filelist_lookup(list, entry->d_name) != NULL) {
- i++;
- strlcpy(file, entry->d_name, sizeof(prefix_dir) - prefix_len);
- unlink_file(prefix_dir);
- if (i == list->count)
- break;
- }
- closedir(dir);
- filelist_free(list);
-}
-
-
-/*
-** Check a path to see if it's okay (not likely to confuse us). This
-** ensures that it doesn't contain elements like "./" or "../" and doesn't
-** contain doubled slashes.
-*/
-static bool
-bad_path(const char *p)
-{
- if (strlen(p) >= MAX_DIR_LEN)
- return true;
- while (*p) {
- if (p[0] == '.' && (p[1] == '/' || (p[1] == '.' && p[2] == '/')))
- return true;
- while (*p && *p != '/')
- p++;
- if (p[0] == '/' && p[1] == '/')
- return true;
- if (*p == '/')
- p++;
- }
- return false;
-}
-
-
-/*
-** Main routine. Parse options, initialize the storage manager, and
-** initalize various global variables, and then go into a loop calling
-** process_line and unlink_filelist as needed.
-*/
-int
-main(int argc, char *argv[])
-{
- const char *name;
- char *p, **arg;
- QIOSTATE *qp;
- filelist *list;
- int filecount, deleted;
- bool empty_error = false;
-
- /* Establish our identity. Since we use the storage manager, we need to
- set up syslog as well, although we won't use it ourselves. */
- name = argv[0];
- if (*name == '\0')
- name = "fastrm";
- else {
- p = strrchr(name, '/');
- if (p != NULL)
- name = p + 1;
- }
- message_program_name = name;
- openlog(name, LOG_CONS | LOG_PID, LOG_INN_PROG);
-
- /* If we're running as root, unlink may remove directories. */
- unlink_dangerous = (geteuid() == 0);
-
- /* Unfortunately, we can't use getopt, because several of our options
- take optional arguments. Bleh. */
- arg = argv + 1;
- while (argc >= 2 && **arg == '-') {
- p = *arg;
- while (*++p) {
- switch (*p) {
- default:
- die("invalid option -- %c", *p);
- case 'a':
- case 'r':
- continue;
- case 'c':
- chdir_threshold = 1;
- if (!CTYPE(isdigit, p[1]))
- continue;
- chdir_threshold = atoi(p + 1);
- break;
- case 'd':
- debug_only = true;
- continue;
- case 'e':
- empty_error = true;
- continue;
- case 's':
- sort_threshold = 5;
- if (!CTYPE(isdigit, p[1]))
- continue;
- sort_threshold = atoi(p + 1);
- break;
- case 'u':
- relative_threshold = 1;
- if (!CTYPE(isdigit, p[1]))
- continue;
- relative_threshold = atoi(p + 1);
- if (relative_threshold >= (int) strlen(dotdots) / 3)
- relative_threshold = strlen(dotdots) / 3 - 1;
- break;
- }
- break;
- }
- argc--;
- arg++;
- }
- if (argc != 2)
- die("usage error, wrong number of arguments");
-
- /* The remaining argument is the base path. Make sure it's valid and
- not excessively large and then change to it. */
- base_dir = *arg;
- if (*base_dir != '/' || bad_path(base_dir))
- die("bad base path %s", base_dir);
- strlcpy(current_dir, base_dir, sizeof(current_dir));
- if (chdir(current_dir) < 0)
- sysdie("can't chdir to base path %s", current_dir);
-
- /* Open our input stream and then loop through it, building filelists
- and processing them until done. */
- qp = QIOfdopen(fileno(stdin));
- if (qp == NULL)
- sysdie("can't reopen stdin");
- while ((list = process_line(qp, &filecount, &deleted)) != NULL) {
- empty_error = false;
- unlink_filelist(list, filecount);
- }
- if (deleted > 0)
- empty_error = false;
-
- /* All done. */
- SMshutdown();
- if (empty_error)
- die("no files to remove");
- exit(error_count > 0 ? 1 : 0);
-}
+++ /dev/null
-/* $Id: grephistory.c 7041 2004-12-19 08:33:49Z rra $
-**
-** Get data from history database.
-*/
-
-#include "clibrary.h"
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-/*
-** Read stdin for list of Message-ID's, output list of ones we
-** don't have. Or, output list of files for ones we DO have.
-*/
-static void
-IhaveSendme(struct history *h, char What)
-{
- char *p;
- char *q;
- char buff[BUFSIZ];
-
- while (fgets(buff, sizeof buff, stdin) != NULL) {
- time_t arrived, posted, expires;
- TOKEN token;
-
- for (p = buff; ISWHITE(*p); p++)
- ;
- if (*p != '<')
- continue;
- for (q = p; *q && *q != '>' && !ISWHITE(*q); q++)
- ;
- if (*q != '>')
- continue;
- *++q = '\0';
-
- if (!HIScheck(h, p)) {
- if (What == 'i')
- printf("%s\n", p);
- continue;
- }
-
- /* Ihave -- say if we want it, and continue. */
- if (What == 'i') {
- continue;
- }
-
- if (HISlookup(h, p, &arrived, &posted, &expires, &token))
- printf("%s\n", TokenToText(token));
- }
-}
-
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: grephistory [flags] MessageID\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- int i;
- const char *History;
- char *key;
- char What;
- struct history *history;
- time_t arrived, posted, expires;
- TOKEN token;
- unsigned int Verbosity = 0;
-
- /* First thing, set up logging and our identity. */
- openlog("grephistory", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "grephistory";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
-
- History = concatpath(innconf->pathdb, _PATH_HISTORY);
-
- What = '?';
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "vf:eilnqs")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'v':
- Verbosity++;
- break;
- case 'f':
- History = optarg;
- break;
- case 'e':
- case 'i':
- case 'l':
- case 'n':
- case 'q':
- case 's':
- if (What != '?') {
- die("only one [eilnqs] flag allowed");
- }
- What = (char)i;
- break;
- }
- ac -= optind;
- av += optind;
-
- history = HISopen(History, innconf->hismethod, HIS_RDONLY);
- if (history == NULL)
- die("cannot open history");
-
- /* Set operating mode. */
- switch (What) {
- case '?':
- What = 'n';
- break;
- case 'i':
- case 's':
- IhaveSendme(history, What);
- HISclose(history);
- exit(0);
- /* NOTREACHED */
- }
-
- /* All modes other than -i -l want a Message-ID. */
- if (ac != 1)
- Usage();
-
- key = av[0];
- if (*key == '[') {
- warn("accessing history by hash isn't supported");
- HISclose(history);
- exit(1);
- } else {
- /* Add optional braces if not already present. */
- if (*key != '<')
- key = concat("<", key, ">", (char *) 0);
- }
-
- if (!HIScheck(history, key)) {
- if (What == 'n') {
- if (Verbosity > 0)
- die("not found (hash is %s)", HashToText(HashMessageID(key)));
- else
- die("not found");
- }
- }
- else if (What != 'q') {
- if (HISlookup(history, key, &arrived, &posted, &expires, &token)) {
- if (What == 'l') {
- printf("[]\t%ld~-~%ld\t%s\n", (long)arrived, (long)posted,
- TokenToText(token));
- }
- else {
- if (Verbosity > 0)
- printf("%s (hash is %s)\n", TokenToText(token),
- HashToText(HashMessageID(key)));
- else
- printf("%s\n", TokenToText(token));
- }
- }
- else if (What == 'n')
- printf("/dev/null\n");
- }
- HISclose(history);
- return 0;
-}
+++ /dev/null
-/* $Id: makedbz.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Rebuild dbz file for history db.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <pwd.h>
-#include <syslog.h>
-
-#include "dbz.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-/* FIXME: once we figure out how to integrate this stuff with the
- * history API this external visibility of internal voodoo should
- * go */
-#define HIS_FIELDSEP '\t'
-
-char *TextFile = NULL;
-char *HistoryDir = NULL;
-char *HISTORY = NULL;
-
-/*
-** Remove the DBZ files for the specified base text file.
-*/
-static void
-RemoveDBZFiles(char *p)
-{
- char buff[SMBUF];
-
- snprintf(buff, sizeof(buff), "%s.dir", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#ifdef DO_TAGGED_HASH
- snprintf(buff, sizeof(buff), "%s.pag", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#else
- snprintf(buff, sizeof(buff), "%s.index", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
- snprintf(buff, sizeof(buff), "%s.hash", p);
- if (unlink(buff) && errno != ENOENT)
- syswarn("cannot unlink %s", buff);
-#endif
-}
-
-
-/*
-** Count lines in the history text. A long-winded way of saying "wc -l"
-*/
-static off_t
-Countlines(void)
-{
- QIOSTATE *qp;
- off_t count;
-
- /* Open the text file. */
- qp = QIOopen(TextFile);
- if (qp == NULL)
- sysdie("cannot open %s", TextFile);
-
- /* Loop through all lines in the text file. */
- count = 0;
- for (; QIOread(qp) != NULL;)
- count++;
- if (QIOerror(qp))
- sysdie("cannot read %s near line %lu", TextFile,
- (unsigned long) count);
- if (QIOtoolong(qp))
- sysdie("line %lu of %s is too long", (unsigned long) count,
- TextFile);
-
- QIOclose(qp);
- return count;
-}
-
-
-/*
-** Rebuild the DBZ file from the text file.
-*/
-static void
-Rebuild(off_t size, bool IgnoreOld, bool Overwrite)
-{
- QIOSTATE *qp;
- char *p;
- char *save;
- off_t count;
- off_t where;
- HASH key;
- char temp[SMBUF];
- dbzoptions opt;
-
- if (chdir(HistoryDir) < 0)
- sysdie("cannot chdir to %s", HistoryDir);
-
- /* If we are ignoring the old database and the user didn't specify a table
- size, determine one ourselves from the size of the text history file.
- Note that this will still use the defaults in dbz if the text file is
- empty, since size will still be left set to 0. */
- if (IgnoreOld == true && size == 0) {
- size = Countlines();
- size += (size / 10);
- if (size > 0)
- warn("no size specified, using %ld", (unsigned long) size);
- }
-
- /* Open the text file. */
- qp = QIOopen(TextFile);
- if (qp == NULL)
- sysdie("cannot open %s", TextFile);
-
- /* If using the standard history file, force DBZ to use history.n. */
- if (strcmp(TextFile, HISTORY) == 0 && !Overwrite) {
- snprintf(temp, sizeof(temp), "%s.n", HISTORY);
- if (link(HISTORY, temp) < 0)
- sysdie("cannot create temporary link to %s", temp);
- RemoveDBZFiles(temp);
- p = temp;
- }
- else {
- temp[0] = '\0';
- /*
- ** only do removedbz files if a. we're using something besides
- ** $pathdb/history, or b. we're ignoring the old db.
- */
- if (strcmp(TextFile, HISTORY) != 0 || IgnoreOld)
- RemoveDBZFiles(TextFile);
- p = TextFile;
- }
-
- /* Open the new database, using the old file if desired and possible. */
- dbzgetoptions(&opt);
- opt.pag_incore = INCORE_MEM;
-#ifndef DO_TAGGED_HASH
- opt.exists_incore = INCORE_MEM;
-#endif
- dbzsetoptions(opt);
- if (IgnoreOld) {
- if (!dbzfresh(p, dbzsize(size))) {
- syswarn("cannot do dbzfresh");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- }
- else {
- if (!dbzagain(p, HISTORY)) {
- syswarn("cannot do dbzagain");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- }
-
- /* Loop through all lines in the text file. */
- count = 0;
- for (where = QIOtell(qp); (p = QIOread(qp)) != NULL; where = QIOtell(qp)) {
- count++;
- if ((save = strchr(p, HIS_FIELDSEP)) == NULL) {
- warn("bad line #%lu: %.40s", (unsigned long) count, p);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- *save = '\0';
- switch (*p) {
- case '[':
- if (strlen(p) != ((sizeof(HASH) * 2) + 2)) {
- warn("invalid length for hash %s, skipping", p);
- continue;
- }
- key = TextToHash(p+1);
- break;
- default:
- warn("invalid message ID %s in history text", p);
- continue;
- }
- switch (dbzstore(key, where)) {
- case DBZSTORE_EXISTS:
- warn("duplicate message ID %s in history text", p);
- break;
- case DBZSTORE_ERROR:
- syswarn("cannot store %s", p);
- if (temp[0])
- unlink(temp);
- exit(1);
- default:
- break;
- }
- }
- if (QIOerror(qp)) {
- syswarn("cannot read %s near line %lu", TextFile,
- (unsigned long) count);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
- if (QIOtoolong(qp)) {
- warn("line %lu is too long", (unsigned long) count);
- if (temp[0])
- unlink(temp);
- exit(1);
- }
-
- /* Close files. */
- QIOclose(qp);
- if (!dbzclose()) {
- syswarn("cannot close history");
- if (temp[0])
- unlink(temp);
- exit(1);
- }
-
- if (temp[0])
- unlink(temp);
-}
-
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: makedbz [-f histfile] [-s numlines] [-i] [-o]\n");
- exit(1);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may create new database files, so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-int
-main(int argc, char **argv)
-{
- bool Overwrite;
- bool IgnoreOld;
- off_t size = 0;
- int i;
- char *p;
-
- /* First thing, set up logging and our identity. */
- openlog("makedbz", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "makedbz";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- TextFile = concatpath(innconf->pathdb, _PATH_HISTORY);
- HISTORY = concatpath(innconf->pathdb, _PATH_HISTORY);
- HistoryDir = innconf->pathdb;
- IgnoreOld = false;
- Overwrite = false;
-
- while ((i = getopt(argc, argv, "s:iof:")) != EOF) {
- switch (i) {
- default:
- Usage();
- case 'f':
- TextFile = optarg;
- break;
- case 's':
- size = atol(optarg);
- IgnoreOld = true;
- break;
- case 'o':
- Overwrite = true;
- break;
- case 'i':
- IgnoreOld = true;
- break;
- }
- }
-
- argc -= optind;
- argv += optind;
- if (argc) {
- Usage();
- }
-
- if ((p = strrchr(TextFile, '/')) == NULL) {
- /* find the default history file directory */
- HistoryDir = innconf->pathdb;
- } else {
- *p = '\0';
- HistoryDir = xstrdup(TextFile);
- *p = '/';
- }
-
- if (chdir(HistoryDir) < 0)
- sysdie("cannot chdir to %s", HistoryDir);
-
- /* Change users if necessary. */
- setuid_news();
-
- Rebuild(size, IgnoreOld, Overwrite);
- closelog();
- exit(0);
-}
+++ /dev/null
-/* $Id: makehistory.c 7468 2005-12-12 03:23:21Z eagle $
-**
-** Rebuild history/overview databases.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-#include <assert.h>
-#include <errno.h>
-#include <pwd.h>
-#include <syslog.h>
-
-#include "inn/buffer.h"
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-#include "storage.h"
-
-static const char usage[] = "\
-Usage: makehistory [-bOIax] [-f file] [-l count] [-s size] [-T tmpdir]\n\
-\n\
- -b delete bad articles from spool\n\
- -e read entire articles to compute proper byte count\n\
- -f write history entries to file (default $pathdb/history)\n\
- -s size size new history database for approximately size entries\n\
- -a open output history file in append mode\n\
- -O create overview entries for articles\n\
- -I do not create overview for articles numbered below lowmark\n\
- -l count size of overview updates (default 10000)\n\
- -x don't write history entries\n\
- -T tmpdir use directory tmpdir for temporary files\n\
- -F fork when writing overview\n";
-
-
-/*
-** Information about the schema of the news overview files.
-*/
-typedef struct _ARTOVERFIELD {
- char *Headername;
- int HeadernameLength;
- bool NeedHeadername;
- const char *Header;
- int HeaderLength;
- bool HasHeader;
-} ARTOVERFIELD;
-
-#define DEFAULT_SEGSIZE 10000;
-
-bool NukeBadArts;
-char *SchemaPath = NULL;
-char *ActivePath = NULL;
-char *HistoryPath = NULL;
-struct history *History;
-FILE *Overchan;
-bool DoOverview;
-bool Fork;
-bool Cutofflow = false;
-char *TmpDir;
-int OverTmpSegSize, OverTmpSegCount;
-FILE *OverTmpFile;
-char *OverTmpPath = NULL;
-bool NoHistory;
-OVSORTTYPE sorttype;
-int RetrMode;
-
-TIMEINFO Now;
-
-/* Misc variables needed for the overview creation code. */
-static char MESSAGEID[] = "Message-ID";
-static char EXPIRES[] = "Expires";
-static char DATE[] = "Date";
-static char XREF[] = "Xref";
-static ARTOVERFIELD *ARTfields; /* overview fields listed in overview.fmt */
-static size_t ARTfieldsize;
-static ARTOVERFIELD *Datep = (ARTOVERFIELD *)NULL;
-static ARTOVERFIELD *Msgidp = (ARTOVERFIELD *)NULL;
-static ARTOVERFIELD *Expp = (ARTOVERFIELD *)NULL;
-static ARTOVERFIELD *Xrefp = (ARTOVERFIELD *)NULL;
-static ARTOVERFIELD *Missfields; /* header fields not listed in
- overview.fmt, but ones that we need
- (e.g. message-id */
-static size_t Missfieldsize = 0;
-
-static void OverAddAllNewsgroups(void);
-
-/*
-** Check and parse an date header line. Return the new value or
-** zero on error.
-*/
-static long
-GetaDate(char *p)
-{
- time_t t;
-
- while (ISWHITE(*p))
- p++;
- if ((t = parsedate(p, &Now)) == -1)
- return 0L;
- return (long)t;
-}
-
-/*
-** Check and parse a Message-ID header line. Return private space.
-*/
-static const char *
-GetMessageID(char *p)
-{
- static struct buffer buffer = { 0, 0, 0, NULL };
-
- while (ISWHITE(*p))
- p++;
- if (p[0] != '<' || p[strlen(p) - 1] != '>')
- return "";
-
- /* Copy into re-used memory space, including NUL. */
- buffer_set(&buffer, p, strlen(p)+1);
- return buffer.data;
-}
-
-/*
- * The overview temp file is used to accumulate overview lines as articles are
- * scanned. The format is
- * (1st) newsgroup name\tToken\toverview data.
- * When about 10000 lines of this overview data are accumulated, the data
- * file is sorted and then read back in and the data added to overview.
- * The sorting/batching helps improve efficiency.
- */
-
-/*
- * Flush the unwritten OverTempFile data to disk, sort the file, read it
- * back in, and add it to overview.
- */
-
-static void
-FlushOverTmpFile(void)
-{
- char temp[SMBUF];
- char *SortedTmpPath;
- int i, pid, fd;
- TOKEN token;
- QIOSTATE *qp;
- int count;
- char *line, *p;
- char *q = NULL;
- char *r = NULL;
- time_t arrived, expires;
- static int first = 1;
-
- if (OverTmpFile == NULL)
- return;
- if (fflush(OverTmpFile) == EOF || ferror(OverTmpFile) || fclose(OverTmpFile) == EOF)
- sysdie("cannot close temporary overview file");
- if(Fork) {
- if(!first) { /* if previous one is running, wait for it */
- int status;
- wait(&status);
- if((WIFEXITED(status) && WEXITSTATUS(status) != 0)
- || WIFSIGNALED(status))
- exit(1);
- }
-
- pid = fork();
- if(pid == -1)
- sysdie("cannot fork");
- if(pid > 0) {
- /* parent */
- first = 0;
- free(OverTmpPath);
- OverTmpPath = NULL;
- return;
- }
-
- /* child */
- /* init the overview setup. */
- if (!OVopen(OV_WRITE)) {
- warn("cannot open overview");
- _exit(1);
- }
- if (!OVctl(OVSORT, (void *)&sorttype)) {
- warn("cannot obtain overview sorting information");
- OVclose();
- _exit(1);
- }
- if (!OVctl(OVCUTOFFLOW, (void *)&Cutofflow)) {
- warn("cannot obtain overview cutoff information");
- OVclose();
- _exit(1);
- }
- }
-
- /* This is a bit odd, but as long as other user's files can't be deleted
- out of the temporary directory, it should work. We're using mkstemp to
- create a file and then passing its name to sort, which will then open
- it again and overwrite it. */
- SortedTmpPath = concatpath(TmpDir, "hisTXXXXXX");
- fd = mkstemp(SortedTmpPath);
- if (fd < 0) {
- syswarn("cannot create temporary file");
- OVclose();
- Fork ? _exit(1) : exit(1);
- }
- close(fd);
- snprintf(temp, sizeof(temp), "exec %s -T %s -t'%c' -o %s %s", _PATH_SORT,
- TmpDir, '\t', SortedTmpPath, OverTmpPath);
-
- i = system(temp) >> 8;
- if (i != 0) {
- syswarn("cannot sort temporary overview file (%s exited %d)",
- _PATH_SORT, i);
- OVclose();
- Fork ? _exit(1) : exit(1);
- }
-
- /* don't need old path anymore. */
- unlink(OverTmpPath);
- free(OverTmpPath);
- OverTmpPath = NULL;
-
- /* read sorted lines. */
- if ((qp = QIOopen(SortedTmpPath)) == NULL) {
- syswarn("cannot open sorted overview file %s", SortedTmpPath);
- OVclose();
- Fork ? _exit(1) : exit(1);
- }
-
- for (count = 1; ; ++count) {
- line = QIOread(qp);
- if (line == NULL) {
- if (QIOtoolong(qp)) {
- warn("overview line %d is too long", count);
- continue;
- } else
- break;
- }
- if ((p = strchr(line, '\t')) == NULL
- || (q = strchr(p+1, '\t')) == NULL
- || (r = strchr(q+1, '\t')) == NULL) {
- warn("sorted overview file %s has a bad line at %d",
- SortedTmpPath, count);
- continue;
- }
- /* p+1 now points to start of token, q+1 points to start of overline. */
- if (sorttype == OVNEWSGROUP) {
- *p++ = '\0';
- *q++ = '\0';
- *r++ = '\0';
- arrived = (time_t)atol(p);
- expires = (time_t)atol(q);
- q = r;
- if ((r = strchr(r, '\t')) == NULL) {
- warn("sorted overview file %s has a bad line at %d",
- SortedTmpPath, count);
- continue;
- }
- *r++ = '\0';
- } else {
- *p++ = '\0';
- *q++ = '\0';
- *r++ = '\0';
- arrived = (time_t)atol(line);
- expires = (time_t)atol(p);
- }
- token = TextToToken(q);
- if (OVadd(token, r, strlen(r), arrived, expires) == OVADDFAILED) {
- if (OVctl(OVSPACE, (void *)&i) && i == OV_NOSPACE) {
- warn("no space left for overview");
- OVclose();
- Fork ? _exit(1) : exit(1);
- }
- warn("cannot write overview data \"%.40s\"", q);
- }
- }
- /* Check for errors and close. */
- if (QIOerror(qp)) {
- syswarn("cannot read sorted overview file %s", SortedTmpPath);
- OVclose();
- Fork ? _exit(1) : exit(1);
- }
- QIOclose(qp);
- /* unlink sorted tmp file */
- unlink(SortedTmpPath);
- free(SortedTmpPath);
- if(Fork) {
- OVclose();
- _exit(0);
- }
-}
-
-
-/*
- * Write a line to the overview temp file.
- */
-static void
-WriteOverLine(TOKEN *token, const char *xrefs, int xrefslen,
- char *overdata, int overlen, time_t arrived, time_t expires)
-{
- char temp[SMBUF];
- const char *p, *q, *r;
- int i, fd;
-
- if (sorttype == OVNOSORT) {
- if (Fork) {
- fprintf(Overchan, "%s %ld %ld ", TokenToText(*token), (long)arrived, (long)expires);
- if (fwrite(overdata, 1, overlen, Overchan) != (size_t) overlen)
- sysdie("writing overview failed");
- fputc('\n', Overchan);
- } else if (OVadd(*token, overdata, overlen, arrived, expires) == OVADDFAILED) {
- if (OVctl(OVSPACE, (void *)&i) && i == OV_NOSPACE) {
- warn("no space left for overview");
- OVclose();
- exit(1);
- }
- warn("cannot write overview data for article %s",
- TokenToText(*token));
- }
- return;
- }
- if (OverTmpPath == NULL) {
- /* need new temp file, so create it. */
- OverTmpPath = concatpath(TmpDir, "histXXXXXX");
- fd = mkstemp(OverTmpPath);
- if (fd < 0)
- sysdie("cannot create temporary file");
- OverTmpFile = fdopen(fd, "w");
- if (OverTmpFile == NULL)
- sysdie("cannot open %s", OverTmpPath);
- OverTmpSegCount = 0;
- }
- if (sorttype == OVNEWSGROUP) {
- /* find first ng name in xref. */
- for (p = xrefs, q=NULL ; p < xrefs+xrefslen ; ++p) {
- if (*p == ' ') {
- q = p+1; /* found space */
- break;
- }
- }
- if (!q) {
- warn("bogus Xref data for %s", TokenToText(*token));
- /* XXX do nuke here? */
- return;
- }
-
- for (p = q, r=NULL ; p < xrefs+xrefslen ; ++p) {
- if (*p == ':') {
- r=p;
- break;
- }
- }
- if (!r) {
- warn("bogus Xref data for %s", TokenToText(*token));
- /* XXX do nuke here? */
- return;
- }
- /* q points to start of ng name, r points to its end. */
- assert(sizeof(temp) > r - q + 1);
- memcpy(temp, q, r - q + 1);
- temp[r - q + 1] = '\0';
- fprintf(OverTmpFile, "%s\t%10lu\t%lu\t%s\t", temp,
- (unsigned long) arrived, (unsigned long) expires,
- TokenToText(*token));
- } else
- fprintf(OverTmpFile, "%10lu\t%lu\t%s\t", (unsigned long) arrived,
- (unsigned long) expires,
- TokenToText(*token));
-
- fwrite(overdata, overlen, 1, OverTmpFile);
- fprintf(OverTmpFile, "\n");
- OverTmpSegCount++;
-
- if (OverTmpSegSize != 0 && OverTmpSegCount >= OverTmpSegSize) {
- FlushOverTmpFile();
- }
-}
-
-
-/*
-** Read the overview schema.
-*/
-static void
-ARTreadschema(bool Overview)
-{
- FILE *F;
- char *p;
- ARTOVERFIELD *fp;
- int i;
- char buff[SMBUF];
- bool foundxreffull = false;
-
- if (Overview) {
- /* Open file, count lines. */
- if ((F = fopen(SchemaPath, "r")) == NULL)
- sysdie("cannot open %s", SchemaPath);
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
- fseeko(F, 0, SEEK_SET);
- ARTfields = xmalloc((i + 1) * sizeof(ARTOVERFIELD));
-
- /* Parse each field. */
- for (fp = ARTfields; fgets(buff, sizeof buff, F) != NULL; ) {
- /* Ignore blank and comment lines. */
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '#')) != NULL)
- *p = '\0';
- if (buff[0] == '\0')
- continue;
- if ((p = strchr(buff, ':')) != NULL) {
- *p++ = '\0';
- fp->NeedHeadername = (strcmp(p, "full") == 0);
- }
- else
- fp->NeedHeadername = false;
- fp->Headername = xstrdup(buff);
- fp->HeadernameLength = strlen(buff);
- fp->Header = (char *)NULL;
- fp->HasHeader = false;
- fp->HeaderLength = 0;
- if (strncasecmp(buff, DATE, strlen(DATE)) == 0)
- Datep = fp;
- if (strncasecmp(buff, MESSAGEID, strlen(MESSAGEID)) == 0)
- Msgidp = fp;
- if (strncasecmp(buff, EXPIRES, strlen(EXPIRES)) == 0)
- Expp = fp;
- if (strncasecmp(buff, XREF, strlen(XREF)) == 0) {
- Xrefp = fp;
- foundxreffull = fp->NeedHeadername;
- }
- fp++;
- }
- ARTfieldsize = fp - ARTfields;
- fclose(F);
- }
- if (Msgidp == (ARTOVERFIELD *)NULL)
- Missfieldsize++;
- if (Datep == (ARTOVERFIELD *)NULL)
- Missfieldsize++;
- if (Expp == (ARTOVERFIELD *)NULL)
- Missfieldsize++;
- if (Overview && (Xrefp == (ARTOVERFIELD *)NULL || !foundxreffull))
- die("Xref:full must be included in %s", SchemaPath);
- if (Missfieldsize > 0) {
- Missfields = xmalloc(Missfieldsize * sizeof(ARTOVERFIELD));
- fp = Missfields;
- if (Msgidp == (ARTOVERFIELD *)NULL) {
- fp->NeedHeadername = false;
- fp->Headername = xstrdup(MESSAGEID);
- fp->HeadernameLength = strlen(MESSAGEID);
- fp->Header = (char *)NULL;
- fp->HasHeader = false;
- fp->HeaderLength = 0;
- Msgidp = fp++;
- }
- if (Datep == (ARTOVERFIELD *)NULL) {
- fp->NeedHeadername = false;
- fp->Headername = xstrdup(DATE);
- fp->HeadernameLength = strlen(DATE);
- fp->Header = (char *)NULL;
- fp->HasHeader = false;
- fp->HeaderLength = 0;
- Datep = fp++;
- }
- if (Expp == (ARTOVERFIELD *)NULL) {
- fp->NeedHeadername = false;
- fp->Headername = xstrdup(EXPIRES);
- fp->HeadernameLength = strlen(EXPIRES);
- fp->Header = (char *)NULL;
- fp->HasHeader = false;
- fp->HeaderLength = 0;
- Expp = fp++;
- }
- if (Overview && Xrefp == (ARTOVERFIELD *)NULL) {
- fp->NeedHeadername = false;
- fp->Headername = xstrdup(XREF);
- fp->HeadernameLength = strlen(XREF);
- fp->Header = (char *)NULL;
- fp->HasHeader = false;
- fp->HeaderLength = 0;
- Xrefp = fp++;
- }
- }
-}
-
-/*
- * Handle a single article. This routine's fairly complicated.
- */
-static void
-DoArt(ARTHANDLE *art)
-{
- ARTOVERFIELD *fp;
- const char *p, *end;
- char *q;
- static struct buffer buffer = { 0, 0, 0, NULL };
- static char SEP[] = "\t";
- static char NUL[] = "\0";
- static char COLONSPACE[] = ": ";
- size_t i, j, len;
- const char *MessageID;
- time_t Arrived;
- time_t Expires;
- time_t Posted;
- char overdata[BIG_BUFFER];
- char bytes[BIG_BUFFER];
- struct artngnum ann;
-
- /* Set up place to store headers. */
- for (fp = ARTfields, i = 0; i < ARTfieldsize; i++, fp++) {
- if (fp->HeaderLength) {
- fp->Header = 0;
- }
- fp->HeaderLength = 0;
- fp->HasHeader = false;
- }
- if (Missfieldsize > 0) {
- for (fp = Missfields, i = 0; i < Missfieldsize; i++, fp++) {
- if (fp->HeaderLength) {
- fp->Header = 0;
- }
- fp->HeaderLength = 0;
- fp->HasHeader = false;
- }
- }
- for (fp = ARTfields, i = 0; i < ARTfieldsize; i++, fp++) {
- fp->Header = wire_findheader(art->data, art->len, fp->Headername);
-
- /* Someone managed to break their server so that they were appending
- multiple Xref headers, and INN had a bug where it wouldn't notice
- this and reject the article. Just in case, see if there are
- multiple Xref headers and use the last one. */
- if (fp == Xrefp) {
- const char *next = fp->Header;
- size_t left;
-
- while (next != NULL) {
- next = wire_endheader(fp->Header, art->data + art->len - 1);
- if (next == NULL)
- break;
- next++;
- left = art->len - (next - art->data);
- next = wire_findheader(next, left, fp->Headername);
- if (next != NULL)
- fp->Header = next;
- }
- }
-
- /* Now, if we have a header, find and record its length. */
- if (fp->Header != NULL) {
- fp->HasHeader = true;
- p = wire_endheader(fp->Header, art->data + art->len - 1);
- if (p == NULL)
- continue;
-
- /* The true length of the header is p - fp->Header + 1, but p
- points to the \n at the end of the header, so subtract 2 to
- peel off the \r\n (we're guaranteed we're dealing with
- wire-format articles. */
- fp->HeaderLength = p - fp->Header - 1;
- } else if (RetrMode == RETR_ALL
- && strcmp(fp->Headername, "Bytes") == 0) {
- snprintf(bytes, sizeof(bytes), "%lu", (unsigned long) art->len);
- fp->HasHeader = true;
- fp->Header = bytes;
- fp->HeaderLength = strlen(bytes);
- }
- }
- if (Missfieldsize > 0) {
- for (fp = Missfields, i = 0; i < Missfieldsize; i++, fp++) {
- fp->Header = wire_findheader(art->data, art->len, fp->Headername);
- if (fp->Header != NULL) {
- fp->HasHeader = true;
- p = wire_endheader(fp->Header, art->data + art->len - 1);
- if (p == NULL)
- continue;
- fp->HeaderLength = p - fp->Header - 1;
- }
- }
- }
- if (DoOverview && Xrefp->HeaderLength == 0) {
- if (!SMprobe(SMARTNGNUM, art->token, (void *)&ann)) {
- Xrefp->Header = NULL;
- Xrefp->HeaderLength = 0;
- } else {
- if (ann.artnum == 0 || ann.groupname == NULL)
- return;
- len = strlen(innconf->pathhost) + 1 + strlen(ann.groupname) + 1
- + 16 + 1;
- if (len > BIG_BUFFER) {
- Xrefp->Header = NULL;
- Xrefp->HeaderLength = 0;
- } else {
- snprintf(overdata, sizeof(overdata), "%s %s:%lu",
- innconf->pathhost, ann.groupname, ann.artnum);
- Xrefp->Header = overdata;
- Xrefp->HeaderLength = strlen(overdata);
- }
- if (ann.groupname != NULL)
- free(ann.groupname);
- }
- }
-
- MessageID = (char *)NULL;
- Arrived = art->arrived;
- Expires = 0;
- Posted = 0;
-
- if (!Msgidp->HasHeader) {
- warn("no Message-ID header in %s", TokenToText(*art->token));
- if (NukeBadArts)
- SMcancel(*art->token);
- return;
- }
-
- buffer_set(&buffer, Msgidp->Header, Msgidp->HeaderLength);
- buffer_append(&buffer, NUL, 1);
- for (i = 0, q = buffer.data; i < buffer.left; q++, i++)
- if (*q == '\t' || *q == '\n' || *q == '\r')
- *q = ' ';
- MessageID = GetMessageID(buffer.data);
- if (*MessageID == '\0') {
- warn("no Message-ID header in %s", TokenToText(*art->token));
- if (NukeBadArts)
- SMcancel(*art->token);
- return;
- }
-
- /*
- * check if msgid is in history if in update mode, or if article is
- * newer than start time of makehistory.
- */
-
- if (!Datep->HasHeader) {
- Posted = Arrived;
- } else {
- buffer_set(&buffer, Datep->Header, Datep->HeaderLength);
- buffer_append(&buffer, NUL, 1);
- for (i = 0, q = buffer.data; i < buffer.left; q++, i++)
- if (*q == '\t' || *q == '\n' || *q == '\r')
- *q = ' ';
- if ((Posted = GetaDate(buffer.data)) == 0)
- Posted = Arrived;
- }
-
- if (Expp->HasHeader) {
- buffer_set(&buffer, Expp->Header, Expp->HeaderLength);
- buffer_append(&buffer, NUL, 1);
- for (i = 0, q = buffer.data; i < buffer.left; q++, i++)
- if (*q == '\t' || *q == '\n' || *q == '\r')
- *q = ' ';
- Expires = GetaDate(buffer.data);
- }
-
- if (DoOverview && Xrefp->HeaderLength > 0) {
- for (fp = ARTfields, j = 0; j < ARTfieldsize; j++, fp++) {
- if (fp == ARTfields)
- buffer_set(&buffer, "", 0);
- else
- buffer_append(&buffer, SEP, strlen(SEP));
- if (fp->HeaderLength == 0)
- continue;
- if (fp->NeedHeadername) {
- buffer_append(&buffer, fp->Headername, fp->HeadernameLength);
- buffer_append(&buffer, COLONSPACE, strlen(COLONSPACE));
- }
- i = buffer.left;
- buffer_resize(&buffer, buffer.left + fp->HeaderLength);
- end = fp->Header + fp->HeaderLength - 1;
- for (p = fp->Header, q = &buffer.data[i]; p <= end; p++) {
- if (*p == '\r' && p < end && p[1] == '\n') {
- p++;
- continue;
- }
- if (*p == '\0' || *p == '\t' || *p == '\n' || *p == '\r')
- *q++ = ' ';
- else
- *q++ = *p;
- buffer.left++;
- }
- }
- WriteOverLine(art->token, Xrefp->Header, Xrefp->HeaderLength,
- buffer.data, buffer.left, Arrived, Expires);
- }
-
- if (!NoHistory) {
- bool r;
-
- r = HISwrite(History, MessageID,
- Arrived, Posted, Expires, art->token);
- if (r == false)
- sysdie("cannot write history line");
- }
-}
-
-
-/*
-** Add all groups to overview group.index. --rmt
-*/
-static void
-OverAddAllNewsgroups(void)
-{
- QIOSTATE *qp;
- int count;
- char *q,*p;
- char *line;
- ARTNUM hi, lo;
-
- if ((qp = QIOopen(ActivePath)) == NULL)
- sysdie("cannot open %s", ActivePath);
- for (count = 1; (line = QIOread(qp)) != NULL; count++) {
- if ((p = strchr(line, ' ')) == NULL) {
- warn("bad active line %d: %.40s", count, line);
- continue;
- }
- *p++ = '\0';
- hi = (ARTNUM)atol(p);
- if ((p = strchr(p, ' ')) == NULL) {
- warn("bad active line %d: %.40s", count, line);
- continue;
- }
- *p++ = '\0';
- lo = (ARTNUM)atol(p);
- if ((q = strrchr(p, ' ')) == NULL) {
- warn("bad active line %d: %.40s", count, line);
- continue;
- }
- /* q+1 points to NG flag */
- if (!OVgroupadd(line, lo, hi, q+1))
- die("cannot add %s to overview group index", line);
- }
- /* Test error conditions; QIOtoolong shouldn't happen. */
- if (QIOtoolong(qp))
- die("active file line %d is too long", count);
- if (QIOerror(qp))
- sysdie("cannot read %s around line %d", ActivePath, count);
- QIOclose(qp);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may create new database files, so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-int
-main(int argc, char **argv)
-{
- ARTHANDLE *art = NULL;
- bool AppendMode;
- int i;
- bool val;
- char *HistoryDir;
- char *p;
- char *buff;
- size_t npairs = 0;
-
- /* First thing, set up logging and our identity. */
- openlog("makehistory", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "makehistory";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- HistoryPath = concatpath(innconf->pathdb, _PATH_HISTORY);
- ActivePath = concatpath(innconf->pathdb, _PATH_ACTIVE);
- TmpDir = innconf->pathtmp;
- SchemaPath = concatpath(innconf->pathetc, _PATH_SCHEMA);
-
- OverTmpSegSize = DEFAULT_SEGSIZE;
- OverTmpSegCount = 0;
- NukeBadArts = false;
- DoOverview = false;
- Fork = false;
- AppendMode = false;
- NoHistory = false;
- RetrMode = RETR_HEAD;
-
- while ((i = getopt(argc, argv, "aebf:Il:OT:xFs:")) != EOF) {
- switch(i) {
- case 'T':
- TmpDir = optarg;
- break;
- case 'x':
- NoHistory = true;
- break;
- case 'a':
- AppendMode = true;
- break;
- case 'b':
- NukeBadArts = true;
- break;
- case 'f':
- HistoryPath = optarg;
- break;
- case 'I':
- Cutofflow = true;
- break;
- case 'l':
- OverTmpSegSize = atoi(optarg);
- break;
- case 'O':
- DoOverview = true;
- break;
- case 'F':
- Fork = true;
- break;
- case 'e':
- RetrMode = RETR_ALL;
- break;
- case 's':
- npairs = atoi(optarg);
- break;
-
- default:
- fprintf(stderr, "%s", usage);
- exit(1);
- break;
- }
- }
- argc -= optind;
- argv += optind;
- if (argc) {
- fprintf(stderr, "%s", usage);
- exit(1);
- }
-
- if ((p = strrchr(HistoryPath, '/')) == NULL) {
- /* find the default history file directory */
- HistoryDir = innconf->pathdb;
- } else {
- *p = '\0';
- HistoryDir = xstrdup(HistoryPath);
- *p = '/';
- }
-
- if (chdir(HistoryDir) < 0)
- sysdie("cannot chdir to %s", HistoryDir);
-
- /* Change users if necessary. */
- setuid_news();
-
- /* Read in the overview schema */
- ARTreadschema(DoOverview);
-
- if (DoOverview) {
- /* init the overview setup. */
- if (!OVopen(OV_WRITE))
- sysdie("cannot open overview");
- if (!OVctl(OVSORT, (void *)&sorttype))
- die("cannot obtain overview sort information");
- if (!Fork) {
- if (!OVctl(OVCUTOFFLOW, (void *)&Cutofflow))
- die("cannot obtain overview cutoff information");
- OverAddAllNewsgroups();
- } else {
- OverAddAllNewsgroups();
- if (sorttype == OVNOSORT) {
- buff = concat(innconf->pathbin, "/", "overchan", NULL);
- if ((Overchan = popen(buff, "w")) == NULL)
- sysdie("cannot fork overchan process");
- free(buff);
- }
- OVclose();
- }
- }
-
- /* Init the Storage Manager */
- val = true;
- if (!SMsetup(SM_RDWR, (void *)&val) || !SMsetup(SM_PREOPEN, (void *)&val))
- sysdie("cannot set up storage manager");
- if (!SMinit())
- sysdie("cannot initialize storage manager: %s", SMerrorstr);
-
- /* Initialise the history manager */
- if (!NoHistory) {
- int flags = HIS_RDWR | HIS_INCORE;
-
- if (!AppendMode)
- flags |= HIS_CREAT;
- History = HISopen(NULL, innconf->hismethod, flags);
- if (History == NULL)
- sysdie("cannot create history handle");
- HISctl(History, HISCTLS_NPAIRS, &npairs);
- if (!HISctl(History, HISCTLS_PATH, HistoryPath))
- sysdie("cannot open %s", HistoryPath);
- }
-
- /* Get the time. Only get it once, which is good enough. */
- if (GetTimeInfo(&Now) < 0)
- sysdie("cannot get the time");
-
- /*
- * Scan the entire spool, nuke any bad arts if needed, and process each
- * article.
- */
-
- while ((art = SMnext(art, RetrMode)) != NULL) {
- if (art->len == 0) {
- if (NukeBadArts && art->data == NULL && art->token != NULL)
- SMcancel(*art->token);
- continue;
- }
- DoArt(art);
- }
-
- if (!NoHistory) {
- /* close history file. */
- if (!HISclose(History))
- sysdie("cannot close history file");
- }
-
- if (DoOverview) {
- if (sorttype == OVNOSORT && Fork)
- if (fflush(Overchan) == EOF || ferror(Overchan) || pclose(Overchan) == EOF)
- sysdie("cannot flush overview data");
- if (sorttype != OVNOSORT) {
- int status;
- FlushOverTmpFile();
- if(Fork)
- wait(&status);
- }
- }
- if(!Fork)
- OVclose();
- exit(0);
-}
-
+++ /dev/null
-/* $Id: prunehistory.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Prune file names from history file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <syslog.h>
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-
-
-/*
-** Print usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: prunehistory [-p] [-f file] [input]\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- char *p;
- int i;
- char buff[BUFSIZ];
- const char *History;
- bool Passing;
- struct history *history = NULL;
- int rc = 0;
-
- /* First thing, set up logging and our identity. */
- openlog("prunehistory", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "prunehistory";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
-
- History = concatpath(innconf->pathdb, _PATH_HISTORY);
- Passing = false;
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "f:p")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'f':
- History = optarg;
- break;
- case 'p':
- Passing = true;
- break;
- }
- ac -= optind;
- av += optind;
- if (ac) {
- Usage();
- rc = 1;
- goto fail;
- }
-
- history = HISopen(History, innconf->hismethod, HIS_RDWR);
- if (history == NULL) {
- syswarn("cannot set up %s database", History);
- rc = 1;
- goto fail;
- }
-
- /* Loop over all input. */
- while (fgets(buff, sizeof buff, stdin) != NULL) {
- time_t arrived, posted, expires;
-
- if ((p = strchr(buff, '\n')) == NULL) {
- if (Passing)
- printf("%s\n", buff);
- else
- warn("line too long, ignored: %.40s", buff);
- continue;
- }
- *p = '\0';
-
- /* Ignore blank and comment lines. */
- if (buff[0] == '\0' || buff[0] == '#') {
- if (Passing)
- printf("%s\n", buff);
- continue;
- }
-
- if (buff[0] != '<' || (p = strchr(buff, '>')) == NULL) {
- if (Passing)
- printf("%s\n", buff);
- else
- warn("line doesn't start with a message ID, ignored: %.40s",
- buff);
- continue;
- }
- *++p = '\0';
-
- if (HISlookup(history, buff, &arrived, &posted, &expires, NULL)) {
- if (!HISreplace(history, buff, arrived, posted, expires, NULL))
- syswarn("cannot write new text for %s", buff);
- } else {
- syswarn("no entry for %s", buff);
- }
- }
-
- fail:
- /* Close files; we're done. */
- if (history != NULL && !HISclose(history)) {
- syswarn("cannot close %s", History);
- rc = 1;
- }
-
- return rc;
-}
+++ /dev/null
-control 0000000000 0000000001 n
-control.cancel 0000000000 0000000001 n
-control.checkgroups 0000000000 0000000001 n
-control.newgroup 0000000000 0000000001 n
-control.rmgroup 0000000000 0000000001 n
-junk 0000000000 0000000001 n
-local.general 0000000000 0000000001 y
-local.test 0000000000 0000000001 y
+++ /dev/null
-#!/bin/bash
-. /usr/lib/news/innshellvars
-
-cd $PATHTMP
-
-KEYSURL=ftp://ftp.isc.org/pub/pgpcontrol/PGPKEYS
-KEYSFILE=PGPKEYS
-
-KEYRING=${NEWSETC}/pgp/pubring.gpg
-
-trap "rm -f $KEYSFILE" 0 1 2 15
-
-rm -f ${KEYSFILE}
-${GETFTP} ${KEYSURL}
-
-test -f ${KEYSFILE} || exit 1
-
-gpg --batch --no-permission-warning \
- --no-default-keyring --keyring=${KEYRING} --no-options \
- --allow-non-selfsigned-uid --fast-import ${KEYSFILE}
-
-exit $$
-# this does not work because gpg refuses to use RSA-style fingerprints
-
-KEYSERVER=keyserver.linux.it
-
-SERVERKEYS=$(grep fingerprint ${CTLFILE} \
- | sed -e 's/ //g' -e 's/.*[:=]/0x/' \
- | grep -v '^#')
-
-for key in $SERVERKEYS; do
- gpg --batch --no-permission-warning --verbose \
- --no-default-keyring --keyring=${KEYRING} --no-options \
- --keyserver=${KEYSERVER} --recv-keys ${key}
-done
-
+++ /dev/null
-#!/bin/sh
-exec /bin/bzip2 -d -c
+++ /dev/null
-#!/bin/sh -e
-
-IN="$1"
-OUT="$2"
-
-for file in debian/$IN.* debian/$IN*.files; do
- case "$file" in
- *.log) continue ;;
- esac
- [ -h $file ] && continue
- base=${file##*/}
- newfile=$(echo $file | sed -re "s#/$IN#/$OUT#")
- [ -e $newfile ] || ln -s $base $newfile
-done
-
+++ /dev/null
-#!/bin/sh -e
-
-# Add this line in /etc/news/newsfeeds:
-# !inpaths:*:Tc,WP:/usr/lib/news/bin/ginpaths2
-
-exec /usr/lib/news/bin/ninpaths -p -d /var/log/news/path/inpaths.%d
+++ /dev/null
-control Various control messages (no posting)
-control.cancel Cancel messages (no posting)
-control.checkgroups Hierarchy check control messages (no posting)
-control.newgroup Newsgroup creation control messages (no posting)
-control.rmgroup Newsgroup removal control messages (no posting)
-junk Unfiled articles (no posting)
-local.general Local general group
-local.test Local test group
+++ /dev/null
-tls_cert_file: /etc/news/nnrpd-cert.pem
-tls_key_file: /etc/news/nnrpd-key.pem
-tls_ca_path: /etc/news
-tls_ca_file: /etc/news/nnrpd-ca-cert.pem
+++ /dev/null
-#
-# send-uucp.cf Configuration file for send-uucp
-#
-# Format: sitename<Space>compressor<Space>maxsize<Space>batchtime
-#
-# compressor, maxsize and batchtime can be left out and will
-# then use the # default values. You can't leave out the second
-# field (compressor) and still use the third (maxsize) etc.!
-# So if you want to set a maxsize, you HAVE to add a
-# compression method.
-#
-# Compress keywords are: compress gzip none
-#
-# You can use flags with your compressor, just add them. Use
-# the `_' character instead of a space.
-# For example compress_-b13 for 13 bits compression.
-#
-# Remember that the size you set is the size *before* compression!
-#
-#zoetermeer gzip 1048576 5,18,22
-#hoofddorp gzip 1048576 5,18,22
-#pa3ebv gzip 1048576 5,18,22
-#drinkel gzip 1048576 5,6,18,20,22,0,2
-#manhole compress 1048576 5,18,22
-#owl compress 1048576 5,18,22
-#able compress 1048576 5,18,22
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS)
-
-ALL = c7unbatch cnfsheadconf cnfsstat ctlinnd decode encode \
- getlist gunbatch inews innconfval mailpost pullnews \
- ovdb_init ovdb_monitor ovdb_server ovdb_stat rnews \
- scanspool sm
-
-SOURCES = ctlinnd.c decode.c encode.c getlist.c inews.c innconfval.c \
- ovdb_init.c ovdb_monitor.c ovdb_server.c ovdb_stat.c rnews.c \
- sm.c
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_INEWS) inews $D$(PATHBIN)/inews
- $(LI_RNEWS) rnews $D$(PATHBIN)/rnews
- $(CP_XPRI) cnfsheadconf $D$(PATHBIN)/cnfsheadconf
- for F in cnfsstat mailpost pullnews scanspool ; do \
- $(CP_XPUB) $$F $D$(PATHBIN)/$$F ; \
- done
- for F in ctlinnd ovdb_init ovdb_monitor ovdb_server ovdb_stat ; do \
- $(LI_XPRI) $$F $D$(PATHBIN)/$$F ; \
- done
- for F in getlist innconfval sm ; do \
- $(LI_XPUB) $$F $D$(PATHBIN)/$$F ; \
- done
- $(CP_XPUB) c7unbatch $D$(PATHBIN)/rnews.libexec/c7unbatch
- $(LI_XPUB) decode $D$(PATHBIN)/rnews.libexec/decode
- $(LI_XPUB) encode $D$(PATHBIN)/rnews.libexec/encode
- $(CP_XPUB) gunbatch $D$(PATHBIN)/rnews.libexec/gunbatch
-
-clean:
- rm -f *.o $(ALL)
- rm -rf .libs
-
-clobber distclean: clean
- rm -f tags
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES)
-
-profiled:
- $(MAKEPROFILING) all
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Compilation rules.
-
-BOTH = $(LIBSTORAGE) $(LIBHIST) $(LIBINN)
-
-LINK = $(LIBLD) $(LDFLAGS) -o $@
-INNLIBS = $(LIBINN) $(LIBS)
-STORELIBS = $(BOTH) $(EXTSTORAGELIBS) $(LIBS)
-
-FIX = $(FIXSCRIPT)
-
-ctlinnd: ctlinnd.o $(LIBINN) ; $(LINK) ctlinnd.o $(INNLIBS)
-decode: decode.o $(LIBINN) ; $(LINK) decode.o $(INNLIBS)
-encode: encode.o ; $(LINK) encode.o
-getlist: getlist.o $(LIBINN) ; $(LINK) getlist.o $(INNLIBS)
-inews: inews.o $(LIBINN) ; $(LINK) inews.o $(INNLIBS)
-innconfval: innconfval.o $(LIBINN) ; $(LINK) innconfval.o $(INNLIBS)
-ovdb_init: ovdb_init.o $(BOTH) ; $(LINK) ovdb_init.o $(STORELIBS)
-ovdb_monitor: ovdb_monitor.o $(BOTH) ; $(LINK) ovdb_monitor.o $(STORELIBS)
-ovdb_server: ovdb_server.o $(BOTH) ; $(LINK) ovdb_server.o $(STORELIBS)
-ovdb_stat: ovdb_stat.o $(BOTH) ; $(LINK) ovdb_stat.o $(STORELIBS)
-rnews: rnews.o $(LIBINN) ; $(LINK) rnews.o $(STORELIBS)
-sm: sm.o $(BOTH) ; $(LINK) sm.o $(STORELIBS)
-
-ovdb_init.o: ovdb_init.c
- $(CC) $(CFLAGS) $(BERKELEY_DB_CFLAGS) -c $<
-
-ovdb_monitor.o: ovdb_monitor.c
- $(CC) $(CFLAGS) $(BERKELEY_DB_CFLAGS) -c $<
-
-ovdb_server.o: ovdb_server.c
- $(CC) $(CFLAGS) $(BERKELEY_DB_CFLAGS) -c $<
-
-ovdb_stat.o: ovdb_stat.c
- $(CC) $(CFLAGS) $(BERKELEY_DB_CFLAGS) -c $<
-
-cnfsheadconf: cnfsheadconf.in $(FIX) ; $(FIX) cnfsheadconf.in
-cnfsstat: cnfsstat.in $(FIX) ; $(FIX) cnfsstat.in
-mailpost: mailpost.in $(FIX) ; $(FIX) mailpost.in
-pullnews: pullnews.in $(FIX) ; $(FIX) -i pullnews.in
-scanspool: scanspool.in $(FIX) ; $(FIX) scanspool.in
-
-c7unbatch: Makefile ../Makefile.global
- ( echo '#! $(SHELL)' ; echo 'decode | $(UNCOMPRESS)' ) > $@
- chmod 755 c7unbatch
-
-gunbatch: Makefile ../Makefile.global
- ( echo '#! $(SHELL)' ; echo 'exec $(GZIP) -d -c' ) > $@
- chmod 755 gunbatch
-
-## Not normally built.
-feedone: feedone.o $(LIBINN) ; $(LINK) feedone.o $(INNLIBS)
-sys2nf: sys2nf.o $(LIBINN) ; $(LINK) sys2nf.o $(INNLIBS)
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSTORAGE): ; (cd ../storage ; $(MAKE))
-$(LIBHIST): ; (cd ../history ; $(MAKE))
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-ctlinnd.o: ctlinnd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inndcomm.h ../include/libinn.h \
- ../include/paths.h
-decode.o: decode.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h
-encode.o: encode.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-getlist.o: getlist.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/qio.h ../include/libinn.h \
- ../include/paths.h
-inews.o: inews.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/messages.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h
-innconfval.o: innconfval.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h
-ovdb_init.o: ovdb_init.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../storage/ovdb/ovdb.h \
- ../storage/ovdb/ovdb-private.h
-ovdb_monitor.o: ovdb_monitor.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/setproctitle.h \
- ../include/config.h ../include/portable/wait.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/messages.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ../storage/ovdb/ovdb.h ../storage/ovdb/ovdb-private.h
-ovdb_server.o: ovdb_server.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h \
- ../include/portable/time.h ../include/portable/setproctitle.h \
- ../include/portable/socket.h ../include/portable/wait.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/paths.h \
- ../include/storage.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../storage/ovdb/ovdb.h \
- ../storage/ovdb/ovdb-private.h
-ovdb_stat.o: ovdb_stat.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ../include/paths.h \
- ../include/storage.h ../storage/ovdb/ovdb.h \
- ../storage/ovdb/ovdb-private.h
-rnews.o: rnews.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/wait.h ../include/config.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/messages.h \
- ../include/inn/wire.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-sm.o: sm.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/qio.h ../include/storage.h
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# $Id: cnfsheadconf.in 6727 2004-05-16 21:21:14Z rra $
-#
-# Copyright Andreas Lamrecht 1998
-# <Andreas.Lamprect@siemens.at>
-#
-# Modified by Kjetil T. Homme 1998
-# <kjetilho@ifi.uio.no>
-#
-# Modified by Robert R. Collier 1998
-# <rob@lspace.org>
-#
-# bigint support added by Duane Currie (sandman@hub.org) 1998
-#
-# cnfsheadconf is originally from cnfsstat 1999
-# <kondou@nec.co.jp>
-
-use vars qw($opt_h $opt_w);
-use Getopt::Long;
-
-# required for >32bit ints
-require 'bigint.pl';
-
-my($conffile) = "$inn::pathetc/cycbuff.conf";
-my($storageconf) = "$inn::pathetc/storage.conf";
-
-# Hex to bigint conversion routine
-# bhex(HEXSTRING) returns BIGINT (with leading + chopped off)
-#
-# In most langauge, unlimited size integers are done using string math
-# libraries usually called bigint. (Java, Perl, etc...)
-
-# Bigint's are really just strings.
-
-# Mathematics routines for bigint's:
-
-# bneg(BINT) return BINT negation
-# babs(BINT) return BINT absolute value
-# bcmp(BINT,BINT) return CODE compare numbers (undef,<0,=0,>0)
-# badd(BINT,BINT) return BINT addition
-# bsub(BINT,BINT) return BINT subtraction
-# bmul(BINT,BINT) return BINT multiplication
-# bdiv(BINT,BINT) return (BINT,BINT) division (quo,rem) just quo if scalar
-# bmod(BINT,BINT) return BINT modulus
-# bgcd(BINT,BINT) return BINT greatest common divisor
-# bnorm(BINT) return BINT normalization
-
-sub bhex {
- my $hexValue = shift;
- $hexValue =~ s/^0x//;
-
- my $integerValue = '0';
- for (my $i = 0; $i < length($hexValue); $i+=2) {
- # Could be more efficient going at larger increments, but byte
- # by byte is safer for the case of 9 byte values, 11 bytes, etc..
-
- my $byte = substr($hexValue,$i,2);
- my $byteIntValue = hex($byte);
-
- $integerValue = bmul($integerValue,'256');
- $integerValue = badd($integerValue,"$byteIntValue");
- }
-
- $integerValue =~ s/^\+//;
- return $integerValue;
- }
-
-sub bint2hex {
- my $d = shift;
- my $o = 0;
-
- while ($d > 0) {
- my $h = bmod("$d",'16');
- $d = bdiv("$d",'16');
- $h =~ s/^\+//;
- $h='a' if $h eq '10';
- $h='b' if $h eq '11';
- $h='c' if $h eq '12';
- $h='d' if $h eq '13';
- $h='e' if $h eq '14';
- $h='f' if $h eq '15';
- $h =~ s/^\+//;
- $o="$h$o";
- }
-
- return "$o";
-}
-
-sub usage {
- print <<_end_;
-Summary tool for cycbuff header manipulation
-
-Usage:
- $0 [-c CYCBUFF] [-h] [-w]
-
- If called without args, does a one-time status of all CNFS buffers
- -c <cycbuff>: prints out status of cycbuff
- -w: change header
- -h: This information
-_end_
- exit(1);
-}
-
-my(@line, %class, %metamode, %buff, %stor, $c, @buffers, $cycbuff);
-
-my($gr, $cl, $min, $max, @storsort, $header_printed);
-
-GetOptions("-c=s", \$cycbuff, "-w", "-h");
-
-&usage if $opt_h;
-
-unless (&read_cycbuffconf) {
- print STDERR "Cannot open CycBuff Conffile $conffile ...\n";
- exit (1);
-}
-
-unless (&read_storageconf) {
- print STDERR "No valid $storageconf.\n";
- exit (1);
-}
-
-sub read_cycbuffconf {
- return 0 unless open (CONFFILE, $conffile);
-
- while(<CONFFILE>) {
- $_ =~ s/^\s*(.*?)\s*$/$1/;
- # \x23 below is #. Emacs perl-mode gets confused by the "comment"
- next if($_ =~ /^\s*$/ || $_ =~ /^\x23/);
- next if($_ =~ /^cycbuffupdate:/ || $_ =~ /^refreshinterval:/);
-
- if($_ =~ /^metacycbuff:/) {
- @line = split(/:/, $_);
- if($class{$line[1]}) {
- print STDERR "Class $line[1] more than one time in CycBuff Conffile $conffile ...\n";
- return 0;
- }
-
- $class{$line[1]} = $line[2];
- if ($line[3] ne "") {
- $metamode{$line[1]} = $line[3];
- } else {
- $metamode{$line[1]} = "INTERLEAVE";
- }
- next;
- }
-
- if ($_ =~ /^cycbuff/) {
- @line = split(/:/, $_);
- if($buff{$line[1]}) {
- print STDERR "Buff $line[1] more than one time in CycBuff Conffile $conffile ...\n";
- return 1;
- }
- $buff{$line[1]} = $line[2];
- next;
- }
-
- print STDERR "Unknown config line \"$_\" in CycBuff Conffile $conffile ...\n";
- }
- close(CONFFILE);
- return 1;
-}
-
-sub read_storageconf {
- my $line = 0;
- return 0 unless open (STOR, $storageconf);
-
- while (<STOR>) {
- ++$line;
- next if /^\s*#/;
-
- # defaults
- %key = ("NEWSGROUPS" => "*",
- "SIZE" => "0,0");
-
- if (/method\s+cnfs\s+\{/) {
- while (<STOR>) {
- ++$line;
- next if /^\s*#/;
- last if /\}/;
- if (/(\w+):\s+(\S+)/i) {
- $key{uc($1)} = $2;
- }
- }
- unless (defined $key{'CLASS'} && defined $key{'OPTIONS'}) {
- print STDERR "storage.conf:$line: ".
- "Missing 'class' or 'options'\n";
- return 0;
- }
-
- $key{'SIZE'} .= ",0" unless $key{'SIZE'} =~ /,/;
- $key{'SIZE'} =~ s/,/:/;
-
- if (defined $stor{$key{'OPTIONS'}}) {
- print STDERR "storage.conf:$line: ".
- "Class $key{'CLASS'} has several criteria\n";
- } else {
- $stor{$key{'OPTIONS'}} = "$key{'NEWSGROUPS'}:$key{'CLASS'}:" .
- "$key{'SIZE'}:$key{'OPTIONS'}";
- push(@storsort, $key{'OPTIONS'});
- }
- }
- }
- return 1;
-}
-
-START:
-
-if (! $buff{$cycbuff} ) {
- print STDERR "No buffer definition for buffer $cycbuff ...\n";
- exit(1);
-}
-&print_cycbuff_head($buff{$cycbuff});
-
-sub make_time {
- my ($t) = @_;
- my (@ret);
-
- my ($sec,$min,$hour,$mday,$mon,$year) =
- (localtime($t))[0..5];
- push (@ret, sprintf("%04d-%02d-%02d %2d:%02d:%02d",
- $year + 1900, $mon + 1, $mday, $hour, $min, $sec));
- $t = time - $t;
-
- $mday = int($t/86400); $t = $t % 86400;
- $hour = int($t/3600); $t = $t % 3600;
- $min = int($t/60); $t = $t % 60;
-
- push (@ret, sprintf("%4d days, %2d:%02d:%02d",
- $mday, $hour, $min, $t));
- return @ret;
-}
-
-sub print_cycbuff_head {
- my($buffpath) = $_[0];
- my($CNFSMASIZ)=8;
- my($CNFSNASIZ)=16;
- my($CNFSPASIZ)=64;
- my($CNFSLASIZ)=16;
- my($headerlength) = 2 * $CNFSMASIZ + 2 * $CNFSNASIZ + $CNFSPASIZ + (5 * $CNFSLASIZ);
- my($buff, @entries, $e);
- my($magic, $name, $path, $lena, $freea, $updatea, $cyclenuma, $metaname, $orderinmeta, $currentbuff);
-
- if ($opt_w) {
- if(! open(BUFF, "+< $buffpath") ) {
- print STDERR "Cannot open Cycbuff $buffpath ...\n";
- exit(1);
- }
- } else {
- if(! open(BUFF, "< $buffpath") ) {
- print STDERR "Cannot open Cycbuff $buffpath ...\n";
- exit(1);
- }
- }
-
- $buff = "";
- if(! read(BUFF, $buff, $headerlength) ) {
- print STDERR "Cannot read $headerlength bytes from file $buffpath...\n";
- exit(1);
- }
-
- ($magic, $name, $path, $lena, $freea, $updatea, $cyclenuma, $metaname, $orderinmeta, $currentbuff) = unpack("a8 a16 a64 a16 a16 a16 a16 a16 a16 a8", $buff);
-
- if(!$magic) {
- print STDERR "Error while unpacking header ...\n";
- exit(1);
- }
-
- my($len) = bhex($lena);
- my($free) = bhex($freea);
- my($update) = hex($updatea);
- my($cyclenum) = hex($cyclenuma) - 1;
-
- my ($nupdate_str, $nago_str) = &make_time ($update);
-
- $name =~ s/\0//g;
- print " Buffer $name, len: ";
- printf("%.2f", $len / (1024 * 1024));
- print " Mbytes, used: ";
- printf("%.2f Mbytes", $free / (1024 * 1024));
- printf(" (%4.1f%%) %3d cycles\n", 100 * $free/$len, $cyclenum);
- print(" Meta $metaname, order: ");
- printf("%d", $orderinmeta);
- print(", current: $currentbuff");
-
- print "\n Newest: $nupdate_str, $nago_str ago\n";
-
- if ($opt_w) {
- print "\nBuffer [$name] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $name = sprintf("%0.9s\0", $in);
- }
- print "Path [$path] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $path = sprintf("%0.65s\0", $in);
- }
- print "Length [$len ($lena)] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $in = bint2hex($in);
- $lena = sprintf("%017.17s\0", $in);
- }
- print "Free [$free ($freea)] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $in = bint2hex($in);
- $freea = sprintf("%017.17s\0", $in);
- }
- print "Meta [$metaname] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $metaname = sprintf("%0.17s\0", $in);
- }
- print "Order [$orderinmeta] => ";
- $in = <>;
- chop $in;
- if ($in ne "") {
- $orderinmeta = sprintf("%016d\0", $in);
- }
- print "Currentbuff [$currentbuff] => ";
- $in = <>;
- chop $in;
- if ($in eq "TRUE" || $in eq "FALSE") {
- $currentbuff = sprintf("%0.8s", $in);
- }
- $buff = pack("a8 a16 a64 a16 a16 a16 a16 a16 a16 a8", $magic, $name, $path, $lena, $freea, $updatea, $cyclenuma, $metaname, $orderinmeta, $currentbuff);
- seek(BUFF, 0, 0);
- if(! syswrite(BUFF, $buff, $headerlength) ) {
- print STDERR "Cannot write $headerlength bytes to file $buffpath...\n";
- exit(1);
- }
- }
- close(BUFF);
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# $Id: cnfsstat.in 7060 2004-12-19 21:36:38Z rra $
-#
-# Copyright Andreas Lamrecht 1998
-# <Andreas.Lamprect@siemens.at>
-#
-# Modified by Kjetil T. Homme 1998, 2000
-# <kjetilho@ifi.uio.no>
-#
-# Modified by Robert R. Collier 1998
-# <rob@lspace.org>
-#
-# bigint support added by Duane Currie (sandman@hub.org) 1998
-
-use vars qw($opt_l $opt_h $opt_a $opt_s);
-use Getopt::Long;
-use Math::BigInt;
-use Math::BigFloat;
-use English;
-
-my($conffile) = "$inn::pathetc/cycbuff.conf";
-my($storageconf) = "$inn::pathetc/storage.conf";
-
-sub usage {
- print <<_end_;
-Summary tool for CNFS
-
-Usage:
- $0 [-c CLASS] [-l [seconds]]
-
- If called without args, does a one-time status of all CNFS buffers
- -a: print the age of the oldest article in the cycbuff
- -c <CLASS>: prints out status of CNFS buffers in class CLASS
- -l seconds: loops like vmstat, default seconds = 600
- -s: logs through syslog
- -h: This information
- -m <BUFFER>: prints out information suitable for mrtg
- -p: prints out an mrtg config file
- -P: write PID into $inn::pathrun/cnfsstat.pid
-_end_
- exit(1);
-}
-
-my(@line, %class, %buff, %stor, $c, @buffers);
-
-my($gr, $cl, $min, $max, @storsort, $oclass, $header_printed);
-
-Getopt::Long::config('no_ignore_case');
-GetOptions("-a", "-c=s", \$oclass, "-h", "-l:i", "-s", "-m=s", \$obuffer,
- "-p", "-P");
-
-&usage if $opt_h;
-
-if ($opt_s) {
- $use_syslog = 0;
- ## Comment out this eval line if you don't want to try to syslog
- eval { require Sys::Syslog; import Sys::Syslog; $use_syslog = 1 };
- if ($use_syslog) {
- if (defined &Sys::Syslog::setlogsock && $] >= 5.00403) {
- # we really need a common module to work all this junk out
- if ($OSNAME eq "dec_osf") {
- sub Sys::Syslog::_PATH_LOG { "/dev/log" }
- }
- Sys::Syslog::setlogsock('unix')
- if $OSNAME =~ /linux|freebsd|dec_osf|darwin/;
- }
- openlog ('cnfsstat', 'pid', $inn::syslog_facility);
- } else {
- print STDERR "Syslog is not available. -s option is ignored.\n";
- }
-}
-
-if ($opt_P) {
- open(FILE, ">$inn::pathrun/cnfsstat.pid") && do {
- print FILE "$$\n";
- close FILE;
- };
-}
-
-my($sleeptime) = (defined($opt_l) && $opt_l > 0) ? $opt_l : 600;
-
-unless (&read_cycbuffconf) {
- print STDERR "Cannot open CycBuff Conffile $conffile ...\n";
- exit (1);
-}
-
-unless (&read_storageconf) {
- print STDERR "No valid $storageconf.\n";
- exit (1);
-}
-
-
-&mrtg($obuffer) if $obuffer;
-&mrtg_config if $opt_p;
-
-#foreach $c (keys(%class)) {
-# print "Class: $c, definition: $class{$c}\n";
-#}
-#foreach $c (keys(%buff)) {
-# print "Buff: $c, definition: $buff{$c}\n";
-#}
-# exit(0);
-
-START:
-
-undef($logline);
-if ($oclass) {
- if ($class{$oclass}) {
- if (!$header_printed) {
- ($gr, $cl, $min, $max) = split(/:/, $stor{$oclass});
- if ($use_syslog) {
- if ($min || $max) {
- $logline = sprintf("Class %s for groups matching \"%s\" article size min/max: %d/%d", $oclass, $gr, $min, $max);
- } else {
- $logline = sprintf("Class %s for groups matching \"%s\"", $oclass, $gr);
- }
- } else {
- print STDOUT "Class $oclass";
- print STDOUT " for groups matching \"$gr\"";
- if ($min || $max) {
- print STDOUT ", article size min/max: $min/$max";
- }
- print STDOUT "\n";
- }
- $header_printed = 1;
- }
-
- @buffers = split(/,/, $class{$oclass});
- if (! @buffers) {
- print STDERR "No buffers in Class $main::ARGV[0] ...\n";
- next;
- }
-
- foreach $b (@buffers) {
- if (! $buff{$b} ) {
- print STDERR "No buffer definition for buffer $b ...\n";
- next;
- }
- &print_cycbuff_head($buff{$b});
- }
- } else {
- print STDERR "Class $ARGV[1] not found ...\n";
- }
-} else { # Print all Classes
-
- foreach $c (@storsort) {
- ($gr, $cl, $min, $max) = split(/:/, $stor{$c});
- if ($use_syslog) {
- if ($min || $max) {
- $logline = sprintf("Class %s for groups matching \"%s\" article size min/max: %d/%d", $c, $gr, $min, $max);
- } else {
- $logline = sprintf("Class %s for groups matching \"%s\"", $c, $gr);
- }
- } else {
- print STDOUT "Class $c ";
- print STDOUT " for groups matching \"$gr\"";
- if($min || $max) {
- print STDOUT ", article size min/max: $min/$max";
- }
- print STDOUT "\n";
- }
- @buffers = split(/,/, $class{$c});
- if(! @buffers) {
- print STDERR "No buffers in Class $c ...\n";
- next;
- }
-
- foreach $b (@buffers) {
- if(! $buff{$b} ) {
- print STDERR "No buffer definition for buffer $b ...\n";
- next;
- }
- &print_cycbuff_head($buff{$b});
- }
- if ($use_syslog == 0) {
- print STDOUT "\n";
- }
- }
-}
-
-if(defined($opt_l)) {
- sleep($sleeptime);
- if ($use_syslog == 0) {
- print STDOUT "$sleeptime seconds later:\n";
- }
- goto START;
-}
-
-sub read_cycbuffconf {
- return 0 unless open (CONFFILE, $conffile);
-
- while(<CONFFILE>) {
- $_ =~ s/^\s*(.*?)\s*$/$1/;
- # Here we handle continuation lines
- while (m/\\$/) {
- $contline = <CONFFILE>;
- $contline =~ s/^\s*(.*?)\s*$/$1/;
- chop;
- $_ .= $contline;
- }
- # \x23 below is #. Emacs perl-mode gets confused by the "comment"
- next if($_ =~ /^\s*$/ || $_ =~ /^\x23/);
- next if($_ =~ /^cycbuffupdate:/ || $_ =~ /^refreshinterval:/);
-
- if($_ =~ /^metacycbuff:/) {
- @line = split(/:/, $_);
- if($class{$line[1]}) {
- print STDERR "Class $line[1] more than one time in CycBuff Conffile $conffile ...\n";
- return 0;
- }
-
- $class{$line[1]} = $line[2];
- next;
- }
-
- if ($_ =~ /^cycbuff/) {
- @line = split(/:/, $_);
- if($buff{$line[1]}) {
- print STDERR "Buff $line[1] more than one time in CycBuff Conffile $conffile ...\n";
- return 1;
- }
- $buff{$line[1]} = $line[2];
- next;
- }
-
- print STDERR "Unknown config line \"$_\" in CycBuff Conffile $conffile ...\n";
- }
- close(CONFFILE);
- return 1;
-}
-
-sub read_storageconf {
- my $line = 0;
- return 0 unless open (STOR, $storageconf);
-
- while (<STOR>) {
- ++$line;
- next if /^\s*#/;
-
- # defaults
- %key = ("NEWSGROUPS" => "*",
- "SIZE" => "0,0");
-
- if (/method\s+cnfs\s+\{/) {
- while (<STOR>) {
- ++$line;
- next if /^\s*#/;
- last if /\}/;
- if (/(\w+):\s+(\S+)/i) {
- $key{uc($1)} = $2;
- }
- }
- unless (defined $key{'CLASS'} && defined $key{'OPTIONS'}) {
- print STDERR "storage.conf:$line: ".
- "Missing 'class' or 'options'\n";
- return 0;
- }
-
- $key{'SIZE'} .= ",0" unless $key{'SIZE'} =~ /,/;
- $key{'SIZE'} =~ s/,/:/;
-
- if (!defined $stor{$key{'OPTIONS'}}) {
- $stor{$key{'OPTIONS'}} = "$key{'NEWSGROUPS'}:$key{'CLASS'}:" .
- "$key{'SIZE'}:$key{'OPTIONS'}";
- push(@storsort, $key{'OPTIONS'});
- }
- }
- }
- return 1;
-}
-
-sub print_cycbuff_head {
- my ($buffpath) = $_[0];
- my ($name, $len, $free, $update, $cyclenum, $oldart) =
- &get_cycbuff_info($buffpath);
-
- if ($use_syslog) {
- ($name) = split(/\s/, $name);
- $name =~ s/\0//g;
- syslog ('notice', '%s Buffer %s, len: %.2f Mbytes, used: %.2f Mbytes (%4.1f%%) %3d cycles',
- $logline, $name, $len / (1024 * 1024),
- Math::BigFloat->new ($free) / (1024 * 1024),
- 100 * Math::BigFloat->new ($free) / $len, $cyclenum);
- return 0;
- }
-
- $name =~ s/\0//g;
- print " Buffer $name, size: ", &human_readable($len, 4);
- print ", position: ", &human_readable($free, 4);
- printf(" %.2f cycles\n", $cyclenum + Math::BigFloat->new ($free) / $len);
- my ($when, $ago) = &make_time($update);
- print " Newest: $when, $ago ago\n";
-
- if ($opt_a) {
- my ($when, $ago) = &make_time($oldart);
- print " Oldest: $when, $ago ago\n";
- }
-}
-
-sub make_time {
- my ($t) = @_;
- my (@ret);
-
- my ($sec,$min,$hour,$mday,$mon,$year) =
- (localtime($t))[0..5];
- push (@ret, sprintf("%04d-%02d-%02d %2d:%02d:%02d",
- $year + 1900, $mon + 1, $mday, $hour, $min, $sec));
- $t = time - $t;
-
- $mday = int($t/86400); $t = $t % 86400;
- $hour = int($t/3600); $t = $t % 3600;
- $min = int($t/60); $t = $t % 60;
-
- push (@ret, sprintf("%4d days, %2d:%02d:%02d",
- $mday, $hour, $min, $t));
- return @ret;
-}
-
-sub human_readable {
- my ($val, $digits) = @_;
- $val =~ s/\+//;
-
- my @name = ("kBytes", "MBytes", "GBytes", "TBytes");
- my $base = 1024;
- my $factor = 1024;
-
- my $unit = -1;
- my $oldscaled = Math::BigFloat->new ($val) / $base;
- my $scaled = $oldscaled;
- while ( ( int($scaled) > 0 ) && ( $unit < $#name ) ) {
- $oldscaled = $scaled;
- $scaled /= $factor;
- $unit++;
- }
- $scaled = $oldscaled;
- my $predigits = length (int($scaled));
- my $postdigits = $digits - $predigits - 1;
- $postdigits = 0 if $postdigits < 0;
- ++$digits;
-
- return sprintf ("%${digits}.${postdigits}f %s", $scaled, $name[$unit]);
-}
-
-sub mrtg {
- my $buffer = shift;
- # print "Buffer = $buff{$buffer}\n";
- @info = &get_cycbuff_info($buff{$buffer});
- print "$info[1]\n";
- print "$info[2]\n";
- print "$info[4]\n";
- print "$info[0]\n";
- exit(0);
-}
-
-sub mrtg_config {
- print "Sub MRTG-CONFIG\n";
- foreach $class (sort(keys(%class))) {
- print "##\n## Class : $class\n## Wildmat: $stor{$class}\n##\n\n";
- foreach $buffer (split /\,/,$class{$class}) {
- &mrtg_buffer($class,$buffer);
- }
- }
- exit(0);
-}
-
-sub mrtg_buffer {
- my ($class,$buffer) = @_;
- #my ($name, $num, $buff, $size) = @_;
- $tag = 'cnfs-' . $buffer;
-
- print 'Target[', $tag, ']: `', "$inn::pathbin/cnfsstat -m ", $buffer, '`', "\n";
- print 'MaxBytes[', $tag, ']: ', (&get_cycbuff_info($buff{$buffer}))[1], "\n";
- print 'Title[', $tag, ']: ', "${buffer} Usage\n";
- print 'Options[', $tag, ']: growright gauge', "\n";
- print 'YLegend[', $tag, ']: ', "${buffer}\n";
- print 'ShortLegend[', $tag, ']: MB', "\n";
- print 'PageTop[', $tag, ']: ', "<H1>Usage of ${buffer}</H1>\n";
- print "<BR><TT>$stor{$class}</TT>\n";
- print "\n";
- 1;
-}
-
-sub bigsysseek {
- my($handle, $offset) = @_;
-
- # $offset may be a bigint; and have a value that doesn't fit in a signed long.
- # Even with largefiles enabled, perl will still truncate the argument to lseek64
- # to 32 bits. So we seek multiple times, <2G at a time.
-
- if($offset > 2147483647) {
- # Since perl truncates the return value of lseek64 to 32 bits, it might
- # see a successful return value as negative, and return FALSE (undef).
- # So we must ignore the return value of sysseek and assume that it worked.
-
- seek($handle, 0, 0);
- while($offset > 2000000000) {
- sysseek($handle, 2000000000, 1) || return 0;
- $offset -= 2000000000;
- }
- sysseek($handle, $offset, 1) || return 0;
- return 1;
- } else {
- return sysseek($handle, $offset, 0);
- }
-}
-
-sub check_read_return {
- my $result = shift;
- die "read: $!\n" unless defined($result);
- die "read reached eof\n" unless $result;
- return $result;
-}
-
-sub get_cycbuff_info {
- my($buffpath) = $_[0];
-
- my($CNFSMASIZ)=8;
- my($CNFSNASIZ)=16;
- my($CNFSPASIZ)=64;
- my($CNFSLASIZ)=16;
- my($headerlength) = $CNFSMASIZ + $CNFSNASIZ + $CNFSPASIZ + (4 * $CNFSLASIZ);
-
- my($buff, @entries, $e);
- my($magic, $name, $path, $lena, $freea, $updatea, $cyclenuma);
-
- if(! open(BUFF, "< $buffpath") ) {
- print STDERR "Cannot open Cycbuff $buffpath ...\n";
- exit(1);
- }
-
- $buff = "";
- if(! read(BUFF, $buff, $headerlength) ) {
- print STDERR "Cannot read $headerlength bytes from file $buffpath...\n";
- exit(1);
- }
-
- ($magic, $name, $path, $lena, $freea, $updatea, $cyclenuma) =
- unpack("a8 a16 a64 a16 a16 a16 a16", $buff);
-
- if(!$magic) {
- print STDERR "Error while unpacking header ...\n";
- exit(1);
- }
-
- my($len) = bhex($lena);
- my($free) = bhex($freea);
- my($update) = hex($updatea);
- my($cyclenum) = hex($cyclenuma) - 1;
-
- if ($opt_a) {
-
- my $pagesize = 16384;
- my $minartoffset = int($len / (512 * 8)) + 512;
- # Align upwards:
- $minartoffset = ($minartoffset + $pagesize) & ~($pagesize - 1);
-
- if ($cyclenum == 0 && $free == $minartoffset) {
- # The cycbuff has no articles yet.
- goto done;
- }
-
- # Don't loop endlessly, set rough upper bound
- my $sentinel = $cyclenum == 0 ? $free : $len;
- my $offset = $cyclenum == 0 ? $minartoffset : $free + $pagesize;
-
- bigsysseek (BUFF, $offset) || die "sysseek: $!\n";
- check_read_return (sysread (BUFF, $buff, $pagesize));
- do {
- check_read_return (sysread (BUFF, $chunk, $pagesize));
-
- $buff .= $chunk;
- while ($buff =~ /^message-id:\s+(<.*?>)/mi) {
- $buff = $POSTMATCH;
- $oldart = &lookup_age ($1);
- next unless $oldart;
-
- # Is the article newer than the last update?
- if ($oldart >= $update) {
- $update = $oldart;
- } elsif ($oldart < $update - 60) {
- goto done;
- }
- }
- # Just in case we chopped Message-ID in two, use the end
- # at the front in next iteration.
- $buff = substr ($buff, -512);
-
- } while ($sentinel -= $pagesize > 0);
- }
-
-done:
- close(BUFF);
- return($name,$len,$free,$update,$cyclenum,$oldart);
-}
-
-sub lookup_age {
- my ($msgid) = @_;
-
- my $history = &safe_run("grephistory", "-l", $msgid);
- if ($history =~ /\t(\d+)~/) {
- return $1;
- }
- print " (Missing $msgid)\n";
- return 0;
-}
-
-sub safe_run {
- my $output = "";
-
- my $pid = open(KID_TO_READ, "-|");
- die "fork: $!\n" unless defined $pid;
- if ($pid) {
- while (<KID_TO_READ>) {
- $output .= $_;
- }
- close(KID_TO_READ);
- } else {
- exec(@_) || die "can't exec $_[0]: $!";
- # NOTREACHED
- }
- return $output;
-}
-
-# Hex to bigint conversion routine
-# bhex(HEXSTRING) returns BIGINT (with leading + chopped off)
-#
-# In most languages, unlimited size integers are done using string math
-# libraries usually called bigint. (Java, Perl, etc...)
-
-# Bigint's are really just strings.
-
-sub bhex {
- my $hexValue = shift;
- $hexValue =~ s/^0x//;
-
- my $integerValue = new Math::BigInt '0';
- for (my $i = 0; $i < length($hexValue); $i += 2) {
- # Could be more efficient going at larger increments, but byte
- # by byte is safer for the case of 9 byte values, 11 bytes, etc..
-
- my $byte = substr($hexValue, $i, 2);
- my $byteIntValue = hex($byte);
-
- $integerValue = $integerValue * "256";
- $integerValue = $integerValue + "$byteIntValue";
- }
-
- $integerValue =~ s/^\+//;
- return $integerValue;
-}
+++ /dev/null
-/* $Id: ctlinnd.c 6155 2003-01-19 19:58:25Z rra $
-**
-** Send control messages to the InterNetNews daemon.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inndcomm.h"
-#include "libinn.h"
-#include "paths.h"
-
-
-/*
-** Datatype for an entry in the command table.
-*/
-typedef struct _COMMAND {
- const char *Command;
- const char *Text;
- int argc;
- char Letter;
- bool Glue;
-} COMMAND;
-
-
-static COMMAND Commands[] = {
- { "addhist", "id arr exp post token...\tAdd history line",
- 5, SC_ADDHIST, true },
- { "allow", "reason...\t\t\tAllow remote connections",
- 1, SC_ALLOW, true },
- { "begin", "site\t\t\tStart newly-added site",
- 1, SC_BEGIN, false },
- { "cancel", "id\t\t\tCancel message locally",
- 1, SC_CANCEL, false },
- { "changegroup", "group rest\tChange mode of group",
- 2, SC_CHANGEGROUP, false },
- { "checkfile", "\t\t\tCheck syntax of newsfeeds file",
- 0, SC_CHECKFILE, false },
- { "drop", "site\t\t\tStop feeding site",
- 1, SC_DROP, false },
- { "feedinfo", "site\t\t\tPrint state of feed to site*",
- 1, SC_FEEDINFO, false },
-#if defined(DO_TCL)
- { "tcl", "flag\t\t\tEnable or disable Tcl filtering",
- 1, SC_FILTER, false },
-#endif /* defined(DO_TCL) */
- { "flush", "site\t\t\tFlush feed for site*",
- 1, SC_FLUSH, false },
- { "flushlogs", "\t\t\tFlush log files",
- 0, SC_FLUSHLOGS, false },
- { "go", "reason...\t\t\tRestart after pause or throttle",
- 1, SC_GO, true },
- { "hangup", "channel\t\tHangup specified incoming channel",
- 1, SC_HANGUP, false },
- { "logmode", "\t\t\t\tSend server mode to syslog",
- 0, SC_LOGMODE, false },
- { "mode", "\t\t\t\tPrint operating mode",
- 0, SC_MODE, false },
- { "name", "nnn\t\t\tPrint name of specified channel*",
- 1, SC_NAME, false },
- { "newgroup", "group rest creator\tCreate new group",
- 3, SC_NEWGROUP, false },
- { "param", "letter value\t\tChange command-line parameters",
- 2, SC_PARAM, false },
- { "pause", "reason...\t\tShort-term pause in accepting articles",
- 1, SC_PAUSE, true },
-#if defined(DO_PERL)
- { "perl", "flag\t\t\tEnable or disable Perl filtering",
- 1, SC_PERL, false },
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- { "python", "flag\t\t\tEnable or disable Python filtering",
- 1, SC_PYTHON, false },
-#endif /* (DO_PYTHON) */
- { "readers", "flag text...\t\tEnable or disable newsreading",
- 2, SC_READERS, true },
- { "reject", "reason...\t\t\tReject remote connections",
- 1, SC_REJECT, true },
- { "reload", "what reason...\t\tRe-read config files*",
- 2, SC_RELOAD, true },
- { "renumber", "group\t\tRenumber the active file*",
- 1, SC_RENUMBER, false },
- { "reserve", "reason...\t\tReserve the next pause or throttle",
- 1, SC_RESERVE, true },
- { "rmgroup", "group\t\t\tRemove named group",
- 1, SC_RMGROUP, false },
- { "send", "feed text...\t\tSend text to exploder feed",
- 2, SC_SEND, true },
- { "shutdown", "reason...\t\tShut down server",
- 1, SC_SHUTDOWN, true },
- { "stathist", "filename|off\t\tLog into filename some history stats",
- 1, SC_STATHIST, false },
- { "status", "interval|off\t\tTurn innd status generation on or off",
- 1, SC_STATUS, false },
- { "kill", "signal site\t\tSend signal to site's process",
- 2, SC_SIGNAL, false },
- { "throttle", "reason...\t\tStop accepting articles",
- 1, SC_THROTTLE, true },
- { "timer", "interval|off\t\tTurn performance monitoring on or off",
- 1, SC_TIMER, false },
- { "trace", "innd|#|nnrpd flag\tTurn tracing on or off",
- 2, SC_TRACE, false },
- { "xabort", "text...\t\tAbort the server",
- 1, SC_XABORT, true },
- { "lowmark", "filename\t\tReset active file low article marks",
- 1, SC_LOWMARK, false },
- { "renumberlow", "filename\t\tReset active file low article marks",
- 1, SC_LOWMARK, false },
- { "xexec", "path\t\t\tExec new server",
- 1, SC_XEXEC, false }
-};
-
-\f
-
-/*
-** Print a help summary.
-*/
-static void
-Help(char *p)
-{
- COMMAND *cp;
-
- if (p == NULL) {
- printf("Command summary:\n");
- for (cp = Commands; cp < ARRAY_END(Commands); cp++)
- printf(" %s %s\n", cp->Command, cp->Text);
- printf("* Empty string means all sites/groups/etc.\n");
- printf("... All trailing words are glued together.\n");
- exit(0);
- }
- for (cp = Commands; cp < ARRAY_END(Commands); cp++)
- if (strcmp(p, cp->Command) == 0) {
- printf("Command usage:\n");
- printf(" %s %s\n", cp->Command, cp->Text);
- exit(0);
- }
- printf("No such command.\n");
- exit(0);
-}
-
-
-/*
-** Print a command-usage message and exit.
-*/
-static void
-WrongArgs(COMMAND *cp)
-{
- printf("Wrong number of arguments -- usage:\n");
- printf(" %s %s\n", cp->Command, cp->Text);
- exit(1);
-}
-
-
-/*
-** Print an error message and exit.
-*/
-static void
-Failed(const char *p)
-{
- if (ICCfailure)
- syswarn("cannot %s (%s failure)", p, ICCfailure);
- else
- syswarn("cannot %s", p);
- ICCclose();
- exit(1);
-}
-
-
-/*
-** Print an error reporting incorrect usage.
-*/
-static void
-Usage(const char *what)
-{
- fprintf(stderr, "Usage error (%s) -- try -h for help.\n", what);
- exit(1);
-}
-
-
-int main(int ac, char *av[])
-{
- static char Y[] = "y";
- static char EMPTY[] = "";
- COMMAND *cp;
- char *p;
- int i;
- bool Silent;
- bool NeedHelp;
- char *reply;
- char *new;
- int length;
- char *nv[4];
- struct stat Sb;
- char buff[SMBUF];
-
- /* First thing, set up our identity. */
- message_program_name = "ctlinnd";
-
- /* Set defaults. */
- if (!innconf_read(NULL))
- exit(1);
- Silent = false;
- NeedHelp = false;
- ICCsettimeout(CTLINND_TIMEOUT);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "hst:")) != EOF)
- switch (i) {
- default:
- Usage("bad flags");
- /* NOTREACHED */
- case 'h': /* Get help */
- NeedHelp = true;
- break;
- case 's': /* Silent -- no output */
- Silent = true;
- break;
- case 't': /* Time to wait for reply */
- ICCsettimeout(atoi(optarg));
- break;
- }
- ac -= optind;
- av += optind;
- if (NeedHelp)
- Help(av[0]);
- if (ac == 0)
- Usage("missing command");
-
- /* Look up the command word and move to the arguments. */
- if (strcmp(av[0], "help") == 0)
- Help(av[1]);
- for (cp = Commands; cp < ARRAY_END(Commands); cp++)
- if (strcmp(av[0], cp->Command) == 0)
- break;
- if (cp == ARRAY_END(Commands))
- Usage("unknown command");
- ac--;
- av++;
-
- /* Check argument count. */
- if (cp->Letter == SC_NEWGROUP) {
- /* Newgroup command has defaults. */
- switch (ac) {
- default:
- WrongArgs(cp);
- /* NOTREACHED */
- case 1:
- nv[0] = av[0];
- nv[1] = Y;
- nv[2] = EMPTY;
- nv[3] = NULL;
- av = nv;
- break;
- case 2:
- nv[0] = av[0];
- nv[1] = av[1];
- nv[2] = EMPTY;
- nv[3] = NULL;
- av = nv;
- break;
- case 3:
- break;
- }
- ac = 3;
- }
- else if (ac > cp->argc && cp->Glue) {
- /* Glue any extra words together. */
- for (length = 0, i = cp->argc - 1; (p = av[i++]) != NULL; )
- length += strlen(p) + 1;
- new = xmalloc(length);
- *new = '\0';
- for (i = cp->argc - 1; av[i]; i++) {
- if (i >= cp->argc)
- strlcat(new, " ", length);
- strlcat(new, av[i], length);
- }
- av[cp->argc - 1] = new;
- av[cp->argc] = NULL;
- }
- else if (ac != cp->argc)
- /* All other commands must have the right number of arguments. */
- WrongArgs(cp);
-
- /* For newgroup and changegroup, make sure the mode is valid. */
- if (cp->Letter == SC_NEWGROUP || cp->Letter == SC_CHANGEGROUP) {
- switch (av[1][0]) {
- default:
- Usage("Bad group mode");
- /* NOTREACHED */
- case NF_FLAG_ALIAS:
- case NF_FLAG_EXCLUDED:
- case NF_FLAG_MODERATED:
- case NF_FLAG_OK:
- case NF_FLAG_NOLOCAL:
- case NF_FLAG_IGNORE:
- break;
- }
- }
-
- /* Make sure there are no separators in the parameters. */
- for (i = 0; (p = av[i++]) != NULL; )
- if (strchr(p, SC_SEP) != NULL)
- die("illegal character \\%03o in %s", SC_SEP, p);
-
- /* Do the real work. */
- if (ICCopen() < 0)
- Failed("setup communication");
- i = ICCcommand(cp->Letter, (const char **) av, &reply);
- if (i < 0) {
- i = errno;
- p = concatpath(innconf->pathrun, _PATH_SERVERPID);
- if (stat(p, &Sb) < 0)
- warn("no innd.pid file; did server die?");
- free(p);
- snprintf(buff, sizeof(buff), "send \"%s\" command", cp->Command);
- errno = i;
- Failed(buff);
- }
-
- if (reply) {
- /* Skip "<exitcode><space>" part of reply. */
- for (p = reply; *p && CTYPE(isdigit, *p); p++)
- continue;
- while (*p && ISWHITE(*p))
- p++;
- if (i != 0)
- warn("%s", p);
- else if (!Silent)
- printf("%s\n", p);
- }
-
- if (ICCclose() < 0)
- Failed("end communication");
-
- exit(i);
- /* NOTREACHED */
-}
+++ /dev/null
-/*
-** Decode seven-bit input into full binary output.
-** From @(#)decode.c 1.3 5/15/85, distributed with B2.11 News.
-**
-** Collect runs of 12 seven-bit characters. Combine them in pairs to
-** make six 13-bit characters. Extract the top bit of each pair to make
-** a 13th six-bit character, and split the remaining six 12-bit
-** characters to form 12 six-bit characters. Collect four six-bit
-** characters and convert it to three eight-bit characters.
-**
-** Got that? All the remaining work in this program is to get the
-** ending conditions right.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-
-
-/*
-** These characters can't appear in normal output, so we use them to
-** mark that the data that follows is the terminator. The character
-** immediately following this pair is the length of the terminator (which
-** otherwise might be indeterminable)
-*/
-#define ENDMARK1 ((90 * 91 + 90) / 91)
-#define ENDMARK2 ((90 * 91 + 90) % 91)
-
-
-static char Buffer[4];
-static int count;
-
-
-static void
-pack6(int n, int last)
-{
- char *q;
- int i;
- char b3[3];
-
- i = 3;
- if (last && (i = Buffer[n - 1]) >= 3) {
- /* Do the best we can. */
- warn("badly-terminated file");
- i = 3;
- }
-
- b3[0] = (Buffer[0] << 2) | ((Buffer[1] >> 4) & 0x03);
- b3[1] = (Buffer[1] << 4) | ((Buffer[2] >> 2) & 0x0F);
- b3[2] = (Buffer[2] << 6) | ( Buffer[3] & 0x3F);
- for (q = b3; --i >= 0; )
- putchar(*q++);
-}
-
-
-static void
-pack12(char *p, int n, int last)
-{
- char *q;
- int c13;
- int c;
- int i;
- char b13[13];
- char b3[3];
-
- for (q = b13, c13 = 0, i = 0; i < n; i += 2) {
- c = *p++ * 91;
- c += *p++;
- c13 <<= 1;
- if (c & (1 << 12))
- c13 |= 1;
- *q++ = (c >> 6) & 0x3F;
- *q++ = c & 0x3F;
- }
- *q++ = (char)c13;
- if (last)
- q = &b13[last];
-
- for (p = b13, n = q - p, i = count, q = &Buffer[count]; --n > 0; ) {
- *q++ = *p++;
- if (++i == 4) {
- /* Inline expansion of pack6. */
- b3[0] = (Buffer[0] << 2) | ((Buffer[1] >> 4) & 0x03);
- b3[1] = (Buffer[1] << 4) | ((Buffer[2] >> 2) & 0x0F);
- b3[2] = (Buffer[2] << 6) | ( Buffer[3] & 0x3F);
- putchar(b3[0]);
- putchar(b3[1]);
- putchar(b3[2]);
- i = 0;
- q = Buffer;
- }
- }
-
- /* The last octet. */
- *q++ = *p++;
- i++;
-
- if (last || i == 4) {
- pack6(i, last);
- i = 0;
- }
-
- count = i;
-}
-
-
-int
-main(void)
-{
- int c;
- char *p;
- int i;
- int first;
- int cnt;
- char *base;
- char b12[12];
- char c12[12];
-
- message_program_name = "decode";
-
- base = p = b12;
- for (i = 12, cnt = 0, first = 1; (c = getchar()) != EOF; ) {
- if (c < ' ' || c >= ' ' + 91)
- die("bad data");
- if (i == 10 && p[-1] == ENDMARK1 && p[-2] == ENDMARK2) {
- cnt = c - ' ';
- i = 12;
- p -= 2;
- continue;
- }
- *p++ = c - ' ';
- if (--i == 0) {
- if (p == &b12[12]) {
- if (!first)
- pack12(c12, 12, 0);
- else
- first = 0;
- base = p = c12;
- }
- else {
- pack12(b12, 12, 0);
- base = p = b12;
- }
- i = 12;
- }
- }
-
- if (base == b12) {
- if (!first)
- pack12(c12, 12, i == 12 ? cnt : 0);
- }
- else
- pack12(b12, 12, i == 12 ? cnt : 0);
-
- if (i != 12)
- pack12(base, 12 - i, cnt);
-
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: encode.c 6119 2003-01-13 07:59:39Z rra $
-**
-** Produce a seven-bit printable encoding of stdin on stdout.
-** From @(#)encode.c 1.3 5/15/85, distributed with B2.11 News.
-**
-** The encoding uses characters from 0x20 (' ') through 0x7A ('z').
-** (That fits nicely into the UUCP 'f' protocol by Piet Beertema.) First,
-** expand three eight-bit charcters into four six-bit ones. Collect
-** until we have 13, and spread the last one over the first 12, so that
-** we have 12 6.5-bit characters. Since there are very few half-bit
-** machines, collect them into pairs, making six 13-bit characters. We
-** can do this as A * 91 + B where A and B are less then 91 after we add
-** 0x20 to make it printable.
-**
-** And if you thought that was unclear, then we won't even get into the
-** terminating conditions!
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-
-/*
-** These characters can't appear in normal output, so we use them to
-** mark that the data that follows is the terminator. The character
-** immediately following this pair is the length of the terminator (which
-** otherwise might be indeterminable)
-*/
-#define ENDMARK1 ((90 * 91 + 90) / 91 + ' ')
-#define ENDMARK2 ((90 * 91 + 90) % 91 + ' ')
-
-static char Buffer[13];
-static int Count;
-
-
-static void
-dumpcode(char *p, int n)
-{
- int last;
- int c;
-
- if (n == 13) {
- n--;
- last = p[12];
- }
- else if (n & 1)
- last = 1 << (6 - 1);
- else
- last = 0;
-
- for (; n > 0; n -= 2) {
- c = *p++ << 6;
- c |= *p++;
- if (last & (1 << (6 - 1)))
- c |= (1 << 12);
- last <<= 1;
-
- putchar((c / 91) + ' ');
- putchar((c % 91) + ' ');
- }
-}
-
-static void
-flushout(void)
-{
- putchar(ENDMARK1);
- putchar(ENDMARK2);
- putchar(Count + ' ');
- dumpcode(Buffer, Count);
-}
-
-
-static void
-encode(char *dest, int n)
-{
- char *p;
- int i;
- int j;
- char b4[4];
-
- b4[0] = (dest[0] >> 2) & 0x3F;
- b4[1] = ((dest[0] & 0x03) << 4) | ((dest[1] >> 4) & 0x0F);
- b4[2] = ((dest[1] & 0x0F) << 2) | ((dest[2] >> 6) & 0x03);
- b4[3] = (char)(n == 3 ? dest[2] & 0x3F : n);
-
- for (p = b4, i = Count, dest = &Buffer[i], j = 4; --j >= 0; i++) {
- if (i == 13) {
- dumpcode(Buffer, 13);
- dest = Buffer;
- i = 0;
- }
- *dest++ = *p++;
- }
- Count = i;
-}
-
-
-int
-main(void)
-{
- char *p;
- int c;
- char b3[3];
-
- for (p = b3; (c = getchar()) != EOF; ) {
- *p++ = (char)c;
- if (p == &b3[3]) {
- encode(b3, 3);
- p = b3;
- }
- }
- encode(b3, (int)(p - b3));
- flushout();
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: feedone.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Connect to the NNTP server and feed one article.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "nntp.h"
-
-
-static FILE *FromServer;
-static FILE *ToServer;
-static int Tracing;
-
-
-/*
-** Read a line from the server or die trying.
-*/
-static void
-GetFromServer(buff, size, text)
- char *buff;
- int size;
- char *text;
-{
- if (fgets(buff, size, FromServer) == NULL)
- sysdie("s", text);
- if (Tracing)
- printf("S: %s", buff);
-}
-
-
-/*
-** Flush a stdio FILE; exit if there are any errors.
-*/
-static void
-SafeFlush(F)
- FILE *F;
-{
- if (fflush(F) == EOF || ferror(F))
- sysdie("cannot send text to server");
-}
-
-
-static void
-SendQuit(x)
- int x;
-{
- char buff[BUFSIZ];
-
- /* Close up. */
- fprintf(ToServer, "quit\r\n");
- SafeFlush(ToServer);
- fclose(ToServer);
- GetFromServer(buff, sizeof buff, "cannot get reply to quit");
- exit(x);
-}
-
-
-static void
-Usage()
-{
- fprintf(stderr, "Usage: feedone [-r|-m msgid] [-p] [-t] articlefile\n");
- exit(1);
-}
-
-
-int
-main(ac, av)
- int ac;
- char *av[];
-{
- static char MESGIDHDR[] = "Message-ID:";
- int i;
- FILE *F;
- char buff[BUFSIZ];
- char *mesgid = NULL;
- size_t length;
- char *p;
- char *q;
- bool PostMode;
-
- /* Set defaults. */
- mesgid[0] = '\0';
- PostMode = false;
- message_program_name = "feedone";
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "m:prt")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'm': /* Specified Message-ID */
- if (*optarg == '<')
- mesgid = optarg;
- else
- mesgid = concat("<", optarg, ">", (char *) 0);
- break;
- case 'p': /* Use Post, not ihave */
- PostMode = true;
- break;
- case 'r': /* Random Message-ID */
- length = snprintf(NULL, 0, "<%ld@%ld>", (long) getpid(),
- (long) time(NULL));
- mesgid = xmalloc(length + 1);
- snprintf(mesgid, length, "<%ld@%ld>", (long) getpid(),
- (long) time(NULL));
- break;
- case 't':
- Tracing = true;
- break;
- }
- ac -= optind;
- av += optind;
-
- /* One argument; the input filename. */
- if (ac != 1)
- Usage();
- if ((F = fopen(av[0], "r")) == NULL)
- sysdie("cannot open input");
-
- /* Scan for the message-id. */
- if (mesgid == NULL) {
- while (fgets(buff, sizeof buff, F) != NULL)
- if (strncasecmp(buff, MESGIDHDR, strlen(MESGIDHDR)) == 0) {
- if ((p = strchr(buff, '<')) == NULL
- || (q = strchr(p, '>')) == NULL)
- die("bad message ID line");
- q[1] = '\0';
- mesgid = xstrdup(p);
- break;
- }
- if (mesgid == NULL)
- die("no message ID");
- }
-
- /* Connect to the server. */
- if (NNTPremoteopen(NNTP_PORT, &FromServer, &ToServer, buff) < 0
- || FromServer == NULL
- || ToServer == NULL) {
- if (buff[0])
- warn("server says: %s", buff);
- sysdie("cannot connect to server");
- }
-
- /* Does the server want this article? */
- if (PostMode) {
- fprintf(ToServer, "post\r\n");
- i = NNTP_START_POST_VAL;
- }
- else {
- fprintf(ToServer, "ihave %s\r\n", mesgid);
- i = NNTP_SENDIT_VAL;
- }
- SafeFlush(ToServer);
- GetFromServer(buff, sizeof buff, "cannot offer article to server");
- if (atoi(buff) != i) {
- warn("server doesn't want the article: %s", buff);
- SendQuit(1);
- }
-
- /* Send the file over. */
- fseeko(F, 0, SEEK_SET);
- while (fgets(buff, sizeof buff, F) != NULL) {
- if (strncasecmp(buff, MESGIDHDR, strlen(MESGIDHDR)) == 0) {
- fprintf(ToServer, "%s %s\r\n", MESGIDHDR, mesgid);
- continue;
- }
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- fprintf(ToServer, buff[0] == '.' ? ".%s\r\n" : "%s\r\n",
- buff);
- SafeFlush(ToServer);
- }
- fprintf(ToServer, ".\r\n");
- SafeFlush(ToServer);
- fclose(F);
-
- /* How did the server respond? */
- GetFromServer(buff, sizeof buff,
- "no reply from server after sending the article");
- i = PostMode ? NNTP_POSTEDOK_VAL : NNTP_TOOKIT_VAL;
- if (atoi(buff) != i)
- sysdie("cannot send article to the server: %s", buff);
-
- SendQuit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: getlist.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Get a file list from an NNTP server.
-*/
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "paths.h"
-
-
-/*
-** Print usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: getlist [-p port] [-h host] [-A] [type [pat [groups]]\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- FILE *active;
- FILE *FromServer;
- FILE *ToServer;
- QIOSTATE *qp;
- char *field4;
- char *types;
- char *host;
- char *line;
- const char *list;
- char *p;
- char *pattern;
- char buff[512 + 1];
- int port;
- int authinfo;
- int i;
-
- /* First thing, set up our identity. */
- message_program_name = "getlist";
-
- if (!innconf_read(NULL))
- exit(1);
-
- /* Set defaults. */
- host = NULL;
- pattern = NULL;
- types = NULL;
- port = NNTP_PORT;
- authinfo = 0;
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "Ah:p:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'A':
- authinfo = 1;
- break;
- case 'h':
- host = optarg;
- break;
- case 'p':
- port = atoi(optarg);
- if (port <= 0)
- die("illegal value for -p option");
- break;
- }
- ac -= optind;
- av += optind;
-
- /* Parse parameters. */
- switch (ac) {
- default:
- Usage();
- /* NOTREACHED */
- case 0:
- case 1:
- break;
- case 2:
- pattern = av[1];
- break;
- case 3:
- pattern = av[1];
- types = av[2];
- break;
- }
- if (av[0] == NULL)
- list = "active";
- else {
- list = av[0];
- if (strcmp(list, "active") != 0 && types != NULL)
- Usage();
- if (strcmp(list, "active") != 0 && strcmp(list, "newsgroups") != 0
- && pattern != NULL)
- Usage();
- }
-
- /* Open a connection to the server. */
- if (host == NULL && (host = innconf->server) == NULL)
- sysdie("cannot get server name");
- buff[0] = '\0';
- if (NNTPconnect(host, port, &FromServer, &ToServer, buff) < 0)
- die("cannot connect to server: %s", buff[0] ? buff : strerror(errno));
- if (authinfo && NNTPsendpassword(host, FromServer, ToServer) < 0)
- die("cannot authenticate to server");
-
- /* Get the data from the server. */
- active = CAlistopen(FromServer, ToServer,
- (strcmp(list, "active") == 0) ? NULL : list);
- if (active == NULL)
- sysdie("cannot retrieve data");
-
- /* Set up to read it quickly. */
- if ((qp = QIOfdopen((int)fileno(active))) == NULL)
- sysdie("cannot read temporary file");
-
- /* Scan server's output, displaying appropriate lines. */
- i = 1;
- while ((line = QIOread(qp)) != NULL) {
- i++;
-
- /* No pattern means print all. */
- if (pattern == NULL) {
- printf("%s\n", line);
- continue;
- }
-
- /* Get the group name, see if it's one we want. */
- if ((p = strchr(line, ' ')) == NULL) {
- warn("line %d is malformed", i);
- continue;
- }
- *p = '\0';
- if (!uwildmat(line, pattern))
- continue;
- *p = ' ';
-
- /* If no group types, we want them all. */
- if (types == NULL) {
- printf("%s\n", line);
- continue;
- }
-
- /* Find the fourth field. */
- if ((p = strchr(p + 1, ' ')) == NULL) {
- warn("line %d (field 2) is malformed", i);
- continue;
- }
- if ((p = strchr(p + 1, ' ')) == NULL) {
- warn("line %d (field 3) is malformed", i);
- continue;
- }
- field4 = p + 1;
- if ((p = strchr(field4, ' ')) != NULL) {
- warn("line %d has more than 4 fields", i);
- continue;
- }
-
- /* Is this the type of line we want? */
- if (strchr(types, field4[0]) != NULL)
- printf("%s\n", line);
- }
-
- /* Determine why we stopped */
- if (QIOerror(qp)) {
- syswarn("cannot read temporary file at line %d", i);
- i = 1;
- }
- else if (QIOtoolong(qp)) {
- warn("line %d is too long", i);
- i = i;
- }
- else
- i = 0;
-
- /* All done. */
- CAclose();
- fprintf(ToServer, "quit\r\n");
- fclose(ToServer);
- fgets(buff, sizeof buff, FromServer);
- fclose(FromServer);
- exit(i);
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: inews.c 7769 2008-04-13 08:11:41Z iulius $
-**
-** Send an article (prepared by someone on the local site) to the
-** master news server.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-/* Signature handling. The separator will be appended before the signature,
- and at most SIG_MAXLINES will be appended. */
-#define SIG_MAXLINES 4
-#define SIG_SEPARATOR "-- \n"
-
-#define FLUSH_ERROR(F) (fflush((F)) == EOF || ferror((F)))
-#define LPAREN '(' /* For vi :-) */
-#define HEADER_DELTA 20
-#define GECOSTERM(c) \
- ((c) == ',' || (c) == ';' || (c) == ':' || (c) == LPAREN)
-#define HEADER_STRLEN 998
-
-typedef enum _HEADERTYPE {
- HTobs,
- HTreq,
- HTstd
-} HEADERTYPE;
-
-typedef struct _HEADER {
- const char *Name;
- bool CanSet;
- HEADERTYPE Type;
- int Size;
- char *Value;
-} HEADER;
-
-static bool Dump;
-static bool Revoked;
-static bool Spooling;
-static char **OtherHeaders;
-static char SIGSEP[] = SIG_SEPARATOR;
-static FILE *FromServer;
-static FILE *ToServer;
-static int OtherCount;
-static int OtherSize;
-static const char *Exclusions = "";
-static const char * const BadDistribs[] = {
- BAD_DISTRIBS
-};
-
-static HEADER Table[] = {
- /* Name Canset Type */
- { "Path", true, HTstd, 0, NULL },
-#define _path 0
- { "From", true, HTstd, 0, NULL },
-#define _from 1
- { "Newsgroups", true, HTreq, 0, NULL },
-#define _newsgroups 2
- { "Subject", true, HTreq, 0, NULL },
-#define _subject 3
- { "Control", true, HTstd, 0, NULL },
-#define _control 4
- { "Supersedes", true, HTstd, 0, NULL },
-#define _supersedes 5
- { "Followup-To", true, HTstd, 0, NULL },
-#define _followupto 6
- { "Date", true, HTstd, 0, NULL },
-#define _date 7
- { "Organization", true, HTstd, 0, NULL },
-#define _organization 8
- { "Lines", true, HTstd, 0, NULL },
-#define _lines 9
- { "Sender", true, HTstd, 0, NULL },
-#define _sender 10
- { "Approved", true, HTstd, 0, NULL },
-#define _approved 11
- { "Distribution", true, HTstd, 0, NULL },
-#define _distribution 12
- { "Expires", true, HTstd, 0, NULL },
-#define _expires 13
- { "Message-ID", true, HTstd, 0, NULL },
-#define _messageid 14
- { "References", true, HTstd, 0, NULL },
-#define _references 15
- { "Reply-To", true, HTstd, 0, NULL },
-#define _replyto 16
- { "Also-Control", true, HTstd, 0, NULL },
-#define _alsocontrol 17
- { "Xref", false, HTstd, 0, NULL },
- { "Summary", true, HTstd, 0, NULL },
- { "Keywords", true, HTstd, 0, NULL },
- { "Date-Received", false, HTobs, 0, NULL },
- { "Received", false, HTobs, 0, NULL },
- { "Posted", false, HTobs, 0, NULL },
- { "Posting-Version", false, HTobs, 0, NULL },
- { "Relay-Version", false, HTobs, 0, NULL },
-};
-
-#define HDR(_x) (Table[(_x)].Value)
-
-\f
-
-/*
-** Send the server a quit message, wait for a reply.
-*/
-static void
-QuitServer(int x)
-{
- char buff[HEADER_STRLEN];
- char *p;
-
- if (Spooling)
- exit(x);
- if (x)
- warn("article not posted");
- fprintf(ToServer, "quit\r\n");
- if (FLUSH_ERROR(ToServer))
- sysdie("cannot send quit to server");
- if (fgets(buff, sizeof buff, FromServer) == NULL)
- sysdie("warning: server did not reply to quit");
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (atoi(buff) != NNTP_GOODBYE_ACK_VAL)
- die("server did not reply to quit properly: %s", buff);
- fclose(FromServer);
- fclose(ToServer);
- exit(x);
-}
-
-
-/*
-** Failure handler, called by die. Calls QuitServer to cleanly shut down the
-** connection with the remote server before exiting.
-*/
-static int
-fatal_cleanup(void)
-{
- /* Don't recurse. */
- message_fatal_cleanup = NULL;
-
- /* QuitServer does all the work. */
- QuitServer(1);
- return 1;
-}
-
-
-/*
-** Flush a stdio FILE; exit if there are any errors.
-*/
-static void
-SafeFlush(FILE *F)
-{
- if (FLUSH_ERROR(F))
- sysdie("cannot send text to server");
-}
-
-
-/*
-** Trim trailing spaces, return pointer to first non-space char.
-*/
-static char *
-TrimSpaces(char *p)
-{
- char *start;
-
- for (start = p; ISWHITE(*start); start++)
- continue;
- for (p = start + strlen(start); p > start && CTYPE(isspace, p[-1]); )
- *--p = '\0';
- return start;
-}
-
-
-/*
-** Mark the end of the header starting at p, and return a pointer
-** to the start of the next one. Handles continuations.
-*/
-static char *
-NextHeader(char *p)
-{
- for ( ; ; p++) {
- if ((p = strchr(p, '\n')) == NULL)
- die("article is all headers");
- if (!ISWHITE(p[1])) {
- *p = '\0';
- return p + 1;
- }
- }
-}
-
-
-/*
-** Strip any headers off the article and dump them into the table.
-*/
-static char *
-StripOffHeaders(char *article)
-{
- char *p;
- char *q;
- HEADER *hp;
- char c;
- int i;
-
- /* Set up the other headers list. */
- OtherSize = HEADER_DELTA;
- OtherHeaders = xmalloc(OtherSize * sizeof(char *));
- OtherCount = 0;
-
- /* Scan through buffer, a header at a time. */
- for (i = 0, p = article; ; i++) {
-
- if ((q = strchr(p, ':')) == NULL)
- die("no colon in header line \"%.30s...\"", p);
- if (q[1] == '\n' && !ISWHITE(q[2])) {
- /* Empty header; ignore this one, get next line. */
- p = NextHeader(p);
- if (*p == '\n')
- break;
- }
-
- if (q[1] != '\0' && !ISWHITE(q[1])) {
- if ((q = strchr(q, '\n')) != NULL)
- *q = '\0';
- die("no space after colon in \"%.30s...\"", p);
- }
-
- /* See if it's a known header. */
- c = CTYPE(islower, *p) ? toupper(*p) : *p;
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (c == hp->Name[0]
- && p[hp->Size] == ':'
- && ISWHITE(p[hp->Size + 1])
- && strncasecmp(p, hp->Name, hp->Size) == 0) {
- if (hp->Type == HTobs)
- die("obsolete header: %s", hp->Name);
- if (hp->Value)
- die("duplicate header: %s", hp->Name);
- for (q = &p[hp->Size + 1]; ISWHITE(*q); q++)
- continue;
- hp->Value = q;
- break;
- }
-
- /* Too many headers? */
- if (++i > 5 * HEADER_DELTA)
- die("more than %d lines of header", i);
-
- /* No; add it to the set of other headers. */
- if (hp == ARRAY_END(Table)) {
- if (OtherCount >= OtherSize - 1) {
- OtherSize += HEADER_DELTA;
- OtherHeaders = xrealloc(OtherHeaders, OtherSize * sizeof(char *));
- }
- OtherHeaders[OtherCount++] = p;
- }
-
- /* Get start of next header; if it's a blank line, we hit the end. */
- p = NextHeader(p);
- if (*p == '\n')
- break;
- }
-
- return p + 1;
-}
-
-\f
-
-/*
-** See if the user is allowed to cancel the indicated message. Assumes
-** that the Sender or From line has already been filled in.
-*/
-static void
-CheckCancel(char *msgid, bool JustReturn)
-{
- char localfrom[SMBUF];
- char *p;
- char buff[BUFSIZ];
- char remotefrom[SMBUF];
-
- /* Ask the server for the article. */
- fprintf(ToServer, "head %s\r\n", msgid);
- SafeFlush(ToServer);
- if (fgets(buff, sizeof buff, FromServer) == NULL
- || atoi(buff) != NNTP_HEAD_FOLLOWS_VAL) {
- if (JustReturn)
- return;
- die("server has no such article");
- }
-
- /* Read the headers, looking for the From or Sender. */
- remotefrom[0] = '\0';
- while (fgets(buff, sizeof buff, FromServer) != NULL) {
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '.' && buff[1] == '\0')
- break;
- if (strncmp(buff, "Sender:", 7) == 0)
- strlcpy(remotefrom, TrimSpaces(&buff[7]), SMBUF);
- else if (remotefrom[0] == '\0' && strncmp(buff, "From:", 5) == 0)
- strlcpy(remotefrom, TrimSpaces(&buff[5]), SMBUF);
- }
- if (remotefrom[0] == '\0') {
- if (JustReturn)
- return;
- die("article is garbled");
- }
- HeaderCleanFrom(remotefrom);
-
- /* Get the local user. */
- strlcpy(localfrom, HDR(_sender) ? HDR(_sender) : HDR(_from), SMBUF);
- HeaderCleanFrom(localfrom);
-
- /* Is the right person cancelling? */
- if (strcasecmp(localfrom, remotefrom) != 0)
- die("article was posted by \"%s\" and you are \"%s\"", remotefrom,
- localfrom);
-}
-
-
-/*
-** See if the user is the news administrator.
-*/
-static bool
-AnAdministrator(char *name, gid_t group)
-{
- struct passwd *pwp;
- struct group *grp;
- char **mem;
- char *p;
-
- if (Revoked)
- return false;
-
- /* Find out who we are. */
- if ((pwp = getpwnam(NEWSUSER)) == NULL)
- /* Silent falure; clients might not have the group. */
- return false;
- if (getuid() == pwp->pw_uid)
- return true;
-
- /* See if the we're in the right group. */
- if ((grp = getgrnam(NEWSGRP)) == NULL || (mem = grp->gr_mem) == NULL)
- /* Silent falure; clients might not have the group. */
- return false;
- if (group == grp->gr_gid)
- return true;
- while ((p = *mem++) != NULL)
- if (strcmp(name, p) == 0)
- return true;
- return false;
-}
-
-
-/*
-** Check the control message, and see if it's legit.
-*/
-static void
-CheckControl(char *ctrl, struct passwd *pwp)
-{
- char *p;
- char *q;
- char save;
- char name[SMBUF];
-
- /* Snip off the first word. */
- for (p = ctrl; ISWHITE(*p); p++)
- continue;
- for (ctrl = p; *p && !ISWHITE(*p); p++)
- continue;
- if (p == ctrl)
- die("emtpy control message");
- save = *p;
- *p = '\0';
-
- if (strcmp(ctrl, "cancel") == 0) {
- for (q = p + 1; ISWHITE(*q); q++)
- continue;
- if (*q == '\0')
- die("message ID missing in cancel");
- if (!Spooling)
- CheckCancel(q, false);
- }
- else if (strcmp(ctrl, "checkgroups") == 0
- || strcmp(ctrl, "ihave") == 0
- || strcmp(ctrl, "sendme") == 0
- || strcmp(ctrl, "newgroup") == 0
- || strcmp(ctrl, "rmgroup") == 0
- || strcmp(ctrl, "sendsys") == 0
- || strcmp(ctrl, "senduuname") == 0
- || strcmp(ctrl, "version") == 0) {
- strlcpy(name, pwp->pw_name, SMBUF);
- if (!AnAdministrator(name, pwp->pw_gid))
- die("ask your news administrator to do the %s for you", ctrl);
- }
- else {
- die("%s is not a valid control message", ctrl);
- }
- *p = save;
-}
-
-\f
-
-/*
-** Parse the GECOS field to get the user's full name. This comes Sendmail's
-** buildfname routine. Ignore leading stuff like "23-" "stuff]-" or
-** "stuff -" as well as trailing whitespace, or anything that comes after
-** a comma, semicolon, or in parentheses. This seems to strip off most of
-** the UCB or ATT stuff people fill out the entries with. Also, turn &
-** into the login name, with perhaps an initial capital. (Everyone seems
-** to hate that, but everyone also supports it.)
-*/
-static char *
-FormatUserName(struct passwd *pwp, char *node)
-{
- char outbuff[SMBUF];
- char *buff;
- char *out;
- char *p;
- int left;
-
-#if !defined(DONT_MUNGE_GETENV)
- memset(outbuff, 0, SMBUF);
- if ((p = getenv("NAME")) != NULL)
- strlcpy(outbuff, p, SMBUF);
- if (strlen(outbuff) == 0) {
-#endif /* !defined(DONT_MUNGE_GETENV) */
-
-
-#ifndef DO_MUNGE_GECOS
- strlcpy(outbuff, pwp->pw_gecos, SMBUF);
-#else
- /* Be very careful here. If we're not, we can potentially overflow our
- * buffer. Remember that on some Unix systems, the content of the GECOS
- * field is under (untrusted) user control and we could be setgid. */
- p = pwp->pw_gecos;
- left = SMBUF - 1;
- if (*p == '*')
- p++;
- for (out = outbuff; *p && !GECOSTERM(*p) && left; p++) {
- if (*p == '&') {
- strncpy(out, pwp->pw_name, left);
- if (CTYPE(islower, *out)
- && (out == outbuff || !CTYPE(isalpha, out[-1])))
- *out = toupper(*out);
- while (*out) {
- out++;
- left--;
- }
- }
- else if (*p == '-'
- && p > pwp->pw_gecos
- && (CTYPE(isdigit, p[-1]) || CTYPE(isspace, p[-1])
- || p[-1] == ']')) {
- out = outbuff;
- left = SMBUF - 1;
- }
- else {
- *out++ = *p;
- left--;
- }
- }
- *out = '\0';
-#endif /* DO_MUNGE_GECOS */
-
-#if !defined(DONT_MUNGE_GETENV)
- }
-#endif /* !defined(DONT_MUNGE_GETENV) */
-
- out = TrimSpaces(outbuff);
- if (out[0])
- buff = concat(pwp->pw_name, "@", node, " (", out, ")", (char *) 0);
- else
- buff = concat(pwp->pw_name, "@", node, (char *) 0);
- return buff;
-}
-
-
-/*
-** Check the Distribution header, and exit on error.
-*/
-static void CheckDistribution(char *p)
-{
- static char SEPS[] = " \t,";
- const char * const *dp;
-
- if ((p = strtok(p, SEPS)) == NULL)
- die("cannot parse Distribution header");
- do {
- for (dp = BadDistribs; *dp; dp++)
- if (uwildmat(p, *dp))
- die("illegal distribution %s", p);
- } while ((p = strtok((char *)NULL, SEPS)) != NULL);
-}
-
-
-/*
-** Process all the headers. FYI, they're done in RFC-order.
-*/
-static void
-ProcessHeaders(bool AddOrg, int linecount, struct passwd *pwp)
-{
- static char PATHFLUFF[] = PATHMASTER;
- HEADER *hp;
- char *p;
- TIMEINFO Now;
- char buff[SMBUF];
- char from[SMBUF];
-
- /* Do some preliminary fix-ups. */
- for (hp = Table; hp < ARRAY_END(Table); hp++) {
- if (!hp->CanSet && hp->Value)
- die("cannot set system header %s", hp->Name);
- if (hp->Value) {
- hp->Value = TrimSpaces(hp->Value);
- if (*hp->Value == '\0')
- hp->Value = NULL;
- }
- }
-
- /* Set From or Sender. */
- if ((p = innconf->fromhost) == NULL)
- sysdie("cannot get hostname");
- if (HDR(_from) == NULL)
- HDR(_from) = FormatUserName(pwp, p);
- else {
- if (strlen(pwp->pw_name) + strlen(p) + 2 > sizeof(buff))
- die("username and host are too long");
- sprintf(buff, "%s@%s", pwp->pw_name, p);
- strlcpy(from, HDR(_from), SMBUF);
- HeaderCleanFrom(from);
- if (strcmp(from, buff) != 0)
- HDR(_sender) = xstrdup(buff);
- }
-
- if (HDR(_date) == NULL) {
- /* Set Date. */
- if (!makedate(-1, true, buff, sizeof(buff)))
- die("cannot generate Date header");
- HDR(_date) = xstrdup(buff);
- }
-
- /* Newsgroups are checked later. */
-
- /* Set Subject; Control overrides the subject. */
- if (HDR(_control)) {
- CheckControl(HDR(_control), pwp);
- }
- else {
- p = HDR(_subject);
- if (p == NULL)
- die("required Subject header is missing or empty");
- else if (HDR(_alsocontrol))
- CheckControl(HDR(_alsocontrol), pwp);
-#if 0
- if (strncmp(p, "Re: ", 4) == 0 && HDR(_references) == NULL)
- die("article subject begins with \"Re: \" but has no references");
-#endif /* 0 */
- }
-
- /* Set Message-ID */
- if (HDR(_messageid) == NULL) {
- if ((p = GenerateMessageID(innconf->domain)) == NULL)
- die("cannot generate Message-ID header");
- HDR(_messageid) = xstrdup(p);
- }
- else if ((p = strchr(HDR(_messageid), '@')) == NULL
- || strchr(++p, '@') != NULL) {
- die("message ID must have exactly one @");
- }
-
- /* Set Path */
- if (HDR(_path) == NULL) {
-#if defined(DO_INEWS_PATH)
- if ((p = innconf->pathhost) != NULL) {
- if (*p)
- HDR(_path) = concat(Exclusions, p, "!", PATHFLUFF, (char *) 0);
- else
- HDR(_path) = concat(Exclusions, PATHFLUFF, (char *) 0);
- }
- else if (innconf->server != NULL) {
- if ((p = GetFQDN(innconf->domain)) == NULL)
- sysdie("cannot get hostname");
- HDR(_path) = concat(Exclusions, p, "!", PATHFLUFF, (char *) 0);
- }
- else {
- HDR(_path) = concat(Exclusions, PATHFLUFF, (char *) 0);
- }
-#else
- HDR(_path) = concat(Exclusions, PATHFLUFF, (char *) 0);
-#endif /* defined(DO_INEWS_PATH) */
- }
-
- /* Reply-To; left alone. */
- /* Sender; set above. */
- /* Followup-To; checked with Newsgroups. */
-
- /* Check Expires. */
- if (GetTimeInfo(&Now) < 0)
- sysdie("cannot get the time");
- if (HDR(_expires) && parsedate(HDR(_expires), &Now) == -1)
- die("cannot parse \"%s\" as an expiration date", HDR(_expires));
-
- /* References; left alone. */
- /* Control; checked above. */
-
- /* Distribution. */
- if ((p = HDR(_distribution)) != NULL) {
- p = xstrdup(p);
- CheckDistribution(p);
- free(p);
- }
-
- /* Set Organization. */
- if (AddOrg
- && HDR(_organization) == NULL
- && (p = innconf->organization) != NULL) {
- HDR(_organization) = xstrdup(p);
- }
-
- /* Keywords; left alone. */
- /* Summary; left alone. */
- /* Approved; left alone. */
-
- /* Set Lines */
- sprintf(buff, "%d", linecount);
- HDR(_lines) = xstrdup(buff);
-
- /* Check Supersedes. */
- if (HDR(_supersedes))
- CheckCancel(HDR(_supersedes), true);
-
- /* Now make sure everything is there. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Type == HTreq && hp->Value == NULL)
- die("required header %s is missing or empty", hp->Name);
-}
-
-
-/*
-** Try to append $HOME/.signature to the article. When in doubt, exit
-** out in order to avoid postings like "Sorry, I forgot my .signature
-** -- here's the article again."
-*/
-static char *
-AppendSignature(bool UseMalloc, char *article, char *homedir, int *linesp)
-{
- static char NOSIG[] = "Can't add your .signature (%s), article not posted";
- int i;
- int length;
- size_t artsize;
- char *p;
- char buff[BUFSIZ];
- FILE *F;
-
- /* Open the file. */
- *linesp = 0;
- if (strlen(homedir) > sizeof(buff) - 14)
- die("home directory path too long");
- sprintf(buff, "%s/.signature", homedir);
- if ((F = fopen(buff, "r")) == NULL) {
- if (errno == ENOENT)
- return article;
- fprintf(stderr, NOSIG, strerror(errno));
- QuitServer(1);
- }
-
- /* Read it in. */
- length = fread(buff, 1, sizeof buff - 2, F);
- i = feof(F);
- fclose(F);
- if (length == 0)
- die("signature file is empty");
- if (length < 0)
- sysdie("cannot read signature file");
- if (length == sizeof buff - 2 && !i)
- die("signature is too large");
-
- /* Make sure the buffer ends with \n\0. */
- if (buff[length - 1] != '\n')
- buff[length++] = '\n';
- buff[length] = '\0';
-
- /* Count the lines. */
- for (i = 0, p = buff; (p = strchr(p, '\n')) != NULL; p++)
- if (++i > SIG_MAXLINES)
- die("signature has too many lines");
- *linesp = 1 + i;
-
- /* Grow the article to have the signature. */
- i = strlen(article);
- artsize = i + sizeof(SIGSEP) - 1 + length + 1;
- if (UseMalloc) {
- p = xmalloc(artsize);
- strlcpy(p, article, artsize);
- article = p;
- }
- else
- article = xrealloc(article, artsize);
- strlcat(article, SIGSEP, artsize);
- strlcat(article, buff, artsize);
- return article;
-}
-
-
-/*
-** See if the user has more included text than new text. Simple-minded, but
-** reasonably effective for catching neophyte's mistakes. A line starting
-** with > is included text. Decrement the count on lines starting with <
-** so that we don't reject diff(1) output.
-*/
-static void
-CheckIncludedText(char *p, int lines)
-{
- int i;
-
- for (i = 0; ; p++) {
- switch (*p) {
- case '>':
- i++;
- break;
- case '|':
- i++;
- break;
- case ':':
- i++;
- break;
- case '<':
- i--;
- break;
- }
- if ((p = strchr(p, '\n')) == NULL)
- break;
- }
- if ((i * 2 > lines) && (lines > 40))
- die("more included text than new text");
-}
-
-\f
-
-/*
-** Read stdin into a string and return it. Can't use ReadInDescriptor
-** since that will fail if stdin is a tty.
-*/
-static char *
-ReadStdin(void)
-{
- int size;
- char *p;
- char *article;
- char *end;
- int i;
-
- size = BUFSIZ;
- article = xmalloc(size);
- end = &article[size - 3];
- for (p = article; (i = getchar()) != EOF; *p++ = (char)i)
- if (p == end) {
- article = xrealloc(article, size + BUFSIZ);
- p = &article[size - 3];
- size += BUFSIZ;
- end = &article[size - 3];
- }
-
- /* Force a \n terminator. */
- if (p > article && p[-1] != '\n')
- *p++ = '\n';
- *p = '\0';
- return article;
-}
-
-\f
-
-/*
-** Offer the article to the server, return its reply.
-*/
-static int
-OfferArticle(char *buff, bool Authorized)
-{
- fprintf(ToServer, "post\r\n");
- SafeFlush(ToServer);
- if (fgets(buff, HEADER_STRLEN, FromServer) == NULL)
- sysdie(Authorized ? "Can't offer article to server (authorized)"
- : "Can't offer article to server");
- return atoi(buff);
-}
-
-
-/*
-** Spool article to temp file.
-*/
-static void
-Spoolit(char *article, size_t Length, char *deadfile)
-{
- HEADER *hp;
- FILE *F;
- int i;
-
- /* Try to write to the deadfile. */
- if (deadfile == NULL)
- return;
- F = xfopena(deadfile);
- if (F == NULL)
- sysdie("cannot create spool file");
-
- /* Write the headers and a blank line. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value)
- fprintf(F, "%s: %s\n", hp->Name, hp->Value);
- for (i = 0; i < OtherCount; i++)
- fprintf(F, "%s\n", OtherHeaders[i]);
- fprintf(F, "\n");
- if (FLUSH_ERROR(F))
- sysdie("cannot write headers");
-
- /* Write the article and exit. */
- if (fwrite(article, 1, Length, F) != Length)
- sysdie("cannot write article");
- if (FLUSH_ERROR(F))
- sysdie("cannot write article");
- if (fclose(F) == EOF)
- sysdie("cannot close spool file");
-}
-
-
-/*
-** Print usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage: inews [-D] [-h] [header_flags] [article]\n");
- /* Don't call QuitServer here -- connection isn't open yet. */
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- static char NOCONNECT[] = "cannot connect to server";
- int i;
- char *p;
- HEADER *hp;
- int j;
- int port;
- int Mode;
- int SigLines;
- struct passwd *pwp;
- char *article;
- char *deadfile;
- char buff[HEADER_STRLEN];
- char SpoolMessage[HEADER_STRLEN];
- bool DoSignature;
- bool AddOrg;
- size_t Length;
- uid_t uid;
-
- /* First thing, set up logging and our identity. */
- message_program_name = "inews";
-
- /* Find out who we are. */
- uid = geteuid();
- if (uid == (uid_t) -1)
- sysdie("cannot get your user ID");
- if ((pwp = getpwuid(uid)) == NULL)
- sysdie("cannot get your passwd entry");
-
- /* Set defaults. */
- Mode = '\0';
- Dump = false;
- DoSignature = true;
- AddOrg = true;
- port = 0;
-
- if (!innconf_read(NULL))
- exit(1);
-
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- while ((i = getopt(ac, av, "DNAVWORShx:a:c:d:e:f:n:p:r:t:F:o:w:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'D':
- case 'N':
- Dump = true;
- break;
- case 'A':
- case 'V':
- case 'W':
- /* Ignore C News options. */
- break;
- case 'O':
- AddOrg = false;
- break;
- case 'R':
- Revoked = true;
- break;
- case 'S':
- DoSignature = false;
- break;
- case 'h':
- Mode = i;
- break;
- case 'x':
- Exclusions = concat(optarg, "!", (char *) 0);
- break;
- case 'p':
- port = atoi(optarg);
- break;
- /* Header lines that can be specified on the command line. */
- case 'a': HDR(_approved) = optarg; break;
- case 'c': HDR(_control) = optarg; break;
- case 'd': HDR(_distribution) = optarg; break;
- case 'e': HDR(_expires) = optarg; break;
- case 'f': HDR(_from) = optarg; break;
- case 'n': HDR(_newsgroups) = optarg; break;
- case 'r': HDR(_replyto) = optarg; break;
- case 't': HDR(_subject) = optarg; break;
- case 'F': HDR(_references) = optarg; break;
- case 'o': HDR(_organization) = optarg; break;
- case 'w': HDR(_followupto) = optarg; break;
- }
- ac -= optind;
- av += optind;
-
- /* Parse positional arguments; at most one, the input file. */
- switch (ac) {
- default:
- Usage();
- /* NOTREACHED */
- case 0:
- /* Read stdin. */
- article = ReadStdin();
- break;
- case 1:
- /* Read named file. */
- article = ReadInFile(av[0], (struct stat *)NULL);
- if (article == NULL)
- sysdie("cannot read input file");
- break;
- }
-
- if (port == 0)
- port = NNTP_PORT;
-
- /* Try to open a connection to the server. */
- if (NNTPremoteopen(port, &FromServer, &ToServer, buff) < 0) {
- Spooling = true;
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- strcpy(SpoolMessage, buff[0] ? buff : NOCONNECT);
- deadfile = concatpath(pwp->pw_dir, "dead.article");
- }
- else {
- /* We now have an open server connection, so close it on failure. */
- message_fatal_cleanup = fatal_cleanup;
-
- /* See if we can post. */
- i = atoi(buff);
-
- /* Tell the server we're posting. */
- setbuf(FromServer, xmalloc(BUFSIZ));
- setbuf(ToServer, xmalloc(BUFSIZ));
- fprintf(ToServer, "mode reader\r\n");
- SafeFlush(ToServer);
- if (fgets(buff, HEADER_STRLEN, FromServer) == NULL)
- sysdie("cannot tell server we're reading");
- if ((j = atoi(buff)) != NNTP_BAD_COMMAND_VAL)
- i = j;
-
- if (i != NNTP_POSTOK_VAL) {
- /* We try to authenticate in case it is all the same possible
- * to post. */
- if (NNTPsendpassword((char *)NULL, FromServer, ToServer) < 0)
- die("you do not have permission to post");
- }
- deadfile = NULL;
- }
-
- /* Basic processing. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- hp->Size = strlen(hp->Name);
- if (Mode == 'h')
- article = StripOffHeaders(article);
- for (i = 0, p = article; (p = strchr(p, '\n')) != NULL; i++, p++)
- continue;
- if (innconf->checkincludedtext)
- CheckIncludedText(article, i);
- if (DoSignature)
- article = AppendSignature(Mode == 'h', article, pwp->pw_dir, &SigLines);
- else
- SigLines = 0;
- ProcessHeaders(AddOrg, i + SigLines, pwp);
- Length = strlen(article);
- if ((innconf->localmaxartsize > 0)
- && (Length > (size_t)innconf->localmaxartsize))
- die("article is larger than local limit of %ld bytes",
- innconf->localmaxartsize);
-
- /* Do final checks. */
- if (i == 0 && HDR(_control) == NULL)
- die("article is empty");
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value && (int)strlen(hp->Value) + hp->Size > HEADER_STRLEN)
- die("%s header is too long", hp->Name);
- for (i = 0; i < OtherCount; i++)
- if ((int)strlen(OtherHeaders[i]) > HEADER_STRLEN)
- die("header too long (maximum length is %d): %.40s...",
- HEADER_STRLEN, OtherHeaders[i]);
-
- if (Dump) {
- /* Write the headers and a blank line. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value)
- printf("%s: %s\n", hp->Name, hp->Value);
- for (i = 0; i < OtherCount; i++)
- printf("%s\n", OtherHeaders[i]);
- printf("\n");
- if (FLUSH_ERROR(stdout))
- sysdie("cannot write headers");
-
- /* Write the article and exit. */
- if (fwrite(article, 1, Length, stdout) != Length)
- sysdie("cannot write article");
- SafeFlush(stdout);
- QuitServer(0);
- }
-
- if (Spooling) {
- warn("warning: %s", SpoolMessage);
- warn("article will be spooled");
- Spoolit(article, Length, deadfile);
- exit(0);
- }
-
- /* Article is prepared, offer it to the server. */
- i = OfferArticle(buff, false);
- if (i == NNTP_AUTH_NEEDED_VAL) {
- /* Posting not allowed, try to authorize. */
- if (NNTPsendpassword((char *)NULL, FromServer, ToServer) < 0)
- sysdie("authorization error");
- i = OfferArticle(buff, true);
- }
- if (i != NNTP_START_POST_VAL)
- die("server doesn't want the article: %s", buff);
-
- /* Write the headers, a blank line, then the article. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value)
- fprintf(ToServer, "%s: %s\r\n", hp->Name, hp->Value);
- for (i = 0; i < OtherCount; i++)
- fprintf(ToServer, "%s\r\n", OtherHeaders[i]);
- fprintf(ToServer, "\r\n");
- if (NNTPsendarticle(article, ToServer, true) < 0)
- sysdie("cannot send article to server");
- SafeFlush(ToServer);
-
- if (fgets(buff, sizeof buff, FromServer) == NULL)
- sysdie("no reply from server after sending the article");
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (atoi(buff) != NNTP_POSTEDOK_VAL)
- die("cannot send article to server: %s", buff);
-
- /* Close up. */
- QuitServer(0);
- /* NOTREACHED */
- return 1;
-}
+++ /dev/null
-/* $Id: innconfval.c 5962 2002-12-08 19:52:13Z rra $
-**
-** Get a config value from INN.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-/*
-** Print the INN version string with appropriate quoting.
-*/
-static void
-print_version(FILE *file, enum innconf_quoting quoting)
-{
- switch (quoting) {
- case INNCONF_QUOTE_NONE:
- fprintf(file, "%s\n", inn_version_string);
- break;
- case INNCONF_QUOTE_SHELL:
- fprintf(file, "VERSION='%s'; export VERSION\n", inn_version_string);
- break;
- case INNCONF_QUOTE_PERL:
- fprintf(file, "$version = '%s';\n", inn_version_string);
- break;
- case INNCONF_QUOTE_TCL:
- fprintf(file, "set inn_version \"%s\"\n", inn_version_string);
- break;
- }
-}
-
-
-/*
-** Main routine. Most of the real work is done by the innconf library
-** routines.
-*/
-int
-main(int argc, char *argv[])
-{
- int option, i;
- char *file = NULL;
- enum innconf_quoting quoting = INNCONF_QUOTE_NONE;
- bool okay = true;
- bool version = false;
- bool checking = false;
-
- message_program_name = "innconfval";
-
- while ((option = getopt(argc, argv, "Ci:pstv")) != EOF)
- switch (option) {
- default:
- die("usage error");
- break;
- case 'C':
- checking = true;
- break;
- case 'i':
- file = optarg;
- break;
- case 'p':
- quoting = INNCONF_QUOTE_PERL;
- break;
- case 's':
- quoting = INNCONF_QUOTE_SHELL;
- break;
- case 't':
- quoting = INNCONF_QUOTE_TCL;
- break;
- case 'v':
- version = true;
- break;
- }
- argc -= optind;
- argv += optind;
-
- if (version) {
- print_version(stdout, quoting);
- exit(0);
- }
- if (checking)
- exit(innconf_check(file) ? 0 : 1);
-
- /* Read in the inn.conf file specified. */
- if (!innconf_read(file))
- exit(1);
-
- /* Perform the specified action. */
- if (argv[0] == NULL) {
- innconf_dump(stdout, quoting);
- print_version(stdout, quoting);
- } else {
- for (i = 0; i < argc; i++)
- if (strcmp(argv[i], "version") == 0)
- print_version(stdout, quoting);
- else if (!innconf_print_value(stdout, argv[i], quoting))
- okay = false;
- }
- exit(okay ? 0 : 1);
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# mailpost - Yet another mail-to-news filter
-#
-# $Id: mailpost.in 7795 2008-04-26 08:28:08Z iulius $
-#
-# 21feb00 [added "lc" to duplicate header fixer stmt to make it case-insensitive]
-# doka 11may99 [fixed duplicate headers problem]
-# brister 19oct98 [cleaned up somewhat for Perl v. 5. and made a little more robust]
-# vixie 29jan95 [RCS'd]
-# vixie 15jun93 [added -m]
-# vixie 30jun92 [added -a and -d]
-# vixie 17jun92 [attempt simple-minded fixup to $path]
-# vixie 14jun92 [original]
-
-use Getopt::Std;
-use IPC::Open3;
-use IO::Select;
-use Sys::Syslog;
-use strict;
-
-my $debugging = 0 ;
-my $tmpfile ;
-my $tmpfile2 ;
-my $msg ;
-
-END {
- unlink ($tmpfile) if $tmpfile ; # in case we die()
- unlink ($tmpfile2) if $tmpfile2 ; # in case we die()
-}
-
-my $LOCK_SH = 1;
-my $LOCK_EX = 2;
-my $LOCK_NB = 4;
-my $LOCK_UN = 8;
-
-my $usage = $0 ;
-$usage =~ s!.*/!! ;
-my $prog = $usage ;
-
-openlog $usage, "pid", $inn::syslog_facility ;
-
-$usage .= "[ -r addr ][ -f addr ][ -a approved ][ -d distribution ]" .
- " [ -m mailing-list ][ -b database ][ -o output-path ] [ -c wait-time ]" .
- " [ -x header[:header...] ] [ -p port ] newsgroups" ;
-
-use vars qw($opt_r $opt_f $opt_a $opt_d $opt_m $opt_b $opt_n $opt_o $opt_h $opt_c $opt_x $opt_p) ;
-getopts("hr:f:a:d:m:b:no:c:x:p:") || die "usage: $usage\n" ;
-die "usage: $usage\n" if $opt_h ;
-
-#
-# $Submit is a program which takes no arguments and whose stdin is supposed
-# to be a news article (without the #!rnews header but with the news hdr).
-#
-
-my $Sendmail = $inn::mta ;
-my $Submit = $inn::inews . " -S -h" . ($opt_p ? " -p $opt_p" : '');
-my $Database = ($opt_b || $inn::pathtmp) . "/mailpost-msgid" ;
-my $Maintainer = $inn::newsmaster || "usenet" ;
-my $WhereTo = $opt_o || $Submit ;
-my $Mailname = $inn::fromhost ;
-
-# Can't use $inn::pathtmp as we're usually not running as news.
-my $Tmpdir = "/var/tmp" ;
-
-if ($debugging || $opt_n) {
- $Sendmail = "cat" ;
- $WhereTo = "cat" ;
-}
-
-chop ($Mailname = `/bin/hostname`) if ! $Mailname ;
-
-
-#
-# Our command-line argument(s) are the list of newsgroups to post to.
-#
-# There may be a "-r sender" or "-f sender" which becomes the $path
-# (which is in turn overridden below by various optional headers).
-#
-# -d (distribution) and -a (approved) are also supported to supply
-# or override the mail headers by those names.
-#
-
-my $path = 'nobody';
-my $newsgroups = undef;
-my $approved = undef;
-my $distribution = undef;
-my $mailing_list = undef;
-my $references = undef;
-my @errorText = ();
-
-if ($opt_r || $opt_f) {
- $path = $opt_r || $opt_f ;
- push @errorText, "((path: $path))\n" ;
-}
-
-if ($opt_a) {
- $approved = &fix_sender_addr($opt_a);
- push @errorText, "((approved: $approved))\n";
-}
-
-if ($opt_d) {
- $distribution = $opt_d ;
- push @errorText, "((distribution: $distribution))\n";
-}
-
-if ($opt_m) {
- $mailing_list = "<" . $opt_m . "> /dev/null";
- push @errorText, "((mailing_list: $mailing_list))\n";
-}
-
-my $exclude = 'Organization|Distribution';
-if ($opt_x) {
- $exclude .= '|' . join('|', split(/:/, $opt_x));
-}
-
-$newsgroups = join ",", @ARGV ;
-
-die "usage: $0 newsgroup [newsgroup ...]\n" unless $newsgroups;
-
-
-#
-# Do the header. Our input is a mail message, with or without the From.
-#
-
-#$message_id = sprintf("<mailpost.%d.%d@%s>", time, $$, $Hostname);
-my $real_news_hdrs = '';
-my $weird_mail_hdrs = '';
-my $fromHdr = "MAILPOST-UNKNOWN-FROM" ;
-my $dateHdr= "MAILPOST-UNKNOWN-DATE" ;
-my $msgIdHdr = "MAILPOST-UNKNOWN-MESSAGE-ID" ;
-my $from = undef;
-my $date = undef;
-my $hdr = undef;
-my $txt = undef;
-my $message_id ;
-my $subject = "(NONE)";
-
-$_ = <STDIN>;
-if (!$_) {
- if ( $debugging || -t STDERR ) {
- die "empty input" ;
- } else {
- syslog "err", "empty input" ;
- exit (0) ;
- }
-}
-
-chomp $_;
-
-my $line = undef;
-if (/^From\s+([^\s]+)\s+/) {
- $path = $1;
- push @errorText, "((path: $path))\n";
- $_ = $';
- if (/ remote from /) {
- $path = $' . '!' . $path;
- $_ = $`;
- }
-} else {
- $line = $_;
-}
-
-for (;;) {
- last if defined($line) && ($line =~ /^$/) ;
-
- $_ = <STDIN> ;
- last unless defined $_ ;
- chomp ;
-
- # Gather up a single header with possible continuation lines into $line.
- if (/^\s+/) {
- if (! $line) {
- $msg = "First line with leading whitespace!" ;
- syslog "err", $msg unless -t STDERR ;
- die "$msg\n" ;
- }
-
- $line .= "\n" . $_ ;
- next ;
- }
-
- # On the first header, $line will be undefined.
- ($_, $line) = ($line, $_) ; # Swap $line and $_.
-
- last if defined($_) && /^$/ ;
- next if /^$/ ; # Only on first header will this happen.
-
- push @errorText, "($_)\n";
-
- next if /^Approved:\s/sio && defined($approved);
- next if /^Distribution:\s/sio && defined($distribution);
-
- if (/^($exclude):\s*/sio) {
- $real_news_hdrs .= "$_\n";
- next;
- }
-
- if (/^Subject:\s*/sio) {
- $subject = $';
- next;
- }
-
- if (/^Message-ID:\s*/sio) {
- $message_id = $';
- next;
- }
-
- if (/^Mailing-List:\s*/sio) {
- $mailing_list = $';
- next;
- }
-
- if (/^(Sender|Approved):\s*/sio) {
- $real_news_hdrs .= "$&" . fix_sender_addr($') . "\n";
- next;
- }
-
- if (/^Return-Path:\s*/sio) {
- $path = $';
- $path = $1 if ($path =~ /\<([^\>]*)\>/);
- push@errorText, "((path: $path))\n";
- next;
- }
-
- if (/^Date:\s*/sio) {
- $date = $';
- next;
- }
-
- if (/^From:\s*/sio) {
- $from = &fix_sender_addr($');
- next;
- }
-
- if (/^References:\s*/sio) {
- $references = $';
- next;
- }
-
- if (!defined($references) && /^In-Reply-To:[^\<]*\<([^\>]+)\>/sio) {
- $references = "<$1>";
- # FALLTHROUGH
- }
-
- if (/^(MIME|Content)-[^:]+:\s*/sio) {
- $real_news_hdrs .= $_ . "\n" ;
- next ;
- }
-
- # Strip out news X-Trace: and X-Complaints-To: headers since otherwise posting
- # may fail. Other trace headers will be renamed to add 'X-' so we don't have
- # to worry about them.
- if (/^X-(Trace|Complaints-To):\s*/sio) {
- next ;
- }
-
- # Random unknown header. Prepend 'X-' if it is not already there.
- $_ = "X-$_" unless /^X-/sio ;
- $weird_mail_hdrs .= "$_\n";
-}
-
-
-$msgIdHdr = $message_id if $message_id ;
-$fromHdr = $from if $from ;
-$dateHdr = $date if $date ;
-
-if ($path !~ /\!/) {
- $path = "$'!$`" if ($path =~ /\@/);
-}
-
-$real_news_hdrs .= "Subject: ${subject}\n";
-$real_news_hdrs .= "Message-ID: ${msgIdHdr}\n" if defined($message_id);
-$real_news_hdrs .= "Mailing-List: ${mailing_list}\n" if defined($mailing_list);
-$real_news_hdrs .= "Distribution: ${distribution}\n" if defined($distribution);
-$real_news_hdrs .= "Approved: ${approved}\n" if defined($approved);
-$real_news_hdrs .= "References: ${references}\n" if defined($references);
-
-# Remove duplicate headers.
-my %headers = ();
-$real_news_hdrs =~ s/((.*?:) .*?($|\n)([ \t]+.*?($|\n))*)/$headers{lc$2}++?"":"$1"/ges;
-
-# inews writes error messages to stdout. We want to capture those and mail
-# them back to the newsmaster. Trying to write and read from a subprocess is
-# ugly and prone to deadlock, so we use a temp file.
-$tmpfile = sprintf "%s/mailpost.%d.%d", $Tmpdir, time, $$ ;
-
-if (!open TMPFILE,">$tmpfile") {
- $msg = "can't open temp file ($tmpfile): $!" ;
- $tmpfile = undef ;
- syslog("err", "$msg\n") unless $debugging || -t STDERR ;
- open(TMPFILE, "|" . sprintf ($Sendmail, $Maintainer)) ||
- die "die(no tmpfile): sendmail: $!\n" ;
- print TMPFILE <<"EOF";
-To: $Maintainer
-Subject: mailpost failure ($newsgroups): $msg
-
--------- Article Contents
-
-EOF
-}
-
-print TMPFILE <<"EOF";
-Path: ${path}
-From: ${fromHdr}
-Newsgroups: ${newsgroups}
-${real_news_hdrs}Date: ${dateHdr}
-${weird_mail_hdrs}
-EOF
-
-my $rest;
-$rest .= $_ while (<STDIN>);
-$rest =~ s/\n*$/\n/g; # Remove trailing \n except very last.
-
-print TMPFILE $rest;
-close TMPFILE ;
-
-if ( ! $tmpfile ) {
- # We had to bail and mail the article to the admin.
- exit (0) ;
-}
-
-
-##
-## We've got the article in a temp file and now we validate some of the
-## data we found and update our Message-ID database.
-##
-
-mailArtAndDie ("no From: found") unless $from;
-mailArtAndDie ("no Message-ID: found") unless $message_id;
-mailArtAndDie ("Malformed Message-ID ($message_id)")
- if ($message_id !~ /\<(\S+)\@(\S+)\>/);
-
-
-# Update (with locking) our Message-ID database. This is used to make sure we
-# don't loop our own gatewayed articles back through the mailing list.
-
-my ($lhs, $rhs) = ($1, $2); # Of message_id matched above.
-$rhs =~ tr/A-Z/a-z/;
-
-$message_id = "${lhs}\@${rhs}";
-
-push @errorText, "(TAS Message-ID database for $message_id)\n";
-
-my $lockfile = sprintf("%s.lock", $Database);
-
-open(LOCKFILE, "<$lockfile") ||
- open(LOCKFILE, ">$lockfile") ||
- mailArtAndDie ("can't open $lockfile: $!") ;
-
-my $i ;
-for ($i = 0 ; $i < 5 ; $i++) {
- flock(LOCKFILE, $LOCK_EX) && last ;
- sleep 1 ;
-}
-
-mailArtAndDie ("can't lock $lockfile: $!") if ($i == 5) ;
-
-my %DATABASE ;
-dbmopen(%DATABASE, $Database, 0666) || mailArtAndDie ("can't dbmopen $Database: $!");
-
-if (defined $DATABASE{$message_id}) {
-
- exit 0 if (!$opt_c) ;
-
-## crosspost -c
- $newsgroups = &append_newsgroups($DATABASE{$message_id}, $newsgroups) ;
- syslog "err", "crosspost $newsgroups\n" if $debugging ;
-}
-
-#$DATABASE{$message_id} = sprintf "%d.%s", time, 'mailpost' ;
-$DATABASE{$message_id} = $newsgroups ;
-
-mailArtAndDie ("TAS didn't set $message_id") unless defined $DATABASE{$message_id};
-
-dbmclose(%DATABASE) || mailArtAndDie ("can't dbmclose $Database: $!") ;
-
-flock(LOCKFILE, $LOCK_UN) || mailArtAndDie ("can't unlock $lockfile: $!");
-close LOCKFILE ;
-
-## For crosspost.
-
-if ($opt_c) {
- if (fork() != 0) {
- undef $tmpfile; # Don't unlink $tmpfile.
- exit 0;
- }
- sleep $opt_c ;
-
- open(LOCKFILE, "<$lockfile") ||
- open(LOCKFILE, ">$lockfile") ||
- mailArtAndDie ("can't open $lockfile: $!") ;
-
- my $i ;
- for ($i = 0 ; $i < 5 ; $i++) {
- flock(LOCKFILE, $LOCK_EX) && last ;
- sleep 1 ;
- }
- mailArtAndDie ("can't lock $lockfile: $!") if ($i == 5) ;
-
- my $umask_bak = umask();
- umask(000);
- dbmopen(%DATABASE, $Database, 0666) || mailArtAndDie ("can't dbmopen $Database: $!");
- umask($umask_bak);
-
- my $dup = undef ;
- syslog "err", "check " . $DATABASE{$message_id} . " : $newsgroups\n" if $debugging ;
- $dup = 1 if ($DATABASE{$message_id} ne $newsgroups) ;
-
- dbmclose(%DATABASE) || mailArtAndDie ("can't dbmclose $Database: $!") ;
-
- flock(LOCKFILE, $LOCK_UN) || mailArtAndDie ("can't unlock $lockfile: $!");
- close LOCKFILE ;
-
- if (defined($dup)) {
- syslog "err", "mismatch $newsgroups\n" if $debugging ;
- exit 0 ;
- }
-
- # Replace Newsgroups:.
- open(TMPFILE, "$tmpfile") || mailArtAndDie ("can't open temp file ($tmpfile): $!") ;
- $tmpfile2 = sprintf "%s/mailpost-crosspost.%d.%d", $Tmpdir, time, $$ ;
- if ( !open TMPFILE2, ">$tmpfile2") {
- $msg = "can't open temp file ($tmpfile2): $!" ;
- $tmpfile2 = undef ;
- die $msg ;
- }
- for (;;) {
- $_ = <TMPFILE> ;
- chomp ;
- last if defined($_) && /^$/ ;
-
- if (/^Newsgroups:\s*/sio) {
- printf TMPFILE2 "Newsgroups: %s\n", $newsgroups ;
- next ;
- }
- print TMPFILE2 "$_\n" ;
- }
- printf TMPFILE2 "\n" ;
-
- my $rest;
- $rest .= $_ while (<TMPFILE>);
- $rest =~ s/\n*$/\n/g; # Remove trailing \n except very last.
-
- print TMPFILE2 $rest;
- close TMPFILE2 ;
- close TMPFILE ;
- rename($tmpfile2, $tmpfile) || mailArtAndDie ("can't rename $tmpfile2 $tmpfile: $!") ;
- $tmpfile2 = undef ;
-
-}
-
-if (!open INEWS, "$WhereTo < $tmpfile 2>&1 |") {
- mailArtAndDie ("can't start $WhereTo: $!") ;
-}
-
-my @inews = <INEWS> ;
-close INEWS ;
-my $status = $? ;
-
-if (@inews) {
- chomp @inews ;
- mailArtAndDie ("inews failed: @inews") ;
-}
-
-unlink $tmpfile ;
-
-exit $status;
-
-sub mailArtAndDie {
- my ($msg) = @_ ;
-
- print STDERR $msg,"\n" if -t STDERR ;
-
- open(SENDMAIL, "|" . sprintf ($Sendmail,$Maintainer)) ||
- die "die($msg): sendmail: $!\n" ;
- print SENDMAIL <<"EOF" ;
-To: $Maintainer
-Subject: mailpost failure ($newsgroups)
-
-$msg
-
-EOF
-
- if ($tmpfile && -f $tmpfile) {
- print SENDMAIL "\n-------- Article Contents\n\n" ;
- open(FILE, "<$tmpfile") || die "open($tmpfile): $!\n" ;
- print SENDMAIL while <FILE> ;
- close FILE ;
- } else {
- print "No article left to send back.\n" ;
- }
- close SENDMAIL ;
-
-# unlink $tmpfile ;
-
- exit (0) ; # Using a non-zero exit may cause problems.
-}
-
-
-#
-# Take 822-format name (either "comment <addr> comment" or "addr (comment)")
-# and return in always-qualified 974-format ("addr (comment)").
-#
-sub fix_sender_addr {
- my ($address) = @_;
- my ($lcomment, $addr, $rcomment, $comment);
- local ($',$`,$_) ;
-
- if ($address =~ /\<([^\>]*)\>/) {
- ($lcomment, $addr, $rcomment) = (&dltb($`), &dltb($1), &dltb($'));
- } elsif ($address =~ /\(([^\)]*)\)/) {
- ($lcomment, $addr, $rcomment) = ('', &dltb($`.$'), &dltb($1));
- } else {
- ($lcomment, $addr, $rcomment) = ('', &dltb($address), '');
- }
-
- #print STDERR "fix_sender_addr($address) == ($lcomment, $addr, $rcomment)\n";
-
- $addr .= "\@$Mailname" unless ($addr =~ /\@/);
-
- if ($lcomment && $rcomment) {
- $comment = $lcomment . ' ' . $rcomment;
- } else {
- $comment = $lcomment . $rcomment;
- }
-
- $_ = $addr;
- $_ .= " ($comment)" if $comment;
-
- #print STDERR "\t-> $_\n";
-
- return $_;
-}
-
-#
-# Delete leading and trailing blanks.
-#
-
-sub dltb {
- my ($str) = @_;
-
- $str =~ s/^\s+//o;
- $str =~ s/\s+$//o;
-
- return $str;
-}
-
-sub append_newsgroups ($$) {
- my (@orig) = split(/,/,$_[0]) ;
- my (@new) = split(/,/,$_[1]) ;
- my $newsgroup ;
-
- foreach $newsgroup (@new) {
- if ( !grep($_ eq $newsgroup,@orig)) {
- push @orig, $newsgroup ;
- } else {
-# mailArtAndDie ("Duplicate Newsgroups: $newsgroup") ;
- }
- }
- return join ",", @orig ;
-
-}
-
+++ /dev/null
-/*
- * ovdb_init
- * Performs recovery on OV database, if needed
- * Performs upgrade of OV database, if needed and if '-u' used
- * Starts ovdb_monitor, if needed
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-#include <errno.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "ov.h"
-#include "../storage/ovdb/ovdb.h"
-#include "../storage/ovdb/ovdb-private.h"
-
-#ifndef USE_BERKELEY_DB
-
-int main(int argc UNUSED, char **argv UNUSED)
-{
- die("BerkeleyDB support not compiled");
-}
-
-#else /* USE_BERKELEY_DB */
-
-static int open_db(DB **db, const char *name, int type)
-{
- int ret;
-#if DB_VERSION_MAJOR == 2
- DB_INFO dbinfo;
- memset(&dbinfo, 0, sizeof dbinfo);
-
- ret = db_open(name, type, DB_CREATE, 0666, OVDBenv, &dbinfo, db);
- if (ret != 0) {
- warn("db_open failed: %s", db_strerror(ret));
- return ret;
- }
-#else
- ret = db_create(db, OVDBenv, 0);
- if (ret != 0) {
- warn("db_create failed: %s\n", db_strerror(ret));
- return ret;
- }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- ret = (*db)->open(*db, NULL, name, NULL, type, DB_CREATE, 0666);
-#else
- ret = (*db)->open(*db, name, NULL, type, DB_CREATE, 0666);
-#endif
- if (ret != 0) {
- (*db)->close(*db, 0);
- warn("%s->open failed: %s", name, db_strerror(ret));
- return ret;
- }
-#endif
- return 0;
-}
-
-/* Upgrade BerkeleyDB version */
-static int upgrade_database(const char *name UNUSED)
-{
-#if DB_VERSION_MAJOR == 2
- return 0;
-#else
- int ret;
- DB *db;
-
- ret = db_create(&db, OVDBenv, 0);
- if (ret != 0)
- return ret;
-
- notice("upgrading %s...", name);
- ret = db->upgrade(db, name, 0);
- if (ret != 0)
- warn("db->upgrade(%s) failed: %s", name, db_strerror(ret));
-
- db->close(db, 0);
- return ret;
-#endif
-}
-
-
-struct groupstats {
- ARTNUM low;
- ARTNUM high;
- int count;
- int flag;
- time_t expired;
-};
-
-static int v1_which_db(char *group)
-{
- HASH grouphash;
- unsigned int i;
-
- grouphash = Hash(group, strlen(group));
- memcpy(&i, &grouphash, sizeof(i));
- return i % ovdb_conf.numdbfiles;
-}
-
-/* Upgrade ovdb data format version 1 to 2 */
-/* groupstats and groupsbyname are replaced by groupinfo */
-static int upgrade_v1_to_v2(void)
-{
- DB *groupstats, *groupsbyname, *groupinfo, *vdb;
- DBT key, val, ikey, ival;
- DBC *cursor;
- group_id_t gid, higid = 0, higidbang = 0;
- struct groupinfo gi;
- struct groupstats gs;
- char group[MAXHEADERSIZE];
- u_int32_t v2 = 2;
- int ret;
- char *p;
-
- notice("upgrading data to version 2");
- ret = open_db(&groupstats, "groupstats", DB_BTREE);
- if (ret != 0)
- return ret;
- ret = open_db(&groupsbyname, "groupsbyname", DB_HASH);
- if (ret != 0)
- return ret;
- ret = open_db(&groupinfo, "groupinfo", DB_BTREE);
- if (ret != 0)
- return ret;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- memset(&ikey, 0, sizeof ikey);
- memset(&ival, 0, sizeof ival);
-
- ret = groupsbyname->cursor(groupsbyname, NULL, &cursor, 0);
- if (ret != 0)
- return ret;
-
- while((ret = cursor->c_get(cursor, &key, &val, DB_NEXT)) == 0) {
- if(key.size == 1 && *((char *)(key.data)) == '!') {
- if(val.size == sizeof(group_id_t))
- memcpy(&higidbang, val.data, sizeof(group_id_t));
- continue;
- }
- if(key.size >= MAXHEADERSIZE)
- continue;
- memcpy(group, key.data, key.size);
- group[key.size] = 0;
-
- if(val.size != sizeof(group_id_t))
- continue;
- memcpy(&gid, val.data, sizeof(group_id_t));
- if(gid > higid)
- higid = gid;
- ikey.data = &gid;
- ikey.size = sizeof(group_id_t);
-
- ret = groupstats->get(groupstats, NULL, &ikey, &ival, 0);
- if (ret != 0)
- continue;
- if(ival.size != sizeof(struct groupstats))
- continue;
- memcpy(&gs, ival.data, sizeof(struct groupstats));
-
- gi.low = gs.low;
- gi.high = gs.high;
- gi.count = gs.count;
- gi.flag = gs.flag;
- gi.expired = gs.expired;
- gi.current_gid = gi.new_gid = gid;
- gi.current_db = gi.new_db = v1_which_db(group);
- gi.expiregrouppid = gi.status = 0;
-
- val.data = &gi;
- val.size = sizeof(gi);
- ret = groupinfo->put(groupinfo, NULL, &key, &val, 0);
- if (ret != 0) {
- warn("groupinfo->put failed: %s", db_strerror(ret));
- cursor->c_close(cursor);
- return ret;
- }
- }
- cursor->c_close(cursor);
- if(ret != DB_NOTFOUND) {
- warn("cursor->get failed: %s", db_strerror(ret));
- return ret;
- }
-
- higid++;
- if(higidbang > higid)
- higid = higidbang;
-
- key.data = (char *) "!groupid_freelist";
- key.size = sizeof("!groupid_freelist");
- val.data = &higid;
- val.size = sizeof(group_id_t);
-
- ret = groupinfo->put(groupinfo, NULL, &key, &val, 0);
- if (ret != 0) {
- warn("groupinfo->put failed: %s", db_strerror(ret));
- return ret;
- }
-
- ret = open_db(&vdb, "version", DB_BTREE);
- if (ret != 0)
- return ret;
-
- key.data = (char *) "dataversion";
- key.size = sizeof("dataversion");
- val.data = &v2;
- val.size = sizeof v2;
-
- ret = vdb->put(vdb, NULL, &key, &val, 0);
- if (ret != 0) {
- warn("version->put failed: %s", db_strerror(ret));
- return ret;
- }
-
- groupstats->close(groupstats, 0);
- groupsbyname->close(groupsbyname, 0);
- groupinfo->close(groupinfo, 0);
- vdb->close(vdb, 0);
-
-#if DB_VERSION_MAJOR >= 3
- ret = db_create(&groupstats, OVDBenv, 0);
- if (ret != 0)
- return ret;
- groupstats->remove(groupstats, "groupstats", NULL, 0);
- ret = db_create(&groupsbyname, OVDBenv, 0);
- if (ret != 0)
- return ret;
- groupsbyname->remove(groupsbyname, "groupsbyname", NULL, 0);
-#else
- /* This won't work if someone changed DB_DATA_DIR in DB_CONFIG */
- p = concatpath(ovdb_conf.home, "groupstats");
- unlink(p);
- free(p);
- p = concatpath(ovdb_conf.home, "groupsbyname");
- unlink(p);
- free(p);
-#endif
-
- return 0;
-}
-
-static int check_upgrade(int do_upgrade)
-{
- int ret, i;
- DB *db;
- DBT key, val;
- u_int32_t dv;
- char name[50];
-
- if(do_upgrade && (ret = upgrade_database("version")))
- return ret;
-
- ret = open_db(&db, "version", DB_BTREE);
- if (ret != 0)
- return ret;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- key.data = (char *) "dataversion";
- key.size = sizeof("dataversion");
- ret = db->get(db, NULL, &key, &val, 0);
- if (ret != 0) {
- if(ret != DB_NOTFOUND) {
- warn("cannot retrieve version: %s", db_strerror(ret));
- db->close(db, 0);
- return ret;
- }
- }
- if(ret == DB_NOTFOUND || val.size != sizeof dv) {
- dv = DATA_VERSION;
-
- val.data = &dv;
- val.size = sizeof dv;
- ret = db->put(db, NULL, &key, &val, 0);
- if (ret != 0) {
- warn("cannot store version: %s", db_strerror(ret));
- db->close(db, 0);
- return ret;
- }
- } else
- memcpy(&dv, val.data, sizeof dv);
-
- key.data = (char *) "numdbfiles";
- key.size = sizeof("numdbfiles");
- if ((ret = db->get(db, NULL, &key, &val, 0)) == 0)
- if(val.size == sizeof(ovdb_conf.numdbfiles))
- memcpy(&(ovdb_conf.numdbfiles), val.data, sizeof(ovdb_conf.numdbfiles));
- db->close(db, 0);
-
- if(do_upgrade) {
- if(dv == 1) {
- ret = upgrade_database("groupstats");
- if (ret != 0)
- return ret;
- ret = upgrade_database("groupsbyname");
- if (ret != 0)
- return ret;
- } else {
- ret = upgrade_database("groupinfo");
- if (ret != 0)
- return ret;
- }
- ret = upgrade_database("groupaliases");
- if (ret != 0)
- return ret;
- for(i = 0; i < ovdb_conf.numdbfiles; i++) {
- snprintf(name, sizeof(name), "ov%05d", i);
- ret = upgrade_database(name);
- if (ret != 0)
- return ret;
- }
- }
-
- if(dv > DATA_VERSION) {
- warn("cannot open database: unknown version %d", dv);
- return EINVAL;
- }
- if(dv < DATA_VERSION) {
- if(do_upgrade)
- return upgrade_v1_to_v2();
-
- warn("database needs to be upgraded");
- return EINVAL;
- }
- return 0;
-}
-
-int
-upgrade_environment(void)
-{
- int ret;
-
- ovdb_close_berkeleydb();
- ret = ovdb_open_berkeleydb(OV_WRITE, OVDB_UPGRADE);
- if (ret != 0)
- return ret;
-#if DB_VERSION_MAJOR >= 3
-#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
- ret = OVDBenv->remove(OVDBenv, ovdb_conf.home, NULL, 0);
-#else
- ret = OVDBenv->remove(OVDBenv, ovdb_conf.home, 0);
-#endif
- if (ret != 0)
- return ret;
- OVDBenv = NULL;
- ret = ovdb_open_berkeleydb(OV_WRITE, 0);
-#endif
- return ret;
-}
-
-int main(int argc, char **argv)
-{
- int ret, c, do_upgrade = 0, recover_only = 0, err = 0;
- bool locked;
- int flags;
-
- openlog("ovdb_init", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "ovdb_init";
-
- if (!innconf_read(NULL))
- exit(1);
-
- if(strcmp(innconf->ovmethod, "ovdb"))
- die("ovmethod not set to ovdb in inn.conf");
-
- if(!ovdb_check_user())
- die("command must be run as user " NEWSUSER);
-
- chdir(innconf->pathtmp);
- ovdb_errmode = OVDB_ERR_STDERR;
-
- while((c = getopt(argc, argv, "ru")) != -1) {
- switch(c) {
- case 'r':
- recover_only = 1;
- break;
- case 'u':
- do_upgrade = 1;
- break;
- case '?':
- warn("unrecognized option -%c", optopt);
- err++;
- break;
- }
- }
- if(recover_only && do_upgrade) {
- warn("cannot use both -r and -u at the same time");
- err++;
- }
- if(err) {
- fprintf(stderr, "Usage: ovdb_init [-r|-u]\n");
- exit(1);
- }
-
- locked = ovdb_getlock(OVDB_LOCK_EXCLUSIVE);
- if(locked) {
- if(do_upgrade) {
- notice("database is quiescent, upgrading");
- flags = OVDB_RECOVER | OVDB_UPGRADE;
- }
- else {
- notice("database is quiescent, running normal recovery");
- flags = OVDB_RECOVER;
- }
- } else {
- warn("database is active");
- if(do_upgrade) {
- warn("upgrade will not be attempted");
- do_upgrade = 0;
- }
- if(recover_only)
- die("recovery will not be attempted");
- ovdb_getlock(OVDB_LOCK_ADMIN);
- flags = 0;
- }
-
- ret = ovdb_open_berkeleydb(OV_WRITE, flags);
- if(ret == DB_RUNRECOVERY) {
- if(locked)
- die("database could not be recovered");
- else {
- warn("database needs recovery but cannot be locked");
- die("other processes accessing the database must exit to start"
- " recovery");
- }
- }
- if(ret != 0)
- die("cannot open BerkeleyDB: %s", db_strerror(ret));
-
- if(recover_only)
- exit(0);
-
- if(do_upgrade) {
- ret = upgrade_environment();
- if(ret != 0)
- die("cannot upgrade BerkeleyDB environment: %s", db_strerror(ret));
- }
-
- if(check_upgrade(do_upgrade)) {
- ovdb_close_berkeleydb();
- exit(1);
- }
-
- ovdb_close_berkeleydb();
- ovdb_releaselock();
-
- if(ovdb_check_pidfile(OVDB_MONITOR_PIDFILE) == false) {
- notice("starting ovdb monitor");
- switch(fork()) {
- case -1:
- sysdie("cannot fork");
- case 0:
- setsid();
- execl(concatpath(innconf->pathbin, "ovdb_monitor"),
- "ovdb_monitor", SPACES, NULL);
- syswarn("cannot exec ovdb_monitor");
- _exit(1);
- }
- sleep(2); /* give the monitor a chance to start */
- } else
- warn("ovdb_monitor already running");
-
- if(ovdb_conf.readserver) {
- if(ovdb_check_pidfile(OVDB_SERVER_PIDFILE) == false) {
- notice("starting ovdb server");
- daemonize(innconf->pathtmp);
- execl(concatpath(innconf->pathbin, "ovdb_server"), "ovdb_server",
- SPACES, NULL);
- syswarn("cannot exec ovdb_server");
- _exit(1);
- } else
- warn("ovdb_server already running");
- }
-
- exit(0);
-}
-#endif /* USE_BERKELEY_DB */
-
+++ /dev/null
-/*
- * ovdb_monitor
- * Performs database maintenance tasks
- * + Transaction checkpoints
- * + Deadlock detection
- * + Transaction log removal
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/setproctitle.h"
-#include "portable/wait.h"
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "ov.h"
-
-#include "../storage/ovdb/ovdb.h"
-#include "../storage/ovdb/ovdb-private.h"
-
-#ifndef USE_BERKELEY_DB
-
-int main(int argc UNUSED, char **argv UNUSED)
-{
- exit(0);
-}
-
-#else /* USE_BERKELEY_DB */
-
-static int signalled = 0;
-static void sigfunc(int sig UNUSED)
-{
- signalled = 1;
-}
-
-
-static pid_t deadlockpid = 0;
-static pid_t checkpointpid = 0;
-static pid_t logremoverpid = 0;
-
-static int putpid(const char *path)
-{
- char buf[30];
- int fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0664);
- if(!fd) {
- syswarn("cannot open %s", path);
- return -1;
- }
- snprintf(buf, sizeof(buf), "%d\n", getpid());
- if(write(fd, buf, strlen(buf)) < 0) {
- syswarn("cannot write to %s", path);
- close(fd);
- return -1;
- }
- close(fd);
- return 0;
-}
-
-static void deadlock(void)
-{
- int ret, status = 0;
- u_int32_t atype = DB_LOCK_YOUNGEST;
-
- if(ovdb_open_berkeleydb(OV_WRITE, 0))
- _exit(1);
-
- setproctitle("deadlock");
-
- while(!signalled) {
-#if DB_VERSION_MAJOR == 2
- ret = lock_detect(OVDBenv->lk_info, 0, atype);
-#elif DB_VERSION_MAJOR == 3
- ret = lock_detect(OVDBenv, 0, atype, NULL);
-#else
- ret = OVDBenv->lock_detect(OVDBenv, 0, atype, NULL);
-#endif
- if(ret != 0) {
- warn("OVDB: lock_detect: %s", db_strerror(ret));
- status = 1;
- break;
- }
- sleep(30);
- }
-
- ovdb_close_berkeleydb();
- _exit(status);
-}
-
-static void checkpoint(void)
-{
- int ret, status = 0;
- DB *db;
-#if DB_VERSION_MAJOR == 2
- DB_INFO dbinfo;
-#endif
-
- if(ovdb_open_berkeleydb(OV_WRITE, 0))
- _exit(1);
-
- setproctitle("checkpoint");
-
- /* Open a database and close it. This is so a necessary initialization
- gets performed (by the db->open function). */
-
-#if DB_VERSION_MAJOR == 2
- memset(&dbinfo, 0, sizeof dbinfo);
- ret = db_open("version", DB_BTREE, DB_CREATE, 0666, OVDBenv, &dbinfo, &db);
- if (ret != 0) {
- warn("OVDB: checkpoint: db_open failed: %s", db_strerror(ret));
- _exit(1);
- }
-#else
- ret = db_create(&db, OVDBenv, 0);
- if (ret != 0) {
- warn("OVDB: checkpoint: db_create: %s", db_strerror(ret));
- _exit(1);
- }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- ret = db->open(db, NULL, "version", NULL, DB_BTREE, DB_CREATE, 0666);
-#else
- ret = db->open(db, "version", NULL, DB_BTREE, DB_CREATE, 0666);
-#endif
- if (ret != 0) {
- db->close(db, 0);
- warn("OVDB: checkpoint: version open: %s", db_strerror(ret));
- _exit(1);
- }
-#endif
- db->close(db, 0);
-
-
- while(!signalled) {
-#if DB_VERSION_MAJOR == 2
- ret = txn_checkpoint(OVDBenv->tx_info, 2048, 1);
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
- ret = txn_checkpoint(OVDBenv, 2048, 1);
-#elif DB_VERSION_MAJOR == 3
- ret = txn_checkpoint(OVDBenv, 2048, 1, 0);
-#elif DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1
- ret = OVDBenv->txn_checkpoint(OVDBenv, 2048, 1, 0);
-#else
- OVDBenv->txn_checkpoint(OVDBenv, 2048, 1, 0);
-#endif
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- sleep(30);
-#else
- if(ret != 0 && ret != DB_INCOMPLETE) {
- warn("OVDB: txn_checkpoint: %s", db_strerror(ret));
- status = 1;
- break;
- }
- if(ret == DB_INCOMPLETE)
- sleep(2);
- else
- sleep(30);
-#endif
- }
-
- ovdb_close_berkeleydb();
- _exit(status);
-}
-
-static void logremover(void)
-{
- int ret, status = 0;
- char **listp, **p;
-
- if(ovdb_open_berkeleydb(OV_WRITE, 0))
- _exit(1);
-
- setproctitle("logremover");
-
- while(!signalled) {
-#if DB_VERSION_MAJOR == 2
- ret = log_archive(OVDBenv->lg_info, &listp, DB_ARCH_ABS, malloc);
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- ret = log_archive(OVDBenv, &listp, DB_ARCH_ABS, malloc);
-#elif DB_VERSION_MAJOR == 3
- ret = log_archive(OVDBenv, &listp, DB_ARCH_ABS);
-#else
- ret = OVDBenv->log_archive(OVDBenv, &listp, DB_ARCH_ABS);
-#endif
- if(ret != 0) {
- warn("OVDB: log_archive: %s", db_strerror(ret));
- status = 1;
- break;
- }
- if(listp != NULL) {
- for(p = listp; *p; p++)
- unlink(*p);
- free(listp);
- }
- sleep(45);
- }
-
- ovdb_close_berkeleydb();
- _exit(status);
-}
-
-static int start_process(pid_t *pid, void (*func)(void))
-{
- pid_t child;
-
- switch(child = fork()) {
- case 0:
- (*func)();
- _exit(0);
- case -1:
- syswarn("cannot fork");
- return -1;
- default:
- *pid = child;
- return 0;
- }
- /*NOTREACHED*/
-}
-
-static void cleanup(int status)
-{
- int cs;
-
- if(deadlockpid)
- kill(deadlockpid, SIGTERM);
- if(checkpointpid)
- kill(checkpointpid, SIGTERM);
- if(logremoverpid)
- kill(logremoverpid, SIGTERM);
-
- xsignal(SIGINT, SIG_DFL);
- xsignal(SIGTERM, SIG_DFL);
- xsignal(SIGHUP, SIG_DFL);
-
- if(deadlockpid)
- waitpid(deadlockpid, &cs, 0);
- if(checkpointpid)
- waitpid(checkpointpid, &cs, 0);
- if(logremoverpid)
- waitpid(logremoverpid, &cs, 0);
-
- unlink(concatpath(innconf->pathrun, OVDB_MONITOR_PIDFILE));
- exit(status);
-}
-
-static void monitorloop(void)
-{
- int cs, restartit;
- pid_t child;
-
- while(!signalled) {
- child = waitpid(-1, &cs, WNOHANG);
- if(child > 0) {
- if(WIFSIGNALED(cs)) {
- restartit = 0;
- } else {
- if(WEXITSTATUS(cs) == 0)
- restartit = 1;
- else
- restartit = 0;
- }
- if(child == deadlockpid) {
- deadlockpid = 0;
- if(restartit && start_process(&deadlockpid, deadlock))
- cleanup(1);
- } else if(child == checkpointpid) {
- checkpointpid = 0;
- if(restartit && start_process(&checkpointpid, checkpoint))
- cleanup(1);
- } else if(child == logremoverpid) {
- logremoverpid = 0;
- if(restartit && start_process(&logremoverpid, logremover))
- cleanup(1);
- }
- if(!restartit)
- cleanup(1);
- }
- sleep(20);
- }
- cleanup(0);
-}
-
-
-int main(int argc, char **argv)
-{
- char *pidfile;
-
- setproctitle_init(argc, argv);
-
- openlog("ovdb_monitor", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "ovdb_monitor";
-
- if(argc != 2 || strcmp(argv[1], SPACES))
- die("should be started by ovdb_init");
- message_handlers_warn(1, message_log_syslog_err);
- message_handlers_die(1, message_log_syslog_err);
-
- if (!innconf_read(NULL))
- exit(1);
-
- if(strcmp(innconf->ovmethod, "ovdb"))
- die("ovmethod not set to ovdb in inn.conf");
- if(!ovdb_check_user())
- die("command must be run as user " NEWSUSER);
- if(!ovdb_getlock(OVDB_LOCK_ADMIN))
- die("cannot lock database");
-
- xsignal(SIGINT, sigfunc);
- xsignal(SIGTERM, sigfunc);
- xsignal(SIGHUP, sigfunc);
-
- pidfile = concatpath(innconf->pathrun, OVDB_MONITOR_PIDFILE);
- if(putpid(pidfile))
- exit(1);
- if(start_process(&deadlockpid, deadlock))
- cleanup(1);
- if(start_process(&checkpointpid, checkpoint))
- cleanup(1);
- if(start_process(&logremoverpid, logremover))
- cleanup(1);
-
- monitorloop();
-
- /* Never reached. */
- return 1;
-}
-
-#endif /* USE_BERKELEY_DB */
-
+++ /dev/null
-/*
- * ovdb_server.c
- * ovdb read server
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include "portable/time.h"
-#include "portable/setproctitle.h"
-#include "portable/socket.h"
-#include "portable/wait.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-#include <syslog.h>
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-#include "ov.h"
-
-#include "../storage/ovdb/ovdb.h"
-#include "../storage/ovdb/ovdb-private.h"
-
-#ifndef USE_BERKELEY_DB
-
-int
-main(int argc UNUSED, char **argv UNUSED)
-{
- die("BerkeleyDB support not compiled");
-}
-
-#else /* USE_BERKELEY_DB */
-
-
-#define SELECT_TIMEOUT 15
-
-
-/* This will work unless user sets a larger clienttimeout
- in readers.conf */
-#define CLIENT_TIMEOUT (innconf->clienttimeout + 60)
-/*#define CLIENT_TIMEOUT 3600*/
-
-
-static int listensock;
-
-#define MODE_READ 0
-#define MODE_WRITE 1
-#define MODE_CLOSED 2
-#define STATE_READCMD 0
-#define STATE_READGROUP 1
-struct reader {
- int fd;
- int mode;
- int state;
- int buflen;
- int bufpos;
- void *buf;
- time_t lastactive;
- void *currentsearch;
-};
-
-static struct reader *readertab;
-static int readertablen;
-static int numreaders;
-static time_t now;
-static pid_t parent;
-
-struct child {
- pid_t pid;
- int num;
- time_t started;
-};
-static struct child *children;
-#define wholistens (children[ovdb_conf.numrsprocs].num)
-
-static int signalled = 0;
-static void
-sigfunc(int sig UNUSED)
-{
- signalled = 1;
-}
-
-static int updated = 0;
-static void
-childsig(int sig UNUSED)
-{
- updated = 1;
-}
-
-static void
-parentsig(int sig UNUSED)
-{
- int i, which, smallest;
- if(wholistens < 0) {
- which = smallest = -1;
- for(i = 0; i < ovdb_conf.numrsprocs; i++) {
- if(children[i].pid == -1)
- continue;
- if(!ovdb_conf.maxrsconn || children[i].num <= ovdb_conf.maxrsconn) {
- if(smallest == -1 || children[i].num < smallest) {
- smallest = children[i].num;
- which = i;
- }
- }
- }
- if(which != -1) {
- wholistens = which;
- kill(children[which].pid, SIGUSR1);
- } else {
- wholistens = -2;
- }
- updated = 1;
- }
-}
-
-static int putpid(const char *path)
-{
- char buf[30];
- int fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0664);
- if(fd == -1) {
- syswarn("cannot open %s", path);
- return -1;
- }
- snprintf(buf, sizeof(buf), "%d\n", getpid());
- if(write(fd, buf, strlen(buf)) < 0) {
- syswarn("cannot write to %s", path);
- close(fd);
- return -1;
- }
- close(fd);
- return 0;
-}
-
-static void
-do_groupstats(struct reader *r)
-{
- struct rs_groupstats *reply;
- char *group = (char *)(r->buf) + sizeof(struct rs_cmd);
- reply = xmalloc(sizeof(struct rs_groupstats));
-
- /*syslog(LOG_DEBUG, "OVDB: rs: do_groupstats '%s'", group);*/
- if(ovdb_groupstats(group, &reply->lo, &reply->hi, &reply->count, &reply->flag)) {
- reply->status = CMD_GROUPSTATS;
- reply->aliaslen = 0;
- } else {
- reply->status = CMD_GROUPSTATS | RPLY_ERROR;
- }
- free(r->buf);
- r->buf = reply;
- r->buflen = sizeof(struct rs_groupstats);
- r->bufpos = 0;
- r->mode = MODE_WRITE;
-}
-
-static void
-do_opensrch(struct reader *r)
-{
- struct rs_cmd *cmd = r->buf;
- struct rs_opensrch *reply;
- char *group = (char *)(r->buf) + sizeof(struct rs_cmd);
- reply = xmalloc(sizeof(struct rs_opensrch));
-
- /*syslog(LOG_DEBUG, "OVDB: rs: do_opensrch '%s' %d %d", group, cmd->artlo, cmd->arthi);*/
-
- if(r->currentsearch != NULL) {
- /* can only open one search at a time */
- reply->status = CMD_OPENSRCH | RPLY_ERROR;
- } else {
- reply->handle = ovdb_opensearch(group, cmd->artlo, cmd->arthi);
- if(reply->handle == NULL) {
- reply->status = CMD_OPENSRCH | RPLY_ERROR;
- } else {
- reply->status = CMD_OPENSRCH;
- }
- r->currentsearch = reply->handle;
- }
- free(r->buf);
- r->buf = reply;
- r->buflen = sizeof(struct rs_opensrch);
- r->bufpos = 0;
- r->mode = MODE_WRITE;
-}
-
-static void
-do_srch(struct reader *r)
-{
- struct rs_cmd *cmd = r->buf;
- struct rs_srch *reply;
- ARTNUM artnum;
- TOKEN token;
- time_t arrived;
- int len;
- char *data;
-
- if(ovdb_search(cmd->handle, &artnum, &data, &len, &token, &arrived)) {
- reply = xmalloc(sizeof(struct rs_srch) + len);
- reply->status = CMD_SRCH;
- reply->artnum = artnum;
- reply->token = token;
- reply->arrived = arrived;
- reply->len = len;
- memcpy((char *)reply + sizeof(struct rs_srch), data, len);
- r->buflen = sizeof(struct rs_srch) + len;
- } else {
- reply = xmalloc(sizeof(struct rs_srch));
- reply->status = CMD_SRCH | RPLY_ERROR;
- r->buflen = sizeof(struct rs_srch);
- }
- free(r->buf);
- r->buf = reply;
- r->bufpos = 0;
- r->mode = MODE_WRITE;
-}
-
-static void
-do_closesrch(struct reader *r)
-{
- struct rs_cmd *cmd = r->buf;
-
- ovdb_closesearch(cmd->handle);
- free(r->buf);
- r->buf = NULL;
- r->bufpos = r->buflen = 0;
- r->mode = MODE_READ;
- r->currentsearch = NULL;
-}
-
-static void
-do_artinfo(struct reader *r)
-{
- struct rs_cmd *cmd = r->buf;
- struct rs_artinfo *reply;
- char *group = (char *)(r->buf) + sizeof(struct rs_cmd);
- TOKEN token;
-
- /*syslog(LOG_DEBUG, "OVDB: rs: do_artinfo: '%s' %d", group, cmd->artlo);*/
- if(ovdb_getartinfo(group, cmd->artlo, &token)) {
- reply = xmalloc(sizeof(struct rs_artinfo));
- reply->status = CMD_ARTINFO;
- reply->token = token;
- r->buflen = sizeof(struct rs_artinfo);
- } else {
- reply = xmalloc(sizeof(struct rs_artinfo));
- reply->status = CMD_ARTINFO | RPLY_ERROR;
- r->buflen = sizeof(struct rs_artinfo);
- }
- free(r->buf);
- r->buf = reply;
- r->bufpos = 0;
- r->mode = MODE_WRITE;
-}
-
-
-static int
-process_cmd(struct reader *r)
-{
- struct rs_cmd *cmd = r->buf;
-
- if(r->state == STATE_READCMD) {
- switch(cmd->what) {
- case CMD_GROUPSTATS:
- case CMD_OPENSRCH:
- case CMD_ARTINFO:
- r->state = STATE_READGROUP;
- if(cmd->grouplen == 0) {
- /* shoudn't happen... */
- r->mode = MODE_CLOSED;
- close(r->fd);
- free(r->buf);
- r->buf = NULL;
- return 0;
- }
- r->buflen += cmd->grouplen;
- r->buf = xrealloc(r->buf, r->buflen);
- return 1;
- }
- }
-
- switch(cmd->what) {
- case CMD_GROUPSTATS:
- ((char *)r->buf)[r->buflen - 1] = 0; /* make sure group is null-terminated */
- do_groupstats(r);
- break;
- case CMD_OPENSRCH:
- ((char *)r->buf)[r->buflen - 1] = 0;
- do_opensrch(r);
- break;
- case CMD_SRCH:
- do_srch(r);
- break;
- case CMD_CLOSESRCH:
- do_closesrch(r);
- break;
- case CMD_ARTINFO:
- ((char *)r->buf)[r->buflen - 1] = 0;
- do_artinfo(r);
- break;
- default:
- r->mode = MODE_CLOSED;
- close(r->fd);
- free(r->buf);
- r->buf = NULL;
- break;
- }
-
- return 0;
-}
-
-static void
-handle_read(struct reader *r)
-{
- int n;
- r->lastactive = now;
-
- if(r->buf == NULL) {
- r->state = STATE_READCMD;
- r->buf = xmalloc(sizeof(struct rs_cmd));
- r->buflen = sizeof(struct rs_cmd);
- r->bufpos = 0;
- }
-again:
- n = read(r->fd, (char *)(r->buf) + r->bufpos, r->buflen - r->bufpos);
- if(n <= 0) {
- if(n < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
- return;
- r->mode = MODE_CLOSED;
- close(r->fd);
- free(r->buf);
- r->buf = NULL;
- }
- r->bufpos += n;
-
- if(r->bufpos >= r->buflen)
- if(process_cmd(r))
- goto again;
-}
-
-static void
-handle_write(struct reader *r)
-{
- int n;
- r->lastactive = now;
-
- if(r->buf == NULL) /* shouldn't happen */
- return;
-
- n = write(r->fd, (char *)(r->buf) + r->bufpos, r->buflen - r->bufpos);
- if(n <= 0) {
- if(n < 0 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
- return;
- r->mode = MODE_CLOSED;
- close(r->fd);
- free(r->buf);
- r->buf = NULL;
- }
- r->bufpos += n;
-
- if(r->bufpos >= r->buflen) {
- free(r->buf);
- r->buf = NULL;
- r->bufpos = r->buflen = 0;
- r->mode = MODE_READ;
- }
-}
-
-static void
-newclient(int fd)
-{
- struct reader *r;
- int i;
-
- nonblocking(fd, 1);
-
- if(numreaders >= readertablen) {
- readertablen += 50;
- readertab = xrealloc(readertab, readertablen * sizeof(struct reader));
- for(i = numreaders; i < readertablen; i++) {
- readertab[i].mode = MODE_CLOSED;
- readertab[i].buf = NULL;
- }
- }
-
- r = &(readertab[numreaders]);
- numreaders++;
-
- r->fd = fd;
- r->mode = MODE_WRITE;
- r->buflen = sizeof(OVDB_SERVER_BANNER);
- r->bufpos = 0;
- r->buf = xstrdup(OVDB_SERVER_BANNER);
- r->lastactive = now;
- r->currentsearch = NULL;
-
- handle_write(r);
-}
-
-static void
-delclient(int which)
-{
- int i;
- struct reader *r = &(readertab[which]);
-
- if(r->mode != MODE_CLOSED)
- close(r->fd);
-
- if(r->buf != NULL) {
- free(r->buf);
- }
- if(r->currentsearch != NULL) {
- ovdb_closesearch(r->currentsearch);
- r->currentsearch = NULL;
- }
-
- /* numreaders will get decremented by the calling function */
- for(i = which; i < numreaders-1; i++)
- readertab[i] = readertab[i+1];
-
- readertab[i].mode = MODE_CLOSED;
- readertab[i].buf = NULL;
-}
-
-static pid_t
-serverproc(int me)
-{
- fd_set rdset, wrset;
- int i, ret, count, lastfd, lastnumreaders;
- socklen_t salen;
- struct sockaddr_in sa;
- struct timeval tv;
- pid_t pid;
-
- pid = fork();
- if (pid != 0)
- return pid;
-
- if (!ovdb_open(OV_READ|OVDB_SERVER))
- die("cannot open overview");
- xsignal_norestart(SIGINT, sigfunc);
- xsignal_norestart(SIGTERM, sigfunc);
- xsignal_norestart(SIGHUP, sigfunc);
- xsignal_norestart(SIGUSR1, childsig);
- xsignal(SIGPIPE, SIG_IGN);
-
- numreaders = lastnumreaders = 0;
- if(ovdb_conf.maxrsconn) {
- readertablen = ovdb_conf.maxrsconn;
- } else {
- readertablen = 50;
- }
- readertab = xmalloc(readertablen * sizeof(struct reader));
- for(i = 0; i < readertablen; i++) {
- readertab[i].mode = MODE_CLOSED;
- readertab[i].buf = NULL;
- }
-
- setproctitle("0 clients");
-
- /* main loop */
- while(!signalled) {
- FD_ZERO(&rdset);
- FD_ZERO(&wrset);
- lastfd = 0;
- if(wholistens == me) {
- if(!ovdb_conf.maxrsconn || numreaders < ovdb_conf.maxrsconn) {
- FD_SET(listensock, &rdset);
- lastfd = listensock;
- setproctitle("%d client%s *", numreaders,
- numreaders == 1 ? "" : "s");
- } else {
- wholistens = -1;
- kill(parent, SIGUSR1);
- }
- }
-
- for(i = 0; i < numreaders; i++) {
- switch(readertab[i].mode) {
- case MODE_READ:
- FD_SET(readertab[i].fd, &rdset);
- break;
- case MODE_WRITE:
- FD_SET(readertab[i].fd, &wrset);
- break;
- default:
- continue;
- }
- if(readertab[i].fd > lastfd)
- lastfd = readertab[i].fd;
- }
- tv.tv_usec = 0;
- tv.tv_sec = SELECT_TIMEOUT;
- count = select(lastfd + 1, &rdset, &wrset, NULL, &tv);
-
- if(signalled)
- break;
- if(count <= 0)
- continue;
-
- now = time(NULL);
-
- if(FD_ISSET(listensock, &rdset)) {
- if(!ovdb_conf.maxrsconn || numreaders < ovdb_conf.maxrsconn) {
- salen = sizeof(sa);
- ret = accept(listensock, (struct sockaddr *)&sa, &salen);
- if(ret >= 0) {
- newclient(ret);
- wholistens = -1;
- children[me].num = numreaders;
- kill(parent, SIGUSR1);
- }
- }
- }
-
- for(i = 0; i < numreaders; i++) {
- switch(readertab[i].mode) {
- case MODE_READ:
- if(FD_ISSET(readertab[i].fd, &rdset))
- handle_read(&(readertab[i]));
- break;
- case MODE_WRITE:
- if(FD_ISSET(readertab[i].fd, &wrset))
- handle_write(&(readertab[i]));
- break;
- }
- }
-
- for(i = 0; i < numreaders; i++) {
- if(readertab[i].mode == MODE_CLOSED
- || readertab[i].lastactive + CLIENT_TIMEOUT < now) {
- delclient(i);
- numreaders--;
- i--;
- }
- }
- if(children[me].num != numreaders) {
- children[me].num = numreaders;
- kill(parent, SIGUSR1);
- }
- if(numreaders != lastnumreaders) {
- lastnumreaders = numreaders;
- setproctitle("%d client%s", numreaders,
- numreaders == 1 ? "" : "s");
- }
- }
-
- ovdb_close();
- exit(0);
-}
-
-static int
-reap(void)
-{
- int i, cs;
- pid_t c;
-
- while((c = waitpid(-1, &cs, WNOHANG)) > 0) {
- for(i = 0; i < ovdb_conf.numrsprocs; i++) {
- if(c == children[i].pid) {
- if(children[i].started + 30 > time(NULL))
- return 1;
-
- children[i].num = 0;
-
- if(wholistens == i)
- wholistens = -1;
-
- if((children[i].pid = serverproc(i)) == -1)
- return 1;
-
- children[i].started = time(NULL);
- break;
- }
- }
- }
- if(wholistens == -1)
- parentsig(SIGUSR1);
- return 0;
-}
-
-#ifndef MAP_ANON
-#ifdef MAP_ANONYMOUS
-#define MAP_ANON MAP_ANONYMOUS
-#endif
-#endif
-
-static void *
-sharemem(size_t len)
-{
-#ifdef MAP_ANON
- return mmap(0, len, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
-#else
- int fd = open("/dev/zero", O_RDWR, 0);
- char *ptr = mmap(0, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
- close(fd);
- return ptr;
-#endif
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, ret;
- socklen_t salen;
- char *path, *pidfile;
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- struct sockaddr_un sa;
-#else
- struct sockaddr_in sa;
-#endif
- struct timeval tv;
- fd_set rdset;
-
- setproctitle_init(argc, argv);
-
- openlog("ovdb_server", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "ovdb_server";
-
- if(argc != 2 || strcmp(argv[1], SPACES))
- die("should be started by ovdb_init");
- message_handlers_warn(1, message_log_syslog_err);
- message_handlers_die(1, message_log_syslog_err);
-
- if (!innconf_read(NULL))
- exit(1);
-
- if(strcmp(innconf->ovmethod, "ovdb"))
- die("ovmethod not set to ovdb in inn.conf");
-
- read_ovdb_conf();
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- listensock = socket(AF_UNIX, SOCK_STREAM, 0);
-#else
- listensock = socket(AF_INET, SOCK_STREAM, 0);
-#endif
- if(listensock < 0)
- sysdie("cannot create socket");
-
- nonblocking(listensock, 1);
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- sa.sun_family = AF_UNIX;
- path = concatpath(innconf->pathrun, OVDB_SERVER_SOCKET);
- strlcpy(sa.sun_path, path, sizeof(sa.sun_path));
- unlink(sa.sun_path);
- free(path);
- ret = bind(listensock, (struct sockaddr *)&sa, sizeof sa);
-#else
- sa.sin_family = AF_INET;
- sa.sin_port = htons(OVDB_SERVER_PORT);
- sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- ret = bind(listensock, (struct sockaddr *)&sa, sizeof sa);
-
- if(ret != 0 && errno == EADDRNOTAVAIL) {
- sa.sin_family = AF_INET;
- sa.sin_port = htons(OVDB_SERVER_PORT);
- sa.sin_addr.s_addr = INADDR_ANY;
- ret = bind(listensock, (struct sockaddr *)&sa, sizeof sa);
- }
-#endif
-
- if(ret != 0)
- sysdie("cannot bind socket");
- if(listen(listensock, MAXLISTEN) < 0)
- sysdie("cannot listen on socket");
-
- pidfile = concatpath(innconf->pathrun, OVDB_SERVER_PIDFILE);
- if(putpid(pidfile))
- exit(1);
-
- xsignal_norestart(SIGINT, sigfunc);
- xsignal_norestart(SIGTERM, sigfunc);
- xsignal_norestart(SIGHUP, sigfunc);
-
- xsignal_norestart(SIGUSR1, parentsig);
- xsignal_norestart(SIGCHLD, childsig);
- parent = getpid();
-
- children = sharemem(sizeof(struct child) * (ovdb_conf.numrsprocs+1));
-
- if(children == NULL)
- sysdie("cannot mmap shared memory");
- for(i = 0; i < ovdb_conf.numrsprocs+1; i++) {
- children[i].pid = -1;
- children[i].num = 0;
- }
-
- for(i = 0; i < ovdb_conf.numrsprocs; i++) {
- if((children[i].pid = serverproc(i)) == -1) {
- for(i--; i >= 0; i--)
- kill(children[i].pid, SIGTERM);
- exit(1);
- }
- children[i].started = time(NULL);
- sleep(1);
- }
-
- while(!signalled) {
- if(reap())
- break;
-
- if(wholistens == -2) {
- FD_ZERO(&rdset);
- FD_SET(listensock, &rdset);
- tv.tv_usec = 0;
- tv.tv_sec = SELECT_TIMEOUT;
- ret = select(listensock+1, &rdset, NULL, NULL, &tv);
-
- if(ret == 1 && wholistens == -2) {
- salen = sizeof(sa);
- ret = accept(listensock, (struct sockaddr *)&sa, &salen);
- if(ret >= 0)
- close(ret);
- }
- } else {
- pause();
- }
- }
-
- for(i = 0; i < ovdb_conf.numrsprocs; i++)
- if(children[i].pid != -1)
- kill(children[i].pid, SIGTERM);
-
- while(wait(&ret) > 0)
- ;
-
- unlink(pidfile);
-
- exit(0);
-}
-
-
-#endif /* USE_BERKELEY_DB */
+++ /dev/null
-/*
- * ovdb_stat.c
- * print information about ovdb database
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <signal.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-#include "storage.h"
-
-#include "../storage/ovdb/ovdb.h"
-#include "../storage/ovdb/ovdb-private.h"
-
-
-#ifndef USE_BERKELEY_DB
-
-int main(int argc UNUSED, char **argv UNUSED)
-{
- die("BerkeleyDB support not compiled");
-}
-
-#else /* USE_BERKELEY_DB */
-
-static int signalled = 0;
-static void sigfunc(int signum UNUSED)
-{
- signalled = 1;
-}
-
-static int html = 0;
-
-typedef enum {
- END,
- INT32, /* 'a' points to u_int32_t */
- HEX32, /* 'a' printed in hex */
- DIFF32, /* 'a' - 'b' - 'c' */
- PCT32, /* 100 * 'a' / ('a' + 'b') */
- FF, /* 'a' = freebytes, 'b' = npages, 'c' = pagesize */
- BYTES, /* 'a' = bytes, 'b' = mbytes, 'c' = gbytes */
- MODE, /* 'a' points to int, printed as octal mode */
- TIME, /* 'a' points to time_t, printed as date/time */
- LSN, /* 'a' points to DB_LSN */
- STR, /* 'a' points to char* */
- SIZE /* 'a' points to size_t */
-} DATATYPE;
-
-struct datatab {
- DATATYPE type;
- ssize_t a;
- ssize_t b;
- ssize_t c;
- const char *desc;
-};
-
-static void display_heading(const char *str)
-{
- if(html)
- printf("<h2>%s<h2>\n", str);
- else
- printf("%s\n", str);
-}
-
-
-static void getval(int i, void *p, struct datatab *tab, char *val, char *sufx)
-{
- int mode = 0;
- u_int32_t a = 0, b = 0, c = 0, bytes = 0, mbytes = 0, gbytes = 0;
- char *cp = p;
- char *tmp = NULL;
- time_t tm = 0;
- size_t sz = 0;
- DB_LSN *dl = NULL;
-
- val[0] = 0;
- sufx[0] = 0;
-
- switch(tab[i].type) {
- case INT32: /* 'a' points to u_int32_t */
- memcpy(&a, cp + tab[i].a, sizeof(a));
- sprintf(val, "%u", a);
- break;
- case HEX32: /* 'a' printed in hex */
- memcpy(&a, cp + tab[i].a, sizeof(a));
- sprintf(val, "%x", a);
- break;
- case DIFF32: /* 'a' - 'b' - 'c' */
- memcpy(&a, cp + tab[i].a, sizeof(a));
- memcpy(&b, cp + tab[i].b, sizeof(b));
- if(tab[i].c != -1) {
- memcpy(&c, cp + tab[i].c, sizeof(c));
- sprintf(val, "%d", a - b - c);
- } else {
- sprintf(val, "%d", a - b);
- }
- break;
- case PCT32: /* 100 * 'a' / ('a' + 'b') */
- memcpy(&a, cp + tab[i].a, sizeof(a));
- memcpy(&b, cp + tab[i].b, sizeof(b));
- sprintf(val, "%.0f", (double) a / (a + b) * 100.0);
- strcpy(sufx, "%");
- break;
- case FF: /* 'a' = freebytes, 'b' = npages, 'c' = pagesize */
- memcpy(&a, cp + tab[i].a, sizeof(a));
- memcpy(&b, cp + tab[i].b, sizeof(b));
- memcpy(&c, cp + tab[i].c, sizeof(c));
- if(b == 0) {
- sprintf(val, "%.0f", 0.0);
- } else {
- sprintf(val, "%.0f", (double)((b * c) - a) / (b * c) * 100);
- }
- strcpy(sufx, "%");
- break;
- case BYTES: /* 'a' = bytes, 'b' = mbytes, 'c' = gbytes */
- if(tab[i].a != -1)
- memcpy(&bytes, cp + tab[i].a, sizeof(bytes));
- else
- bytes = 0;
- if(tab[i].b != -1)
- memcpy(&mbytes, cp + tab[i].b, sizeof(mbytes));
- else
- mbytes = 0;
- if(tab[i].c != -1)
- memcpy(&gbytes, cp + tab[i].c, sizeof(gbytes));
- else
- gbytes = 0;
- if(gbytes > 0 || mbytes > 0) {
- mbytes += gbytes * 1024;
- if(bytes > (1024*1024))
- mbytes += bytes / (1024*1024);
- sprintf(val, "%u", mbytes);
- strcpy(sufx, "MB");
- } else {
- sprintf(val, "%u", bytes);
- }
- break;
- case MODE: /* 'a' points to int, printed as octal mode */
- memcpy(&mode, cp + tab[i].a, sizeof(mode));
- sprintf(val, "%04o", mode);
- break;
- case TIME: /* 'a' points to time_t, printed as date/time */
- memcpy(&tm, cp + tab[i].a, sizeof(tm));
- if(tm == 0) {
- strcpy(val, "none");
- } else {
- strftime(val, SMBUF, "%Y-%m-%d %T %Z", localtime(&tm));
- }
- break;
- case LSN: /* 'a' points to DB_LSN */
- dl = (DB_LSN *)(cp + tab[i].a);
- if(dl->file == 0) {
- strcpy(val, "none");
- } else {
- sprintf(val, "%u/%u", dl->file, dl->offset);
- }
- break;
- case STR: /* 'a' points to char* */
- memcpy(&tmp, cp + tab[i].a, sizeof(tmp));
- strcpy(val, tmp);
- break;
- case SIZE: /* 'a' points to size_t */
- memcpy(&sz, cp + tab[i].a, sizeof(sz));
- sprintf(val, "%lu", (unsigned long) sz);
- break;
- case END:
- break;
- }
-}
-
-static char *myctime(time_t *tm)
-{
- static char val[SMBUF];
- strftime(val, SMBUF, "%Y-%m-%d %T %Z", localtime(tm));
- return val;
-}
-
-static void display_data(void *p, struct datatab *tab)
-{
- int i;
- char val[SMBUF], sufx[SMBUF];
- if(html)
- puts("<table border=0 cellpadding=1>");
- for(i = 0; tab[i].type != END; i++) {
- getval(i, p, tab, val, sufx);
- if(html)
- printf("<tr><td align=right>%s<td>%s<td>%s\n", val, sufx, tab[i].desc);
- else
- printf("%16s%-2s %s\n", val, sufx, tab[i].desc);
- }
- if(html)
- puts("</table><p>");
-}
-
-static void start_table(const char *label, struct datatab *tab)
-{
- int i;
- if(html) {
- printf("<h2>%s</h2>\n", label);
- puts("<table border=0 cellpadding=1>\n<tr bgcolor=#3399aa>");
- for(i = 0; tab[i].type != END; i++)
- printf("<th colspan=2>%s\n", tab[i].desc);
- }
-}
-
-static void display_row(void *p, struct datatab *tab)
-{
- int i;
- char val[SMBUF], sufx[SMBUF];
- if(html) {
- puts("<tr>");
- for(i = 0; tab[i].type != END; i++) {
- getval(i, p, tab, val, sufx);
- printf("<td align=right>%s<td>%s\n", val, sufx);
- }
- } else {
- puts("---------------------------------------------");
- display_data(p, tab);
- }
-}
-
-static void end_table(void)
-{
- if(html)
- puts("</table><p>");
-}
-
-#define OFFSETOF(type, f) ((char *)&(((type *)0)->f) - (char *)0)
-
-#define F(f) OFFSETOF(DB_LOCK_STAT, f)
-
-static struct datatab LOCK_tab[] = {
-#if DB_VERSION_MAJOR >= 3
- { INT32,
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- F(st_id),
-#else
- F(st_lastid),
-#endif
- -1, -1, "Last allocated locker ID" },
-#endif
- { INT32, F(st_maxlocks), -1, -1, "Maximum number of locks possible" },
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
- { INT32, F(st_maxlockers), -1, -1, "Maximum number of lockers possible" },
- { INT32, F(st_maxobjects), -1, -1, "Maximum number of objects possible" },
-#endif
- { INT32, F(st_nmodes), -1, -1, "Lock modes" },
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
- { INT32, F(st_nlocks), -1, -1, "Current locks" },
- { INT32, F(st_maxnlocks), -1, -1, "Maximum locks" },
-#endif
- { INT32, F(st_nlockers), -1, -1, "Current lockers" },
-#if DB_VERSION_MAJOR >= 3
- { INT32, F(st_maxnlockers), -1, -1, "Maximum lockers" },
-#else
- { INT32, F(st_numobjs), -1, -1, "Lock objects" },
-#endif
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
- { INT32, F(st_nobjects), -1, -1, "Current objects" },
- { INT32, F(st_maxnobjects), -1, -1, "Maximum objects" },
-#endif
-#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 4
- { INT32, F(st_lock_wait), -1, -1, "Lock conflicts" },
-#else
- { INT32, F(st_nconflicts), -1, -1, "Lock conflicts" },
-#endif
- { INT32, F(st_nrequests), -1, -1, "Lock requests" },
- { INT32, F(st_nreleases), -1, -1, "Lock releases" },
- { DIFF32, F(st_nrequests), F(st_nreleases), F(st_ndeadlocks), "Outstanding locks" },
-#if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 4
- { INT32, F(st_lock_nowait), -1, -1, "Lock conflicts w/o subsequent wait" },
-#elif DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 0)
- { INT32, F(st_nnowaits), -1, -1, "Lock conflicts w/o subsequent wait" },
-#endif
- { INT32, F(st_ndeadlocks), -1, -1, "Deadlocks" },
-#if DB_VERSION_MAJOR >= 4
- { INT32, F(st_nlocktimeouts), -1, -1, "Lock timeouts" },
- { INT32, F(st_ntxntimeouts), -1, -1, "Transaction timeouts" },
-#endif
- { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting" },
- { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting" },
- { BYTES, F(st_regsize), -1, -1, "Lock region size" },
- { END, -1, -1, -1, NULL }
-};
-
-static int display_lock(void)
-{
- DB_LOCK_STAT *sp;
-
-#if DB_VERSION_MAJOR == 2
- if(lock_stat(OVDBenv->lk_info, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- if(lock_stat(OVDBenv, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3
- if(lock_stat(OVDBenv, &sp) != 0)
-#else
- if(OVDBenv->lock_stat(OVDBenv, &sp, 0) != 0)
-#endif
- return 1;
-
- display_heading("Lock Region Statistics");
- display_data(sp, LOCK_tab);
-
- free(sp);
- return 0;
-}
-
-
-#undef F
-#define F(f) OFFSETOF(DB_LOG_STAT, f)
-
-static struct datatab LOG_tab[] = {
- { HEX32, F(st_magic), -1, -1, "Log magic number" },
- { INT32, F(st_version), -1, -1, "Log version number" },
- { MODE, F(st_mode), -1, -1, "Log file mode" },
-#if DB_VERSION_MAJOR >= 3
- { BYTES, F(st_lg_bsize), -1, -1, "Log record cache size" },
-#endif
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- { BYTES, F(st_lg_size), -1, -1, "The current log file size" },
-#else
- { BYTES, F(st_lg_max), -1, -1, "Max log file size" },
-#endif
- { BYTES, F(st_w_bytes), F(st_w_mbytes), -1, "Log bytes written" },
- { BYTES, F(st_wc_bytes), F(st_wc_mbytes), -1, "Log bytes written since last checkpoint" },
- { INT32, F(st_wcount), -1, -1, "Total log writes" },
-#if DB_VERSION_MAJOR >= 3
- { INT32, F(st_wcount_fill), -1, -1, "Total log writes due to overflow" },
-#endif
- { INT32, F(st_scount), -1, -1, "Total log flushes" },
- { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting" },
- { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting" },
- { INT32, F(st_cur_file), -1, -1, "Current log file number" },
- { INT32, F(st_cur_offset), -1, -1, "Current log file offset" },
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
- { INT32, F(st_disk_file), -1, -1, "Known on disk log file number" },
- { INT32, F(st_disk_offset), -1, -1, "Known on disk log file offset" },
-#endif
- { BYTES, F(st_regsize), -1, -1, "Log region size" },
-#if DB_VERSION_MAJOR >= 4
-#if DB_VERSION_MINOR < 1
- { INT32, F(st_flushcommit), -1, -1, "Flushes containing a commit"},
-#endif
- { INT32, F(st_maxcommitperflush), -1, -1, "Max number of commits in a flush"},
- { INT32, F(st_mincommitperflush), -1, -1, "Min number of commits in a flush"},
-#endif
- { END, -1, -1, -1, NULL }
-};
-
-static int display_log(void)
-{
- DB_LOG_STAT *sp;
-
-#if DB_VERSION_MAJOR == 2
- if(log_stat(OVDBenv->lg_info, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- if(log_stat(OVDBenv, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3
- if(log_stat(OVDBenv, &sp) != 0)
-#else
- if(OVDBenv->log_stat(OVDBenv, &sp, 0) != 0)
-#endif
- return 1;
-
- display_heading("Log Region Statistics");
- display_data(sp, LOG_tab);
-
- free(sp);
- return 0;
-}
-
-
-#undef F
-#define F(f) OFFSETOF(DB_MPOOL_STAT, f)
-
-static struct datatab MEM_tab[] = {
- { INT32, F(st_cache_hit), -1, -1, "Cache hits"},
- { INT32, F(st_cache_miss), -1, -1, "Cache misses"},
- { PCT32, F(st_cache_hit), F(st_cache_miss), -1, "Cache hit percentage"},
-#if DB_VERSION_MAJOR == 2
- { INT32, F(st_cachesize), -1, -1, "Total cache size"},
- { INT32, F(st_regsize), -1, -1, "Pool region size"},
-#else
- { BYTES, F(st_bytes), -1, F(st_gbytes), "Total cache size"},
-#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
- { INT32, F(st_regsize), -1, -1, "Pool region size"},
-#else
- { INT32, F(st_ncache), -1, -1, "Number of caches"},
- { INT32, F(st_regsize), -1, -1, "Pool individual cache size"},
-#endif
-#endif
- { INT32, F(st_map), -1, -1, "Memory mapped pages"},
- { INT32, F(st_page_create), -1, -1, "Pages created in the cache"},
- { INT32, F(st_page_in), -1, -1, "Pages read into the cache"},
- { INT32, F(st_page_out), -1, -1, "Pages written from the cache to the backing file"},
- { INT32, F(st_ro_evict), -1, -1, "Clean pages forced from the cache"},
- { INT32, F(st_rw_evict), -1, -1, "Dirty pages forced from the cache"},
- { INT32, F(st_hash_buckets), -1, -1, "Hash buckets used for page location"},
- { INT32, F(st_hash_searches), -1, -1, "Total hash chain searches"},
- { INT32, F(st_hash_longest), -1, -1, "Longest hash chain searched"},
- { INT32, F(st_hash_examined), -1, -1, "Total hash entries searched"},
- { INT32, F(st_page_trickle), -1, -1, "Dirty buffers written by trickle-sync thread"},
- { INT32, F(st_page_clean), -1, -1, "Current clean buffer count"},
- { INT32, F(st_page_dirty), -1, -1, "Current dirty buffer count"},
- { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting"},
- { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting"},
- { END, -1, -1, -1, NULL }
-};
-
-#undef F
-#define F(f) OFFSETOF(DB_MPOOL_FSTAT, f)
-
-static struct datatab MEMF_tab[] = {
- { STR, F(file_name), -1, -1, "Database"},
- { SIZE, F(st_pagesize), -1, -1, "Page size"},
- { INT32, F(st_cache_hit), -1, -1, "Cache hits"},
- { INT32, F(st_cache_miss), -1, -1, "Cache misses"},
- { PCT32, F(st_cache_hit), F(st_cache_miss), -1, "Cache hit percentage"},
- { INT32, F(st_map), -1, -1, "Memory mapped pages"},
- { INT32, F(st_page_create), -1, -1, "Pages created in the cache"},
- { INT32, F(st_page_in), -1, -1, "Pages read into the cache"},
- { INT32, F(st_page_out), -1, -1, "Pages written from the cache to the backing file"},
- { END, -1, -1, -1, NULL }
-};
-
-static int display_mem(int all)
-{
- DB_MPOOL_FSTAT **fsp;
- DB_MPOOL_STAT *gsp;
-
-#if DB_VERSION_MAJOR == 2
- if(memp_stat(OVDBenv->mp_info, &gsp, &fsp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- if(memp_stat(OVDBenv, &gsp, &fsp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3
- if(memp_stat(OVDBenv, &gsp, &fsp) != 0)
-#else
- if(OVDBenv->memp_stat(OVDBenv, &gsp, &fsp, 0) != 0)
-#endif
- return 1;
-
- display_heading("Memory Pool Statistics");
- display_data(gsp, MEM_tab);
-
- if(all) {
- DB_MPOOL_FSTAT **p = fsp;
-
- start_table("Per-database Memory Pool Statistics", MEMF_tab);
- for(; p != NULL && *p != NULL; ++p) {
- display_row(*p, MEMF_tab);
- }
- end_table();
- }
-
- free(fsp);
- free(gsp);
- return 0;
-}
-
-static int txn_compare(const void *a, const void *b)
-{
- if (((const DB_TXN_ACTIVE *)a)->txnid > ((const DB_TXN_ACTIVE *)b)->txnid)
- return 1;
- if (((const DB_TXN_ACTIVE *)a)->txnid < ((const DB_TXN_ACTIVE *)b)->txnid)
- return -1;
- return 0;
-}
-
-#undef F
-#define F(f) OFFSETOF(DB_TXN_STAT, f)
-
-static struct datatab TXN_tab[] = {
- { LSN, F(st_last_ckp), -1, -1, "File/offset for last checkpoint LSN" },
-#if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
- { LSN, F(st_pending_ckp), -1, -1, "File/offset for last pending checkpoint LSN" },
-#endif
- { TIME, F(st_time_ckp), -1, -1, "Checkpoint timestamp" },
- { HEX32, F(st_last_txnid), -1, -1, "Last transaction ID allocated" },
- { INT32, F(st_maxtxns), -1, -1, "Maximum active transactions possible" },
- { INT32, F(st_nactive), -1, -1, "Active transactions" },
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
- { INT32, F(st_nrestores), -1, -1, "Restored transactions after recovery" },
-#endif
-#if DB_VERSION_MAJOR >= 3
- { INT32, F(st_maxnactive), -1, -1, "Maximum active transactions" },
-#endif
- { INT32, F(st_nbegins), -1, -1, "Transactions started" },
- { INT32, F(st_ncommits), -1, -1, "Transactions committed" },
- { INT32, F(st_naborts), -1, -1, "Transactions aborted" },
- { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting"},
- { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting"},
- { BYTES, F(st_regsize), -1, -1, "Transaction region size" },
- { END, -1, -1, -1, NULL }
-};
-
-#undef F
-#define F(f) OFFSETOF(DB_TXN_ACTIVE, f)
-
-static struct datatab TXNA_tab[] = {
- { INT32, F(txnid), -1, -1, "Transaction ID" },
-#if DB_VERSION_MAJOR >= 3
- { INT32, F(parentid), -1, -1, "Parent Transaction ID" },
-#endif
- { LSN, F(lsn), -1, -1, "Initial LSN file/offset" },
- { END, -1, -1, -1, NULL }
-};
-
-static int display_txn(void)
-{
- DB_TXN_STAT *sp;
- u_int32_t i;
-
-#if DB_VERSION_MAJOR == 2
- if(txn_stat(OVDBenv->tx_info, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- if(txn_stat(OVDBenv, &sp, NULL) != 0)
-#elif DB_VERSION_MAJOR == 3
- if(txn_stat(OVDBenv, &sp) != 0)
-#else
- if(OVDBenv->txn_stat(OVDBenv, &sp, 0) != 0)
-#endif
- return 1;
-
- display_heading("Transaction Region Statistics");
- display_data(sp, TXN_tab);
-
- if(sp->st_nactive) {
- qsort(sp->st_txnarray, sp->st_nactive, sizeof(sp->st_txnarray[0]), txn_compare);
- start_table("Active Transactions", TXNA_tab);
- for (i = 0; i < sp->st_nactive; ++i)
- display_row(&(sp->st_txnarray[i]), TXNA_tab);
- end_table();
- }
- free(sp);
- return 0;
-}
-
-static int display_ver(void)
-{
- if(html) puts("<p>");
- printf("ovdb data version: %d\n", DATA_VERSION);
- if(html) puts("<br>");
- printf("BerkeleyDB version: %s\n", db_version(NULL,NULL,NULL));
- if(html) puts("<p>");
- return 0;
-}
-
-#undef F
-#define F(f) OFFSETOF(DB_BTREE_STAT, f)
-
-static struct datatab BTREE_tab[] = {
- { HEX32, F(bt_magic), -1, -1, "Btree magic number" },
- { INT32, F(bt_version), -1, -1, "Btree version number" },
- { INT32, F(bt_minkey), -1, -1, "Minimum keys per page (minkey)" },
- { INT32, F(bt_pagesize), -1, -1, "Database page size" },
- { INT32, F(bt_levels), -1, -1, "Levels in the tree" },
-#if DB_VERSION_MAJOR == 2 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0)
- { INT32, F(bt_nrecs), -1, -1, "Keys in the tree" },
-#else
- { INT32, F(bt_nkeys), -1, -1, "Unique keys in the tree" },
- { INT32, F(bt_ndata), -1, -1, "Data items in the tree" },
-#endif
- { INT32, F(bt_int_pg), -1, -1, "Tree internal pages" },
- { BYTES, F(bt_int_pgfree), -1, -1, "Bytes free in internal pages" },
- { FF, F(bt_int_pgfree), F(bt_int_pg), F(bt_pagesize), "Internal page fill factor" },
-
- { INT32, F(bt_leaf_pg), -1, -1, "Tree leaf pages" },
- { BYTES, F(bt_leaf_pgfree), -1, -1, "Bytes free in leaf pages" },
- { FF, F(bt_leaf_pgfree), F(bt_leaf_pg), F(bt_pagesize), "Leaf page fill factor" },
-
- { INT32, F(bt_dup_pg), -1, -1, "Tree duplicate pages" },
- { BYTES, F(bt_dup_pgfree), -1, -1, "Bytes free in duplicate pages" },
- { FF, F(bt_dup_pgfree), F(bt_dup_pg), F(bt_pagesize), "Duplicate page fill factor" },
-
- { INT32, F(bt_over_pg), -1, -1, "Tree overflow pages" },
- { BYTES, F(bt_over_pgfree), -1, -1, "Bytes free overflow pages" },
- { FF, F(bt_over_pgfree), F(bt_over_pg), F(bt_pagesize), "Overflow page fill factor" },
-
-#if DB_VERSION_MAJOR >= 3
- { INT32, F(bt_free), -1, -1, "Pages on the free list" },
-#endif
- { END, -1, -1, -1, NULL }
-};
-
-static int display_btree(DB *db)
-{
- DB_BTREE_STAT *sp;
-
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
- if(db->stat(db, NULL, &sp, 0))
-#else
-#if DB_VERSION_MAJOR == 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
- if(db->stat(db, &sp, 0))
-#else
- if(db->stat(db, &sp, NULL, 0))
-#endif
-#endif
- return 1;
-
- display_heading("Btree Statistics");
- display_data(sp, BTREE_tab);
-
- free(sp);
- return 0;
-}
-
-
-#if DB_VERSION_MAJOR >= 3
-
-#undef F
-#define F(f) OFFSETOF(DB_HASH_STAT, f)
-
-static struct datatab HASH_tab[] = {
- { HEX32, F(hash_magic), -1, -1, "Hash magic number" },
- { INT32, F(hash_version), -1, -1, "Hash version number" },
- { INT32, F(hash_pagesize), -1, -1, "Database page size" },
-#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
- { INT32, F(hash_nrecs), -1, -1, "Keys in the database" },
-#else
- { INT32, F(hash_nkeys), -1, -1, "Keys in the database" },
- { INT32, F(hash_ndata), -1, -1, "Data items in the database" },
-#endif
- { INT32, F(hash_buckets), -1, -1, "Hash buckets" },
- { BYTES, F(hash_bfree), -1, -1, "Bytes free on bucket pages" },
- { FF, F(hash_buckets), F(hash_bfree), F(hash_pagesize), "Bucket page fill factor" },
-
- { INT32, F(hash_bigpages), -1, -1, "Overflow pages" },
- { BYTES, F(hash_big_bfree), -1, -1, "Bytes free on Overflow pages" },
- { FF, F(hash_bigpages), F(hash_big_bfree), F(hash_pagesize), "Overflow page fill factor" },
-
- { INT32, F(hash_overflows), -1, -1, "Bucket overflow pages" },
- { BYTES, F(hash_ovfl_free), -1, -1, "Bytes free on bucket overflow pages" },
- { FF, F(hash_overflows), F(hash_ovfl_free), F(hash_pagesize), "Bucket overflow page fill factor" },
-
- { INT32, F(hash_dup), -1, -1, "Duplicate pages" },
- { BYTES, F(hash_dup_free), -1, -1, "Bytes free in duplicate pages" },
- { FF, F(hash_dup), F(hash_dup_free), F(hash_pagesize), "Duplicate page fill factor" },
-
- { INT32, F(hash_free), -1, -1, "Pages on the free list"},
- { END, -1, -1, -1, NULL }
-};
-#endif
-
-static int display_hash(DB *db UNUSED)
-{
-#if DB_VERSION_MAJOR == 2
- printf("Hash statistics not available.\n");
- return 0;
-#else
- DB_HASH_STAT *sp;
-
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
- if(db->stat(db, NULL, &sp, 0))
-#else
-#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
- if(db->stat(db, &sp, NULL, 0))
-#else
- if(db->stat(db, &sp, 0))
-#endif
-#endif
- return 1;
-
- display_heading("Hash Information");
- display_data(sp, HASH_tab);
-
- return 0;
-#endif
-}
-
-static int display_db(char *dbfile)
-{
- int ret;
- DB *db;
-
-#if DB_VERSION_MAJOR == 2
- if(db_open(dbfile, DB_UNKNOWN, DB_RDONLY, 0, OVDBenv, NULL, &db))
- return 1;
-#else
- if(db_create(&db, OVDBenv, 0))
- return 1;
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- if(db->open(db, NULL, dbfile, NULL, DB_UNKNOWN, DB_RDONLY, 0))
-#else
- if(db->open(db, dbfile, NULL, DB_UNKNOWN, DB_RDONLY, 0))
-#endif
- return 1;
-#endif
-
- switch(db->type) {
- case DB_BTREE:
- case DB_RECNO:
- ret = display_btree(db);
- break;
- case DB_HASH:
- ret = display_hash(db);
- break;
- default:
- ret = 1;
- break;
- }
- db->close(db, 0);
- return ret;
-}
-
-static int parse_artrange(char *str, ARTNUM *start, ARTNUM *stop)
-{
- char *c;
- int i;
-
- c = strchr(str, '-');
- if(c == NULL) {
- i = atoi(str);
- if(i == 0) {
- return 1;
- }
- *start = *stop = i;
- return 0;
- }
- if(c == str) {
- *start = 0;
- *stop = atoi(str+1);
- return (*stop == 0);
- }
- if (strlen(str) == (size_t)(c - str + 1)) {
- *start = atoi(str);
- *stop = 0xffffffff;
- return (*start == 0);
- }
- *start = atoi(str);
- *stop = atoi(c+1);
- if(*start == 0 || *stop == 0 || *start > *stop)
- return 1;
-
- return 0;
-}
-
-static void htwrite(char *data, int len)
-{
- int i;
- for(i = 0; i < len; i++) {
- switch(data[i]) {
- case '<':
- case '>':
- case '&':
- printf("&#%d;", (int)data[i]);
- break;
- default:
- putchar(data[i]);
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- void *s;
- ARTNUM a, start=0, stop=0, low, high;
- char *data, *disp_db = NULL;
- int len, c, count, flag, lowi, highi;
- int getgs=0, getcount=0, getinfo=0, err=0, gotone=0;
- int disp_lock=0, disp_log=0, disp_mem=0, disp_mem_all=0, disp_txn=0, disp_ver=0;
- int needng=0, o;
-
- openlog("ovdb_stat", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_program_name = "ovdb_stat";
-
- if (!innconf_read(NULL))
- exit(1);
-
- if(!ovdb_check_user())
- die("command must be run as user " NEWSUSER);
- if(!ovdb_getlock(OVDB_LOCK_ADMIN))
- sysdie("cannot lock database");
- if(!ovdb_open(OV_READ|OVDB_SERVER))
- sysdie("cannot open overview; check syslog for OVDB messages");
-
- xsignal(SIGINT, sigfunc);
- xsignal(SIGTERM, sigfunc);
- xsignal(SIGHUP, sigfunc);
-
- while((c = getopt(argc, argv, ":Hgcir:klmMtvd:")) != -1) {
- switch(c) {
- case 'H':
- html = 1;
- break;
- case 'g':
- getgs = 1;
- needng = 1;
- gotone++;
- break;
- case 'c':
- getcount = 1;
- needng = 1;
- gotone++;
- break;
- case 'i':
- getinfo = 1;
- needng = 1;
- gotone++;
- break;
- case 'r':
- if(parse_artrange(optarg, &start, &stop))
- err++;
- needng = 1;
- gotone++;
- break;
- case 'k':
- disp_lock = 1;
- gotone++;
- break;
- case 'l':
- disp_log = 1;
- gotone++;
- break;
- case 'm':
- disp_mem = 1;
- gotone++;
- break;
- case 'M':
- disp_mem = 1;
- disp_mem_all = 1;
- gotone++;
- break;
- case 't':
- disp_txn = 1;
- gotone++;
- break;
- case 'v':
- disp_ver = 1;
- gotone++;
- break;
- case 'd':
- disp_db = optarg;
- gotone++;
- break;
- case ':':
- warn("option -%c requires an argument", optopt);
- err++;
- break;
- case '?':
- warn("unrecognized option -%c", optopt);
- err++;
- break;
- }
- }
- if(!gotone) {
- err++;
- } else if(optind == argc && needng) {
- warn("missing newsgroup argument(s)");
- err++;
- }
- if(err) {
- fprintf(stderr, "\
-Usage:\n\
- ovdb_stat -Hgci [-r artnum] newsgroup [newsgroup ...]\n\
- -H : output in HTML\n\
- -g : show groupstats info\n\
- -c : show groupstats info by counting actual records\n\
- -i : show additional group info\n\
- -r artnum-range : retrieve OV records for article number range\n\
-\n\
- ovdb_stat -Hklmtv [-d <database>]\n\
- -H : output in HTML\n\
- -k : Display lock region statistics\n\
- -l : Display log region statistics\n\
- -m : Display global memory cache statistics\n\
- -M : Display all memory cache statistics\n\
- -t : Display transaction statistics\n\
- -v : Display version information\n\
- -d database : Display statistics of specified database\n");
-
- goto out;
- }
-
- if(html)
- puts("<html><head><title>ovdb_stat</title></head><body><p>");
- if(disp_lock)
- display_lock();
- if(disp_log)
- display_log();
- if(disp_mem)
- display_mem(disp_mem_all);
- if(disp_txn)
- display_txn();
- if(disp_ver)
- display_ver();
- if(disp_db)
- display_db(disp_db);
-
- if(getgs || getcount || getinfo) {
- if(html) {
- puts("<table border=0 cellpadding=1 width=90%>\n<tr bgcolor=#3399aa>");
- puts("<th rowspan=2>Group");
- if(getgs)
- puts("<th colspan=4>Groupstats");
- if(getcount)
- puts("<th colspan=3>Counted");
- if(getinfo)
- puts("<th>Status<th colspan=2>Current<th colspan=2>Pending");
- puts("<th rowspan=2>Expired<th rowspan=2>Expire PID<tr bgcolor=#3399aa>");
- if(getgs)
- puts("<th>Low<th>High<th>Count<th>Flag");
- if(getcount)
- puts("<th>Low<th>High<th>Count");
- if(getinfo)
- puts("<th>Flags<th>GroupID<th>DB<th>GroupID<th>DB");
- }
- for(o = optind ; o < argc; o++) {
- if(html)
- printf("<tr><td>%s", argv[o]);
- if(getgs) {
- if(ovdb_groupstats(argv[o], &lowi, &highi, &count, &flag)) {
- if(html)
- printf("<td>%d<td>%d<td>%d<td>%c", lowi, highi, count, flag);
- else
- printf("%s: groupstats: low: %d, high: %d, count: %d, flag: %c\n",
- argv[o], lowi, highi, count, flag);
- }
- }
- if(getcount) {
- low = high = count = 0;
- s = ovdb_opensearch(argv[o], 1, 0xffffffff);
- if (s != NULL) {
- while(ovdb_search(s, &a, NULL, NULL, NULL, NULL)) {
- if(low == 0 || a < low)
- low = a;
- if(a > high)
- high = a;
- count++;
- if(signalled)
- break;
- }
- ovdb_closesearch(s);
- if(signalled)
- goto out;
- if(html)
- printf("<td>%ld<td>%ld<td>%d", low, high, count);
- else
- printf("%s: counted: low: %ld, high: %ld, count: %d\n",
- argv[o], low, high, count);
- }
- }
- if(getinfo) {
- int ret;
- struct groupinfo gi;
-
- ret = ovdb_getgroupinfo(argv[o], &gi, false, NULL, 0);
- if (ret != 0) {
- warn("%s: ovdb_getgroupinfo error: %s", argv[o],
- db_strerror(ret));
- continue;
- }
- if(html) {
- printf("<td>%s%s%s%s",
- (gi.status & GROUPINFO_DELETED) ? "D ":"",
- (gi.status & GROUPINFO_EXPIRING) ? "E ":"",
- (gi.status & GROUPINFO_MOVING) ? "M":"",
- (gi.status == 0) ? " ":"");
- printf("<td>%d<td>ov%05d", gi.current_gid, gi.current_db);
- if(gi.status & GROUPINFO_MOVING)
- printf("<td>%d<td>ov%05d", gi.new_gid, gi.new_db);
- else
- printf("<td> <td> ");
- if(gi.expired)
- printf("<td>%s<td>%lu", myctime(&gi.expired),
- (unsigned long) gi.expiregrouppid);
- else
- printf("<td> <td> ");
- putchar('\n');
- } else {
- printf("%s: flags: %s%s%s%s\n", argv[o],
- (gi.status & GROUPINFO_DELETED) ? "DELETED ":"",
- (gi.status & GROUPINFO_EXPIRING) ? "EXPIRING ":"",
- (gi.status & GROUPINFO_MOVING) ? "MOVING":"",
- (gi.status == 0) ? "none":"");
-
- printf("%s: gid: %d; Stored in: ov%05d\n", argv[o], gi.current_gid, gi.current_db);
- if(gi.status & GROUPINFO_MOVING)
- printf("%s: pending gid: %d; pending db: ov%05d\n", argv[o], gi.new_gid, gi.new_db);
- if(gi.expired) {
- printf("%s: last expired: %s\n", argv[o], myctime(&gi.expired));
- printf("%s: by process id: %lu\n", argv[o],
- (unsigned long) gi.expiregrouppid);
- }
- }
- }
- if(signalled)
- goto out;
- }
- if(html)
- puts("</table><p>");
- }
- if(start || stop) {
- if(html)
- puts("<pre>");
- for(o = optind ; o < argc; o++) {
- s = ovdb_opensearch(argv[o], start, stop);
- if (s != NULL) {
- while(ovdb_search(s, &a, &data, &len, NULL, NULL)) {
- if(html)
- htwrite(data, len);
- else
- fwrite(data, len, 1, stdout);
- if(signalled)
- break;
- }
- ovdb_closesearch(s);
- if(signalled)
- goto out;
- }
- if(signalled)
- goto out;
- }
- if(html)
- puts("</pre>");
- }
-out:
- if(html)
- puts("<p></body></html>");
- ovdb_close();
- return 0;
-}
-
-#endif /* USE_BERKELEY_DB */
-
+++ /dev/null
-#! /usr/bin/perl -w
-#
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Sat, 10 Oct 1998 21:40:11 +0200
-# Project: INN
-# File: pullnews.pl
-# RCSId: $Id: pullnews.in 7862 2008-06-08 09:15:41Z iulius $
-#
-# History: May 2008: Geraint A. Edwards greatly improved pullnews, adding
-# -b, -C, -d, -G, -H, -k, -l, -m, -M, -n, -P, -Q, -R, -t, -T, -w and
-# improving -s as well as fixing some bugs.
-# He also integrated the backupfeed contrib script by Kai Henningsen,
-# adding -f, -F, -N, -S, -z and -Z to pullnews.
-#
-# Description: A simple pull feeder. Connects to multiple upstream
-# machines (in the guise of a reader), and pulls over articles
-# and feeds them to a downstream server (in the guise of a feeder).
-#
-# Uses a simple configuration file: $HOME/.pullnews to define
-# which machines to pull articles from and which groups at each
-# machine to pull over. There is also support for more specific
-# configurations like cross-posted newsgroups to kill, thanks to
-# the -m flag which allows articles with headers matching regexp
-# to be dropped.
-#
-# A configuration file looks like:
-#
-# data.pa.vix.com
-# news.software.nntp 0 0
-# comp.lang.c 0 0
-# news.uu.net username password
-# uunet.announce 0 0
-# uunet.help 0 0
-#
-# Hostname lines have no leading space and may have an optional
-# username and password after the hostname; all the
-# subsequent group lines for that host must have leading
-# spaces. The two integers on the group line will be updated by
-# the program when it runs. They are the Unix time the group was
-# accessed, and the highest numbered article that was pulled
-# over.
-#
-
-require 5.004;
-
-$0 =~ s!.*/!!;
-
-my $rcsID =<<'EOM';
-$Id: pullnews.in 7862 2008-06-08 09:15:41Z iulius $
-EOM
-
-$SIG{INT} = \&outtaHere;
-$SIG{QUIT} = \&bail;
-
-use Net::NNTP 2.18; # With libnet 1.0606 (10-Dec-1998) because older versions
- # issued MODE READER with Net::NNTP::new().
-use Getopt::Std;
-use IO::Handle;
-use POSIX qw(ceil floor);
-use Fcntl;
-use Fcntl qw(:flock);
-use strict;
-
-my $usage = $0;
-my $defaultConfig = "$ENV{HOME}/.pullnews";
-my $defaultPort = 119;
-my $defaultHost = "localhost";
-my $defaultCheckPoint = 0;
-my $defaultRetries = 0;
-my $defaultDebug = 0;
-my $defaultRetryTime = 1;
-my $defaultProgressWidth = 50;
-my $defaultMaxArts;
-
-$usage =~ s!.*/!!;
-$usage .= " [ -hnqRx -b fraction -c config -C width -d level
- -f fraction -F fakehop -g groups -G newsgroups -H headers
- -k checkpt -l logfile -m header_pats -M num -N num
- -p port -P hop_limit -Q level -r file -s host[:port] -S num
- -t retries -T seconds -w num -z num -Z num ]
- [ upstream_host ... ]
-
- -b fraction backtrack on server numbering reset. The proportion
- (0.0 to 1.0) of a group's articles to pull when the
- server's article number is less than our high for that
- group. When fraction is 1.0, pull all the articles on
- the server. The default is to do nothing.
-
- -c config specify the configuration file instead of the
- default of $ENV{HOME}/.pullnews (also called ~/.pullnews).
-
- -C width use width characters for progress (default is $defaultProgressWidth).
-
- -d level set debugging level to this integer (default is $defaultDebug).
-
- -f fraction proportion of articles to get in each group (0.0 to 1.0).
-
- -F fakehop prepend fakehop as a host to the Path: header.
-
- -g groups specify a collection of groups to get. The value must be
- a single argument with commas between group names:
-
- -g comp.lang.c,comp.lang.lisp,comp.lang.python
-
- The groups must be defined in the config file somewhere.
- Only the hosts that carry those groups will be contacted.
-
- -G newsgroups add these groups to the configuration (see -g and -w).
-
- -h print this message.
-
- -H headers remove these named headers (colon-separated list).
-
- -k checkpt checkpoint the config file every checkpt articles
- (default is $defaultCheckPoint). A value of 0 means
- normally (at end).
-
- -l logfile log progress/stats to logfile (default is stdout).
-
- -m 'Hdr1:regexp1 !Hdr2:regexp2 ...'
- feed article only if:
- the Hdr1: header matches regexp1
- and the Hdr2: header does not match regexp2.
-
- -M num maximum number of articles (per group) to process before
- bailing out.
-
- -n do nothing -- just fake it.
-
- -N num timeout length when establishing NNTP connection.
-
- -p port specify the port to connect to in order to feed articles
- (default is $defaultPort).
-
- -P hop_limit count hops ('!') in the Path: header, feed article only if:
- hop_limit is '+num' and hop_count is more than num;
- or hop_limit is '-num' and hop_count is less than num.
-
- -q $0 will normally be verbose about what it is doing. This
- option will make it quiet.
-
- -Q level set the quietness level (-Q 2 is equivalent to -q).
-
- -r file rather than feeding to a server, $0 will instead
- create an rnews-compatible file.
-
- -R be a reader (use MODE READER and POST)
-
- -s host[:port]
- specify the downstream hostname (and optional port)
- (default is $defaultHost).
-
- -S num specify the maximum time (in seconds) to run.
-
- -t retries number of attempts to connect to a server
- (default is $defaultRetries, see also -T).
-
- -T secs time (in seconds) to pause between retries
- (default is $defaultRetryTime, see also -t).
-
- -w num set highwater mark to num (if num is negative, use Current+num
- instead); a num of 0 will re-get all articles on the server;
- but a num of -0 will get no old articles, set mark to Current.
-
- -x insert an Xref: header in any article that lacks one.
-
- -z num time (in seconds) to sleep between articles.
-
- -Z num time (in seconds) to sleep between groups.
-";
-
-
-use vars qw($opt_b $opt_c $opt_C $opt_d $opt_f $opt_F $opt_g $opt_G
- $opt_h $opt_H $opt_k $opt_l $opt_m $opt_M $opt_n
- $opt_N $opt_p $opt_P $opt_q $opt_Q $opt_r $opt_R $opt_s
- $opt_S $opt_t $opt_T $opt_w $opt_x $opt_z $opt_Z);
-getopts("b:c:C:d:f:F:g:G:hH:k:l:m:M:nN:p:P:qQ:r:Rs:S:t:T:w:xz:Z:") || die $usage;
-
-die $usage if $opt_h;
-
-my @groupsToGet = (); # Empty list means all groups in config file.
-my @groupsToAdd = ();
-my $rnews = $opt_r;
-my $groupFile = $opt_c || $defaultConfig;
-my $localServer = $opt_s || $defaultHost;
-my $localPort = $opt_p || $defaultPort;
-my $quiet = $opt_q;
-my $watermark = $opt_w;
-my $retries = $opt_t || $defaultRetries;
-my $retryTime = $opt_T || $defaultRetryTime;
-my $checkPoint = $opt_k || $defaultCheckPoint;
-my $debug = $opt_d || $defaultDebug;
-my $progressWidth = $opt_C || $defaultProgressWidth;
-my $maxArts = $opt_M || $defaultMaxArts;
-my $no_op = $opt_n || 0;
-my $reader = $opt_R || 0;
-my $quietness = $opt_Q || 0;
-my $skip_headers = lc($opt_H) || '';
-my $logFile = '>&STDOUT';
-$logFile = ">>$opt_l" if $opt_l;
-my @hdr_to_match = split(/\s+/, $opt_m) if defined $opt_m;
-my $pathSteps = $opt_P if defined $opt_P;
-my $path_limit;
-
-$localPort = $1 if not defined $opt_p and $localServer =~ s/:(\d+)$//;
-
-die "can\'t have both ``-s'' and ``-r''\n" if $opt_s && $opt_r;
-
-die "``-b'' value not 0.0-1.0: $opt_b\n" if defined $opt_b and $opt_b !~ /^([01](\.0*)?|0?\.\d+)$/;
-die "``-C'' value not an integer: $opt_C\n" if $progressWidth !~ m!^\d+$!;
-die "``-d'' value not an integer: $opt_d\n" if $debug !~ m!^\d+$!;
-die "``-f'' value not 0.0-1.0: $opt_f\n" if defined $opt_f and $opt_f !~ /^([01](\.0*)?|0?\.\d+)$/;
-die "``-F'' value not a hostname: $opt_F\n" if defined $opt_f and $opt_f !~ m!^[\w\-\.]+$!;
-die "``-k'' value not an integer: $opt_k\n" if $checkPoint !~ m!^\d+$!;
-die "``-M'' value not an integer: $opt_M\n" if defined $maxArts and $maxArts !~ m!^\d+$!;
-die "``-N'' value not an integer: $opt_N\n" if defined $opt_N and $opt_N !~ /^\d+$/;
-die "``-p'' value not an integer: $opt_p\n" if $localPort !~ m!^\d+$!;
-if (defined $pathSteps) {
- die "``-P'' value not a signed integer: $opt_P\n" if $pathSteps !~ /^[-+](\d+)$/;
- $path_limit = $1;
-}
-die "option ``-r -'' needs ``-l'' option\n" if defined $opt_r and $opt_r eq '-' and not $opt_l;
-die "``-S'' value not an integer: $opt_S\n" if defined $opt_S and $opt_S !~ /^\d+$/;
-die "``-t'' value not an integer: $opt_t\n" if $retries !~ m!^\d+$!;
-die "``-w'' value not an integer: $opt_w\n" if defined $watermark and $watermark !~ /^-?\d+$/;
-die "``-z'' value not an integer: $opt_z\n" if defined $opt_z and $opt_z !~ /^\d+$/;
-die "``-Z'' value not an integer: $opt_Z\n" if defined $opt_Z and $opt_Z !~ /^\d+$/;
-
-$quiet = 1 if $quietness > 1;
-my %NNTP_Args = ();
-$NNTP_Args{'Timeout'} = $opt_N if defined $opt_N;
-
-@groupsToGet = map { s!^\s*(\S+)\s*!$1!; $_ } split (",", $opt_g) if $opt_g;
-@groupsToAdd = map { s!^\s*(\S+)\s*!$1!; $_ } split (",", $opt_G) if $opt_G;
-
-$| = 1;
-
-my $servers = {};
-my $sname = undef;
-my %fed = ();
-my %refused = ();
-my %rejected = ();
-my $pulled = {};
-my %passwd = ();
-my %info = (
- fed => 0,
- refused => 0,
- rejected => 0,
- bytes => 0,
-);
-
-if ($rnews) {
- if ($no_op) {
- print "Would write to rnews file $rnews\n";
- } else {
- open(RNEWS, ">$rnews") ||
- die "can't open rnews-format output: $rnews: $!\n";
- }
-}
-open(LOG, $logFile) || die "can't open logfile ($logFile)!: $!\n";
-
-my $oldfh = select;
-$| = 1; select LOG; $| = 1; select $oldfh;
-
-my $lockfile = $ENV{HOME} . "/.pullnews.pid";
-sysopen (LOCK, "$lockfile", O_RDWR | O_CREAT, 0700) ||
- die "can't create lock file ($lockfile): $!\n";
-$oldfh = select; select LOCK; $| = 1; select $oldfh;
-
-if (!flock (LOCK, LOCK_EX | LOCK_NB)) {
- seek LOCK, 0, 0;
- my $otherpid = <LOCK>;
- chomp $otherpid;
- die "Another pullnews (pid: $otherpid) seems to be running.\n";
-}
-
-print LOCK "$$\n";
-
-print LOG scalar(localtime(time)), " start\n\n" unless $quiet;
-
-if (@groupsToGet && ! $quiet) {
- print LOG "Checking for specific groups:\n";
- map { printf LOG "\t%s\n", $_ } @groupsToGet;
- print LOG "\n";
-}
-
-open(FILE, "<$groupFile") || die "can't open group file $groupFile\n";
-while (<FILE>) {
- next if m!^\s*\#! || m!^\s*$!;
-
- if (m!^(\S+)(\s+(\S+)\s+(\S+))?\s*$!) {
- $sname = $1;
- $servers->{$sname} = {};
- $passwd{$sname} = [ $3, $4 ] if defined $3 and $3 ne "";
- } elsif (m!^\s+(\S+)\s+(\d+)\s+(\d+)!) {
- my ($group,$date,$high) = ($1,$2,$3);
- $servers->{$sname}->{$group} = [ $date, $high ];
- } elsif (m!^\s+(\S+)\s*$!) {
- # Assume this is a new group.
- my ($group,$date,$high) = ($1,0,0);
- print LOG "Looking for new group $group on $sname\n" unless $quiet;
- $servers->{$sname}->{$group} = [ $date, $high ];
- } else {
- die "Fatal error in $groupFile: $.: $_\n";
- }
-}
-close FILE;
-
-my @servers = (@ARGV || sort keys %$servers);
-
-die "No servers!\n" if ! @servers;
-
-my $localcxn;
-
-if ( not $rnews ) {
- print LOG "Connecting to downstream host: $localServer " .
- "port: $localPort ..."
- unless $quiet;
-
- my %localopts = ("Port" => "$localPort", "Reader" => $reader, %NNTP_Args);
- $localcxn = Net::NNTP->new($localServer, %localopts) ||
- die "Can't connect to server $localServer\n";
-}
-
-if ( not $quiet and not $quietness ) {
- print LOG "done.\n\n";
- print LOG "Legend: ``.'' is an article the downstream server refused\n";
- print LOG " ``*'' is an article the downstream server rejected\n";
- print LOG " ``+'' is an article the downstream server accepted\n";
- print LOG " ``x'' is an article the upstream server couldn't ";
- print LOG "give out\n";
- print LOG " ``m'' is an article skipped due to headers (-m)\n";
- print LOG "\n";
- print LOG "Writing to rnews-format output: $rnews\n\n" if $rnews;
-}
-
-foreach my $server (@servers) {
- my ($username, $passwd);
-
- foreach my $addGroup (@groupsToAdd) {
- next if defined $servers->{$server}->{$addGroup};
- $servers->{$server}->{$addGroup} = [ 0, 0 ];
- }
-
- if (@groupsToGet > 0) {
- my $ok;
- foreach my $sgroup (keys %{$servers->{$server}}) {
- $ok = 1 if grep($_ eq $sgroup, @groupsToGet);
- }
-
- if (! $ok) {
- # User gave -g and the server doesn't have those groups.
- warn "Skipping server $server. Doesn't have specified groups.\n";
- next;
- }
- }
-
- if (exists $passwd{$server}) {
- ($username, $passwd) = @{$passwd{$server}};
- }
-
- if (!exists($servers->{$server})) {
- warn "No such upstream host $server configured.\n";
- next;
- }
-
- my $shash = $servers->{$server};
-
- my $connectionAttempts = 0;
- my $upstream;
- {{
- print LOG "connecting to upstream server $server..." unless $quiet;
- $upstream = Net::NNTP->new($server, %NNTP_Args);
- $connectionAttempts++;
- if (!$upstream && $connectionAttempts <= $retries) {
- sleep $retryTime;
- next;
- }
- }}
-
- if (!$upstream) {
- print LOG "failed.\n" unless $quiet;
- warn "can't connect to upstream server $server: $!\n";
- next;
- } else {
- print LOG "done.\n" unless $quiet;
- }
-
- if ($username && !$upstream->authinfo($username, $passwd)) {
- warn sprintf ("failed to authorize: %s %s\n",
- $upstream->code(), $upstream->message());
- next;
- }
-
- $info{server}->{$server}->{bytes} = 0;
- $info{server}->{$server}->{fed} = 0;
- $info{server}->{$server}->{refused} = 0;
- $info{server}->{$server}->{rejected} = 0;
-
- foreach my $group (sort keys %{$servers->{$server}}) {
- next if (@groupsToGet && !grep ($_ eq $group, @groupsToGet));
-
- last if !crossFeedGroup ($upstream,$localcxn,$server,$group,$shash);
- last if defined $opt_S and time >= $^T+$opt_S;
- sleep $opt_Z if defined $opt_Z;
- }
-
- $upstream->quit();
- last if defined $opt_S and time >= $^T+$opt_S;
-}
-
-saveConfig ();
-stats() unless $quiet;
-
-if ($rnews) {
- if (not $no_op and not close RNEWS) {
- print LOG "\nRNEWS close failure: $!";
- }
- unlink $rnews if -f $rnews and not -s $rnews;
-}
-
-print LOG "\nDone ", scalar(localtime(time)), "\n" unless $quiet;
-
-cleanLock();
-exit (0);
-
-###############################################################################
-
-sub stats {
- my $ltotal = 0;
- my $reftotal = 0;
- my $rejtotal = 0;
- my $sum;
-
- map { $reftotal += $refused{$_} } keys %refused;
- map { $rejtotal += $rejected{$_} } keys %rejected;
- map { $ltotal += $fed{$_} } keys %fed;
-
- $sum = $reftotal + $rejtotal + $ltotal;
-
- if ($quiet) {
- printf LOG localtime() . " [$$] %d article%s to $localServer\n",
- $sum, ($sum != 1 ? "s" : "");
- } else {
- printf LOG "\n%d article%s offered to server on $localServer\n",
- $sum, ($sum != 1 ? "s were" : " was");
- }
-
- return if ($sum == 0);
-
- if ($quiet) {
- print LOG localtime() . " [$$] $ltotal ok, $reftotal ref, $rejtotal rej\n";
- } else {
- printf LOG "%d article%s accepted\n",
- $ltotal, ($ltotal != 1 ? "s were" : " was")
- if ($ltotal != 0);
- printf LOG "%d article%s refused\n",
- $reftotal, ($reftotal != 1 ? "s were" : " was")
- if ($reftotal != 0);
- printf LOG "%d article%s rejected\n",
- $rejtotal, ($rejtotal != 1 ? "s were" : " was")
- if ($rejtotal != 0);
- }
-
- map {
- print LOG "\nUpstream server $_:\n" if not $quiet;
- my $server = $_;
- my $width = 0;
-
- map {
- $width = length if length > $width;
- } sort keys %{$pulled->{$server}} if not $quiet;
-
- map {
- if ($quiet) {
- printf LOG "%s [$$] from $server $_ %s\n", localtime(), $pulled->{$server}->{$_};
- } else {
- printf LOG "\t%${width}s %d\n", $_, $pulled->{$server}->{$_};
- }
- } sort keys %{$pulled->{$server}};
- } sort keys %{$pulled};
-}
-
-sub saveConfig {
- return if $no_op;
-
- $SIG{INT} = $SIG{QUIT} = 'IGNORE';
-
- open(FILE,">$groupFile") || die "can't open $groupFile: $!\n";
- my $server;
- my $group;
-
- print LOG "\nSaving config\n" unless $quiet;
- print FILE "# Format: (date is epoch seconds)\n";
- print FILE "# hostname [username password]\n";
- print FILE "# group date high\n";
- foreach $server (sort keys %$servers) {
- print FILE "$server";
- if (defined $passwd{$server}) {
- printf FILE " %s %s", $passwd{$server}->[0], $passwd{$server}->[1];
- }
- print FILE "\n";
- foreach $group (sort keys %{$servers->{$server}}) {
- my ($date,$high) = @{$servers->{$server}->{$group}};
- printf FILE "\t%s %d %d\n",$group,$date,$high;
- }
- }
- close FILE;
-}
-
-
-sub outtaHere {
- saveConfig();
- cleanLock();
- exit (0);
-}
-
-sub cleanLock {
- flock (LOCK, LOCK_UN);
- unlink $lockfile if defined $lockfile;
-}
-
-sub bail {
- warn "received QUIT signal. Not saving config.\n";
- cleanLock();
- exit (0);
-}
-
-sub crossFeedGroup {
- my ($fromServer,$toServer,$server,$group,$shash) = @_;
- my ($date,$high) = @{$shash->{$group}};
- my ($prevDate,$prevHigh) = @{$shash->{$group}};
- my ($narticles,$first,$last,$name) = $fromServer->group($group);
- my $count = 0;
- my $code;
- my $startTime = time;
- my ($prevRefused, $prevRejected) = ($info{refused}, $info{rejected});
-
- if (!defined($narticles)) { # Group command failed.
- warn sprintf ("Group command failed: %s %s\n",
- $fromServer->code(), $fromServer->message());
- return undef;
- }
-
- if (not $quiet) {
- printf LOG "\n%s:\n", $name;
- printf LOG "\tlast checked: %s\n", scalar(localtime($prevDate));
- printf LOG "\t%d articles available. First %d Last %d\n",
- $narticles, $first, $last;
- }
- if (defined $watermark) {
- printf LOG "\tOur previous highest: %d\n", $prevHigh if not $quiet;
- $high = $watermark;
- $high = $last+$watermark if substr($watermark, 0, 1) eq '-';
- $high = 0 if $high < 0;
- $shash->{$group} = [ time, $high ];
- }
- printf LOG "\tOur current highest: %d", $high if not $quiet;
-
- return 0 if ! $name;
- if ($narticles == 0) {
- print LOG " (nothing to get)\n" unless $quiet;
- return 1;
- }
-
- my $toget = (($last - $high) < $narticles ?
- $last - $high : $narticles);
- $toget = ceil($toget * $opt_f) if defined $opt_f;
- if ($last < $high and $opt_b) {
- $high = $first+floor(($last-$first+1)*(1-$opt_b));
- $toget = $last - $high;
- print LOG " (reset highwater mark to $high)" unless $quiet;
- } elsif ($prevHigh == -1 || $last <= $prevHigh) {
- # We connected OK but there's nothing there, or we just want
- # to reset our highwater mark.
- $shash->{$group} = [ time, $high ];
- print LOG " (nothing to get)\n" unless $quiet;
- return 1;
- }
- print LOG " ($toget to get)\n" unless $quiet;
-
- my $i;
- my @warns;
- for ($i = ($first > $high ? $first : $high + 1) ; $i <= $last ; $i++) {
- last if defined $maxArts and $count >= $maxArts;
- last if defined $opt_f and $count >= $toget;
- $count++;
- sleep $opt_z if defined $opt_z and $count > 1;
- my $article = $fromServer->article($i);
- if ($article) {
- my $msgid;
- my $xref = 0;
- my $headers = 1;
- my $idx;
- my $len = 0; # Received article length (bytes) (for stats).
- my $tx_len = 0; # Transmitted article length (bytes) (for rnews).
- my @header_nums_to_go = ();
- my $match_all_hdrs = 1; # Assume no headers to match.
- my $skip_due_to_hdrs = 0;
- my %m_found_hdrs = ();
- my $curr_hdr = '';
-
- for ($idx = 0 ; $idx < @{$article} ; $idx++) {
- $len += length($article->[$idx]);
- $tx_len += length($article->[$idx]);
- next if not $headers;
-
- $curr_hdr = lc($1) if $article->[$idx] =~ /^([^:[:blank:]]+):/;
- $curr_hdr = ' ' if $article->[$idx] eq "\n";
-
- if ($match_all_hdrs and @hdr_to_match and $article->[$idx] =~ /^[^[:blank:]]/) {
- # Check header matches -m flag if new header.
-
- # Unfold this header (with following lines).
- my $unfolded_art_hdr = $article->[$idx];
- for (my $idx_step = $idx+1; $article->[$idx_step] =~ /^[[:space:]](.+)/; $idx_step++) {
- # While next line is continuation...
- my $more_line = $1;
- chomp $unfolded_art_hdr;
- $unfolded_art_hdr .= $more_line;
- }
-
- my ($hdr_un, $val_un) = split(':', $unfolded_art_hdr, 2);
- $val_un = '' if not defined $val_un;
- $val_un =~ s/^\s*//;
- for my $tuple_match (@hdr_to_match) {
- my ($hdr_m, $val_m) = split(':', $tuple_match, 2);
- my $negate_h = ($hdr_m =~ s/^!//);
- next if lc($hdr_un) ne lc($hdr_m);
- $m_found_hdrs{lc($hdr_m)} = 1;
- if ($negate_h) {
- if ($val_un =~ /$val_m/i) {
- print LOG "\tDEBUGGING $i\t-- $hdr_un [$1]\n" if $debug >= 2;
- $match_all_hdrs = 0;
- }
- } elsif (not $val_un =~ /$val_m/i) {
- print LOG "\tDEBUGGING $i\t++ $hdr_un [$1]\n" if $debug >= 2;
- $match_all_hdrs = 0;
- }
- last if not $match_all_hdrs;
- }
- }
-
- if (grep { $curr_hdr eq $_ } split(':', $skip_headers)) {
- print LOG "\tDEBUGGING $i\tskip_hdr $idx\t$curr_hdr\n" if $debug >= 2;
- push @header_nums_to_go, $idx;
- }
- if ($article->[$idx] =~ m!^message-id:\s*(\S+)!i) {
- $msgid = $1;
- }
- if (not $skip_due_to_hdrs and defined $pathSteps and $article->[$idx] =~ m!^Path:\s*!i) {
- my $path_count = $article->[$idx];
- $path_count = ($path_count =~ s@!@@g) || 0;
- if (substr($pathSteps, 0, 1) eq '-') {
- $skip_due_to_hdrs = 1 if $path_count >= $path_limit;
- } elsif (substr($pathSteps, 0, 1) eq '+') {
- $skip_due_to_hdrs = 1 if $path_count <= $path_limit;
- }
- if ($skip_due_to_hdrs) {
- print LOG "\tDEBUGGING $i\tNpath_skip_art $i\n" if $debug >= 2;
- } elsif (defined $opt_F) {
- $tx_len += length($opt_F)+1;
- $article->[$idx] =~ s/^Path:\s*/$&$opt_F!/i;
- }
- }
-
- if ($opt_x && $article->[$idx] =~ m!^xref:!i) {
- $xref = 1;
- }
-
- # Catch some of the more common problems with articles.
- if ($article->[$idx] =~ m!^\s+\n$! and $curr_hdr ne 'subject') {
- print STDERR "Fixing bad header line[$idx]-1: $article->[$idx-1]" if $idx > 0;
- print STDERR "Fixing bad header line[$idx]::: $article->[$idx]";
- print STDERR "Fixing bad header line[$idx]+1: $article->[$idx+1]";
- $tx_len -= length($article->[$idx])-1;
- $article->[$idx] = "\n";
- }
-
- $headers = 0 if $article->[$idx] eq "\n";
- }
- if (@hdr_to_match and (not $match_all_hdrs or @hdr_to_match != scalar(keys %m_found_hdrs))) {
- print LOG "\tDEBUGGING $i\thdr_skip_art $i\n" if $debug >= 2;
- $skip_due_to_hdrs = 1;
- }
- while (@header_nums_to_go) {
- my $idx = pop @header_nums_to_go; # Start from last.
- my $cut = join("\n\t", splice(@{$article}, $idx, 1));
- $tx_len -= length($cut);
- print LOG "\tDEBUGGING $i\tcut1 $cut" if $debug >= 2;
- while ($article->[$idx] =~ /^[[:space:]](.+)/) {
- # Folded lines.
- my $cut = join("\n\t", splice(@{$article}, $idx, 1));
- $tx_len -= length($cut);
- print LOG "\tDEBUGGING $i\tcut_ $cut" if $debug >= 2;
- }
- }
-
- if (!$msgid) {
- warn "No Message-ID: header found in article\n";
- next;
- } else {
- print LOG "\tDEBUGGING $i\tMessage-ID: $msgid\n" if $debug >= 2;
- }
-
- # Some old servers lack Xref:, which bothers a downstream INN if
- # it has xrefslave set, so add one just before the blank line.
- if ($opt_x && !$xref) {
- warn "No Xref: header found in article, adding\n";
- my $xref_h = "Xref: $server $group: $i\n";
- splice(@{$article}, $idx, 0, $xref_h);
- $tx_len += length($xref_h);
- }
-
- $pulled->{$server}->{$group}++;
- $info{server}->{$server}->{bytes} += $len;
- $info{bytes} += $len;
-
- if ($skip_due_to_hdrs) {
- print LOG "m" unless $quiet;
- } elsif ($rnews) {
- printf RNEWS "#! rnews %d\n", $tx_len;
- map { print RNEWS $_ } @{$article};
- print LOG "+" unless $quiet;
- } else {
- if ($no_op) {
- print "Would offer $msgid\n";
-
- } elsif ($reader and not $toServer->post($article)) {
- # 240 article posted ok
- # 340 send article to be posted. End with <CR-LF>.<CR-LF>
- # 440 posting not allowed
- # 441 posting failed
- my $code = $toServer->code();
- my $msg = $toServer->message();
- print LOG "\tDEBUGGING $i\tPost $code: Msg: <" . join('//', split(/\r?\n/, $msg)) . ">\n" if $debug >= 2;
- $msg =~ s/^340 .*?\n(?=.)//o;
- if ($msg =~ /^240 /) {
- print LOG "+" unless $quiet;
- push @warns, "Post $i ok ($code): $msg";
- $fed{$group}++;
- $info{server}->{$server}->{fed}++;
- $info{fed}++;
- } elsif ($msg =~ /^435 / or $msg =~ /duplicate message-id/io) {
- print LOG "." unless $quiet;
- push @warns, "Post $i to server declined ($code): $msg"
- if $msg !~ /^435 $msgid$/
- and $msg !~ /duplicate message-id/io;
- $refused{$group}++;
- $info{server}->{$server}->{refused}++;
- $info{refused}++;
- } else {
- warn "Post $i to server failed ($code): $msg\n";
- $toServer->quit();
- }
-
- } elsif (not $reader and not $toServer->ihave($msgid,$article)) {
- # 235 article transferred ok
- # 335 send article to be transferred. End with <CR-LF>.<CR-LF>
- # 435 article not wanted -- do not send it
- # 436 transfer failed -- try again later
- # 437 article rejected -- do not try again
- my $code = $toServer->code();
- my $msg = $toServer->message();
- print LOG "\tDEBUGGING $i\tPost $code: Msg: <" . join('//', split(/\r?\n/, $msg)) . ">\n" if $debug >= 2;
- if ($code == 435) {
- print LOG "." unless $quiet;
- $refused{$group}++;
- $info{server}->{$server}->{refused}++;
- $info{refused}++;
- } elsif ($code == 437) {
- print LOG "*" unless $quiet;
- $rejected{$group}++;
- $info{server}->{$server}->{rejected}++;
- $info{rejected}++;
- } else {
- warn "Transfer to server failed ($code): $msg\n";
- $toServer->quit();
- saveConfig();
- exit (1);
- }
-
- } else {
- my $code = $toServer->code();
- my $msg = $toServer->message();
- print LOG "\tDEBUGGING $i\tPost $code: Msg: <" . join('//', split(/\r?\n/, $msg)) . ">\n" if $debug >= 2;
- print LOG "+" unless $quiet;
- $fed{$group}++;
- $info{server}->{$server}->{fed}++;
- $info{fed}++;
- }
- }
-
- $shash->{$group} = [ time, $high = $i ];
- } else {
- $shash->{$group} = [ time, $high = $i ] if $fromServer->code() == 430; # no such article, do not retry
- print LOG "x" unless $quiet;
- printf LOG ("\nDEBUGGING $i %s %s\n", $fromServer->code(),
- $fromServer->message()) if $debug >= 2;
- }
- saveConfig() if $checkPoint and ($count % $checkPoint) == 0;
- print LOG "\n" if (!$quiet && (($count % $progressWidth) == 0));
- last if defined $opt_S and time >= $^T+$opt_S;
- }
- print LOG "\n" unless $quiet;
- print LOG join("\n\t", '', @warns) . "\n\n" if @warns;
- my $elapsed_time = time - $startTime + 1;
- if ($quiet) {
- my $rejectedDiff = $info{rejected}-$prevRejected;
- my $refusedDiff = $info{refused}-$prevRefused;
- my $destServer = ($localServer ne $defaultHost ? " to $localServer" : '');
- print LOG localtime() . "[$$] $server$destServer $name $narticles $first-$last : $count $prevHigh-" .
- ($high == $last ? '' : $high) . " $refusedDiff $rejectedDiff\n"
- unless $prevHigh == $high and $count == 0;
- } else {
- printf LOG "%s article%s retrieved in %d seconds (%d bytes, %d cps)\n",
- $count, ($count == 1 ? "" : "s"), $elapsed_time,
- $info{server}->{$server}->{bytes},
- int($info{server}->{$server}->{bytes}*100/$elapsed_time)/100;
- }
- return 1;
-}
+++ /dev/null
-/* $Id: rnews.c 7424 2005-10-09 05:04:12Z eagle $
-**
-** A front-end for InterNetNews.
-**
-** Read UUCP batches and offer them up NNTP-style. Because we may end
-** up sending our input down a pipe to uncompress, we have to be careful
-** to do unbuffered reads.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pwd.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "storage.h"
-
-
-typedef struct _HEADER {
- const char *Name;
- int size;
-} HEADER;
-
-
-static bool Verbose;
-static const char *InputFile = "stdin";
-static char *UUCPHost;
-static char *PathBadNews = NULL;
-static char *remoteServer;
-static FILE *FromServer;
-static FILE *ToServer;
-static char UNPACK[] = "gzip";
-static HEADER RequiredHeaders[] = {
- { "Message-ID", 10 },
-#define _messageid 0
- { "Newsgroups", 10 },
-#define _newsgroups 1
- { "From", 4 },
-#define _from 2
- { "Date", 4 },
-#define _date 3
- { "Subject", 7 },
-#define _subject 4
- { "Path", 4 },
-#define _path 5
-};
-#define IS_MESGID(hp) ((hp) == &RequiredHeaders[_messageid])
-#define IS_PATH(hp) ((hp) == &RequiredHeaders[_path])
-
-\f
-
-/*
-** Open up a pipe to a process with fd tied to its stdin. Return a
-** descriptor tied to its stdout or -1 on error.
-*/
-static int
-StartChild(int fd, const char *path, const char *argv[])
-{
- int pan[2];
- int i;
- pid_t pid;
-
- /* Create a pipe. */
- if (pipe(pan) < 0)
- sysdie("cannot pipe for %s", path);
-
- /* Get a child. */
- for (i = 0; (pid = fork()) < 0; i++) {
- if (i == innconf->maxforks) {
- syswarn("cannot fork %s, spooling", path);
- return -1;
- }
- notice("cannot fork %s, waiting", path);
- sleep(60);
- }
-
- /* Run the child, with redirection. */
- if (pid == 0) {
- close(pan[PIPE_READ]);
-
- /* Stdin comes from our old input. */
- if (fd != STDIN_FILENO) {
- if ((i = dup2(fd, STDIN_FILENO)) != STDIN_FILENO) {
- syswarn("cannot dup2 %d to 0, got %d", fd, i);
- _exit(1);
- }
- close(fd);
- }
-
- /* Stdout goes down the pipe. */
- if (pan[PIPE_WRITE] != STDOUT_FILENO) {
- if ((i = dup2(pan[PIPE_WRITE], STDOUT_FILENO)) != STDOUT_FILENO) {
- syswarn("cannot dup2 %d to 1, got %d", pan[PIPE_WRITE], i);
- _exit(1);
- }
- close(pan[PIPE_WRITE]);
- }
-
- execv(path, (char * const *)argv);
- syswarn("cannot execv %s", path);
- _exit(1);
- }
-
- close(pan[PIPE_WRITE]);
- close(fd);
- return pan[PIPE_READ];
-}
-
-
-/*
-** Wait for the specified number of children.
-*/
-static void
-WaitForChildren(int n)
-{
- pid_t pid;
-
- while (--n >= 0) {
- pid = waitpid(-1, NULL, WNOHANG);
- if (pid == (pid_t) -1 && errno != EINTR) {
- if (errno != ECHILD)
- syswarn("cannot wait");
- break;
- }
- }
-}
-
-
-\f
-
-/*
-** Clean up the NNTP escapes from a line.
-*/
-static char *REMclean(char *buff)
-{
- char *p;
-
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
-
- /* The dot-escape is only in text, not command responses. */
- return buff;
-}
-
-
-/*
-** Write an article to the rejected directory.
-*/
-static void
-Reject(const char *article, size_t length UNUSED, const char *reason,
- const char *arg)
-{
-#if defined(DO_RNEWS_SAVE_BAD)
- char *filename;
- FILE *F;
- int fd;
-#endif /* defined(DO_RNEWS_SAVE_BAD) */
-
- notice(reason, arg);
- if (Verbose) {
- fprintf(stderr, "%s: ", InputFile);
- fprintf(stderr, reason, arg);
- fprintf(stderr, " [%.40s...]\n", article);
- }
-
-#if defined(DO_RNEWS_SAVE_BAD)
- filename = concat(PathBadNews, "/XXXXXX", (char *) 0);
- fd = mkstemp(filename);
- if (fd < 0) {
- warn("cannot create temporary file");
- return;
- }
- F = fdopen(fd, "w");
- if (F == NULL) {
- warn("cannot fdopen %s", filename);
- return;
- }
- if (fwrite(article, 1, length, F) != length)
- warn("cannot fwrite to %s", filename);
- if (fclose(F) == EOF)
- warn("cannot close %s", filename);
- free(filename);
-#endif /* defined(DO_RNEWS_SAVE_BAD) */
-}
-
-
-/*
-** Process one article. Return true if the article was okay; false if the
-** whole batch needs to be saved (such as when the server goes down or if
-** the file is corrupted).
-*/
-static bool
-Process(char *article, size_t artlen)
-{
- HEADER *hp;
- const char *p;
- size_t length;
- char *wirefmt, *q;
- const char *id = NULL;
- char *msgid;
- char buff[SMBUF];
-#if defined(FILE_RNEWS_LOG_DUPS)
- FILE *F;
-#endif /* defined(FILE_RNEWS_LOG_DUPS) */
-#if !defined(DONT_RNEWS_LOG_DUPS)
- char path[40];
-#endif /* !defined(DONT_RNEWS_LOG_DUPS) */
-
- /* Empty article? */
- if (*article == '\0')
- return true;
-
- /* Convert the article to wire format. */
- wirefmt = ToWireFmt(article, artlen, &length);
-
- /* Make sure that all the headers are there, note the ID. */
- for (hp = RequiredHeaders; hp < ARRAY_END(RequiredHeaders); hp++) {
- p = wire_findheader(wirefmt, length, hp->Name);
- if (p == NULL) {
- free(wirefmt);
- Reject(article, artlen, "bad_article missing %s", hp->Name);
- return true;
- }
- if (IS_MESGID(hp)) {
- id = p;
- continue;
- }
-#if !defined(DONT_RNEWS_LOG_DUPS)
- if (IS_PATH(hp)) {
- strlcpy(path, p, sizeof(path));
- if ((q = strchr(path, '\r')) != NULL)
- *q = '\0';
- }
-#endif /* !defined(DONT_RNEWS_LOG_DUPS) */
- }
-
- /* Send the NNTP "ihave" message. */
- if ((p = strchr(id, '\r')) == NULL) {
- free(wirefmt);
- Reject(article, artlen, "bad_article unterminated %s header",
- "Message-ID");
- return true;
- }
- msgid = xstrndup(id, p - id);
- fprintf(ToServer, "ihave %s\r\n", msgid);
- fflush(ToServer);
- if (UUCPHost)
- notice("offered %s %s", msgid, UUCPHost);
- free(msgid);
-
- /* Get a reply, see if they want the article. */
- if (fgets(buff, sizeof buff, FromServer) == NULL) {
- free(wirefmt);
- if (ferror(FromServer))
- syswarn("cannot fgets after ihave");
- else
- warn("unexpected EOF from server after ihave");
- return false;
- }
- REMclean(buff);
- if (!CTYPE(isdigit, buff[0])) {
- free(wirefmt);
- notice("bad_reply after ihave %s", buff);
- return false;
- }
- switch (atoi(buff)) {
- default:
- free(wirefmt);
- notice("unknown_reply after ihave %s", buff);
- return false;
- case NNTP_RESENDIT_VAL:
- free(wirefmt);
- return false;
- case NNTP_SENDIT_VAL:
- break;
- case NNTP_HAVEIT_VAL:
-#if defined(SYSLOG_RNEWS_LOG_DUPS)
- *p = '\0';
- notice("duplicate %s %s", id, path);
-#endif /* defined(SYSLOG_RNEWS_LOG_DUPS) */
-#if defined(FILE_RNEWS_LOG_DUPS)
- if ((F = fopen(_PATH_RNEWS_DUP_LOG, "a")) != NULL) {
- *p = '\0';
- fprintf(F, "duplicate %s %s\n", id, path);
- fclose(F);
- }
-#endif /* defined(FILE_RNEWS_LOG_DUPS) */
- free(wirefmt);
- return true;
- }
-
- /* Send the article to the server. */
- if (fwrite(wirefmt, length, 1, ToServer) != 1) {
- free(wirefmt);
- sysnotice("cant sendarticle");
- return false;
- }
- free(wirefmt);
-
- /* Flush the server buffer. */
- if (fflush(ToServer) == EOF) {
- syswarn("cant fflush after article");
- return false;
- }
-
- /* Process server reply code. */
- if (fgets(buff, sizeof buff, FromServer) == NULL) {
- if (ferror(FromServer))
- syswarn("cannot fgets after article");
- else
- warn("unexpected EOF from server after article");
- return false;
- }
- REMclean(buff);
- if (!CTYPE(isdigit, buff[0])) {
- notice("bad_reply after article %s", buff);
- return false;
- }
- switch (atoi(buff)) {
- default:
- notice("unknown_reply after article %s", buff);
- /* FALLTHROUGH */
- case NNTP_RESENDIT_VAL:
- return false;
- case NNTP_TOOKIT_VAL:
- break;
- case NNTP_REJECTIT_VAL:
- Reject(article, artlen, "rejected %s", buff);
- break;
- }
- return true;
-}
-
-
-/*
-** Read the rest of the input as an article.
-*/
-static bool
-ReadRemainder(int fd, char first, char second)
-{
- char *article;
- char *p;
- char buf[BUFSIZ];
- int size;
- int used;
- int left;
- int skipnl;
- int i, n;
- bool ok;
-
- /* Get an initial allocation, leaving space for the \0. */
- size = BUFSIZ + 1;
- article = xmalloc(size + 2);
- article[0] = first;
- article[1] = second;
- used = second ? 2 : 1;
- left = size - used;
- skipnl = 0;
-
- /* Read the input, coverting line ends as we go if necessary. */
- while ((n = read(fd, buf, sizeof(buf))) > 0) {
- p = article + used;
- for (i = 0; i < n; i++) {
- if (skipnl) {
- skipnl = 0;
- if (buf[i] == '\n') continue;
- }
- if (buf[i] == '\r') {
- buf[i] = '\n';
- skipnl = 1;
- }
- *p++ = buf[i];
- used++;
- left--;
- if (left < SMBUF) {
- size += BUFSIZ;
- left += BUFSIZ;
- article = xrealloc(article, size);
- p = article + used;
- }
- }
- }
- if (n < 0)
- sysdie("cannot read after %d bytes", used);
-
- if (article[used - 1] != '\n')
- article[used++] = '\n';
- article[used] = '\0';
-
- ok = Process(article, used);
- free(article);
- return ok;
-}
-
-
-/*
-** Read an article from the input stream that is artsize bytes long.
-*/
-static bool
-ReadBytecount(int fd, int artsize)
-{
- static char *article;
- static int oldsize;
- char *p;
- int left;
- int i;
-
- /* If we haven't gotten any memory before, or we didn't get enough,
- * then get some. */
- if (article == NULL) {
- oldsize = artsize;
- article = xmalloc(oldsize + 1 + 1);
- }
- else if (artsize > oldsize) {
- oldsize = artsize;
- article = xrealloc(article, oldsize + 1 + 1);
- }
-
- /* Read in the article. */
- for (p = article, left = artsize; left; p += i, left -= i)
- if ((i = read(fd, p, left)) <= 0) {
- i = errno;
- warn("cannot read, wanted %d got %d", artsize, artsize - left);
-#if 0
- /* Don't do this -- if the article gets re-processed we
- * will end up accepting the truncated version. */
- artsize = p - article;
- article[artsize] = '\0';
- Reject(article, "short read (%s?)", strerror(i));
-#endif /* 0 */
- return true;
- }
- if (p[-1] != '\n') {
- *p++ = '\n';
- artsize++;
- }
- *p = '\0';
-
- return Process(article, artsize);
-}
-
-\f
-
-/*
-** Read a single text line; not unlike fgets(). Just more inefficient.
-*/
-static bool
-ReadLine(char *p, int size, int fd)
-{
- char *save;
-
- /* Fill the buffer, a byte at a time. */
- for (save = p; size > 0; p++, size--) {
- if (read(fd, p, 1) != 1) {
- *p = '\0';
- sysdie("cannot read first line, got %s", save);
- }
- if (*p == '\n') {
- *p = '\0';
- return true;
- }
- }
- *p = '\0';
- warn("bad_line too long %s", save);
- return false;
-}
-
-
-/*
-** Unpack a single batch.
-*/
-static bool
-UnpackOne(int *fdp, size_t *countp)
-{
-#if defined(DO_RNEWSPROGS)
- char path[(SMBUF * 2) + 1];
- char *p;
-#endif /* defined(DO_RNEWSPROGS) */
- char buff[SMBUF];
- const char *cargv[4];
- int artsize;
- int i;
- int gzip = 0;
- bool HadCount;
- bool SawCunbatch;
- int len;
-
- *countp = 0;
- for (SawCunbatch = false, HadCount = false; ; ) {
- /* Get the first character. */
- if ((i = read(*fdp, &buff[0], 1)) < 0) {
- syswarn("cannot read first character");
- return false;
- }
- if (i == 0)
- break;
-
- if (buff[0] == 0x1f)
- gzip = 1;
- else if (buff[0] != '#')
- /* Not a batch file. If we already got one count, the batch
- * is corrupted, else read rest of input as an article. */
- return HadCount ? false : ReadRemainder(*fdp, buff[0], '\0');
-
- /* Get the second character. */
- if ((i = read(*fdp, &buff[1], 1)) < 0) {
- syswarn("cannot read second character");
- return false;
- }
- if (i == 0)
- /* A one-byte batch? */
- return false;
-
- /* Check second magic character. */
- /* gzipped ($1f$8b) or compressed ($1f$9d) */
- if (gzip && ((buff[1] == (char)0x8b) || (buff[1] == (char)0x9d))) {
- cargv[0] = "gzip";
- cargv[1] = "-d";
- cargv[2] = NULL;
- lseek(*fdp, 0, 0); /* Back to the beginning */
- *fdp = StartChild(*fdp, _PATH_GZIP, cargv);
- if (*fdp < 0)
- return false;
- (*countp)++;
- SawCunbatch = true;
- continue;
- }
- if (buff[1] != '!')
- return HadCount ? false : ReadRemainder(*fdp, buff[0], buff[1]);
-
- /* Some kind of batch -- get the command. */
- if (!ReadLine(&buff[2], (int)(sizeof buff - 3), *fdp))
- return false;
-
- if (strncmp(buff, "#! rnews ", 9) == 0) {
- artsize = atoi(&buff[9]);
- if (artsize <= 0) {
- syswarn("bad_line bad count %s", buff);
- return false;
- }
- HadCount = true;
- if (ReadBytecount(*fdp, artsize))
- continue;
- return false;
- }
-
- if (HadCount)
- /* Already saw a bytecount -- probably corrupted. */
- return false;
-
- if (strcmp(buff, "#! cunbatch") == 0) {
- if (SawCunbatch) {
- syswarn("nested_cunbatch");
- return false;
- }
- cargv[0] = UNPACK;
- cargv[1] = "-d";
- cargv[2] = NULL;
- *fdp = StartChild(*fdp, _PATH_GZIP, cargv);
- if (*fdp < 0)
- return false;
- (*countp)++;
- SawCunbatch = true;
- continue;
- }
-
-#if defined(DO_RNEWSPROGS)
- cargv[0] = UNPACK;
- cargv[1] = NULL;
- /* Ignore any possible leading pathnames, to avoid trouble. */
- if ((p = strrchr(&buff[3], '/')) != NULL)
- p++;
- else
- p = &buff[3];
- if (strchr(_PATH_RNEWSPROGS, '/') == NULL) {
- snprintf(path, sizeof(path), "%s/%s/%s", innconf->pathbin,
- _PATH_RNEWSPROGS, p);
- len = strlen(innconf->pathbin) + 1 + sizeof _PATH_RNEWSPROGS;
- } else {
- snprintf(path, sizeof(path), "%s/%s", _PATH_RNEWSPROGS, p);
- len = sizeof _PATH_RNEWSPROGS;
- }
- for (p = &path[len]; *p; p++)
- if (ISWHITE(*p)) {
- *p = '\0';
- break;
- }
- *fdp = StartChild(*fdp, path, cargv);
- if (*fdp < 0)
- return false;
- (*countp)++;
- continue;
-#else
- warn("bad_format unknown command %s", buff);
- return false;
-#endif /* defined(DO_RNEWSPROGS) */
- }
- return true;
-}
-
-
-/*
-** Read all articles in the spool directory and unpack them. Print all
-** errors with xperror as well as syslog, since we're probably being run
-** interactively.
-*/
-static void
-Unspool(void)
-{
- DIR *dp;
- struct dirent *ep;
- bool ok;
- struct stat Sb;
- char hostname[10];
- int fd;
- size_t i;
- char *uuhost;
-
- message_handlers_die(2, message_log_stderr, message_log_syslog_err);
- message_handlers_warn(2, message_log_stderr, message_log_syslog_err);
-
- /* Go to the spool directory, get ready to scan it. */
- if (chdir(innconf->pathincoming) < 0)
- sysdie("cannot chdir to %s", innconf->pathincoming);
- if ((dp = opendir(".")) == NULL)
- sysdie("cannot open spool directory");
-
- /* Loop over all files, and parse them. */
- while ((ep = readdir(dp)) != NULL) {
- InputFile = ep->d_name;
- if (InputFile[0] == '.')
- continue;
- if (stat(InputFile, &Sb) < 0 && errno != ENOENT) {
- syswarn("cannot stat %s", InputFile);
- continue;
- }
-
- if (!S_ISREG(Sb.st_mode))
- continue;
-
- if ((fd = open(InputFile, O_RDWR)) < 0) {
- if (errno != ENOENT)
- syswarn("cannot open %s", InputFile);
- continue;
- }
-
- /* Make sure multiple Unspools don't stomp on eachother. */
- if (!inn_lock_file(fd, INN_LOCK_WRITE, 0)) {
- close(fd);
- continue;
- }
-
- /* Get UUCP host from spool file, deleting the mktemp XXXXXX suffix. */
- uuhost = UUCPHost;
- hostname[0] = 0;
- if ((i = strlen(InputFile)) > 6) {
- i -= 6;
- if (i > sizeof hostname - 1)
- /* Just in case someone wrote their own spooled file. */
- i = sizeof hostname - 1;
- strlcpy(hostname, InputFile, i + 1);
- UUCPHost = hostname;
- }
- ok = UnpackOne(&fd, &i);
- WaitForChildren(i);
- UUCPHost = uuhost;
-
- /* If UnpackOne returned true, the article has been dealt with one way
- or the other, so remove it. Otherwise, leave it in place; either
- we got an unknown error from the server or we got a deferral, and
- for both we want to try later. */
- if (ok) {
- if (unlink(InputFile) < 0)
- syswarn("cannot remove %s", InputFile);
- }
-
- close(fd);
- }
- closedir(dp);
-
- message_handlers_die(1, message_log_syslog_err);
- message_handlers_warn(1, message_log_syslog_err);
-}
-
-\f
-
-/*
-** Can't connect to the server, so spool our input. There isn't much
-** we can do if this routine fails, unfortunately. Perhaps try to use
-** an alternate filesystem?
-*/
-static void
-Spool(int fd, int mode)
-{
- int spfd;
- int i;
- int j;
- char *tmpspool, *spoolfile, *p;
- char buff[BUFSIZ];
- int count;
- int status;
-
- if (mode == 'N')
- exit(9);
- tmpspool = concat(innconf->pathincoming, "/.",
- UUCPHost ? UUCPHost : "", "XXXXXX", (char *)0);
- spfd = mkstemp(tmpspool);
- if (spfd < 0)
- sysdie("cannot create temporary batch file %s", tmpspool);
- if (fchmod(spfd, BATCHFILE_MODE) < 0)
- sysdie("cannot chmod temporary batch file %s", tmpspool);
-
- /* Read until we there is nothing left. */
- for (status = 0, count = 0; (i = read(fd, buff, sizeof buff)) != 0; ) {
- /* Break out on error. */
- if (i < 0) {
- syswarn("cannot read after %d", count);
- status++;
- break;
- }
- /* Write out what we read. */
- for (count += i, p = buff; i; p += j, i -= j)
- if ((j = write(spfd, p, i)) <= 0) {
- syswarn("cannot write around %d", count);
- status++;
- break;
- }
- }
-
- /* Close the file. */
- if (close(spfd) < 0) {
- syswarn("cannot close spooled article %s", tmpspool);
- status++;
- }
-
- /* Move temp file into the spool area, and exit appropriately. */
- spoolfile = concat(innconf->pathincoming, "/",
- UUCPHost ? UUCPHost : "", "XXXXXX", (char *)0);
- spfd = mkstemp(spoolfile);
- if (spfd < 0) {
- syswarn("cannot create spool file %s", spoolfile);
- status++;
- } else {
- close(spfd);
- if (rename(tmpspool, spoolfile) < 0) {
- syswarn("cannot rename %s to %s", tmpspool, spoolfile);
- status++;
- }
- }
- free(tmpspool);
- free(spoolfile);
- exit(status);
- /* NOTREACHED */
-}
-
-
-/*
-** Try to read the password file and open a connection to a remote
-** NNTP server.
-*/
-static bool OpenRemote(char *server, int port, char *buff)
-{
- int i;
-
- /* Open the remote connection. */
- if (server)
- i = NNTPconnect(server, port, &FromServer, &ToServer, buff);
- else
- i = NNTPremoteopen(port, &FromServer, &ToServer, buff);
- if (i < 0)
- return false;
-
- *buff = '\0';
- if (NNTPsendpassword(server, FromServer, ToServer) < 0) {
- int oerrno = errno;
- fclose(FromServer);
- fclose(ToServer);
- errno = oerrno;
- return false;
- }
- return true;
-}
-
-
-/*
-** Can't connect to server; print message and spool if necessary.
-*/
-static void
-CantConnect(char *buff, int mode, int fd)
-{
- if (buff[0])
- notice("rejected connection %s", REMclean(buff));
- else
- syswarn("cant open_remote");
- if (mode != 'U')
- Spool(fd, mode);
- exit(1);
-}
-
-
-int main(int ac, char *av[])
-{
- int fd;
- int i;
- size_t count;
- int mode;
- char buff[SMBUF];
- int port = NNTP_PORT;
-
- /* First thing, set up logging and our identity. */
- openlog("rnews", L_OPENLOG_FLAGS, LOG_INN_PROG);
- message_program_name = "rnews";
- message_handlers_notice(1, message_log_syslog_notice);
- message_handlers_warn(1, message_log_syslog_err);
- message_handlers_die(1, message_log_syslog_err);
-
- /* The reason for the following is somewhat obscure and is done only
- because rnews is sometimes installed setuid.
-
- The stderr stream used by message_log_syslog_err is associated with
- file descriptor 2, generally even if that file descriptor is closed.
- Someone running rnews may close all of the standard file descriptors
- before running it, in which case, later in its operations, one of the
- article files or network connections it has open could be file
- descriptor 2. If an error occurs at that point, the error message may
- be written to that file or network connection instead of to stderr,
- with unpredictable results.
-
- We avoid this by burning three file descriptors if the real and
- effective user IDs don't match, or if we're running as root. (If they
- do match, there is no escalation of privileges and at worst the user is
- just managing to produce a strange bug.) */
- if (getuid() != geteuid() || geteuid() == 0) {
- if (open("/dev/null", O_RDONLY) < 0)
- sysdie("cannot open /dev/null");
- if (open("/dev/null", O_RDONLY) < 0)
- sysdie("cannot open /dev/null");
- if (open("/dev/null", O_RDONLY) < 0)
- sysdie("cannot open /dev/null");
- }
-
- /* Make sure that we switch to the news user if we're running as root,
- since we may spool files and don't want those files owned by root.
- Don't require that we be running as the news user, though; there are
- other setups where rnews might be setuid news or be run by other
- processes in the news group. */
- if (getuid() == 0 || geteuid() == 0) {
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)",
- NEWSUSER);
- setuid(pwd->pw_uid);
- }
-
- if (!innconf_read(NULL))
- exit(1);
- UUCPHost = getenv(_ENV_UUCPHOST);
- PathBadNews = concatpath(innconf->pathincoming, _PATH_BADNEWS);
- port = innconf->nnrpdpostport;
-
- umask(NEWSUMASK);
-
- /* Parse JCL. */
- fd = STDIN_FILENO;
- mode = '\0';
- while ((i = getopt(ac, av, "h:P:NUvr:S:")) != EOF)
- switch (i) {
- default:
- die("usage error");
- /* NOTRTEACHED */
- case 'h':
- UUCPHost = *optarg ? optarg : NULL;
- break;
- case 'N':
- case 'U':
- mode = i;
- break;
- case 'P':
- port = atoi(optarg);
- break;
- case 'v':
- Verbose = true;
- break;
- case 'r':
- case 'S':
- remoteServer = optarg;
- break;
- }
- ac -= optind;
- av += optind;
-
- /* Parse arguments. At most one, the input file. */
- switch (ac) {
- default:
- die("usage error");
- /* NOTREACHED */
- case 0:
- break;
- case 1:
- if (mode == 'U')
- die("usage error");
- if (freopen(av[0], "r", stdin) == NULL)
- sysdie("cannot freopen %s", av[0]);
- fd = fileno(stdin);
- InputFile = av[0];
- break;
- }
-
- /* Open the link to the server. */
- if (remoteServer != NULL) {
- if (!OpenRemote(remoteServer,port,buff))
- CantConnect(buff,mode,fd);
- } else if (innconf->nnrpdposthost != NULL) {
- if (!OpenRemote(innconf->nnrpdposthost,
- (port != NNTP_PORT) ? port : innconf->nnrpdpostport, buff))
- CantConnect(buff, mode, fd);
- }
- else {
-#if defined(DO_RNEWSLOCALCONNECT)
- if (NNTPlocalopen(&FromServer, &ToServer, buff) < 0) {
- /* If server rejected us, no point in continuing. */
- if (buff[0])
- CantConnect(buff, mode, fd);
- if (!OpenRemote((char *)NULL,
- (port != NNTP_PORT) ? port : innconf->port, buff))
- CantConnect(buff, mode, fd);
- }
-#else
- if (!OpenRemote((char *)NULL,
- (port != NNTP_PORT) ? port : innconf->port, buff))
- CantConnect(buff, mode, fd);
-#endif /* defined(DO_RNEWSLOCALCONNECT) */
- }
- close_on_exec(fileno(FromServer), true);
- close_on_exec(fileno(ToServer), true);
-
- /* Execute the command. */
- if (mode == 'U')
- Unspool();
- else {
- if (!UnpackOne(&fd, &count)) {
- lseek(fd, 0, 0);
- Spool(fd, mode);
- }
- close(fd);
- WaitForChildren(count);
- }
-
- /* Tell the server we're quitting, get his okay message. */
- fprintf(ToServer, "quit\r\n");
- fflush(ToServer);
- fgets(buff, sizeof buff, FromServer);
-
- /* Return the appropriate status. */
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# @(#)scanspool.pl 1.20 4/6/92 00:47:35
-#
-# Written by: Landon Curt Noll (chongo was here /\../\)
-#
-# This code is placed in the public domain.
-#
-# scanspool - perform a big scan over all articles in /usr/spool/news
-#
-# usage:
-# scanspool [-a active_file] [-s spool_dir] [-v] [-c] [-n]
-#
-# -a active_file active file to use (default /usr/lib/news/active)
-# -s spool_dir spool tree (default /usr/spool/news)
-# -v verbose mode
-# verbose messages begin with a tab
-# show articles found in non-active directories
-# -c check article filenames, don't scan the articles
-# -n don't throttle innd
-#
-# NOTE: This take a while, -v is a good thing if you want to know
-# how far this program has progressed.
-#
-# This program will scan first the active file, noting problems such as:
-#
-# malformed line
-# group aliased to a non-existent group
-# group aliased to a group tat is also aliased
-#
-# Then it will examine all articles under your news spool directory,
-# looking for articles that:
-#
-# basename that starts with a leading 0
-# basename that is out of range with the active file
-# does not contain a Newsgroups: line
-# article that is all header and no text
-# is in a directory for which there is no active group
-# article that is in a group to which it does not belong
-#
-# Scanspool understands aliased groups. Thus, if an article is posted
-# to foo.old.name that is aliases to foo.bar, it will be expected to
-# be found under foo.bar and not foo.old.name.
-#
-# Any group that is of type 'j' or 'x' (4th field of the active file)
-# will be allowed to show up under the junk group.
-#
-# Scanspool assumes that the path of a valid newsgroup's directory
-# from the top of the spool tree will not contain any "." character.
-# Thus, directories such as out.going, tmp.dir, in.coming and
-# news.archive will not be searched. This program also assumes that
-# article basenames contain only decimal digits. Last, files under
-# the top level directory "lost+found" are not scanned.
-#
-# The output of scanspool will start with one of 4 forms:
-#
-# FATAL: fatal or internal error (to stderr)
-#
-# WARN: active or article format problem, (to stderr)
-# group alias problem, find error,
-# article open error
-#
-# path/123: basename starts with 0, (to stdout)
-# article number out of range,
-# article in the wrong directory,
-# article in directory not related to
-# an active non-aliases newsgroup
-#
-# \t ... verbose message starting with a tab (to stdout)
-
-
-# Data structures
-#
-# $gname2type{$name}
-# $name - newsgroup name in foo.dot.form
-# produces => 4th active field (y, n, x, ...)
-# alias type is "=", not "=foo.bar"
-#
-# $realgname{$name}
-# $name - newsgroup name in foo.dot.form
-# produces => newsgroup name in foo.dot.form
-# if type is =, this will be a.b, not $name
-#
-# $lowart{$name}
-# $name - newsgroup name in foo.dot.form
-# produces => lowest article allowed in the group
-# if type is =, this is not valid
-#
-# $highart{$name}
-# $name - newsgroup name in foo.dot.form
-# produces => highest article allowed in the group
-# if type is =, this is not valid
-# If $highart{$name} < $lowart{$name},
-# then the group should be empty
-
-# perl requirements
-#
-require "getopts.pl";
-
-# setup non-buffered stdout and stderr
-#
-select(STDERR);
-$|=1;
-select(STDOUT);
-$|=1;
-
-# global constants
-#
-$prog = $0; # our name
-$spool = "$inn::patharticles";
-$active = "$inn::pathdb/active";
-$ctlinnd = "$inn::pathbin/ctlinnd";
-$reason = "running scanspool"; # throttle reason
-
-# parse args
-#
-&Getopts("a:s:vcn");
-$active = $opt_a if (defined($opt_a));
-$spool = $opt_s if (defined($opt_s));
-
-# throttle innd unless -n
-#
-if (! defined($opt_n)) {
- system("$ctlinnd throttle '$reason' >/dev/null 2>&1");
-}
-
-# process the active file
-#
-&parse_active($active);
-
-# check the spool directory
-#
-&check_spool($spool);
-
-# unthrottle innd unless -n
-#
-if (! defined($opt_n)) {
- system("$ctlinnd go '$reason' >/dev/null 2>&1");
-}
-
-# all done
-exit(0);
-
-
-# parse_active - parse the active file
-#
-# From the active file, fill out the @gname2type (type of newsgroup)
-# and @realgname (real/non-aliased name of group), @lowart & @highart
-# (low and high article numbers). This routine will also check for
-# aliases to missing groups or groups that are also aliases.
-#
-sub parse_active
-{
- local ($active) = $_[0]; # the name of the active file to use
- local (*ACTIVE); # active file handle
- local ($line); # active file line
- local ($name); # name of newsgroup
- local ($low); # low article number
- local ($high); # high article number
- local ($type); # type of newsgroup (4th active field)
- local ($field5); # 5th active field (should not exist)
- local ($dir); # directory path of group from $spool
- local ($alias); # realname of an aliased group
- local ($linenum); # active file line number
-
- # if verbose (-v), say what we are doing
- print "\tscanning $active\n" if defined($opt_v);
-
- # open the active file
- open (ACTIVE, $active) || &fatal(1, "cannot open $active");
-
- # parse each line
- $linenum = 0;
- while ($line = <ACTIVE>) {
-
- # count the line
- ++$linenum;
-
- # verify that we have a correct number of tokens
- if ($line !~ /^\S+ 0*(\d+) 0*(\d+) \S+$/o) {
- &problem("WARNING: active line is mal-formed at line $linenum");
- next;
- }
- ($name, $high, $low, $type) = $line =~ /^(\S+) 0*(\d+) 0*(\d+) (\S+)$/o;
-
- # watch for duplicate entries
- if (defined($realgname{$name})) {
- &problem("WARNING: ignoring dup group: $name, at line $linenum");
- next;
- }
-
- # record which type it is
- $gname2type{$name} = $type;
-
- # record the low and high article numbers
- $lowart{$name} = $low;
- $highart{$name} = $high;
-
- # determine the directory and real group name
- if ($type eq "j" || $type eq "x") {
- $dir = "junk";
- $alias = $name;
- } elsif ($type =~ /^=(.+)/o) {
- $alias = $1;
- ($dir = $alias) =~ s#\.#/#go;
- $gname2type{$name} = "="; # rename type to be just =
- } else {
- $dir = $name;
- $dir =~ s#\.#/#go;
- $alias = $name;
- }
- $realgname{$name} = $alias;
- }
-
- # close the active file
- close (ACTIVE);
-
- # be sure that any alias type is aliased to a real group
- foreach $name (keys %realgname) {
-
- # skip if not an alias type
- next if $gname2type{$name} ne "=";
-
- # be sure that the alias exists
- $alias = $realgname{$name};
- if (! defined($realgname{$alias})) {
- &problem("WARNING: alias for $name: $alias, is not a group");
- next;
- }
-
- # be sure that the alias is not an alias of something else
- if ($gname2type{$alias} eq "=") {
- &problem("WARNING: alias for $name: $alias, is also an alias");
- next;
- }
- }
-}
-
-
-# problem - report a problem to stdout
-#
-# Print a message to stdout. Parameters are space separated.
-# A final newline is appended to it.
-#
-# usage:
-# &problem(arg, arg2, ...)
-#
-sub problem
-{
- local ($line); # the line to write
-
- # print the line with the header and newline
- $line = join(" ", @_);
- print STDERR $line, "\n";
-}
-
-
-# fatal - report a fatal error to stderr and exit
-#
-# Print a message to stderr. The message has the program name prepended
-# to it. Parameters are space separated. A final newline is appended
-# to it. This function exists with the code of exitval.
-#
-# usage:
-# &fatal(exitval, arg, arg2, ...)
-#
-sub fatal
-{
- local ($exitval) = $_[0]; # what to exit with
-
- # firewall
- if ($#_ < 1) {
- print STDERR "FATAL: fatal called with only ", $#_-1, " arguments\n";
- if ($#_ < 0) {
- $exitval = -1;
- }
- }
-
- # print the error message
- shift(@_);
- $line = join(" ", @_);
- print STDERR "$prog: ", $line, "\n";
-
- # unthrottle innd unless -n
- #
- if (! defined($opt_n)) {
- system("$ctlinnd go '$reason' >/dev/null 2>&1");
- }
-
- # exit
- exit($exitval);
-}
-
-
-# check_spool - check the articles found in the spool directory
-#
-# This subroutine will check all articles found under the $spool directory.
-# It will examine only file path that do not contain any "." or whitespace
-# character, and whose basename is completely numeric. Files under
-# lost+found will also be ignored.
-#
-# given:
-# $spooldir - top of /usr/spool/news article tree
-#
-sub check_spool
-{
- local ($spooldir) = $_[0]; # top of article tree
- local (*FILEFILE); # pipe from the find files process
- local ($filename); # article pathname under $spool
- local ($artgrp); # group of an article
- local ($artnum); # article number in a group
- local ($prevgrp); # previous different value of $artgrp
- local ($preverrgrp); # previous non-active $artgrp
- local (*ARTICLE); # article handle
- local ($aline); # header line from an article
- local (@group); # array of groups from the Newsgroup header
- local ($j);
-
- # if verbose, say what we are doing
- print "\tfinding articles under $spooldir\n" if defined($opt_v);
-
- # move to the $spool directory
- chdir $spooldir || &fatal(2, "cannot chdir to $spool");
-
- # start finding files
- #
- if (!open (FINDFILE,
- "find . \\( -type f -o -type l \\) -name '[0-9]*' -print 2>&1 |")) {
- &fatal(3, "cannot start find in $spool");
- }
-
- # process each history line
- #
- while ($filename = <FINDFILE>) {
-
- # if the line contains find:, assume it is a find error and print it
- chop($filename);
- if ($filename =~ /find:\s/o) {
- &problem("WARNING:", $filename);
- next;
- }
-
- # remove the \n and ./ that find put in our path
- $filename =~ s#^\./##o;
-
- # skip is this path has a . in it (beyond a leading ./)
- next if ($filename =~ /\./o);
-
- # skip if lost+found
- next if ($filename =~ m:^lost+found/:o);
-
- # skip if not a numeric basename
- next if ($filename !~ m:/\d+$:o);
-
- # get the article's newsgroup name (based on its path from $spool)
- $artgrp = $filename;
- $artgrp =~ s#/\d+$##o;
- $artgrp =~ s#/#.#go;
-
- # if verbose (-v), then note if our group changed
- if (defined($opt_v) && $artgrp ne $prevgrp) {
- print "\t$artgrp\n";
- $prevgrp = $artgrp;
- }
-
- # note if the article is not in a directory that is used by
- # a real (non-aliased) group in the active file
- #
- # If we complained about this dgroup before, don't complain again.
- # If verbose, note files that could be removed.
- #
- if (!defined($gname2type{$artgrp}) || $gname2type{$artgrp} =~ /[=jx]/o){
- if ($preverrgrp ne $artgrp) {
- &problem("$artgrp: not an active group directory");
- $preverrgrp = $artgrp;
- }
- if (defined($opt_v)) {
- &problem("$filename: article found in non-active directory");
- }
- next;
- }
-
- # check on the article number
- $artnum = $filename;
- $artnum =~ s#^.+/##o;
- if ($artnum =~ m/^0/o) {
- &problem("$filename: article basename starts with a 0");
- }
- if (defined($gname2type{$artgrp})) {
- if ($lowart{$artgrp} > $highart{$artgrp}) {
- &problem("$filename: active indicates group should be empty");
- } elsif ($artnum < $lowart{$artgrp}) {
- &problem("$filename: article number is too low");
- } elsif ($artnum > $highart{$artgrp}) {
- &problem("$filename: article number is too high");
- }
- }
-
- # if check filenames only (-c), then do nothing else with the file
- next if (defined($opt_c));
-
- # don't open a control or junk, they can be from anywhere
- next if ($artgrp eq "control" || $artgrp eq "junk");
-
- # try open the file
- if (!open(ARTICLE, $filename)) {
-
- # the find is now gone (expired?), give up on it
- &problem("WARNING: cannot open $filename");
- next;
- }
-
- # read until the Newsgroup header line is found
- AREADLINE:
- while ($aline = <ARTICLE>) {
-
- # catch the newsgroup: header
- if ($aline =~ /^Newsgroups:\w*\W/io) {
-
- # convert $aline into a comma separated list of groups
- $aline =~ s/^Newsgroups://io;
- $aline =~ tr/ \t\n//d;
-
- # form an array of news groups
- @group = split(",", $aline);
-
- # see if any groups in the Newsgroup list are our group
- for ($j=0; $j <= $#group; ++$j) {
-
- # look at the group
- if ($realgname{$group[$j]} eq $artgrp) {
- # this article was posted to this group
- last AREADLINE;
- }
- }
-
- # no group or group alias was found
- &problem("$filename: does not belong in $artgrp");
- last;
-
- # else watch for the end of the header
- } elsif ($aline =~ /^\s*$/o) {
-
- # no Newsgroup: header found
- &problem("WARNING: $filename: no Newsgroup header");
- last;
- }
- if (eof(ARTICLE)) {
- &problem("WARNING: $filename: EOF found while reading header");
- }
- }
-
- # close the article
- close(ARTICLE);
- }
-
- # all done with the find
- close(FINDFILE);
-}
+++ /dev/null
-/* $Id: sm.c 6682 2004-03-06 18:31:15Z rra $
-**
-** Provide a command line interface to the storage manager
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "storage.h"
-
-static const char usage[] = "\
-Usage: sm [-dHiqrRS] [token ...]\n\
-\n\
-Command-line interface to the INN storage manager. The default action is\n\
-to display the complete article associated with each token given. If no\n\
-tokens are specified on the command line, they're read from stdin, one per\n\
-line.\n\
-\n\
- -d, -r Delete the articles associated with the given tokens\n\
- -H Display the headers of articles only\n\
- -i Translate tokens into newsgroup names and article numbers\n\
- -q Suppress all error messages except usage\n\
- -R Display the raw article rather than undoing wire format\n\
- -S Output articles in rnews batch file format\n";
-
-/* The options that can be set on the command line, used to determine what to
- do with each token. */
-struct options {
- bool artinfo; /* Show newsgroup and article number. */
- bool delete; /* Delete articles instead of showing them. */
- bool header; /* Display article headers only. */
- bool raw; /* Show the raw wire-format articles. */
- bool rnews; /* Output articles as rnews batch files. */
-};
-
-
-/*
-** Process a single token, performing the operations specified in the given
-** options struct. Calls warn and die to display error messages; -q is
-** implemented by removing all the warn and die error handlers.
-*/
-static bool
-process_token(const char *id, const struct options *options)
-{
- TOKEN token;
- struct artngnum artinfo;
- ARTHANDLE *article;
- size_t length;
- char *text;
-
- if (!IsToken(id)) {
- warn("%s is not a storage token", id);
- return false;
- }
- token = TextToToken(id);
-
- if (options->artinfo) {
- if (!SMprobe(SMARTNGNUM, &token, &artinfo)) {
- warn("could not get article information for %s", id);
- return false;
- } else {
- printf("%s: %lu\n", artinfo.groupname, artinfo.artnum);
- free(artinfo.groupname);
- }
- } else if (options->delete) {
- if (!SMcancel(token)) {
- warn("could not remove %s: %s", id, SMerrorstr);
- return false;
- }
- } else {
- article = SMretrieve(token, options->header ? RETR_HEAD : RETR_ALL);
- if (article == NULL) {
- warn("could not retrieve %s", id);
- return false;
- }
- if (options->raw) {
- if (fwrite(article->data, article->len, 1, stdout) != 1)
- die("output failed");
- } else {
- text = FromWireFmt(article->data, article->len, &length);
- if (options->rnews)
- printf("#! rnews %lu\n", (unsigned long) length);
- if (fwrite(text, length, 1, stdout) != 1)
- die("output failed");
- free(text);
- }
- SMfreearticle(article);
- }
- return true;
-}
-
-
-int
-main(int argc, char *argv[])
-{
- int option;
- bool okay, status;
- struct options options = { false, false, false, false, false };
-
- message_program_name = "sm";
-
- if (!innconf_read(NULL))
- exit(1);
-
- while ((option = getopt(argc, argv, "iqrdRSH")) != EOF) {
- switch (option) {
- case 'd':
- case 'r':
- options.delete = true;
- break;
- case 'H':
- options.header = true;
- break;
- case 'i':
- options.artinfo = true;
- break;
- case 'q':
- message_handlers_warn(0);
- message_handlers_die(0);
- break;
- case 'R':
- options.raw = true;
- break;
- case 'S':
- options.rnews = true;
- break;
- default:
- fprintf(stderr, usage);
- exit(1);
- }
- }
-
- /* Check options for consistency. */
- if (options.artinfo && options.delete)
- die("-i cannot be used with -r, -d");
- if (options.artinfo && (options.header || options.raw || options.rnews))
- die("-i cannot be used with -H, -R, or -S");
- if (options.delete && (options.header || options.rnews))
- die("-r or -d cannot be used with -H or -S");
- if (options.raw && options.rnews)
- die("-R cannot be used with -S");
- if (options.header && options.rnews)
- die("-H cannot be used with -S");
-
- /* Initialize the storage manager. If we're doing article deletions, we
- need to open it read/write. */
- if (options.delete) {
- bool value = true;
-
- if (!SMsetup(SM_RDWR, &value))
- die("cannot set up storage manager");
- }
- if (!SMinit())
- die("cannot initialize storage manager: %s", SMerrorstr);
-
- /* Process tokens. If no arguments were given on the command line,
- process tokens from stdin. Otherwise, walk through the remaining
- command line arguments. */
- okay = true;
- if (optind == argc) {
- QIOSTATE *qp;
- char *line;
-
- qp = QIOfdopen(fileno(stdin));
- for (line = QIOread(qp); line != NULL; line = QIOread(qp)) {
- status = process_token(line, &options);
- okay = okay && status;
- }
- if (QIOerror(qp)) {
- if (QIOtoolong(qp))
- die("input line too long");
- sysdie("error reading stdin");
- }
- QIOclose(qp);
- } else {
- int i;
-
- for (i = optind; i < argc; i++) {
- status = process_token(argv[i], &options);
- okay = okay && status;
- }
- }
-
- SMshutdown();
- exit(okay ? 0 : 1);
-}
+++ /dev/null
-/* $Id: sys2nf.c 7741 2008-04-06 09:51:47Z iulius $
-**
-** Read a C news "sys" file and split it up into a set of INN
-** newsfeeds entries. Also works with B news.
-**
-** Once done, edit all files that have HELP or all in them.
-** Review all files, anyway.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-
-#define TEMPFILE ":tmp"
-static char **Groups;
-
-
-/*
-** Fill in the Groups array with the names of all active newsgroups.
-*/
-static void
-ReadActive(act)
- char *act;
-{
- FILE *F;
- int i;
- char buff[BUFSIZ];
- char *p;
-
- /* Open file, count lines. */
- if ((F = fopen(act, "r")) == NULL) {
- perror(act);
- exit(1);
- }
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
- Groups = xmalloc((i + 2) * sizeof(char *));
-
- /* Fill in each word. */
- rewind(F);
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++) {
- if ((p = strchr(buff, ' ')) != NULL)
- *p = '\0';
- Groups[i] = xstrdup(buff);
- }
- Groups[i] = NULL;
- fclose(F);
-}
-
-
-/*
-** Read in the sys file and turn it into an array of strings, one
-** per continued line.
-*/
-char **
-ReadSys(sys)
- char *sys;
-{
- char *p;
- char *to;
- char *site;
- int i;
- char *data;
- char **strings;
-
- /* Read in the file, get rough count. */
- if ((data = ReadInFile(sys, (struct stat *)NULL)) == NULL) {
- perror(sys);
- exit(1);
- }
- for (p = data, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)
- continue;
-
- /* Scan the file, glue all multi-line entries. */
- for (strings = xmalloc((i + 1) * sizeof(char *)), i = 0, to = p = data; *p; ) {
- for (site = to; *p; ) {
- if (*p == '\n') {
- p++;
- *to = '\0';
- break;
- }
- if (*p == '\\' && p[1] == '\n')
- while (*++p && CTYPE(isspace, *p))
- continue;
- else
- *to++ = *p++;
- }
- *to++ = '\0';
- if (*site == '\0')
- continue;
- strings[i++] = xstrdup(site);
- }
- strings[i] = NULL;
- free(data);
- return strings;
-}
-
-
-/*
-** Is this the name of a top-level group? We want a simple name, "foo",
-** and should find a "foo." in the group list.
-*/
-static bool
-Toplevel(p)
- char *p;
-{
- char **gp;
- char *g;
- int i;
-
- if (strchr(p, '.') != NULL)
- return false;
- for (i = strlen(p) - 1, gp = Groups; (g = *gp++) != NULL; )
- if (strncmp(p, g, i) == 0 && g[i + 1] == '.')
- return true;
- return false;
-}
-
-
-/*
-** Do we have a name that's a prefix for more then one newsgroup?
-** For "foo.bar", we must find more then one "foo.bar" or "foo.bar."
-*/
-static bool
-GroupPrefix(p)
- char *p;
-{
- char **gp;
- char *g;
- int count;
- int i;
-
- if (strchr(p, '.') == NULL)
- return false;
- for (i = strlen(p), count = 0, gp = Groups; (g = *gp++) != NULL; )
- if (strcmp(p, g) == 0 || (strncmp(p, g, i) == 0 && g[i] == '.'))
- count++;
- return count > 1;
-}
-
-
-/*
-** Step through the old subscription list, try to update each one in
-** turn.
-*/
-static void
-DoSub(F, p)
- FILE *F;
- char *p;
-{
- char *s;
- int len, i;
- bool matched;
- bool SawBang;
- bool SawAll;
-
- /* Distributions, not newsgroups. */
- static const char * const distributions[] = {
- "world", "na", "usa", "inet", "mod", "net", "local"
- };
-
- /* Newsgroup hierarchies. */
- static const char * const hierarchies[] = {
- "comp", "misc", "news", "rec", "sci", "soc", "talk", "alt", "bionet",
- "bit", "biz", "clari", "ddn", "gnu", "ieee", "k12", "pubnet", "trial",
- "u3b", "vmsnet",
-
- "ba", "ca", "dc", "ne", "ny", "tx",
-
- "info", "mail", "opinions", "uunet"
- }
-
- if ((s = strtok(p, ",")) == NULL)
- return;
-
- fprintf(F, "!*");
- len = 8 + 1 + 2;
- do {
- for (matched = false, i = 0; i < ARRAY_SIZE(distributions); i++)
- if (strcmp(s, distributions[i]) == 0) {
- matched = true;
- break;
- }
- if (matched)
- continue;
-
- if (innconf->mergetogroups)
- if (strcmp(s, "!to") == 0 || strncmp(s, "to.", 3) == 0)
- continue;
-
- putc(',', F);
- len++;
-
- if (len + strlen(s) + 3 > 72) {
- fprintf(F,"\\\n\t ");
- len = 12;
- }
-
- SawBang = *s == '!';
- if (SawBang) {
- putc('!', F);
- len++;
- s++;
- }
-
- SawAll = (strcmp(s, "all") == 0);
- if (SawAll)
- s = SawBang ? "*" : "*,!control,!control.*";
- len += strlen(s);
- fprintf(F, "%s", s);
-
- if (SawAll)
- ;
- else {
- for (matched = false, i = 0; i < ARRAY_SIZE(distributions); i++)
- if (strcmp(s, hierarchies[i]) == 0) {
- matched = true;
- break;
- }
-
- if (matched) {
- fprintf(F, ".*");
- len += 2;
- } else if (GroupPrefix(s)) {
- putc('*', F);
- len++;
- }
- }
- } while ((s = strtok((char *)NULL, ",")) != NULL);
-}
-
-
-int
-main(ac, av)
- int ac;
- char *av[];
-{
- FILE *F;
- FILE *out;
- char **sites;
- char *f2;
- char *f3;
- char *f4;
- char *p;
- char *q;
- char *site;
- char buff[256];
- char *act;
- char *dir;
- char *sys;
- int i;
-
- if (!innconf_read(NULL))
- exit(1);
- /* Set defaults. */
- act = "/usr/local/lib/newslib/active";
- sys = "sys";
- dir = "feeds";
- while ((i = getopt(ac, av, "a:s:d:")) != EOF)
- switch (i) {
- default:
- exit(1);
- /* NOTREACHED */
- case 'a': act = optarg; break;
- case 'd': dir = optarg; break;
- case 's': sys = optarg; break;
- }
-
- sites = ReadSys(sys);
- ReadActive(act);
- if (mkdir(dir, 0777) < 0 && errno != EEXIST)
- perror(dir), exit(1);
- if (chdir(dir) < 0)
- perror("chdir"), exit(1);
- for ( ; ; ) {
- /* Get next non-comment ilne. */
- if ((p = *sites++) == NULL)
- break;
- for (F = fopen(TEMPFILE, "w"); p && *p == '#'; p = *sites++)
- fprintf(F, "%s\n", p);
- if (p == NULL) {
- fclose(F);
- break;
- }
- site = xstrdup(p);
- if ((f2 = strchr(site, ':')) == NULL)
- f2 = "HELP";
- else
- *f2++ = '\0';
- if ((f3 = strchr(f2, ':')) == NULL)
- f3 = "HELP";
- else
- *f3++ = '\0';
- if ((f4 = strchr(f3, ':')) == NULL)
- f4 = "HELP";
- else
- *f4++ = '\0';
-
- /* Write the fields. */
- fprintf(F, "%s\\\n", site);
- fprintf(F, "\t:");
- DoSub(F, f2);
- fprintf(F, "\\\n");
- if (strcmp(f3, "n") == 0)
- fprintf(F, "\t:Tf,Wnm\\\n", f3);
- else
- fprintf(F, "\t:HELP%s\\\n", f3);
- fprintf(F, "\t:%s\n", f4);
- if (ferror(F) || fclose(F) == EOF)
- perror(TEMPFILE), exit(1);
-
- free(site);
-
- /* Find the sitename. */
- for (q = p; *q && *q != '/' && *q != ':'; q++)
- continue;
- *q = '\0';
-
- /* Append temp file to site file. */
- if ((F = fopen(TEMPFILE, "r")) == NULL)
- perror(TEMPFILE), exit(1);
- if ((out = xfopena(p)) == NULL)
- perror(p), exit(1);
- while ((i = fread(buff, 1, sizeof buff, F)) > 0)
- if (fwrite(buff, 1, i, out) != i)
- perror(p), exit(1);
- fclose(F);
- if (fclose(out) == EOF)
- perror(p), exit(1);
-
- if (unlink(TEMPFILE) < 0)
- perror("can't unlink temp file");
- }
-
- exit(0);
- /* NOTREACHED */
-}
+++ /dev/null
-# This file is automatically generated by buildconfig
-
-METHOD_SOURCES = hisv6/hisv6.c
-EXTRA_SOURCES =
-PROGRAMS =
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) -I.
-
-SOURCES = his.c hismethods.c $(METHOD_SOURCES)
-OBJECTS = $(SOURCES:.c=.o)
-LOBJECTS = $(OBJECTS:.o=.lo)
-
-.SUFFIXES: .lo
-
-all: library programs
-
-# Included here after the all target, since additional rules are defined in
-# Make.methods to be sure that we recurse properly to build the methods.
-include Make.methods
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPUB) libinnhist.$(EXTLIB) $(D)$(PATHLIB)/libinnhist.$(EXTLIB)
-
-library: libinnhist.$(EXTLIB)
-
-programs: $(PROGRAMS)
-
-clobber clean distclean:
- rm -f *.o *.lo */*.o */*.lo libinnhist.la libinnhist.a
- rm -f libinnhist_pure_*.a .pure $(PROGRAMS)
- rm -f buildconfig hismethods.c hismethods.h
- rm -f profiled libinnhist$(PROFSUFFIX).a
- rm -rf .libs */.libs
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES) ../include/*.h
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-libinnhist.la: $(OBJECTS) $(LIBSTORAGE) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(LOBJECTS) \
- $(LIBSTORAGE) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS) \
- -rpath $(PATHLIB) -version-info 2:0:0
-
-libinnhist.a: $(OBJECTS)
- ar r $@ $(OBJECTS)
- $(RANLIB) libinnhist.a
-
-# Try to set up these rules so that buildconfig is only run once.
-# Make.methods is included in the distribution tarball since some non-GNU
-# makes can't deal with including a non-existent file, so don't depend on
-# it. The dependencies aren't entirely accurate; you really want to re-run
-# buildconfig each time a new subdirectory is added to the directory. But
-# adding a dependency on . is a bit too non-portable for my taste and causes
-# too many rebuilds.
-Make.methods hismethods.h: hismethods.c buildconfig
-hismethods.c: buildconfig
- ./buildconfig
-
-buildconfig: buildconfig.in $(FIXSCRIPT)
- $(FIXSCRIPT) -i buildconfig.in
-
-.c.o .c.lo:
- $(LIBCC) $(CFLAGS) $(CCOUTPUT)
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSTORAGE): ; (cd ../storage ; $(MAKE) library)
-
-
-## Profiling. The rules are a bit brute-force, but good enough.
-
-profiled: libinnhist$(PROFSUFFIX).a
- date >$@
-
-libinnhist$(PROFSUFFIX).a: $(SOURCES)
- rm -f $(OBJECTS)
- $(MAKEPROFILING) libinnhist.a
- mv libinnhist.a libinnhist$(PROFSUFFIX).a
- $(RANLIB) libinnhist$(PROFSUFFIX).a
- rm -f $(OBJECTS)
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: $(SOURCES) $(EXTRA_SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES) $(EXTRA_SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-his.o: his.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h ../include/inn/history.h \
- ../include/inn/defines.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/storage.h \
- hisinterface.h hismethods.h
-hismethods.o: hismethods.c hisinterface.h ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h hismethods.h \
- hisv6/hisv6.h
-hisv6/hisv6.o: hisv6/hisv6.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- hisinterface.h ../include/config.h hisv6/hisv6.h hisv6/hisv6-private.h \
- ../include/inn/history.h ../include/inn/defines.h ../include/storage.h \
- ../include/libinn.h ../include/dbz.h ../include/libinn.h \
- ../include/inn/innconf.h ../include/inn/timer.h ../include/inn/qio.h \
- ../include/inn/sequence.h ../include/inndcomm.h
+++ /dev/null
-#! /usr/bin/perl
-
-## $Id: buildconfig.in 6806 2004-05-18 01:18:57Z rra $
-##
-## Generate linkage code and makefiles for storage and overview methods.
-##
-## Goes through all subdirectories of the current directory and finds
-## directories that history methods or overview methods. Builds
-## hismethods.[ch] as well as makefile stubs.
-
-require 5.003;
-
-use strict;
-use vars qw(@HISTORY);
-
-# History API functions.
-@HISTORY = qw(open close sync lookup check write replace expire walk remember
- ctl);
-
-# Used to make heredocs more readable.
-sub unquote { my ($string) = @_; $string =~ s/^:( {0,7}|\t)//gm; $string }
-
-# Parse a hismethod.config file for a history method, putting information
-# about that history method into the given hash ref.
-sub parse_config {
- my ($dir, $file, $config) = @_;
- local $_;
- $$config{sources} ||= [];
- $$config{extra} ||= [];
- $$config{programs} ||= [];
- $$config{makefiles} ||= [];
- open (CONFIG, "$dir/$file") or die "Can't open $dir/$file: $!\n";
- while (<CONFIG>) {
- s/^\s+//;
- s/\s+$//;
- if (/^name\s*=\s*(\S+)$/) {
- my $method = $1;
- die "$dir/$file: $method has already been defined\n"
- if (defined $$config{method}{$method});
- $$config{method}{$method} = $dir;
- } elsif (/^number\s*=\s*(\d+)$/) {
- my $number = $1;
- if (defined $$config{number}{$number}) {
- die "$dir/$file: method number $number was already "
- . "allocated in $$config{number}{$number}\n";
- }
- $$config{number}{$dir} = $number;
- } elsif (/^sources\s*=\s*(.*)/) {
- my $sources = $1;
- my @sources = split (' ', $sources);
- push (@{ $$config{sources} }, map { "$dir/$_" } @sources);
- } elsif (/^extra-sources\s*=\s*(.*)/) {
- my $extra = $1;
- my @extra = split (' ', $extra);
- push (@{ $$config{extra} }, map { "$dir/$_" } @extra);
- } elsif (/^programs\s*=\s*(.*)/) {
- my $programs = $1;
- my @programs = split (' ', $programs);
- push (@{ $$config{programs} }, map { "$dir/$_" } @programs);
- } else {
- warn "$dir/$file: ignoring unknown line: $_\n";
- }
- }
-
- # If there is a makefile fragment in the directory, note it.
- if (-f "$dir/hismethod.mk") {
- push (@{ $$config{makefiles} }, "$dir/hismethod.mk");
- }
-}
-
-# Write out include directives for a list of files.
-sub write_includes {
- my ($fh, $config) = @_;
- my $method;
- for $method (sort keys %{ $$config{method} }) {
- my $path = $$config{method}{$method};
- print $fh qq(\#include "$path/$method.h"\n);
- }
-}
-
-# Write out the method struct.
-sub write_methods {
- my ($fh, $config, $prefix, @funcs) = @_;
- my ($notfirst, $method);
- for $method (sort keys %{ $$config{method} }) {
- print $fh "\n},\n" if $notfirst;
- print $fh qq(\{\n "$method");
- print $fh ', ', $prefix, '_', uc ($method) if $prefix;
- for (@funcs) {
- print $fh ",\n ${method}_$_";
- }
- $notfirst++;
- }
- print $fh "\n}\n};\n\n";
-}
-
-# Write out hismethods.c and hismethods.h for the interface to the history
-# methods.
-sub write_history {
- my $history = shift;
- open (DEF, '> hismethods.c.new')
- or die "Can't create hismethods.c.new: $!\n";
- print DEF unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig. */
-:
-: #include "hisinterface.h"
-: #include "hismethods.h"
-EOE
- my $method;
- write_includes (\*DEF, $history);
- print DEF "\nHIS_METHOD his_methods[",
- scalar (keys %{ $$history{method} }), "] = {\n";
- write_methods (\*DEF, $history, undef, @HISTORY);
- close DEF;
- rename ('hismethods.c.new', 'hismethods.c');
-
- open (H, '> hismethods.h.new') or die "Can't open hismethods.h.new: $!\n";
- print H unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig */
-:
-: #ifndef HISMETHODS_H
-: #define HISMETHODS_H 1
-:
-: #include "hisinterface.h"
-:
-EOE
- print H '#define NUM_HIS_METHODS ',
- scalar (keys %{ $$history{method} }), "\n";
- print H unquote (<<'EOE');
-:
-: extern HIS_METHOD his_methods[NUM_HIS_METHODS];
-:
-: #endif /* HISMETHODS_H */
-EOE
- close H;
- rename ('hismethods.h.new', 'hismethods.h');
-}
-
-# Return a string setting a makefile variable. Tab over the = properly and
-# wrap to fit our coding standards.
-sub makefile_var {
- my ($variable, @values) = @_;
- my $output;
- $output = sprintf ("%-15s =", $variable);
- my $column = 17;
- for (@values) {
- if ($column > 17 && 77 - $column < length ($_)) {
- $output .= " \\\n" . ' ' x 17;
- $column = 17;
- }
- $output .= " $_";
- $column += 1 + length ($_);
- }
- $output .= "\n";
- return $output;
-}
-
-# Write out the makefile fragment for history methods.
-sub write_makefile {
- my ($dirs, $sources, $extra, $programs, $makefiles) = @_;
- open (MAKE, '> Make.methods.new')
- or die "Can't create Make.methods.new: $!\n";
- print MAKE "# This file is automatically generated by buildconfig\n\n";
- print MAKE makefile_var ('METHOD_SOURCES', @$sources);
- print MAKE makefile_var ('EXTRA_SOURCES', @$extra);
- print MAKE makefile_var ('PROGRAMS', @$programs);
- for (@$makefiles) {
- print MAKE "\n\n## Included from $_\n\n";
- open (FRAG, $_) or die "Can't open $_: $!\n";
- print MAKE <FRAG>;
- close FRAG;
- }
- rename ('Make.methods.new', 'Make.methods');
-}
-
-my ($dir, %history);
-if (!-d 'hisv6') {
- if (-d 'history/cnfs') {
- chdir 'history' or die "Can't chdir to history: $!\n";
- } else {
- die "Can't find history directory (looking for history/hisv6)\n";
- }
-}
-opendir (D, ".") or die "Can't open current directory: $!\n";
-my @dirs = sort readdir D;
-for $dir (@dirs) {
- if (-e "$dir/hismethod.config") {
- parse_config ($dir, 'hismethod.config', \%history);
- }
-}
-write_history (\%history);
-@dirs = sort values %{ $history{method} };
-my @sources = sort @{ $history{sources} };
-my @extra = sort @{ $history{extra} };
-my @programs = sort @{ $history{programs} };
-my @makefiles = sort @{ $history{makefiles} };
-write_makefile (\@dirs, \@sources, \@extra, \@programs, \@makefiles);
+++ /dev/null
-/* $Id: his.c 6351 2003-05-19 02:00:06Z rra $
-**
-** API to history routines
-**
-** Copyright (c) 2001, Thus plc
-**
-** Redistribution and use of the source code in source and binary
-** forms, with or without modification, are permitted provided that
-** the following 3 conditions are met:
-**
-** 1. Redistributions of the source code must retain the above
-** copyright notice, this list of conditions and the disclaimer
-** set out below.
-**
-** 2. Redistributions of the source code in binary form must
-** reproduce the above copyright notice, this list of conditions
-** and the disclaimer set out below in the documentation and/or
-** other materials provided with the distribution.
-**
-** 3. Neither the name of the Thus plc nor the names of its
-** contributors may be used to endorse or promote products
-** derived from this software without specific prior written
-** permission from Thus plc.
-**
-** Disclaimer:
-**
-** "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DIRECTORS
-** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <errno.h>
-#include <syslog.h>
-
-#include "inn/history.h"
-#include "inn/messages.h"
-#include "inn/timer.h"
-#include "libinn.h"
-#include "storage.h"
-
-#include "hisinterface.h"
-#include "hismethods.h"
-
-struct hiscache {
- HASH Hash; /* Hash value of the message-id using Hash() */
- bool Found; /* Whether this entry is in the dbz file yet */
-};
-
-struct history {
- struct hismethod *methods;
- void *sub;
- struct hiscache *cache;
- size_t cachesize;
- const char *error;
- struct histstats stats;
-};
-
-enum HISRESULT {HIScachehit, HIScachemiss, HIScachedne};
-
-static const struct histstats nullhist = {0};
-
-/*
-** Put an entry into the history cache
-*/
-static void
-his_cacheadd(struct history *h, HASH MessageID, bool Found)
-{
- unsigned int i, loc;
-
- his_logger("HIScacheadd begin", S_HIScacheadd);
- if (h->cache != NULL) {
- memcpy(&loc, ((char *)&MessageID) + (sizeof(HASH) - sizeof(loc)),
- sizeof(loc));
- i = loc % h->cachesize;
- memcpy((char *)&h->cache[i].Hash, (char *)&MessageID, sizeof(HASH));
- h->cache[i].Found = Found;
- }
- his_logger("HIScacheadd end", S_HIScacheadd);
-}
-
-/*
-** Lookup an entry in the history cache
-*/
-static enum HISRESULT
-his_cachelookup(struct history *h, HASH MessageID)
-{
- unsigned int i, loc;
-
- if (h->cache == NULL)
- return HIScachedne;
- his_logger("HIScachelookup begin", S_HIScachelookup);
- memcpy(&loc, ((char *)&MessageID) + (sizeof(HASH) - sizeof(loc)), sizeof(loc));
- i = loc % h->cachesize;
- if (memcmp((char *)&h->cache[i].Hash, (char *)&MessageID, sizeof(HASH)) == 0) {
- his_logger("HIScachelookup end", S_HIScachelookup);
- if (h->cache[i].Found) {
- return HIScachehit;
- } else {
- return HIScachemiss;
- }
- } else {
- his_logger("HIScachelookup end", S_HIScachelookup);
- return HIScachedne;
- }
-}
-
-/*
-** set error status to that indicated by s; doesn't copy the string,
-** assumes the caller did that for us
-*/
-void
-his_seterror(struct history *h, const char *s)
-{
- if (h != NULL) {
- if (h->error)
- free((void *)h->error);
- h->error = s;
- }
- if (s != NULL)
- warn("%s", s);
-}
-
-struct history *
-HISopen(const char *path, const char *method, int flags)
-{
- struct history *h;
- int i;
-
- for (i = 0; i < NUM_HIS_METHODS; ++i) {
- if (strcmp(method, his_methods[i].name) == 0)
- break;
- }
- if (i == NUM_HIS_METHODS) {
- warn("`%s' isn't a valid history method", method);
- return NULL;
- }
-
- /* allocate up our structure and start subordinate history
- * manager */
- h = xmalloc(sizeof *h);
- h->methods = &his_methods[i];
- h->cache = NULL;
- h->error = NULL;
- h->cachesize = 0;
- h->stats = nullhist;
- h->sub = (*h->methods->open)(path, flags, h);
- if (h->sub == NULL) {
- free(h);
- h = NULL;
- }
- return h;
-}
-
-static bool
-his_checknull(struct history *h)
-{
- if (h != NULL)
- return false;
- errno = EBADF;
- return true;
-
-}
-
-bool
-HISclose(struct history *h)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- r = (*h->methods->close)(h->sub);
- if (h->cache) {
- free(h->cache);
- h->cache = NULL;
- }
- if (h->error) {
- free((void *)h->error);
- h->error = NULL;
- }
- free(h);
- return r;
-}
-
-bool
-HISsync(struct history *h)
-{
- bool r = false;
-
- if (his_checknull(h))
- return false;
- TMRstart(TMR_HISSYNC);
- r = (*h->methods->sync)(h->sub);
- TMRstop(TMR_HISSYNC);
- return r;
-}
-
-bool
-HISlookup(struct history *h, const char *key, time_t *arrived,
- time_t *posted, time_t *expires, TOKEN *token)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- TMRstart(TMR_HISGREP);
- r = (*h->methods->lookup)(h->sub, key, arrived, posted, expires, token);
- TMRstop(TMR_HISGREP);
- return r;
-}
-
-bool
-HIScheck(struct history *h, const char *key)
-{
- bool r = false;
- HASH hash;
-
- if (his_checknull(h))
- return false;
- TMRstart(TMR_HISHAVE);
- hash = HashMessageID(key);
- switch (his_cachelookup(h, hash)) {
- case HIScachehit:
- h->stats.hitpos++;
- r = true;
- break;
-
- case HIScachemiss:
- h->stats.hitneg++;
- r = false;
- break;
-
- case HIScachedne:
- r = (*h->methods->check)(h->sub, key);
- his_cacheadd(h, hash, r);
- if (r)
- h->stats.misses++;
- else
- h->stats.dne++;
- break;
- }
- TMRstop(TMR_HISHAVE);
- return r;
-}
-
-bool
-HISwrite(struct history *h, const char *key, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- TMRstart(TMR_HISWRITE);
- r = (*h->methods->write)(h->sub, key, arrived, posted, expires, token);
- if (r == true) {
- HASH hash;
-
- /* if we successfully wrote it, add it to the cache */
- hash = HashMessageID(key);
- his_cacheadd(h, hash, true);
- }
- TMRstop(TMR_HISWRITE);
-
- return r;
-}
-
-bool
-HISremember(struct history *h, const char *key, time_t arrived)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- TMRstart(TMR_HISWRITE);
- r = (*h->methods->remember)(h->sub, key, arrived);
- if (r == true) {
- HASH hash;
-
- /* if we successfully wrote it, add it to the cache */
- hash = HashMessageID(key);
- his_cacheadd(h, hash, true);
- }
- TMRstop(TMR_HISWRITE);
-
- return r;
-}
-
-bool
-HISreplace(struct history *h, const char *key, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- r = (*h->methods->replace)(h->sub, key, arrived, posted, expires, token);
- if (r == true) {
- HASH hash;
-
- /* if we successfully wrote it, add it to the cache */
- hash = HashMessageID(key);
- his_cacheadd(h, hash, true);
- }
- return r;
-}
-
-bool
-HISwalk(struct history *h, const char *reason, void *cookie,
- bool (*callback)(void *, time_t, time_t, time_t, const TOKEN *))
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- r = (*h->methods->walk)(h->sub, reason, cookie, callback);
- return r;
-}
-
-bool
-HISexpire(struct history *h, const char *path, const char *reason,
- bool writing, void *cookie, time_t threshold,
- bool (*exists)(void *, time_t, time_t, time_t, TOKEN *))
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- r = (*h->methods->expire)(h->sub, path, reason, writing,
- cookie, threshold, exists);
- return r;
-}
-
-void
-HISsetcache(struct history *h, size_t size)
-{
- if (h == NULL)
- return;
- if (h->cache) {
- free(h->cache);
- h->cache = NULL;
- }
- h->cachesize = size / sizeof(struct hiscache);
- if (h->cachesize != 0)
- h->cache = xcalloc(h->cachesize, sizeof(struct hiscache));
- h->stats = nullhist;
-}
-
-
-/*
-** return current history cache stats and zero the counters
-*/
-struct histstats
-HISstats(struct history *h)
-{
- struct histstats r;
-
- if (h == NULL)
- return nullhist;
- r = h->stats;
- h->stats = nullhist;
- return r;
-}
-
-
-/*
-** return current error status to caller
-*/
-const char *
-HISerror(struct history *h)
-{
- if (h == NULL)
- return NULL;
- return h->error;
-}
-
-
-/*
-** control interface to underlying method
-*/
-bool
-HISctl(struct history *h, int selector, void *val)
-{
- bool r;
-
- if (his_checknull(h))
- return false;
- r = (*h->methods->ctl)(h->sub, selector, val);
- return r;
-}
-
-
-/*
-** This code doesn't fit well with the generic history API, it really
-** needs migrating to use the new nested timers
-*/
-
-FILE *HISfdlog = NULL; /* filehandle for history logging purpose */
-
-static struct timeval HISstat_start[S_HIS_MAX];
-static struct timeval HISstat_total[S_HIS_MAX];
-static unsigned long HISstat_count[S_HIS_MAX];
-
-void HISlogclose(void) {
- if (HISfdlog != NULL)
- Fclose(HISfdlog);
- HISfdlog = NULL;
-}
-
-void HISlogto(const char *s) {
- int i;
-
- HISlogclose();
- if ((HISfdlog = Fopen(s, "a", INND_HISLOG)) == NULL)
- syslog(L_FATAL, "cant open %s %m", s);
- /* initialize our counters */
- for (i = 0; i < S_HIS_MAX; i++) {
- HISstat_start[i].tv_sec = 0;
- HISstat_start[i].tv_usec = 0;
- HISstat_total[i].tv_sec = 0;
- HISstat_total[i].tv_usec = 0;
- HISstat_count[i] = 0;
- }
-}
-
-void
-his_logger(char *s, int code)
-{
- struct timeval tv;
- struct tm *tm;
-
- if (HISfdlog == NULL) /* do nothing unless HISlogto() has been called */
- return;
-
- gettimeofday(&tv, NULL);
- tm = localtime((const time_t *)&(tv.tv_sec));
- if (HISstat_start[code].tv_sec != 0) {
- fprintf(HISfdlog, "%d/%d/%d %02d:%02d:%02d.%06d: [%d] %s (%.6f)\n",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
- tm->tm_min, tm->tm_sec, (int)tv.tv_usec, code, s, (float) tv.tv_sec +
- (float) tv.tv_usec / 1000000 - (float) HISstat_start[code].tv_sec -
- (float) HISstat_start[code].tv_usec / 1000000);
- if (tv.tv_usec < HISstat_start[code].tv_usec) {
- HISstat_total[code].tv_sec++;
- HISstat_total[code].tv_usec +=
- tv.tv_usec - HISstat_start[code].tv_usec + 1000000;
- }
- else
- HISstat_total[code].tv_usec +=
- tv.tv_usec - HISstat_start[code].tv_usec;
- HISstat_total[code].tv_sec += tv.tv_sec - HISstat_start[code].tv_sec;
- HISstat_count[code]++;
- HISstat_start[code].tv_sec = 0;
- HISstat_start[code].tv_usec = 0;
- }
- else {
- fprintf(HISfdlog, "%d/%d/%d %02d:%02d:%02d.%06d: [%d] %s\n",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
- tm->tm_min, tm->tm_sec, (int)tv.tv_usec, code, s);
- HISstat_start[code].tv_sec = tv.tv_sec;
- HISstat_start[code].tv_usec = tv.tv_usec;
- }
-}
+++ /dev/null
-/* $Id: hisinterface.h 5745 2002-09-08 19:52:12Z rra $
-**
-** Interface to history API modules
-*/
-
-#ifndef HISINTERFACE_H
-#define HISINTERFACE_H
-
-#include "config.h"
-#include <sys/types.h>
-
-struct token;
-struct histopts;
-struct history;
-
-typedef struct hismethod {
- const char *name;
- void *(*open)(const char *path, int flags, struct history *);
- bool (*close)(void *);
- bool (*sync)(void *);
- bool (*lookup)(void *, const char *, time_t *, time_t *, time_t *,
- struct token *);
- bool (*check)(void *, const char *);
- bool (*write)(void *, const char *, time_t, time_t, time_t,
- const struct token *);
- bool (*replace)(void *, const char *, time_t, time_t, time_t,
- const struct token *);
- bool (*expire)(void *, const char *, const char *, bool, void *, time_t,
- bool (*)(void *, time_t, time_t, time_t,
- struct token *));
- bool (*walk)(void *, const char *, void *,
- bool (*)(void *, time_t, time_t, time_t,
- const struct token *));
- bool (*remember)(void *, const char *, time_t);
- bool (*ctl)(void *, int, void *);
-} HIS_METHOD;
-
-/* subordinate history manager private methods */
-void his_seterror(struct history *, const char *);
-
-enum { S_HIScacheadd, S_HIScachelookup, S_HISsetup, S_HISsync,
- S_HISlogstats, S_HISclose, S_HISfilesfor, S_HIShavearticle,
- S_HISwrite, S_HISremember, S_HIS_MAX };
-
-/* fine grained history logging */
-void his_logger(char *s, int code);
-#endif
+++ /dev/null
-name = hisv6
-number = 0
-sources = hisv6.c
+++ /dev/null
-#ifndef HISV6_PRIVATE_H
-#define HISV6_PRIVATE_H
-
-#include "config.h"
-#include <stdio.h>
-#include <time.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include "inn/history.h"
-#include "storage.h"
-#include "libinn.h"
-
-/* Used by lots of stuff that parses history file entries. Should be moved
- into a header specifically for history parsing. */
-#define HISV6_BADCHAR '_'
-#define HISV6_FIELDSEP '\t'
-#define HISV6_NOEXP '-'
-#define HISV6_SUBFIELDSEP '~'
-
-/* maximum length of a history line:
- 34 - hash
- 1 - \t
- 20 - arrived
- 1 - ~
- 20 - expires
- 1 - ~
- 20 - posted
- 1 - tab
- 38 - token
- 1 - \n */
-#define HISV6_MAXLINE 137
-
-/* minimum length of a history line:
- 34 - hash
- 1 - \t
- 1 - arrived
- 1 - \n */
-#define HISV6_MINLINE 37
-
-struct hisv6 {
- char *histpath;
- FILE *writefp;
- off_t offset; /* Offset into writefp. */
- unsigned long nextcheck;
- struct history *history;
- time_t statinterval;
- size_t synccount;
- size_t dirty;
- ssize_t npairs;
- int readfd;
- int flags;
- struct stat st;
-};
-
-/* values in the bitmap returned from hisv6_splitline */
-#define HISV6_HAVE_HASH (1<<0)
-#define HISV6_HAVE_ARRIVED (1<<1)
-#define HISV6_HAVE_POSTED (1<<2)
-#define HISV6_HAVE_EXPIRES (1<<3)
-#define HISV6_HAVE_TOKEN (1<<4)
-
-/* structure used to hold the callback and cookie so we don't try
- * passing too many parameters into the callers callback */
-struct hisv6_walkstate {
- union {
- bool (*expire)(void *, time_t, time_t, time_t, TOKEN *);
- bool (*walk)(void *, time_t, time_t, time_t, const TOKEN *);
- } cb;
- void *cookie;
- bool paused;
- bool ignore;
- /* the next two fields are only used during expire... they should
- * probably be linked off of cookie, but I've been lazy */
- struct hisv6 *new;
- time_t threshold;
-};
-
-/* maximum length of the string from hisv6_errloc */
-#define HISV6_MAX_LOCATION 22
-
-#endif
+++ /dev/null
-/* $Id: hisv6.c 7339 2005-06-20 03:16:41Z eagle $
-**
-** History v6 implementation against the history API.
-**
-** Copyright (c) 2001, Thus plc
-**
-** Redistribution and use of the source code in source and binary
-** forms, with or without modification, are permitted provided that
-** the following 3 conditions are met:
-**
-** 1. Redistributions of the source code must retain the above
-** copyright notice, this list of conditions and the disclaimer
-** set out below.
-**
-** 2. Redistributions of the source code in binary form must
-** reproduce the above copyright notice, this list of conditions
-** and the disclaimer set out below in the documentation and/or
-** other materials provided with the distribution.
-**
-** 3. Neither the name of the Thus plc nor the names of its
-** contributors may be used to endorse or promote products
-** derived from this software without specific prior written
-** permission from Thus plc.
-**
-** Disclaimer:
-**
-** "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE DIRECTORS
-** OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <fcntl.h>
-#include <limits.h>
-#include <errno.h>
-#include "hisinterface.h"
-#include "hisv6.h"
-#include "hisv6-private.h"
-#include "dbz.h"
-#include "inn/innconf.h"
-#include "inn/timer.h"
-#include "inn/qio.h"
-#include "inn/sequence.h"
-#include "inndcomm.h"
-
-/*
-** because we can only have one open dbz per process, we keep a
-** pointer to which of the current history structures owns it
-*/
-static struct hisv6 *hisv6_dbzowner;
-
-
-/*
-** set error status to that indicated by s; doesn't copy the string,
-** assumes the caller did that for us
-*/
-static void
-hisv6_seterror(struct hisv6 *h, const char *s)
-{
- his_seterror(h->history, s);
-}
-
-
-/*
-** format line or offset into a string for error reporting
-*/
-static void
-hisv6_errloc(char *s, size_t line, off_t offset)
-{
- if (offset != -1) {
- /* really we want an autoconf test for %ll/%L/%I64, sigh */
- sprintf(s, "@%.0f", (double)offset);
- } else {
- sprintf(s, ":%lu", (unsigned long)line);
- }
-}
-
-
-/*
-** split a history line into its constituent components; return a
-** bitmap indicating which components we're returning are valid (or
-** would be valid if a NULL pointer is passed for that component) or
-** -1 for error. *error is set to a string which describes the
-** failure.
-*/
-static int
-hisv6_splitline(const char *line, const char **error, HASH *hash,
- time_t *arrived, time_t *posted, time_t *expires,
- TOKEN *token)
-{
- char *p = (char *)line;
- unsigned long l;
- int r = 0;
-
- /* parse the [...] hash field */
- if (*p != '[') {
- *error = "`[' missing from history line";
- return -1;
- }
- ++p;
- if (hash)
- *hash = TextToHash(p);
- p += 32;
- if (*p != ']') {
- *error = "`]' missing from history line";
- return -1;
- }
- ++p;
- r |= HISV6_HAVE_HASH;
- if (*p != HISV6_FIELDSEP) {
- *error = "field separator missing from history line";
- return -1;
- }
-
- /* parse the arrived field */
- l = strtoul(p + 1, &p, 10);
- if (l == ULONG_MAX) {
- *error = "arrived timestamp out of range";
- return -1;
- }
- r |= HISV6_HAVE_ARRIVED;
- if (arrived)
- *arrived = (time_t)l;
- if (*p != HISV6_SUBFIELDSEP) {
- /* no expires or posted time */
- if (posted)
- *posted = 0;
- if (expires)
- *expires = 0;
- } else {
- /* parse out the expires field */
- ++p;
- if (*p == HISV6_NOEXP) {
- ++p;
- if (expires)
- *expires = 0;
- } else {
- l = strtoul(p, &p, 10);
- if (l == ULONG_MAX) {
- *error = "expires timestamp out of range";
- return -1;
- }
- r |= HISV6_HAVE_EXPIRES;
- if (expires)
- *expires = (time_t)l;
- }
- /* parse out the posted field */
- if (*p != HISV6_SUBFIELDSEP) {
- /* no posted time */
- if (posted)
- *posted = 0;
- } else {
- ++p;
- l = strtoul(p, &p, 10);
- if (l == ULONG_MAX) {
- *error = "posted timestamp out of range";
- return -1;
- }
- r |= HISV6_HAVE_POSTED;
- if (posted)
- *posted = (time_t)l;
- }
- }
-
- /* parse the token */
- if (*p == HISV6_FIELDSEP)
- ++p;
- else if (*p != '\0') {
- *error = "field separator missing from history line";
- return -1;
- }
- /* IsToken false would imply a remembered line, or where someone's
- * used prunehistory */
- if (IsToken(p)) {
- r |= HISV6_HAVE_TOKEN;
- if (token)
- *token = TextToToken(p);
- }
- return r;
-}
-
-
-/*
-** Given the time, now, return the time at which we should next check
-** the history file
-*/
-static unsigned long
-hisv6_nextcheck(struct hisv6 *h, unsigned long now)
-{
- return now + h->statinterval;
-}
-
-
-/*
-** close any dbz structures associated with h; we also manage the
-** single dbz instance voodoo
-*/
-static bool
-hisv6_dbzclose(struct hisv6 *h)
-{
- bool r = true;
-
- if (h == hisv6_dbzowner) {
- if (!hisv6_sync(h))
- r = false;
- if (!dbzclose()) {
- hisv6_seterror(h, concat("can't dbzclose ",
- h->histpath, " ",
- strerror(errno), NULL));
- r = false;
- }
- hisv6_dbzowner = NULL;
- }
- return r;
-}
-
-
-/*
-** close an existing history structure, cleaning it to the point
-** where we can reopon without leaking resources
-*/
-static bool
-hisv6_closefiles(struct hisv6 *h)
-{
- bool r = true;
-
- if (!hisv6_dbzclose(h))
- r = false;
-
- if (h->readfd != -1) {
- if (close(h->readfd) != 0 && errno != EINTR) {
- hisv6_seterror(h, concat("can't close history ",
- h->histpath, " ",
- strerror(errno),NULL));
- r = false;
- }
- h->readfd = -1;
- }
-
- if (h->writefp != NULL) {
- if (ferror(h->writefp) || fflush(h->writefp) == EOF) {
- hisv6_seterror(h, concat("error on history ",
- h->histpath, " ",
- strerror(errno), NULL));
- r = false;
- }
- if (Fclose(h->writefp) == EOF) {
- hisv6_seterror(h, concat("can't fclose history ",
- h->histpath, " ",
- strerror(errno), NULL));
- r = false;
- }
- h->writefp = NULL;
- h->offset = 0;
- }
-
- h->nextcheck = 0;
- h->st.st_ino = (ino_t)-1;
- h->st.st_dev = (dev_t)-1;
- return r;
-}
-
-
-/*
-** Reopen (or open from fresh) a history structure; assumes the flags
-** & path are all set up, ready to roll. If we don't own the dbz, we
-** suppress the dbz code; this is needed during expiry (since the dbz
-** code doesn't yet understand multiple open contexts... yes its a
-** hack)
-*/
-static bool
-hisv6_reopen(struct hisv6 *h)
-{
- bool r = false;
-
- if (h->flags & HIS_RDWR) {
- const char *mode;
-
- if (h->flags & HIS_CREAT)
- mode = "w";
- else
- mode = "r+";
- if ((h->writefp = Fopen(h->histpath, mode, INND_HISTORY)) == NULL) {
- hisv6_seterror(h, concat("can't fopen history ",
- h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- if (fseeko(h->writefp, 0, SEEK_END) == -1) {
- hisv6_seterror(h, concat("can't fseek to end of ",
- h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- h->offset = ftello(h->writefp);
- if (h->offset == -1) {
- hisv6_seterror(h, concat("can't ftello ", h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- close_on_exec(fileno(h->writefp), true);
- }
-
- /* Open the history file for reading. */
- if ((h->readfd = open(h->histpath, O_RDONLY)) < 0) {
- hisv6_seterror(h, concat("can't open ", h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- close_on_exec(h->readfd, true);
-
- /* if there's no current dbz owner, claim it here */
- if (hisv6_dbzowner == NULL) {
- hisv6_dbzowner = h;
- }
-
- /* During expiry we need two history structures in place, so we
- have to select which one gets the dbz file */
- if (h == hisv6_dbzowner) {
- dbzoptions opt;
-
- /* Open the DBZ file. */
- dbzgetoptions(&opt);
-
- /* HIS_INCORE usually means we're rebuilding from scratch, so
- keep the whole lot in core until we flush */
- if (h->flags & HIS_INCORE) {
- opt.writethrough = false;
- opt.pag_incore = INCORE_MEM;
-#ifndef DO_TAGGED_HASH
- opt.exists_incore = INCORE_MEM;
-#endif
- } else {
- opt.writethrough = true;
-#ifdef DO_TAGGED_HASH
- opt.pag_incore = INCORE_MMAP;
-#else
- /*opt.pag_incore = INCORE_NO;*/
- opt.pag_incore = (h->flags & HIS_MMAP) ? INCORE_MMAP : INCORE_NO;
- opt.exists_incore = (h->flags & HIS_MMAP) ? INCORE_MMAP : INCORE_NO;
-
-# if defined(MMAP_NEEDS_MSYNC) && INND_DBZINCORE == 1
- /* Systems that have MMAP_NEEDS_MSYNC defined will have their
- on-disk copies out of sync with the mmap'ed copies most of
- the time. So if innd is using INCORE_MMAP, then we force
- everything else to use it, too (unless we're on NFS) */
- if(!innconf->nfsreader) {
- opt.pag_incore = INCORE_MMAP;
- opt.exists_incore = INCORE_MMAP;
- }
-# endif
-#endif
- }
- dbzsetoptions(opt);
- if (h->flags & HIS_CREAT) {
- size_t npairs;
-
- /* must only do this once! */
- h->flags &= ~HIS_CREAT;
- npairs = (h->npairs == -1) ? 0 : h->npairs;
- if (!dbzfresh(h->histpath, dbzsize(npairs))) {
- hisv6_seterror(h, concat("can't dbzfresh ", h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- } else if (!dbzinit(h->histpath)) {
- hisv6_seterror(h, concat("can't dbzinit ", h->histpath, " ",
- strerror(errno), NULL));
- hisv6_closefiles(h);
- goto fail;
- }
- }
- h->nextcheck = hisv6_nextcheck(h, TMRnow());
- r = true;
- fail:
- return r;
-}
-
-
-/*
-** check if the history file has changed, if so rotate to the new
-** history file. Returns false on failure (which is probably fatal as
-** we'll have closed the files)
-*/
-static bool
-hisv6_checkfiles(struct hisv6 *h)
-{
- unsigned long t = TMRnow();
-
- if (h->statinterval == 0)
- return true;
-
- if (h->readfd == -1) {
- /* this can happen if a previous checkfiles() has failed to
- * reopen the handles, but our caller hasn't realised... */
- hisv6_closefiles(h);
- if (!hisv6_reopen(h)) {
- hisv6_closefiles(h);
- return false;
- }
- }
- if (seq_lcompare(t, h->nextcheck) == 1) {
- struct stat st;
-
- if (stat(h->histpath, &st) == 0 &&
- (st.st_ino != h->st.st_ino ||
- st.st_dev != h->st.st_dev)) {
- /* there's a possible race on the history file here... */
- hisv6_closefiles(h);
- if (!hisv6_reopen(h)) {
- hisv6_closefiles(h);
- return false;
- }
- h->st = st;
- }
- h->nextcheck = hisv6_nextcheck(h, t);
- }
- return true;
-}
-
-
-/*
-** dispose (and clean up) an existing history structure
-*/
-static bool
-hisv6_dispose(struct hisv6 *h)
-{
- bool r;
-
- r = hisv6_closefiles(h);
- if (h->histpath) {
- free(h->histpath);
- h->histpath = NULL;
- }
-
- free(h);
- return r;
-}
-
-
-/*
-** return a newly constructed, but empty, history structure
-*/
-static struct hisv6 *
-hisv6_new(const char *path, int flags, struct history *history)
-{
- struct hisv6 *h;
-
- h = xmalloc(sizeof *h);
- h->histpath = path ? xstrdup(path) : NULL;
- h->flags = flags;
- h->writefp = NULL;
- h->offset = 0;
- h->history = history;
- h->readfd = -1;
- h->nextcheck = 0;
- h->statinterval = 0;
- h->npairs = 0;
- h->dirty = 0;
- h->synccount = 0;
- h->st.st_ino = (ino_t)-1;
- h->st.st_dev = (dev_t)-1;
- return h;
-}
-
-
-/*
-** open the history database identified by path in mode flags
-*/
-void *
-hisv6_open(const char *path, int flags, struct history *history)
-{
- struct hisv6 *h;
-
- his_logger("HISsetup begin", S_HISsetup);
-
- h = hisv6_new(path, flags, history);
- if (path) {
- if (!hisv6_reopen(h)) {
- hisv6_dispose(h);
- h = NULL;
- }
- }
- his_logger("HISsetup end", S_HISsetup);
- return h;
-}
-
-
-/*
-** close and free a history handle
-*/
-bool
-hisv6_close(void *history)
-{
- struct hisv6 *h = history;
- bool r;
-
- his_logger("HISclose begin", S_HISclose);
- r = hisv6_dispose(h);
- his_logger("HISclose end", S_HISclose);
- return r;
-}
-
-
-/*
-** synchronise any outstanding history changes to disk
-*/
-bool
-hisv6_sync(void *history)
-{
- struct hisv6 *h = history;
- bool r = true;
-
- if (h->writefp != NULL) {
- his_logger("HISsync begin", S_HISsync);
- if (fflush(h->writefp) == EOF) {
- hisv6_seterror(h, concat("error on history ",
- h->histpath, " ",
- strerror(errno), NULL));
- r = false;
- }
- if (h->dirty && h == hisv6_dbzowner) {
- if (!dbzsync()) {
- hisv6_seterror(h, concat("can't dbzsync ", h->histpath,
- " ", strerror(errno), NULL));
- r = false;
- } else {
- h->dirty = 0;
- }
- }
- his_logger("HISsync end", S_HISsync);
- }
- return r;
-}
-
-
-/*
-** fetch the line associated with `hash' in the history database into
-** buf; buf must be at least HISV6_MAXLINE+1 bytes. `poff' is filled
-** with the offset of the line in the history file.
-*/
-static bool
-hisv6_fetchline(struct hisv6 *h, const HASH *hash, char *buf, off_t *poff)
-{
- off_t offset;
- bool r;
-
- if (h != hisv6_dbzowner) {
- hisv6_seterror(h, concat("dbz not open for this history file ",
- h->histpath, NULL));
- return false;
- }
- if ((h->flags & (HIS_RDWR | HIS_INCORE)) == (HIS_RDWR | HIS_INCORE)) {
- /* need to fflush as we may be reading uncommitted data
- written via writefp */
- if (fflush(h->writefp) == EOF) {
- hisv6_seterror(h, concat("error on history ",
- h->histpath, " ",
- strerror(errno), NULL));
- r = false;
- goto fail;
- }
- }
-
- /* Get the seek value into the history file. */
- errno = 0;
- r = dbzfetch(*hash, &offset);
-#ifdef ESTALE
- /* If your history is on NFS need to deal with stale NFS
- * handles */
- if (!r && errno == ESTALE) {
- hisv6_closefiles(h);
- if (!hisv6_reopen(h)) {
- hisv6_closefiles(h);
- r = false;
- goto fail;
- }
- }
-#endif
- if (r) {
- ssize_t n;
-
- do {
- n = pread(h->readfd, buf, HISV6_MAXLINE, offset);
-#ifdef ESTALE
- if (n == -1 && errno == ESTALE) {
- hisv6_closefiles(h);
- if (!hisv6_reopen(h)) {
- hisv6_closefiles(h);
- r = false;
- goto fail;
- }
- }
-#endif
- } while (n == -1 && errno == EINTR);
- if (n >= HISV6_MINLINE) {
- char *p;
-
- buf[n] = '\0';
- p = strchr(buf, '\n');
- if (!p) {
- char location[HISV6_MAX_LOCATION];
-
- hisv6_errloc(location, (size_t)-1, offset);
- hisv6_seterror(h,
- concat("can't locate end of line in history ",
- h->histpath, location,
- NULL));
- r = false;
- } else {
- *p = '\0';
- *poff = offset;
- r = true;
- }
- } else {
- char location[HISV6_MAX_LOCATION];
-
- hisv6_errloc(location, (size_t)-1, offset);
- hisv6_seterror(h, concat("line too short in history ",
- h->histpath, location,
- NULL));
- r = false;
-
- }
- } else {
- /* not found */
- r = false;
- }
- fail:
- return r;
-}
-
-
-/*
-** lookup up the entry `key' in the history database, returning
-** arrived, posted and expires (for those which aren't NULL
-** pointers), and any storage token associated with the entry.
-**
-** If any of arrived, posted or expires aren't available, return zero
-** for that component.
-*/
-bool
-hisv6_lookup(void *history, const char *key, time_t *arrived,
- time_t *posted, time_t *expires, TOKEN *token)
-{
- struct hisv6 *h = history;
- HASH messageid;
- bool r;
- off_t offset;
- char buf[HISV6_MAXLINE + 1];
-
- his_logger("HISfilesfor begin", S_HISfilesfor);
- hisv6_checkfiles(h);
-
- messageid = HashMessageID(key);
- r = hisv6_fetchline(h, &messageid, buf, &offset);
- if (r == true) {
- int status;
- const char *error;
-
- status = hisv6_splitline(buf, &error, NULL,
- arrived, posted, expires, token);
- if (status < 0) {
- char location[HISV6_MAX_LOCATION];
-
- hisv6_errloc(location, (size_t)-1, offset);
- hisv6_seterror(h, concat(error, " ",
- h->histpath, location,
- NULL));
- r = false;
- } else {
- /* if we have a token then we have the article */
- r = !!(status & HISV6_HAVE_TOKEN);
- }
- }
- his_logger("HISfilesfor end", S_HISfilesfor);
- return r;
-}
-
-
-/*
-** check `key' has been seen in this history database
-*/
-bool
-hisv6_check(void *history, const char *key)
-{
- struct hisv6 *h = history;
- bool r;
- HASH hash;
-
- if (h != hisv6_dbzowner) {
- hisv6_seterror(h, concat("dbz not open for this history file ",
- h->histpath, NULL));
- return false;
- }
-
- his_logger("HIShavearticle begin", S_HIShavearticle);
- hisv6_checkfiles(h);
- hash = HashMessageID(key);
- r = dbzexists(hash);
- his_logger("HIShavearticle end", S_HIShavearticle);
- return r;
-}
-
-
-/*
-** Format a history line. s should hold at least HISV6_MAXLINE + 1
-** characters (to allow for the nul). Returns the length of the data
-** written, 0 if there was some error or if the data was too long to write.
-*/
-static int
-hisv6_formatline(char *s, const HASH *hash, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- int i;
- const char *hashtext = HashToText(*hash);
-
- if (token == NULL) {
- i = snprintf(s, HISV6_MAXLINE, "[%s]%c%lu%c%c\n",
- hashtext, HISV6_FIELDSEP,
- (unsigned long)arrived, HISV6_SUBFIELDSEP, HISV6_NOEXP);
- } else {
- const char *texttok;
-
- texttok = TokenToText(*token);
- if (expires <= 0) {
- i = snprintf(s, HISV6_MAXLINE, "[%s]%c%lu%c%c%c%lu%c%s\n",
- hashtext, HISV6_FIELDSEP,
- (unsigned long)arrived, HISV6_SUBFIELDSEP,
- HISV6_NOEXP, HISV6_SUBFIELDSEP,
- (unsigned long)posted, HISV6_FIELDSEP,
- texttok);
- } else {
- i = snprintf(s, HISV6_MAXLINE, "[%s]%c%lu%c%lu%c%lu%c%s\n",
- hashtext, HISV6_FIELDSEP,
- (unsigned long)arrived, HISV6_SUBFIELDSEP,
- (unsigned long)expires, HISV6_SUBFIELDSEP,
- (unsigned long)posted, HISV6_FIELDSEP,
- texttok);
- }
- }
- if (i < 0 || i >= HISV6_MAXLINE)
- return 0;
- return i;
-}
-
-
-/*
-** write the hash and offset to the dbz
-*/
-static bool
-hisv6_writedbz(struct hisv6 *h, const HASH *hash, off_t offset)
-{
- bool r;
- char location[HISV6_MAX_LOCATION];
- const char *error;
-
- /* store the offset in the database */
- switch (dbzstore(*hash, offset)) {
- case DBZSTORE_EXISTS:
- error = "dbzstore duplicate message-id ";
- /* not `false' so that we duplicate the pre-existing
- behaviour */
- r = true;
- break;
-
- case DBZSTORE_ERROR:
- error = "dbzstore error ";
- r = false;
- break;
-
- default:
- error = NULL;
- r = true;
- break;
- }
- if (error) {
- hisv6_errloc(location, (size_t)-1, offset);
- hisv6_seterror(h, concat(error, h->histpath,
- ":[", HashToText(*hash), "]",
- location, " ", strerror(errno), NULL));
- }
- if (r && h->synccount != 0 && ++h->dirty >= h->synccount)
- r = hisv6_sync(h);
-
- return r;
-}
-
-
-/*
-** write a history entry, hash, with times arrived, posted and
-** expires, and storage token.
-*/
-static bool
-hisv6_writeline(struct hisv6 *h, const HASH *hash, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- bool r;
- size_t i, length;
- char hisline[HISV6_MAXLINE + 1];
- char location[HISV6_MAX_LOCATION];
-
- if (h != hisv6_dbzowner) {
- hisv6_seterror(h, concat("dbz not open for this history file ",
- h->histpath, NULL));
- return false;
- }
-
- if (!(h->flags & HIS_RDWR)) {
- hisv6_seterror(h, concat("history not open for writing ",
- h->histpath, NULL));
- return false;
- }
-
- length = hisv6_formatline(hisline, hash, arrived, posted, expires, token);
- if (length == 0) {
- hisv6_seterror(h, concat("error formatting history line ",
- h->histpath, NULL));
- return false;
- }
-
- i = fwrite(hisline, 1, length, h->writefp);
-
- /* If the write failed, the history line is now an orphan. Attempt to
- rewind the write pointer to our offset to avoid leaving behind a
- partial write and desyncing the offset from our file position. */
- if (i < length ||
- (!(h->flags & HIS_INCORE) && fflush(h->writefp) == EOF)) {
- hisv6_errloc(location, (size_t)-1, h->offset);
- hisv6_seterror(h, concat("can't write history ", h->histpath,
- location, " ", strerror(errno), NULL));
- if (fseeko(h->writefp, h->offset, SEEK_SET) == -1)
- h->offset += i;
- r = false;
- goto fail;
- }
-
- r = hisv6_writedbz(h, hash, h->offset);
- h->offset += length; /* increment regardless of error from writedbz */
- fail:
- return r;
-}
-
-
-/*
-** write a history entry, key, with times arrived, posted and
-** expires, and storage token.
-*/
-bool
-hisv6_write(void *history, const char *key, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- struct hisv6 *h = history;
- HASH hash;
- bool r;
-
- his_logger("HISwrite begin", S_HISwrite);
- hash = HashMessageID(key);
- r = hisv6_writeline(h, &hash, arrived, posted, expires, token);
- his_logger("HISwrite end", S_HISwrite);
- return r;
-}
-
-
-/*
-** remember a history entry, key, with arrival time arrived.
-*/
-bool
-hisv6_remember(void *history, const char *key, time_t arrived)
-{
- struct hisv6 *h = history;
- HASH hash;
- bool r;
-
- his_logger("HISwrite begin", S_HISwrite);
- hash = HashMessageID(key);
- r = hisv6_writeline(h, &hash, arrived, 0, 0, NULL);
- his_logger("HISwrite end", S_HISwrite);
- return r;
-}
-
-
-/*
-** replace an existing history entry, `key', with times arrived,
-** posted and expires, and (optionally) storage token `token'. The
-** new history line must fit in the space allocated for the old one -
-** if it had previously just been HISremember()ed you'll almost
-** certainly lose.
-*/
-bool
-hisv6_replace(void *history, const char *key, time_t arrived,
- time_t posted, time_t expires, const TOKEN *token)
-{
- struct hisv6 *h = history;
- HASH hash;
- bool r;
- off_t offset;
- char old[HISV6_MAXLINE + 1];
-
- if (!(h->flags & HIS_RDWR)) {
- hisv6_seterror(h, concat("history not open for writing ",
- h->histpath, NULL));
- return false;
- }
-
- hash = HashMessageID(key);
- r = hisv6_fetchline(h, &hash, old, &offset);
- if (r == true) {
- char new[HISV6_MAXLINE + 1];
-
- if (hisv6_formatline(new, &hash, arrived, posted, expires,
- token) == 0) {
- hisv6_seterror(h, concat("error formatting history line ",
- h->histpath, NULL));
- r = false;
- } else {
- size_t oldlen, newlen;
-
- oldlen = strlen(old);
- newlen = strlen(new);
- if (new[newlen - 1] == '\n')
- newlen--;
- if (newlen > oldlen) {
- hisv6_seterror(h, concat("new history line too long ",
- h->histpath, NULL));
- r = false;
- } else {
- ssize_t n;
-
- /* space fill any excess in the tail of new */
- memset(new + newlen, ' ', oldlen - newlen);
-
- do {
- n = pwrite(fileno(h->writefp), new, oldlen, offset);
- } while (n == -1 && errno == EINTR);
- if (n != oldlen) {
- char location[HISV6_MAX_LOCATION];
-
- hisv6_errloc(location, (size_t)-1, offset);
- hisv6_seterror(h, concat("can't write history ",
- h->histpath, location, " ",
- strerror(errno), NULL));
- r = false;
- }
- }
- }
- }
- return r;
-}
-
-
-/*
-** traverse a history database, passing the pieces through a
-** callback; note that we have more parameters in the callback than
-** the public interface, we add the internal history struct and the
-** message hash so we can use those if we need them. If the callback
-** returns false we abort the traversal.
-**/
-static bool
-hisv6_traverse(struct hisv6 *h, struct hisv6_walkstate *cookie,
- const char *reason,
- bool (*callback)(struct hisv6 *, void *, const HASH *hash,
- time_t, time_t, time_t,
- const TOKEN *))
-{
- bool r = false;
- QIOSTATE *qp;
- void *p;
- size_t line;
- char location[HISV6_MAX_LOCATION];
-
- if ((qp = QIOopen(h->histpath)) == NULL) {
- hisv6_seterror(h, concat("can't QIOopen history file ",
- h->histpath, strerror(errno), NULL));
- return false;
- }
-
- line = 1;
- /* we come back to again after we hit EOF for the first time, when
- we pause the server & clean up any lines which sneak through in
- the interim */
- again:
- while ((p = QIOread(qp)) != NULL) {
- time_t arrived, posted, expires;
- int status;
- TOKEN token;
- HASH hash;
- const char *error;
-
- status = hisv6_splitline(p, &error, &hash,
- &arrived, &posted, &expires, &token);
- if (status > 0) {
- r = (*callback)(h, cookie, &hash, arrived, posted, expires,
- (status & HISV6_HAVE_TOKEN) ? &token : NULL);
- if (r == false)
- hisv6_seterror(h, concat("callback failed ",
- h->histpath, NULL));
- } else {
- hisv6_errloc(location, line, (off_t)-1);
- hisv6_seterror(h, concat(error, " ", h->histpath, location,
- NULL));
- /* if we're not ignoring errors set the status */
- if (!cookie->ignore)
- r = false;
- }
- if (r == false)
- goto fail;
- ++line;
- }
-
- if (p == NULL) {
- /* read or line-format error? */
- if (QIOerror(qp) || QIOtoolong(qp)) {
- hisv6_errloc(location, line, (off_t)-1);
- if (QIOtoolong(qp)) {
- hisv6_seterror(h, concat("line too long ",
- h->histpath, location, NULL));
- /* if we're not ignoring errors set the status */
- if (!cookie->ignore)
- r = false;
- } else {
- hisv6_seterror(h, concat("can't read line ",
- h->histpath, location, " ",
- strerror(errno), NULL));
- r = false;
- }
- if (r == false)
- goto fail;
- }
-
- /* must have been EOF, pause the server & clean up any
- * stragglers */
- if (reason && !cookie->paused) {
- if (ICCpause(reason) != 0) {
- hisv6_seterror(h, concat("can't pause server ",
- h->histpath, strerror(errno), NULL));
- r = false;
- goto fail;
- }
- cookie->paused = true;
- goto again;
- }
- }
- fail:
- QIOclose(qp);
- return r;
-}
-
-
-/*
-** internal callback used during hisv6_traverse; we just pass on the
-** parameters the user callback expects
-**/
-static bool
-hisv6_traversecb(struct hisv6 *h UNUSED, void *cookie, const HASH *hash UNUSED,
- time_t arrived, time_t posted, time_t expires,
- const TOKEN *token)
-{
- struct hisv6_walkstate *hiscookie = cookie;
-
- return (*hiscookie->cb.walk)(hiscookie->cookie,
- arrived, posted, expires,
- token);
-}
-
-
-/*
-** history API interface to the database traversal routine
-*/
-bool
-hisv6_walk(void *history, const char *reason, void *cookie,
- bool (*callback)(void *, time_t, time_t, time_t,
- const TOKEN *))
-{
- struct hisv6 *h = history;
- struct hisv6_walkstate hiscookie;
- bool r;
-
- /* our internal walk routine passes too many parameters, so add a
- wrapper */
- hiscookie.cb.walk = callback;
- hiscookie.cookie = cookie;
- hiscookie.new = NULL;
- hiscookie.paused = false;
- hiscookie.ignore = false;
-
- r = hisv6_traverse(h, &hiscookie, reason, hisv6_traversecb);
-
- return r;
-}
-
-
-/*
-** internal callback used during expire
-**/
-static bool
-hisv6_expirecb(struct hisv6 *h, void *cookie, const HASH *hash,
- time_t arrived, time_t posted, time_t expires,
- const TOKEN *token)
-{
- struct hisv6_walkstate *hiscookie = cookie;
- bool r = true;
-
- /* check if we've seen this message id already */
- if (hiscookie->new && dbzexists(*hash)) {
- /* continue after duplicates, it serious, but not fatal */
- hisv6_seterror(h, concat("duplicate message-id [",
- HashToText(*hash), "] in history ",
- hiscookie->new->histpath, NULL));
- } else {
- struct hisv6_walkstate *hiscookie = cookie;
- TOKEN ltoken, *t;
-
- /* if we have a token pass it to the discrimination function */
- if (token) {
- bool keep;
-
- /* make a local copy of the token so the callback can
- * modify it */
- ltoken = *token;
- t = <oken;
- keep = (*hiscookie->cb.expire)(hiscookie->cookie,
- arrived, posted, expires,
- t);
- /* if the callback returns true, we should keep the
- token for the time being, else we just remember
- it */
- if (keep == false) {
- t = NULL;
- posted = expires = 0;
- }
- } else {
- t = NULL;
- }
- if (hiscookie->new &&
- (t != NULL || arrived >= hiscookie->threshold)) {
- r = hisv6_writeline(hiscookie->new, hash,
- arrived, posted, expires, t);
- }
- }
- return r;
-}
-
-
-/*
-** unlink files associated with the history structure h
-*/
-static bool
-hisv6_unlink(struct hisv6 *h)
-{
- bool r = true;
- char *p;
-
-#ifdef DO_TAGGED_HASH
- p = concat(h->histpath, ".pag", NULL);
- r = (unlink(p) == 0) && r;
- free(p);
-#else
- p = concat(h->histpath, ".index", NULL);
- r = (unlink(p) == 0) && r;
- free(p);
-
- p = concat(h->histpath, ".hash", NULL);
- r = (unlink(p) == 0) && r;
- free(p);
-#endif
-
- p = concat(h->histpath, ".dir", NULL);
- r = (unlink(p) == 0) && r;
- free(p);
-
- r = (unlink(h->histpath) == 0) && r;
- return r;
-}
-
-
-/*
-** rename files associated with hold to hnew
-*/
-static bool
-hisv6_rename(struct hisv6 *hold, struct hisv6 *hnew)
-{
- bool r = true;
- char *old, *new;
-
-#ifdef DO_TAGGED_HASH
- old = concat(hold->histpath, ".pag", NULL);
- new = concat(hnew->histpath, ".pag", NULL);
- r = (rename(old, new) == 0) && r;
- free(old);
- free(new);
-#else
- old = concat(hold->histpath, ".index", NULL);
- new = concat(hnew->histpath, ".index", NULL);
- r = (rename(old, new) == 0) && r;
- free(old);
- free(new);
-
- old = concat(hold->histpath, ".hash", NULL);
- new = concat(hnew->histpath, ".hash", NULL);
- r = (rename(old, new) == 0) && r;
- free(old);
- free(new);
-#endif
-
- old = concat(hold->histpath, ".dir", NULL);
- new = concat(hnew->histpath, ".dir", NULL);
- r = (rename(old, new) == 0) && r;
- free(old);
- free(new);
-
- r = (rename(hold->histpath, hnew->histpath) == 0) && r;
- return r;
-}
-
-
-/*
-** expire the history database, history.
-*/
-bool
-hisv6_expire(void *history, const char *path, const char *reason,
- bool writing, void *cookie, time_t threshold,
- bool (*exists)(void *, time_t, time_t, time_t, TOKEN *))
-{
- struct hisv6 *h = history, *hnew = NULL;
- const char *nhistory = NULL;
- dbzoptions opt;
- bool r;
- struct hisv6_walkstate hiscookie;
-
- /* this flag is always tested in the fail clause, so initialise it
- now */
- hiscookie.paused = false;
-
- /* during expire we ignore errors whilst reading the history file
- * so any errors in it get fixed automagically */
- hiscookie.ignore = true;
-
- if (writing && (h->flags & HIS_RDWR)) {
- hisv6_seterror(h, concat("can't expire from read/write history ",
- h->histpath, NULL));
- r = false;
- goto fail;
- }
-
- if (writing) {
- /* form base name for new history file */
- if (path != NULL) {
- nhistory = concat(path, ".n", NULL);
- } else {
- nhistory = concat(h->histpath, ".n", NULL);
- }
-
- hnew = hisv6_new(nhistory, HIS_CREAT | HIS_RDWR | HIS_INCORE,
- h->history);
- if (!hisv6_reopen(hnew)) {
- hisv6_dispose(hnew);
- hnew = NULL;
- r = false;
- goto fail;
- }
-
- /* this is icky... we can only have one dbz open at a time; we
- really want to make dbz take a state structure. For now we'll
- just close the existing one and create our new one they way we
- need it */
- if (!hisv6_dbzclose(h)) {
- r = false;
- goto fail;
- }
-
- dbzgetoptions(&opt);
- opt.writethrough = false;
- opt.pag_incore = INCORE_MEM;
-#ifndef DO_TAGGED_HASH
- opt.exists_incore = INCORE_MEM;
-#endif
- dbzsetoptions(opt);
-
- if (h->npairs == 0) {
- if (!dbzagain(hnew->histpath, h->histpath)) {
- hisv6_seterror(h, concat("can't dbzagain ",
- hnew->histpath, ":", h->histpath,
- strerror(errno), NULL));
- r = false;
- goto fail;
- }
- } else {
- size_t npairs;
-
- npairs = (h->npairs == -1) ? 0 : h->npairs;
- if (!dbzfresh(hnew->histpath, dbzsize(npairs))) {
- hisv6_seterror(h, concat("can't dbzfresh ",
- hnew->histpath, ":", h->histpath,
- strerror(errno), NULL));
- r = false;
- goto fail;
- }
- }
- hisv6_dbzowner = hnew;
- }
-
- /* set up the callback handler */
- hiscookie.cb.expire = exists;
- hiscookie.cookie = cookie;
- hiscookie.new = hnew;
- hiscookie.threshold = threshold;
- r = hisv6_traverse(h, &hiscookie, reason, hisv6_expirecb);
-
- fail:
- if (writing) {
- if (hnew && !hisv6_closefiles(hnew)) {
- /* error will already have been set */
- r = false;
- }
-
- /* reopen will synchronise the dbz stuff for us */
- if (!hisv6_closefiles(h)) {
- /* error will already have been set */
- r = false;
- }
-
- if (r) {
- /* if the new path was explicitly specified don't move the
- files around, our caller is planning to do it out of
- band */
- if (path == NULL) {
- /* unlink the old files */
- r = hisv6_unlink(h);
-
- if (r) {
- r = hisv6_rename(hnew, h);
- }
- }
- } else if (hnew) {
- /* something went pear shaped, unlink the new files */
- hisv6_unlink(hnew);
- }
-
- /* re-enable dbz on the old history file */
- if (!hisv6_reopen(h)) {
- hisv6_closefiles(h);
- }
- }
-
- if (hnew && !hisv6_dispose(hnew))
- r = false;
- if (nhistory && nhistory != path)
- free((char *)nhistory);
- if (r == false && hiscookie.paused)
- ICCgo(reason);
- return r;
-}
-
-
-/*
-** control interface
-*/
-bool
-hisv6_ctl(void *history, int selector, void *val)
-{
- struct hisv6 *h = history;
- bool r = true;
-
- switch (selector) {
- case HISCTLG_PATH:
- *(char **)val = h->histpath;
- break;
-
- case HISCTLS_PATH:
- if (h->histpath) {
- hisv6_seterror(h, concat("path already set in handle", NULL));
- r = false;
- } else {
- h->histpath = xstrdup((char *)val);
- if (!hisv6_reopen(h)) {
- free(h->histpath);
- h->histpath = NULL;
- r = false;
- }
- }
- break;
-
- case HISCTLS_STATINTERVAL:
- h->statinterval = *(time_t *)val * 1000;
- break;
-
- case HISCTLS_SYNCCOUNT:
- h->synccount = *(size_t *)val;
- break;
-
- case HISCTLS_NPAIRS:
- h->npairs = (ssize_t)*(size_t *)val;
- break;
-
- case HISCTLS_IGNOREOLD:
- if (h->npairs == 0 && *(bool *)val) {
- h->npairs = -1;
- } else if (h->npairs == -1 && !*(bool *)val) {
- h->npairs = 0;
- }
- break;
-
- default:
- /* deliberately doesn't call hisv6_seterror as we don't want
- * to spam the error log if someone's passing in stuff which
- * would be relevant to a different history manager */
- r = false;
- break;
- }
- return r;
-}
+++ /dev/null
-/* $Id: hisv6.h 4959 2001-07-25 12:23:32Z alexk $
-**
-** Internal history API interface exposed to HISxxx
-*/
-
-#ifndef HISV6_H
-#define HISV6_H
-
-struct token;
-struct histopts;
-struct history;
-
-void *hisv6_open(const char *path, int flags, struct history *);
-
-bool hisv6_close(void *);
-
-bool hisv6_sync(void *);
-
-bool hisv6_lookup(void *, const char *key, time_t *arrived,
- time_t *posted, time_t *expires, struct token *token);
-
-bool hisv6_check(void *, const char *key);
-
-bool hisv6_write(void *, const char *key, time_t arrived,
- time_t posted, time_t expires, const struct token *token);
-
-bool hisv6_replace(void *, const char *key, time_t arrived,
- time_t posted, time_t expires, const struct token *token);
-
-bool hisv6_expire(void *, const char *, const char *, bool,
- void *, time_t threshold,
- bool (*exists)(void *, time_t, time_t, time_t,
- struct token *));
-
-bool hisv6_walk(void *, const char *, void *,
- bool (*)(void *, time_t, time_t, time_t,
- const struct token *));
-
-const char *hisv6_error(void *);
-
-bool hisv6_remember(void *, const char *key, time_t arrived);
-
-bool hisv6_ctl(void *, int, void *);
-
-#endif
+++ /dev/null
-## $Id: Makefile 6326 2003-05-05 21:47:43Z rra $
-##
-## Currently just handles creation of the automatically generated header
-## files. Eventually, rules for installing INN's header files will go
-## here.
-
-include ../Makefile.global
-
-top = ..
-
-ALL = inn/system.h inn/version.h
-
-EXTRA = config.h paths.h
-
-PUBLIC = config.h conffile.h dbz.h inndcomm.h libinn.h nntp.h ov.h \
- paths.h storage.h
-
-all: $(ALL) $(EXTRA)
-
-clean:
- rm -f $(ALL)
-
-clobber distclean: clean
- rm -f $(EXTRA)
-
-depend tags ctags:
-
-profiled: all
-
-$(EXTRA) $(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Build rules.
-
-inn/system.h: config.h $(top)/support/mksystem
- $(top)/support/mksystem $(AWK) config.h > $@
-
-inn/version.h: $(top)/support/mkversion $(top)/Makefile.global
- $(top)/support/mkversion '$(VERSION)' '$(VERSION_EXTRA)' > $@
-
-
-## Installation rules.
-
-install:
- for F in $(PUBLIC) ; do \
- $(CP_RPUB) $$F $D$(PATHINCLUDE)/$$F ; \
- done
- $(top)/support/install-sh $(OWNER) -m 0755 -d $D$(PATHINCLUDE)/inn
- for F in inn/*.h ; do \
- $(CP_RPUB) $$F $D$(PATHINCLUDE)/$$F ; \
- done
+++ /dev/null
-/* $Id: acconfig.h 6717 2004-05-16 20:48:51Z rra $
-**
-** Here be configuration data used by various InterNetNews programs. This
-** file is used as source for the autoheader script, which from it and
-** configure.in generates a config.h.in file that will be used by autoconf
-** as the repository of all wisdom.
-**
-** Stuff before TOP and after BOTTOM is copied verbatim to config.h.in;
-** the rest of this file is in the desired form for autoconfiscation.
-** Only stuff that autoconf 2.13 couldn't figure out for itself or that
-** needs a larger comment is included here.
-*/
-
-#ifndef CONFIG_H
-#define CONFIG_H 1
-
-/* Portable defines that don't rely on autoconf results come from here. */
-#include "inn/defines.h"
-
-/*
-** GENERAL SETTINGS
-**
-** Look over these settings and make sure they're correct for your site.
-** These values don't come from configure and therefore may need manual
-** editing. The defaults normally should be fine.
-**
-** For boolean #defines, uncomment and change #undef to #define to enable,
-** do the reverse to disable.
-*/
-
-/* A null-terminated list of uwildmat(3) patterns matching illegal
- distributions. inews and nnrpd will reject posts with a distribution
- matching one of these patterns. */
-#define BAD_DISTRIBS "*.*", NULL
-
-/* Default timeout period for ctlinnd, overridden by the -t flag. If set to
- zero, ctlinnd will never time out, but will check every two minutes to
- see if the server is still running so it won't hang forever on a dead
- server. */
-#define CTLINND_TIMEOUT 0
-
-/* Reject articles posted more than this many seconds in the future. */
-#define DATE_FUZZ (24L * 60L * 60L)
-
-/* innd will flush the history and active file after this many seconds. */
-#define DEFAULT_TIMEOUT 300
-
-/* Define if inews should put hostnames into the Path header itself. */
-#define DO_INEWS_PATH
-
-/* Define if inews should munge the GECOS entry of the passwd file when
- attempting to determine a poster's real name. Use this if your GECOS
- entries have other stuff after trailing commas or before dashes, things
- in parentheses that aren't part of the name, etc. See frontends/inews.c
- for the full algorithm. */
-#define DO_MUNGE_GECOS
-
-/* Define if rnews should try to connect to the local host. */
-#define DO_RNEWSLOCALCONNECT
-
-/* Define if rnews should syslog articles rejected as duplicates. */
-/* #undef DO_RNEWS_LOG_DUPS */
-
-/* Define if rnews should look in _PATH_RNEWSPROGS for batch unpackers. */
-#define DO_RNEWSPROGS
-
-/* Define if rnews should save articles rejected by the server. */
-/* #undef DO_RNEWS_SAVE_BAD */
-
-/* Value to pass to dbzincore() inside innd. Under some bizarre low memory
- circumstance you may want this not to be 1, but normally you always want
- to load the full history indexes into innd's memory. Has no effect if
- using tagged hash (which is always in core). */
-#define INND_DBZINCORE 1
-
-/* A null-terminated list of unknown commands that, when seen by innd,
- shouldn't be logged to syslog. Normally innd logs all unknown commands,
- but sometimes some are so frequent that it's not worth it. */
-#define INND_QUIET_BADLIST NULL
-
-/* innd will throttle itself after this many I/O errors. The count is reset
- on a ctlinnd go. (ENOSPC is special and will always cause an immediate
- throttle.) */
-#define IO_ERROR_COUNT 50
-
-/* Length of listen queue for innd. */
-#define MAXLISTEN 25
-
-/* The standard NNTP port. */
-#define NNTP_PORT 119
-
-/* What to use for a Path tail for local posts. */
-#define PATHMASTER "not-for-mail"
-
-
-/*
-** CONFIGURE RESULTS
-**
-** Things determined automatically by autoconf. Nothing below this point
-** should require manual editing; if anything here is wrong, see if you
-** should be passing a flag to configure to set it correctly for your
-** system.
-**
-** Be aware that success of some tests will cause other tests to be skipped
-** since their results aren't then needed. For example, if you have
-** standard C headers, INN won't bother looking for stdlib.h, and
-** HAVE_STDLIB_H will be false whether you have it or not. This is normal.
-**
-** Fodder for autoheader is provided in sort -df order (alphabetical,
-** case-insensitive, ignoring punctuation) to make it easier to check
-** whether a given entry is in the file.
-*/
-@TOP@
-
-/* Define to a suitable 32-bit type if standard headers don't define. */
-#undef int32_t
-
-/* Define to `long' if <sys/types.h> doesn't define. */
-#undef ptrdiff_t
-
-/* Define to `int' if <signal.h> doesn't define. */
-#undef sig_atomic_t
-
-/* Define to `int' if <sys/socket.h> doesn't define. */
-#undef socklen_t
-
-/* Define to `int' if <sys/types.h> doesn't define. */
-#undef ssize_t
-
-/* Define to a suitable 32-bit type if standard headers don't define. */
-#undef uint32_t
-
-@BOTTOM@
-
-
-/*
-** BUFFER SIZES AND DATA LENGTHS
-**
-** You shouldn't need to change any of the following, and changing some of
-** them may cause other things to break. Some standard buffer sizes and
-** lengths of data types for various different things.
-*/
-
-/* The data type to use for article numbers. This probably can't be
- increased without a lot of work due to assumptions about the active file
- format, etc. */
-typedef unsigned long ARTNUM;
-
-/* Input buffers start at START_BUFF_SIZE. While reading input, if we have
- less than LOW_WATER bytes left free in the buffer, use the current
- buffersize as input to GROW_AMOUNT to determine how much to realloc.
- Growth must be at least NNTP_STRLEN bytes! The default settings provide
- aggressive, exponential buffer growth. */
-#define START_BUFF_SIZE (4 * 1024)
-#define LOW_WATER (1 * 1024)
-#define GROW_AMOUNT(x) ((x) < 128 * 1024 ? (x) : 128 * 1024)
-
-/* The size of a large buffer. Free dynamically allocated buffers larger
- than this when we're done with them. */
-#define BIG_BUFFER (2 * START_BUFF_SIZE)
-
-/* The maximum length of a single header, used as a good guess at a buffer
- size for some header parsing code. This is currently also used by innd
- to determine whether to reject a message for an excessively long header;
- this behavior should be fixed. */
-#define MAXHEADERSIZE 1024
-
-/* Default buffer size for outgoing feeds from innd. */
-#define SITE_BUFFER_SIZE (16 * 1024)
-
-/* The size of a small buffer. */
-#define SMBUF 256
-
-/* Maximum size of a pathname in the spool directory. */
-#define SPOOLNAMEBUFF 512
-
-
-/*
-** LEGACY
-**
-** Everything below this point is here so that parts of INN that haven't
-** been tweaked to use more standard constructs don't break. Don't count
-** on any of this staying in this file. If you have a chance, consider
-** following the comments before each item and fixing it.
-*/
-
-/* Used to send commands to exploders. Should be moved into a more specific
- header file; used by innd/site.c and backends/buffchan.c. */
-#define EXP_CONTROL '!'
-
-/* Only used by innd and cvtbatch, should be moved to a more specific header
- file. */
-#define FEED_BYTESIZE 'b'
-#define FEED_FULLNAME 'f'
-#define FEED_HASH 'h'
-#define FEED_HDR_DISTRIB 'D'
-#define FEED_HDR_NEWSGROUP 'N'
-#define FEED_MESSAGEID 'm'
-#define FEED_FNLNAMES '*'
-#define FEED_HEADERS 'H'
-#define FEED_NAME 'n'
-#define FEED_STOREDGROUP 'G'
-#define FEED_NEWSGROUP 'g'
-#define FEED_OVERVIEW 'O'
-#define FEED_PATH 'P'
-#define FEED_REPLIC 'R'
-#define FEED_SITE 's'
-#define FEED_TIMEEXPIRED 'e'
-#define FEED_TIMERECEIVED 't'
-#define FEED_TIMEPOSTED 'p'
-
-/* Maximum number of flags for a feed in newsfeeds. Only used in innd,
- should be moved there (or made dynamic). */
-#define FEED_MAXFLAGS 20
-
-/* Maximum length of argv vectors used in innd/site.c. This should be moved
- out of here into that file, or even better hard-coded rather than
- defined; this value isn't affected by user data and the right value can
- be determined by looking at the code and seeing how big of an argv it
- will attempt to construct. */
-#define MAX_BUILTIN_ARGV 20
-
-/* active file flags. Should be moved to a more specific header file. */
-#define NF_FLAG_ALIAS '='
-#define NF_FLAG_EXCLUDED 'j'
-#define NF_FLAG_MODERATED 'm'
-#define NF_FLAG_OK 'y'
-#define NF_FLAG_NOLOCAL 'n'
-#define NF_FLAG_IGNORE 'x'
-
-/* Used for parsing the Newsgroups header. Should be rolled into a library
- for parsing headers, combining all the code that's currently scattered
- all over INN for doing that. */
-#define NG_SEPARATOR ","
-#define NG_ISSEP(c) ((c) == ',')
-
-/* There's no reason to make all of these #defines except possibly for
- L_CC_CMD and even that's a stretch. Since we're logging to our own
- distinguished log facility, provided that we spread things out between a
- reasonable variety of log levels, the sysadmin shouldn't have to change
- any of this. (Some of this is arguably wrong; L_NOTICE should be
- LOG_NOTICE, for example.) */
-
-/* Flags to use in opening the logs; some programs add LOG_PID. */
-#define L_OPENLOG_FLAGS (LOG_CONS | LOG_NDELAY)
-
-/* Fatal error, program is about to exit. */
-#define L_FATAL LOG_CRIT
-
-/* Log an error that might mean one or more articles get lost. */
-#define L_ERROR LOG_ERR
-
-/* Informational notice, usually not worth caring about. */
-#define L_NOTICE LOG_WARNING
-
-/* A protocol trace. */
-#define L_TRACE LOG_DEBUG
-
-/* All incoming control commands (ctlinnd, etc). */
-#define L_CC_CMD LOG_INFO
-
-#endif /* !CONFIG_H */
+++ /dev/null
-/* $Id: clibrary.h 6704 2004-05-16 19:46:20Z rra $
-**
-** Here be declarations of routines and variables in the C library.
-** Including this file is the equivalent of including all of the following
-** headers, portably:
-**
-** #include <sys/types.h>
-** #include <stdarg.h>
-** #include <stdio.h>
-** #include <stdlib.h>
-** #include <stddef.h>
-** #include <stdint.h>
-** #include <string.h>
-** #include <unistd.h>
-**
-** Missing functions are provided via #define or prototyped if we'll be
-** adding them to INN's library. If the system doesn't define a SUN_LEN
-** macro, one will be provided. Also provides some standard #defines.
-*/
-
-#ifndef CLIBRARY_H
-#define CLIBRARY_H 1
-
-/* Make sure we have our configuration information. */
-#include "config.h"
-
-/* Assume stdarg is available; don't bother with varargs support any more.
- We need this to be able to declare vsnprintf. */
-#include <stdarg.h>
-
-/* This is the same method used by autoconf as of 2000-07-29 for including
- the basic system headers with the addition of handling of strchr,
- strrchr, and memcpy. Note that we don't attempt to declare any of the
- functions; the number of systems left without ANSI-compatible function
- prototypes isn't high enough to be worth the trouble. */
-#include <stdio.h>
-#include <sys/types.h>
-#if STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# if HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-# if !HAVE_STRCHR
-# define strchr index
-# define strrchr rindex
-# endif
-# if !HAVE_MEMCPY
-# define memcpy(d, s, n) bcopy((s), (d), (n))
-# endif
-#endif
-#if HAVE_STRING_H
-# if !STDC_HEADERS && HAVE_MEMORY_H
-# include <memory.h>
-# endif
-# include <string.h>
-#else
-# if HAVE_STRINGS_H
-# include <strings.h>
-# endif
-#endif
-
-#if HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#if HAVE_STDINT_H
-# include <stdint.h>
-#endif
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-/* SCO OpenServer gets int32_t from here. */
-#if HAVE_SYS_BITYPES_H
-# include <sys/bitypes.h>
-#endif
-
-BEGIN_DECLS
-
-/* Provide prototypes for functions not declared in system headers. Use the
- NEED_DECLARATION macros for those functions that may be prototyped but
- implemented incorrectly. */
-#if !HAVE_FSEEKO
-extern int fseeko(FILE *, off_t, int);
-#endif
-#if !HAVE_FTELLO
-extern off_t ftello(FILE *);
-#endif
-#if !HAVE_HSTRERROR
-extern const char * hstrerror(int);
-#endif
-#if !HAVE_MKSTEMP
-extern int mkstemp(char *);
-#endif
-#if !HAVE_PREAD
-extern ssize_t pread(int, void *, size_t, off_t);
-#endif
-#if !HAVE_PWRITE
-extern ssize_t pwrite(int, const void *, size_t, off_t);
-#endif
-#if !HAVE_SETENV
-extern int setenv(const char *, const char *, int);
-#endif
-#if !HAVE_SETEUID
-extern int seteuid(uid_t);
-#endif
-#if NEED_DECLARATION_SNPRINTF
-extern int snprintf(char *, size_t, const char *, ...)
- __attribute__((__format__(printf, 3, 4)));
-#endif
-#if !HAVE_STRERROR
-extern const char * strerror(int);
-#endif
-#if !HAVE_STRLCAT
-extern size_t strlcat(char *, const char *, size_t);
-#endif
-#if !HAVE_STRLCPY
-extern size_t strlcpy(char *, const char *, size_t);
-#endif
-#if NEED_DECLARATION_VSNPRINTF
-extern int vsnprintf(char *, size_t, const char *, va_list);
-#endif
-
-END_DECLS
-
-/* "Good enough" replacements for standard functions. */
-#if !HAVE_ATEXIT
-# define atexit(arg) on_exit((arg), 0)
-#endif
-#if !HAVE_STRTOUL
-# define strtoul(a, b, c) (unsigned long) strtol((a), (b), (c))
-#endif
-
-/* This almost certainly isn't necessary, but it's not hurting anything.
- gcc assumes that if SEEK_SET isn't defined none of the rest are either,
- so we certainly can as well. */
-#ifndef SEEK_SET
-# define SEEK_SET 0
-# define SEEK_CUR 1
-# define SEEK_END 2
-#endif
-
-/* POSIX requires that these be defined in <unistd.h>. If one of them has
- been defined, all the rest almost certainly have. */
-#ifndef STDIN_FILENO
-# define STDIN_FILENO 0
-# define STDOUT_FILENO 1
-# define STDERR_FILENO 2
-#endif
-
-/* On some systems, the macros defined by <ctype.h> are only vaild on ASCII
- characters (those characters that isascii() says are ASCII). This comes
- into play when applying <ctype.h> macros to eight-bit data. autoconf
- checks for this with as part of AC_HEADER_STDC, so if autoconf doesn't
- think our headers are standard, check isascii() first. */
-#if STDC_HEADERS
-# define CTYPE(isXXXXX, c) (isXXXXX((unsigned char)(c)))
-#else
-# define CTYPE(isXXXXX, c) \
- (isascii((unsigned char)(c)) && isXXXXX((unsigned char)(c)))
-#endif
-
-/* POSIX.1g requires <sys/un.h> to define a SUN_LEN macro for determining
- the real length of a struct sockaddr_un, but it's not available
- everywhere yet. If autoconf couldn't find it, define our own. This
- definition is from 4.4BSD by way of Stevens, Unix Network Programming
- (2nd edition), vol. 1, pg. 917. */
-#if !HAVE_SUN_LEN
-# define SUN_LEN(sun) \
- (sizeof(*(sun)) - sizeof((sun)->sun_path) + strlen((sun)->sun_path))
-#endif
-
-/* Used to name the elements of the array passed to pipe(). */
-#define PIPE_READ 0
-#define PIPE_WRITE 1
-
-/* Used for iterating through arrays. ARRAY_SIZE returns the number of
- elements in the array (useful for a < upper bound in a for loop) and
- ARRAY_END returns a pointer to the element past the end (ISO C99 makes it
- legal to refer to such a pointer as long as it's never dereferenced). */
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
-#define ARRAY_END(array) (&(array)[ARRAY_SIZE(array)])
-
-
-#endif /* !CLIBRARY_H */
+++ /dev/null
-/* $Revision: 5086 $
-**
-** Data structures, functions and cetera used for config file parsing.
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- FILE *f;
- char *buf;
- unsigned int sbuf;
- int lineno;
- int array_len;
- char **array;
- char *filename;
-} CONFFILE;
-
-typedef struct {
- int type;
-#define CONFstring -1
- char *name;
-} CONFTOKEN;
-
-extern char CONFerror[];
-
-extern CONFFILE *CONFfopen(char*);
-extern void CONFfclose(CONFFILE*);
-
-extern CONFTOKEN *CONFgettoken(CONFTOKEN*, CONFFILE*);
-
-#ifdef __cplusplus
-}
-#endif
+++ /dev/null
-#ifndef __DBZ_H__
-#define __DBZ_H__
-
-/* Need the definition of HASH. */
-#include "libinn.h"
-
-BEGIN_DECLS
-
-/* This is the number of bytes of the md5 to actually store in
- * the .pag file. This number directly effects the collision
- * rate and memory usage. You can probably set this number as
- * low as 5 w/o problems and some sites may want to set it as
- * high as 8. Anything higher than that is probably not useful.
- * Note at the internal hash size isn't the only factor that
- * effects collision rate. The table index is used as an implicit
- * part of the hash value stored also.
- */
-#ifdef DO_TAGGED_HASH
-#define DBZMAXKEY 255
-#define DBZ_INTERNAL_HASH_SIZE 4
-#else
-#define DBZ_INTERNAL_HASH_SIZE 6
-#endif
-
-typedef enum {DBZSTORE_OK, DBZSTORE_EXISTS, DBZSTORE_ERROR} DBZSTORE_RESULT;
-typedef enum {INCORE_NO, INCORE_MEM, INCORE_MMAP} dbz_incore_val;
-
-typedef struct {
- /* Whether to write to the filesystem in addition to updating the incore
- copy. This will replace a single large write to disk when dbzsync is
- called. */
- bool writethrough;
- /* Whether to do hash lookups from disk, memory or a mmap'ed file */
- dbz_incore_val pag_incore;
- dbz_incore_val exists_incore;
- /* Whether dbzstore should update the database async or sync. This
- is only applicable if you're not mmaping the database */
- bool nonblock;
-} dbzoptions;
-
-#ifdef __GNUC__
-#define PACKED __attribute__ ((packed))
-#else
-#if !defined(PACKED)
-#define PACKED
-#endif
-#endif
-
-#if !defined(lint) && (defined(__SUNPRO_C) || defined(_nec_ews))
-#pragma pack(1)
-#endif /* nor lint, nor __SUNPRO_C, nor sgi, nor _nec_ews */
-typedef struct {
- char hash[DBZ_INTERNAL_HASH_SIZE];
-} PACKED erec;
-#if !defined(lint) && (defined(__SUNPRO_C) || defined(_nec_ews))
-#pragma pack()
-#endif /* nor lint, nor__SUNPRO_C, nor _nec_ews */
-
-/* standard dbm functions */
-extern bool dbzinit(const char *name);
-extern bool dbzclose(void);
-
-/* new stuff for dbz */
-extern bool dbzfresh(const char *name, off_t size);
-extern bool dbzagain(const char *name, const char *oldname);
-extern bool dbzexists(const HASH key);
-extern bool dbzfetch(const HASH key, off_t *value);
-extern DBZSTORE_RESULT dbzstore(const HASH key, off_t data);
-extern bool dbzsync(void);
-extern long dbzsize(off_t contents);
-extern void dbzsetoptions(const dbzoptions options);
-extern void dbzgetoptions(dbzoptions *options);
-
-END_DECLS
-
-#endif /* __DBZ_H__ */
+++ /dev/null
-/* $Id: buffer.h 6295 2003-04-16 05:46:38Z rra $
-**
-** Counted, reusable memory buffer.
-**
-** A buffer is an allocated bit of memory with a known size and a separate
-** data length. It's intended to store strings and can be reused repeatedly
-** to minimize the number of memory allocations. Buffers increase in
-** increments of 1K.
-**
-** A buffer contains a notion of the data that's been used and the data
-** that's been left, used when the buffer is an I/O buffer where lots of data
-** is buffered and then slowly processed out of the buffer. The total length
-** of the data is used + left. If a buffer is just used to store some data,
-** used can be set to 0 and left stores the length of the data.
-*/
-
-#ifndef INN_BUFFER_H
-#define INN_BUFFER_H 1
-
-#include <inn/defines.h>
-
-struct buffer {
- size_t size; /* Total allocated length. */
- size_t used; /* Data already used. */
- size_t left; /* Remaining unused data. */
- char *data; /* Pointer to allocated memory. */
-};
-
-BEGIN_DECLS
-
-/* Allocate a new buffer and initialize its contents. */
-struct buffer *buffer_new(void);
-
-/* Resize a buffer to be at least as large as the provided size. */
-void buffer_resize(struct buffer *, size_t);
-
-/* Set the buffer contents, ignoring anything currently there. */
-void buffer_set(struct buffer *, const char *data, size_t length);
-
-/* Append data to the buffer. */
-void buffer_append(struct buffer *, const char *data, size_t length);
-
-/* Swap the contents of two buffers. */
-void buffer_swap(struct buffer *, struct buffer *);
-
-END_DECLS
-
-#endif /* INN_BUFFER_H */
+++ /dev/null
-/* $Id: confparse.h 5114 2002-02-18 01:17:24Z rra $
-**
-** Configuration file parsing interface.
-*/
-
-#ifndef INN_CONFPARSE_H
-#define INN_CONFPARSE_H 1
-
-#include <inn/defines.h>
-
-/* Avoid including <inn/vector.h> unless the client needs it. */
-struct vector;
-
-/* The opaque data type representing a configuration tree. */
-struct config_group;
-
-BEGIN_DECLS
-
-/* Parse the given file and build a configuration tree. This does purely
- syntactic parsing; no semantic checking is done. After the file name, a
- NULL-terminated list of const char * pointers should be given, naming the
- top-level group types that the caller is interested in. If none are given
- (if the second argument is NULL), the entire file is parsed. (This is
- purely for efficiency reasons; if one doesn't care about speed, everything
- will work the same if no types are given.)
-
- Returns a config_group for the top-level group representing the entire
- file. Generally one never wants to query parameters in this group;
- instead, the client should then call config_find_group for the group type
- of interest. Returns NULL on failure to read the file or on a parse
- failure; errors are reported via warn. */
-struct config_group *config_parse_file(const char *filename, /* types */ ...);
-
-/* config_find_group returns the first group of the given type found in the
- tree rooted at its argument. config_next_group returns the next group in
- the tree of the same type as the given group (or NULL if none is found).
- This can be used to do such things as enumerate all "peer" groups in a
- configuration file. */
-struct config_group *config_find_group(struct config_group *,
- const char *type);
-struct config_group *config_next_group(struct config_group *);
-
-/* Accessor functions for group information. */
-const char *config_group_type(struct config_group *);
-const char *config_group_tag(struct config_group *);
-
-/* Look up a parameter in a given config tree. The second argument is the
- name of the parameter, and the result will be stored in the third argument
- if the function returns true. If it returns false, the third argument is
- unchanged and that parameter wasn't set (or was set to an invalid value for
- the expected type). */
-bool config_param_boolean(struct config_group *, const char *, bool *);
-bool config_param_integer(struct config_group *, const char *, long *);
-bool config_param_real(struct config_group *, const char *, double *);
-bool config_param_string(struct config_group *, const char *, const char **);
-bool config_param_list(struct config_group *, const char *, struct vector *);
-
-/* Used for checking a configuration file, returns a vector of all parameters
- set for the given config_group, including inherited ones. */
-struct vector *config_params(struct config_group *);
-
-/* Used for reporting semantic errors, config_error_param reports the given
- error at a particular parameter in a config_group and config_error_group
- reports an error at the definition of that group. The error is reported
- using warn. */
-void config_error_group(struct config_group *, const char *format, ...);
-void config_error_param(struct config_group *, const char *key,
- const char *format, ...);
-
-/* Free all space allocated by the tree rooted at config_group. One normally
- never wants to do this. WARNING: This includes the storage allocated for
- all strings returned by config_param_string and config_param_list for any
- configuration groups in this tree. */
-void config_free(struct config_group *);
-
-END_DECLS
-
-#endif /* INN_CONFPARSE_H */
+++ /dev/null
-/* $Id: defines.h 6124 2003-01-14 06:03:29Z rra $
-**
-** Portable defines used by other INN header files.
-**
-** In order to make the libraries built by INN usable by other software,
-** INN needs to install several header files. Installing autoconf-
-** generated header files, however, is a bad idea, since the defines will
-** conflict with other software that uses autoconf.
-**
-** This header contains common definitions, such as internal typedefs and
-** macros, common to INN's header files but not based on autoconf probes.
-** As such, it's limited in what it can do; if compiling software against
-** INN's header files on a system not supporting basic ANSI C features
-** (such as const) or standard types (like size_t), the software may need
-** to duplicate the tests that INN itself performs, generate a config.h,
-** and make sure that config.h is included before any INN header files.
-*/
-
-#ifndef INN_DEFINES_H
-#define INN_DEFINES_H 1
-
-#include <inn/system.h>
-
-/* BEGIN_DECLS is used at the beginning of declarations so that C++
- compilers don't mangle their names. END_DECLS is used at the end. */
-#undef BEGIN_DECLS
-#undef END_DECLS
-#ifdef __cplusplus
-# define BEGIN_DECLS extern "C" {
-# define END_DECLS }
-#else
-# define BEGIN_DECLS /* empty */
-# define END_DECLS /* empty */
-#endif
-
-/* __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7
- could you use the __format__ form of the attributes, which is what we use
- (to avoid confusion with other macros). */
-#ifndef __attribute__
-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
-# define __attribute__(spec) /* empty */
-# endif
-#endif
-
-/* Used for unused parameters to silence gcc warnings. */
-#define UNUSED __attribute__((__unused__))
-
-/* Make available the bool type. */
-#if INN_HAVE_STDBOOL_H
-# include <stdbool.h>
-#else
-# undef true
-# undef false
-# define true (1)
-# define false (0)
-# ifndef __cplusplus
-# define bool int
-# endif
-#endif /* INN_HAVE_STDBOOL_H */
-
-/* Tell Perl that we have a bool type. */
-#ifndef HAS_BOOL
-# define HAS_BOOL 1
-#endif
-
-#endif /* !INN_DEFINES_H */
+++ /dev/null
-/* $Id: hashtab.h 5944 2002-12-08 02:33:08Z rra $
-**
-** Generic hash table interface.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** A hash table takes a hash function that acts on keys, a function to
-** extract the key from a data item stored in a hash, a function that takes
-** a key and a data item and returns true if the key matches, and a
-** function to be called on any data item being deleted from the hash.
-**
-** hash_create creates a hash and hash_free frees all the space allocated
-** by one. hash_insert, hash_replace, and hash_delete modify it, and
-** hash_lookup extracts values. hash_traverse can be used to walk the
-** hash, and hash_count returns the number of elements currently stored in
-** the hash. hash_searches, hash_collisions, and hash_expansions extract
-** performance and debugging statistics.
-*/
-
-#ifndef INN_HASHTAB_H
-#define INN_HASHTAB_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/* The layout of this struct is entirely internal to the implementation. */
-struct hash;
-
-/* Data types for function pointers used by the hash table interface. */
-typedef unsigned long (*hash_func)(const void *);
-typedef const void * (*hash_key_func)(const void *);
-typedef bool (*hash_equal_func)(const void *, const void *);
-typedef void (*hash_delete_func)(void *);
-typedef void (*hash_traverse_func)(void *, void *);
-
-/* Generic hash table interface. */
-struct hash * hash_create(size_t, hash_func, hash_key_func,
- hash_equal_func, hash_delete_func);
-void hash_free(struct hash *);
-void * hash_lookup(struct hash *, const void *key);
-bool hash_insert(struct hash *, const void *key, void *datum);
-bool hash_replace(struct hash *, const void *key, void *datum);
-bool hash_delete(struct hash *, const void *key);
-void hash_traverse(struct hash *, hash_traverse_func, void *);
-unsigned long hash_count(struct hash *);
-unsigned long hash_searches(struct hash *);
-unsigned long hash_collisions(struct hash *);
-unsigned long hash_expansions(struct hash *);
-
-/* Hash functions available for callers. */
-unsigned long hash_string(const void *);
-
-/* Functions useful for constructing new hashes. */
-unsigned long hash_lookup2(const char *, size_t, unsigned long partial);
-
-END_DECLS
-
-#endif /* INN_HASHTAB_H */
+++ /dev/null
-/* $Id: history.h 4916 2001-07-18 12:33:01Z alexk $
-**
-** Interface to history API
-*/
-
-#ifndef INN_HISTORY_H
-#define INN_HISTORY_H
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/*
-** ensure appropriate scoping; we don't pull inn/storage.h as we
-** don't need; our caller then has the option
-*/
-struct history;
-struct token;
-
-/*
-** structure giving cache statistics returned from HISstats
-*/
-struct histstats {
- /* number of positive hits */
- int hitpos;
- /* number of negative hits */
- int hitneg;
- /* number of misses (positive hit, but not in cache) */
- int misses;
- /* number of does not exists (negative hit, but not in cache) */
- int dne;
-};
-
-
-/*
-** flags passed to HISopen
-*/
-
-/* open database read only */
-#define HIS_RDONLY (0)
-
-/* open database read/write */
-#define HIS_RDWR (1<<0)
-
-/* create on open */
-#define HIS_CREAT (1<<1)
-
-/* hint that the data should be kept on disk */
-#define HIS_ONDISK (1<<2)
-
-/* hint that the data should be kept in core */
-#define HIS_INCORE (1<<3)
-
-/* hint that the data should be kept mmap()ed */
-#define HIS_MMAP (1<<4)
-
-/*
-** values passed to HISctl
-*/
-enum {
- /* (char **) get history path */
- HISCTLG_PATH,
-
- /* (char *) set history path */
- HISCTLS_PATH,
-
- /* (int) how many history writes may be outstanding */
- HISCTLS_SYNCCOUNT,
-
- /* (size_t) number of pairs for which the database should be sized */
- HISCTLS_NPAIRS,
-
- /* (bool) Ignore old database during expire */
- HISCTLS_IGNOREOLD,
-
- /* (time_t) interval, in s, between stats of the history database
- * for * detecting a replacement, or 0 to disable (no checks);
- * defaults {hisv6, taggedhash} */
- HISCTLS_STATINTERVAL
-
-};
-
-struct history * HISopen(const char *, const char *, int);
-bool HISclose(struct history *);
-bool HISsync(struct history *);
-void HISsetcache(struct history *, size_t);
-bool HISlookup(struct history *, const char *, time_t *,
- time_t *, time_t *, struct token *);
-bool HIScheck(struct history *, const char *);
-bool HISwrite(struct history *, const char *, time_t,
- time_t, time_t, const struct token *);
-bool HISremember(struct history *, const char *, time_t);
-bool HISreplace(struct history *, const char *, time_t,
- time_t, time_t, const struct token *);
-bool HISexpire(struct history *, const char *, const char *,
- bool, void *, time_t,
- bool (*)(void *, time_t, time_t, time_t,
- struct token *));
-bool HISwalk(struct history *, const char *, void *,
- bool (*)(void *, time_t, time_t, time_t,
- const struct token *));
-struct histstats HISstats(struct history *);
-const char * HISerror(struct history *);
-bool HISctl(struct history *, int, void *);
-void HISlogclose(void);
-void HISlogto(const char *s);
-
-END_DECLS
-
-#endif
+++ /dev/null
-/* $Id: innconf.h 7751 2008-04-06 14:35:40Z iulius $
-**
-** inn.conf parser interface.
-**
-** The interface to reading inn.conf configuration files and managing the
-** resulting innconf struct.
-*/
-
-#ifndef INN_INNCONF_H
-#define INN_INNCONF_H 1
-
-#include <inn/defines.h>
-#include <stdio.h>
-
-/*
-** This structure is organized in the same order as the variables contained
-** in it are mentioned in the inn.conf documentation, and broken down into
-** the same sections. Note that due to the implementation, only three types
-** of variables are permissible here: char *, bool, and long.
-*/
-struct innconf {
- /* General Settings */
- char *domain; /* Default domain of local host */
- char *innflags; /* Flags to pass to innd on startup */
- char *mailcmd; /* Command to send report/control type mail */
- char *mta; /* MTA for mailing to moderators, innmail */
- char *pathhost; /* Entry for the Path line */
- char *server; /* Default server to connect to */
-
- /* Feed Configuration */
- long artcutoff; /* Max accepted article age */
- char *bindaddress; /* Which interface IP to bind to */
- char *bindaddress6; /* Which interface IPv6 to bind to */
- bool dontrejectfiltered; /* Don't reject filtered article? */
- long hiscachesize; /* Size of the history cache in kB */
- bool ignorenewsgroups; /* Propagate cmsgs by affected group? */
- bool immediatecancel; /* Immediately cancel timecaf messages? */
- long linecountfuzz; /* Check linecount and reject if off by more */
- long maxartsize; /* Reject articles bigger than this */
- long maxconnections; /* Max number of incoming NNTP connections */
- char *pathalias; /* Prepended Host for the Path line */
- char *pathcluster; /* Appended Host for the Path line */
- bool pgpverify; /* Verify control messages with pgpverify? */
- long port; /* Which port innd should listen on */
- bool refusecybercancels; /* Reject message IDs with "<cancel."? */
- bool remembertrash; /* Put unwanted article IDs into history */
- char *sourceaddress; /* Source IP for outgoing NNTP connections */
- char *sourceaddress6; /* Source IPv6 for outgoing NNTP connections */
- bool verifycancels; /* Verify cancels against article author */
- bool wanttrash; /* Put unwanted articles in junk */
- long wipcheck; /* How long to defer other copies of article */
- long wipexpire; /* How long to keep pending article record */
-
- /* History settings */
- char *hismethod; /* Which history method to use */
-
- /* Article Storage */
- long cnfscheckfudgesize; /* Additional CNFS integrity checking */
- bool enableoverview; /* Store overview info for articles? */
- bool groupbaseexpiry; /* Do expiry by newsgroup? */
- bool mergetogroups; /* Refile articles from to.* into to */
- bool nfswriter; /* Use NFS writer functionality */
- long overcachesize; /* fd size cache for tradindexed */
- char *ovgrouppat; /* Newsgroups to store overview for */
- char *ovmethod; /* Which overview method to use */
- bool storeonxref; /* SMstore use Xref to detemine class? */
- bool useoverchan; /* overchan write the overview, not innd? */
- bool wireformat; /* Store tradspool artilces in wire format? */
- bool xrefslave; /* Act as a slave of another server? */
-
- /* Reading */
- bool allownewnews; /* Allow use of the NEWNEWS command */
- bool articlemmap; /* Use mmap to read articles? */
- long clienttimeout; /* How long nnrpd can be inactive */
- long initialtimeout; /* How long nnrpd waits for first command */
- long msgidcachesize; /* Number of entries in the message ID cache */
- bool nfsreader; /* Use NFS reader functionality */
- long nfsreaderdelay; /* Delay applied to article arrival */
- bool nnrpdcheckart; /* Check article existence before returning? */
- char *nnrpdflags; /* Arguments to pass when spawning nnrpd */
- long nnrpdloadlimit; /* Maximum getloadvg() we allow */
- bool noreader; /* Refuse to fork nnrpd for readers? */
- bool readerswhenstopped; /* Allow nnrpd when server is paused */
- bool readertrack; /* Use the reader tracking system? */
- bool tradindexedmmap; /* Whether to mmap for tradindexed */
-
- /* Reading -- Keyword Support */
- bool keywords; /* Generate keywords in overview? */
- long keyartlimit; /* Max article size for keyword generation */
- long keylimit; /* Max allocated space for keywords */
- long keymaxwords; /* Max count of interesting works */
-
- /* Posting */
- bool addnntppostingdate; /* Add NNTP-Posting-Date: to posts */
- bool addnntppostinghost; /* Add NNTP-Posting-Host: to posts */
- bool checkincludedtext; /* Reject if too much included text */
- char *complaints; /* Address for X-Complaints-To: */
- char *fromhost; /* Host for the From: line */
- long localmaxartsize; /* Max article size of local postings */
- char *moderatormailer; /* Default host to mail moderated articles */
- bool nnrpdauthsender; /* Add authenticated Sender: header? */
- char *nnrpdposthost; /* Host postings should be forwarded to */
- long nnrpdpostport; /* Port postings should be forwarded to */
- char *organization; /* Data for the Organization: header */
- bool spoolfirst; /* Spool all posted articles? */
- bool strippostcc; /* Strip To:, Cc: and Bcc: from posts */
-
- /* Posting -- Exponential Backoff */
- bool backoffauth; /* Backoff by user, not IP address */
- char *backoffdb; /* Directory for backoff databases */
- long backoffk; /* Multiple for the sleep time */
- long backoffpostfast; /* Upper time limit for fast posting */
- long backoffpostslow; /* Lower time limit for slow posting */
- long backofftrigger; /* Number of postings before triggered */
-
- /* Monitoring */
- bool doinnwatch; /* Start innwatch from rc.news? */
- long innwatchbatchspace; /* Minimum free space in pathoutgoing */
- long innwatchlibspace; /* Minimum free space in pathdb */
- long innwatchloload; /* Load times 100 at which to restart */
- long innwatchhiload; /* Load times 100 at which to throttle */
- long innwatchpauseload; /* Load times 100 at which to pause */
- long innwatchsleeptime; /* Seconds to wait between checks */
- long innwatchspoolnodes; /* Minimum free inodes in patharticles */
- long innwatchspoolspace; /* Minimum free space in patharticles */
-
- /* Logging */
- bool docnfsstat; /* Run cnfsstat in the background? */
- bool logartsize; /* Log article sizes? */
- bool logcancelcomm; /* Log ctlinnd cancel commands to syslog? */
- long logcycles; /* How many old logs scanlogs should keep */
- bool logipaddr; /* Log by host IP address? */
- bool logsitename; /* Log outgoing site names? */
- bool nnrpdoverstats; /* Log overview statistics? */
- long nntpactsync; /* Checkpoint log after this many articles */
- bool nntplinklog; /* Put storage token into the log? */
- long status; /* Status file update interval */
- long timer; /* Performance monitoring interval */
- char *stathist; /* Filename for history profiler outputs */
-
- /* System Tuning */
- long badiocount; /* Failure count before dropping channel */
- long blockbackoff; /* Multiplier for sleep in EAGAIN writes */
- long chaninacttime; /* Wait before noticing inactive channels */
- long chanretrytime; /* How long before channel restarts */
- long icdsynccount; /* Articles between active & history updates */
- long keepmmappedthreshold; /* Threshold for keeping mmap in buffindexed */
- long maxforks; /* Give up after this many fork failure */
- long nicekids; /* Child processes get niced to this */
- long nicenewnews; /* If NEWNEWS command is used, nice to this */
- long nicennrpd; /* nnrpd is niced to this */
- long pauseretrytime; /* Seconds before seeing if pause is ended */
- long peertimeout; /* How long peers can be inactive */
- long rlimitnofile; /* File descriptor limit to set */
- long maxcmdreadsize; /* max NNTP command read size used by innd */
- long datamovethreshold; /* threshold no to extend buffer for ever */
-
- /* Paths */
- char *patharchive; /* Archived news. */
- char *patharticles; /* Articles. */
- char *pathbin; /* News binaries. */
- char *pathcontrol; /* Path to control message handlers */
- char *pathdb; /* News database files */
- char *pathetc; /* News configuration files */
- char *pathfilter; /* Filtering code */
- char *pathhttp; /* HTML files */
- char *pathincoming; /* Incoming spooled news */
- char *pathlog; /* Log files */
- char *pathnews; /* Home directory for news user */
- char *pathoutgoing; /* Outgoing news batch files */
- char *pathoverview; /* Overview infomation */
- char *pathrun; /* Runtime state and sockets */
- char *pathspool; /* Root of news spool hierarchy */
- char *pathtmp; /* Temporary files for the news system */
-};
-
-/* The global innconf variable used in programs. */
-extern struct innconf *innconf;
-
-/* Used to request various types of quoting when printing out values. */
-enum innconf_quoting {
- INNCONF_QUOTE_NONE,
- INNCONF_QUOTE_SHELL,
- INNCONF_QUOTE_PERL,
- INNCONF_QUOTE_TCL
-};
-
-BEGIN_DECLS
-
-/* Parse the given file into innconf, using the default path if NULL. */
-bool innconf_read(const char *path);
-
-/* Free an innconf struct and all allocated memory for it. */
-void innconf_free(struct innconf *);
-
-/* Print a single value with appropriate quoting, return whether found. */
-bool innconf_print_value(FILE *, const char *key, enum innconf_quoting);
-
-/* Dump the entire configuration with appropriate quoting. */
-void innconf_dump(FILE *, enum innconf_quoting);
-
-/* Compare two instances of an innconf struct, for testing. */
-bool innconf_compare(struct innconf *, struct innconf *);
-
-/* Check the validity of an inn.conf file. Does innconf_read plus checking
- for any unknown parameters that are set. */
-bool innconf_check(const char *path);
-
-END_DECLS
-
-#endif /* INN_INNCONF_H */
+++ /dev/null
-/* $Id: list.h 6168 2003-01-21 06:27:32Z alexk $
-**
-*/
-
-#ifndef INN_LIST_H
-#define INN_LIST_H 1
-
-#include <inn/defines.h>
-
-struct node {
- struct node *succ;
- struct node *pred;
-};
-
-struct list {
- struct node *head;
- struct node *tail;
- struct node *tailpred;
-};
-
-BEGIN_DECLS
-
-/* initialise a new list */
-void list_new(struct list *list);
-
-/* add a node to the head of the list */
-struct node *list_addhead(struct list *list, struct node *node);
-
-/* add a node to the tail of the list */
-struct node *list_addtail(struct list *list, struct node *node);
-
-/* return a pointer to the first node on the list */
-struct node *list_head(struct list *list);
-
-/* return a pointer to the last node on the list */
-struct node *list_tail(struct list *list);
-
-struct node *list_succ(struct node *node);
-struct node *list_pred(struct node *node);
-
-struct node *list_remhead(struct list *list);
-struct node *list_remove(struct node *node);
-struct node *list_remtail(struct list *list);
-struct node *list_insert(struct list *list, struct node *node,
- struct node *pred);
-
-bool list_isempty(struct list *list);
-
-END_DECLS
-
-#endif /* INN_LIST_H */
+++ /dev/null
-/* $Id: md5.h 4567 2001-02-24 08:10:16Z rra $
-**
-** RSA Data Security, Inc. MD5 Message-Digest Algorithm
-**
-** LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-** INCLUDING ALL IMPLIED WARRANTIES OF MER- CHANTABILITY AND FITNESS. IN
-** NO EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
-** USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-** OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-** PERFORMANCE OF THIS SOFTWARE.
-**
-** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.
-**
-** License to copy and use this software is granted provided that it is
-** identified as the "RSA Data Security, Inc. MD5 Message-Digest
-** Algorithm" in all material mentioning or referencing this software or
-** this function.
-**
-** License is also granted to make and use derivative works provided that
-** such works are identified as "derived from the RSA Data Security,
-** Inc. MD5 Message-Digest Algorithm" in all material mentioning or
-** referencing the derived work.
-**
-** RSA Data Security, Inc. makes no representations concerning either the
-** merchantability of this software or the suitability of this software for
-** any particular purpose. It is provided "as is" without express or
-** implied warranty of any kind.
-**
-** These notices must be retained in any copies of any part of this
-** documentation and/or software.
-*/
-
-#ifndef INN_MD5_H
-#define INN_MD5_H 1
-
-#include <inn/defines.h>
-
-/* Make sure we have uint32_t. */
-#include <sys/types.h>
-#if INN_HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-
-/* SCO OpenServer gets int32_t from here. */
-#if INN_HAVE_SYS_BITYPES_H
-# include <sys/bitypes.h>
-#endif
-
-/* Bytes to process at once, defined by the algorithm. */
-#define MD5_CHUNKSIZE (1 << 6)
-#define MD5_CHUNKWORDS (MD5_CHUNKSIZE / sizeof(uint32_t))
-
-/* Length of the digest, defined by the algorithm. */
-#define MD5_DIGESTSIZE 16
-#define MD5_DIGESTWORDS (MD5_DIGESTSIZE / sizeof(uint32_t))
-
-BEGIN_DECLS
-
-/* Data structure for MD5 message-digest computation. */
-struct md5_context {
- uint32_t count[2]; /* A 64-bit byte count. */
- uint32_t buf[MD5_DIGESTWORDS]; /* Scratch buffer. */
- union {
- unsigned char byte[MD5_CHUNKSIZE]; /* Byte chunk buffer. */
- uint32_t word[MD5_CHUNKWORDS]; /* Word chunk buffer. */
- } in;
- unsigned int datalen; /* Length of data in in. */
- unsigned char digest[MD5_DIGESTSIZE]; /* Final digest. */
-};
-
-extern void md5_hash(const unsigned char *, size_t, unsigned char *);
-extern void md5_init(struct md5_context *);
-extern void md5_update(struct md5_context *, const unsigned char *, size_t);
-extern void md5_final(struct md5_context *);
-
-END_DECLS
-
-#endif /* !INN_MD5_H */
+++ /dev/null
-/* $Id: messages.h 5496 2002-06-07 13:59:06Z alexk $
-**
-** Logging, debugging, and error reporting functions.
-**
-** This collection of functions facilitate logging, debugging, and error
-** reporting in a flexible manner that can be used by libraries as well as by
-** programs. The functions are based around the idea of handlers, which take
-** a message and do something appropriate with it. The program can set the
-** appropriate handlers for all the message reporting functions, and then
-** library code can use them with impunity and know the right thing will
-** happen with the messages.
-*/
-
-#ifndef INN_MESSAGES_H
-#define INN_MESSAGES_H 1
-
-#include <inn/defines.h>
-#include <stdarg.h>
-
-BEGIN_DECLS
-
-/* These are the currently-supported types of traces. */
-enum message_trace {
- TRACE_NETWORK, /* Network traffic. */
- TRACE_PROGRAM, /* Stages of program execution. */
- TRACE_ALL /* All traces; this must be last. */
-};
-
-/* The reporting functions. The ones prefaced by "sys" add a colon, a space,
- and the results of strerror(errno) to the output and are intended for
- reporting failures of system calls. */
-extern void trace(enum message_trace, const char *, ...)
- __attribute__((__format__(printf, 2, 3)));
-extern void notice(const char *, ...)
- __attribute__((__format__(printf, 1, 2)));
-extern void sysnotice(const char *, ...)
- __attribute__((__format__(printf, 1, 2)));
-extern void warn(const char *, ...)
- __attribute__((__format__(printf, 1, 2)));
-extern void syswarn(const char *, ...)
- __attribute__((__format__(printf, 1, 2)));
-extern void die(const char *, ...)
- __attribute__((__noreturn__, __format__(printf, 1, 2)));
-extern void sysdie(const char *, ...)
- __attribute__((__noreturn__, __format__(printf, 1, 2)));
-
-/* Debug is handled specially, since we want to make the code disappear
- completely unless we're built with -DDEBUG. We can only do that with
- support for variadic macros, though; otherwise, the function just won't do
- anything. */
-#if !defined(DEBUG) && (INN_HAVE_C99_VAMACROS || INN_HAVE_GNU_VAMACROS)
-# if INN_HAVE_C99_VAMACROS
-# define debug(format, ...) /* empty */
-# elif INN_HAVE_GNU_VAMACROS
-# define debug(format, args...) /* empty */
-# endif
-#else
-extern void debug(const char *, ...)
- __attribute__((__format__(printf, 1, 2)));
-#endif
-
-/* Set the handlers for various message functions. All of these functions
- take a count of the number of handlers and then function pointers for each
- of those handlers. These functions are not thread-safe; they set global
- variables. */
-extern void message_handlers_debug(int count, ...);
-extern void message_handlers_trace(int count, ...);
-extern void message_handlers_notice(int count, ...);
-extern void message_handlers_warn(int count, ...);
-extern void message_handlers_die(int count, ...);
-
-/* Enable or disable tracing for particular classes of messages. */
-extern void message_trace_enable(enum message_trace, bool);
-
-/* Some useful handlers, intended to be passed to message_handlers_*. All
- handlers take the length of the formatted message, the format, a variadic
- argument list, and the errno setting if any. */
-extern void message_log_stdout(int, const char *, va_list, int);
-extern void message_log_stderr(int, const char *, va_list, int);
-extern void message_log_syslog_debug(int, const char *, va_list, int);
-extern void message_log_syslog_info(int, const char *, va_list, int);
-extern void message_log_syslog_notice(int, const char *, va_list, int);
-extern void message_log_syslog_warning(int, const char *, va_list, int);
-extern void message_log_syslog_err(int, const char *, va_list, int);
-extern void message_log_syslog_crit(int, const char *, va_list, int);
-
-/* The type of a message handler. */
-typedef void (*message_handler_func)(int, const char *, va_list, int);
-
-/* If non-NULL, called before exit and its return value passed to exit. */
-extern int (*message_fatal_cleanup)(void);
-
-/* If non-NULL, prepended (followed by ": ") to all messages printed by either
- message_log_stdout or message_log_stderr. */
-extern const char *message_program_name;
-
-END_DECLS
-
-#endif /* INN_MESSAGE_H */
+++ /dev/null
-/* $Id: mmap.h 7598 2007-02-09 02:40:51Z eagle $
-**
-** MMap manipulation routines
-**
-** Written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** These routines work with mmap()ed memory
-*/
-
-#ifndef INN_MMAP_H
-#define INN_MMAP_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/* Figure out what page an address is in and flush those pages. This is the
- internal function, which we wrap with a define below. */
-void inn__mapcntl(void *, size_t, int);
-
-/* Some platforms only support two arguments to msync. On those platforms,
- make the third argument to mapcntl always be zero, getting rid of whatever
- the caller tried to pass. This avoids undefined symbols for MS_ASYNC and
- friends on platforms with two-argument msync functions. */
-#ifdef INN_HAVE_MSYNC_3_ARG
-# define inn_mapcntl inn__mapcntl
-#else
-# define inn_mapcntl(p, l, f) inn__mapcntl((p), (l), 0)
-#endif
-
-END_DECLS
-
-#endif /* INN_MMAP_H */
+++ /dev/null
-/* $Id: qio.h 3653 2000-07-29 02:57:50Z rra $
-**
-** Quick I/O package.
-**
-** The interface to the Quick I/O package, optimized for reading through
-** files line by line. This package uses internal buffering like stdio,
-** but is even more aggressive about its buffering.
-*/
-
-#ifndef INN_QIO_H
-#define INN_QIO_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/*
-** State for a quick open file, equivalent to FILE for stdio. All callers
-** should treat this structure as opaque and instead use the functions and
-** macros defined below.
-*/
-enum QIOflag { QIO_ok, QIO_error, QIO_long };
-
-typedef struct {
- int _fd;
- size_t _length; /* Length of the current string. */
- size_t _size; /* Size of the internal buffer. */
- char * _buffer;
- char * _start; /* Start of the unread data. */
- char * _end; /* End of the available data. */
- off_t _count; /* Number of bytes read so far. */
- enum QIOflag _flag;
-} QIOSTATE;
-
-#define QIOerror(qp) ((qp)->_flag != QIO_ok)
-#define QIOtoolong(qp) ((qp)->_flag == QIO_long)
-#define QIOfileno(qp) ((qp)->_fd)
-#define QIOlength(qp) ((qp)->_length)
-#define QIOtell(qp) ((qp)->_count - ((qp)->_end - (qp)->_start))
-
-extern QIOSTATE * QIOopen(const char *name);
-extern QIOSTATE * QIOfdopen(int fd);
-extern char * QIOread(QIOSTATE *qp);
-extern void QIOclose(QIOSTATE *qp);
-extern int QIOrewind(QIOSTATE *qp);
-
-END_DECLS
-
-#endif /* !INN_QIO_H */
+++ /dev/null
-/* $Id: sequence.h 4871 2001-07-09 08:09:58Z alexk $
-**
-** Sequence space arithmetic routines.
-**
-** This is a set of routines for implementing so called sequence
-** space arithmetic (typically used for DNS serial numbers). The
-** implementation here is taken from RFC 1982.
-*/
-
-#ifndef INN_SEQUENCE_H
-#define INN_SEQUENCE_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-int seq_lcompare(unsigned long, unsigned long);
-
-END_DECLS
-
-#endif /* INN_SEQUENCE_H */
+++ /dev/null
-/* $Id: timer.h 6129 2003-01-19 00:39:49Z rra $
-**
-** Timer library interface.
-**
-** An interface to a simple profiling library. An application can declare
-** its intent to use n timers by calling TMRinit(n), and then start and
-** stop numbered timers with TMRstart and TMRstop. TMRsummary logs the
-** results to syslog given labels for each numbered timer.
-*/
-
-#ifndef INN_TIMER_H
-#define INN_TIMER_H
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-enum {
- TMR_HISHAVE, /* Looking up ID in history (yes/no). */
- TMR_HISGREP, /* Looking up ID in history (data). */
- TMR_HISWRITE, /* Writing to history. */
- TMR_HISSYNC, /* Syncing history to disk. */
- TMR_APPLICATION /* Application numbering starts here. */
-};
-
-void TMRinit(unsigned int);
-void TMRstart(unsigned int);
-void TMRstop(unsigned int);
-void TMRsummary(const char *prefix, const char *const *labels);
-unsigned long TMRnow(void);
-void TMRfree(void);
-
-/* Return the current time as a double of seconds and fractional sections. */
-double TMRnow_double(void);
-
-END_DECLS
-
-#endif /* INN_TIMER_H */
+++ /dev/null
-/* $Id: tst.h 6083 2002-12-27 07:24:36Z rra $
-**
-** Ternary search trie implementation.
-**
-** This implementation is based on the implementation by Peter A. Friend
-** (version 1.3), but has been assimilated into INN and modified to use INN
-** formatting conventions.
-**
-** Copyright (c) 2002, Peter A. Friend
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-**
-** Redistributions of source code must retain the above copyright notice,
-** this list of conditions and the following disclaimer.
-**
-** Redistributions in binary form must reproduce the above copyright notice,
-** this list of conditions and the following disclaimer in the documentation
-** and/or other materials provided with the distribution.
-**
-** Neither the name of Peter A. Friend nor the names of its contributors may
-** be used to endorse or promote products derived from this software without
-** specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef INN_TST_H
-#define INN_TST_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/* Constants used for return values and options. */
-enum tst_constants {
- TST_OK,
- TST_NULL_KEY,
- TST_NULL_DATA,
- TST_DUPLICATE_KEY,
- TST_REPLACE
-};
-
-/* Opaque data type returned by and used by ternary search trie functions. */
-struct tst;
-
-/* Allocate a new ternary search trie. width is the number of nodes allocated
- at a time and should be chosen carefully. One node is required for every
- character in the tree. If you choose a value that is too small, your
- application will spend too much time calling malloc and your node space
- will be too spread out. Too large a value is just a waste of space. */
-struct tst *tst_init(int width);
-
-/* Insert a value into the tree. If the key already exists in the tree,
- option determiens the behavior. If set to TST_REPLACE, the data for that
- key is replaced with the new data value and the old value is returned in
- exist_ptr. Otherwise, TST_DUPLICATE_KEY is returned. If key is zero
- length, TST_NULL_KEY is returned. If data is NULL, TST_NULL_DATA is
- returned. On success, TST_OK is returned.
-
- The data argument may not be NULL. For a simple existence tree, use the
- struct tst pointer as the data. */
-int tst_insert(struct tst *, const unsigned char *key, void *data, int option,
- void **exist_ptr);
-
-/* Search for a key and return the associated data, or NULL if not found. */
-void *tst_search(struct tst *, const unsigned char *key);
-
-/* Delete the given key out of the trie, returning the data that it pointed
- to. If the key was not found, returns NULL. */
-void *tst_delete(struct tst *, const unsigned char *key);
-
-/* Free the given ternary search trie and all resources it uses. */
-void tst_cleanup(struct tst *);
-
-#endif /* !INN_TST_H */
+++ /dev/null
-/* $Id: vector.h 5450 2002-04-23 06:06:10Z rra $
-**
-** Vector handling (counted lists of char *'s).
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** A vector is a simple array of char *'s combined with a count. It's a
-** convenient way of managing a list of strings, as well as a reasonable
-** output data structure for functions that split up a string. There are
-** two basic types of vectors, regular vectors (in which case strings are
-** copied when put into a vector and freed when the vector is freed) and
-** cvectors or const vectors (where each pointer is a const char * to some
-** external string that isn't freed when the vector is freed).
-**
-** There are two interfaces here, one for vectors and one for cvectors,
-** with the basic operations being the same between the two.
-*/
-
-#ifndef INN_VECTOR_H
-#define INN_VECTOR_H 1
-
-#include <inn/defines.h>
-
-struct vector {
- size_t count;
- size_t allocated;
- char **strings;
-};
-
-struct cvector {
- size_t count;
- size_t allocated;
- const char **strings;
-};
-
-BEGIN_DECLS
-
-/* Create a new, empty vector. */
-struct vector *vector_new(void);
-struct cvector *cvector_new(void);
-
-/* Add a string to a vector. Resizes the vector if necessary. */
-void vector_add(struct vector *, const char *string);
-void cvector_add(struct cvector *, const char *string);
-
-/* Resize the array of strings to hold size entries. Saves reallocation work
- in vector_add if it's known in advance how many entries there will be. */
-void vector_resize(struct vector *, size_t size);
-void cvector_resize(struct cvector *, size_t size);
-
-/* Reset the number of elements to zero, freeing all of the strings for a
- regular vector, but not freeing the strings array (to cut down on memory
- allocations if the vector will be reused). */
-void vector_clear(struct vector *);
-void cvector_clear(struct cvector *);
-
-/* Free the vector and all resources allocated for it. */
-void vector_free(struct vector *);
-void cvector_free(struct cvector *);
-
-/* Split functions build a vector from a string. vector_split splits on a
- specified character, while vector_split_space splits on any sequence of
- spaces or tabs (not any sequence of whitespace, as just spaces or tabs is
- more useful for INN). The cvector versions destructively modify the
- provided string in-place to insert nul characters between the strings. If
- the vector argument is NULL, a new vector is allocated; otherwise, the
- provided one is reused.
-
- Empty strings will yield zero-length vectors. Adjacent delimiters are
- treated as a single delimiter by *_split_space, but *not* by *_split, so
- callers of *_split should be prepared for zero-length strings in the
- vector. */
-struct vector *vector_split(const char *string, char sep, struct vector *);
-struct vector *vector_split_space(const char *string, struct vector *);
-struct cvector *cvector_split(char *string, char sep, struct cvector *);
-struct cvector *cvector_split_space(char *string, struct cvector *);
-
-/* Build a string from a vector by joining its components together with the
- specified string as separator. Returns a newly allocated string; caller is
- responsible for freeing. */
-char *vector_join(const struct vector *, const char *seperator);
-char *cvector_join(const struct cvector *, const char *separator);
-
-END_DECLS
-
-#endif /* INN_VECTOR_H */
+++ /dev/null
-/* $Id: wire.h 6028 2002-12-24 05:10:39Z rra $
-**
-** Wire format article utilities.
-**
-** Originally written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** These routines manipulate wire format articles; in particular, they should
-** be safe in the presence of embedded NULs and UTF-8 characters.
-*/
-
-#ifndef INN_WIRE_H
-#define INN_WIRE_H 1
-
-#include <inn/defines.h>
-
-BEGIN_DECLS
-
-/* Given a pointer to the start of an article, locate the first octet
- of the body (which may be the octet beyond the end of the buffer if
- your article is bodyless). */
-char *wire_findbody(const char *, size_t);
-
-/* Given a pointer into an article and a pointer to the end of the article,
- find the start of the next line or return NULL if there are no more lines
- remaining in the article. */
-char *wire_nextline(const char *, const char *end);
-
-/* Given a pointer to the start of an article and the name of a header, find
- the beginning of the value of the given header (the returned pointer will
- be after the name of the header and any initial whitespace). Headers whose
- only content is whitespace are ignored. If the header isn't found, returns
- NULL.
-
- WARNING: This function does not comply with RFC 2822's idea of header
- content, particularly in its skipping of initial whitespace. */
-char *wire_findheader(const char *article, size_t, const char *header);
-
-/* Given a pointer inside a header's value and a pointer to the end of the
- article, returns a pointer to the end of the header value (the \n at the
- end of the terminating \r\n with folding taken into account), or NULL if no
- such terminator was found before the end of the article. */
-char *wire_endheader(const char *header, const char *end);
-
-END_DECLS
-
-#endif /* INN_WIRE_H */
+++ /dev/null
-/* $Revision: 6786 $
-**
-** Here be values used for communicating with the server once it is
-** running.
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/* The header for the ICC protocol is a one-byte protocol version followed
- by a 2 byte messages length*/
-#define HEADER_SIZE (sizeof (ICC_PROTOCOLTYPE) + sizeof (ICC_MSGLENTYPE))
-
-typedef unsigned short ICC_MSGLENTYPE; /* Length code to prefix commands to
- ** the server. */
-typedef char ICC_PROTOCOLTYPE ;
-
-/* Values for the protocol version field of the message. 8 bits wide. */
-#define ICC_PROTOCOL_1 'a'
-
-
-
-#define SC_SEP '\001'
-#define SC_MAXFIELDS 6
-
-#define SC_ADDHIST 'a'
-#define SC_ALLOW 'D'
-#define SC_BEGIN 'b'
-#define SC_CANCEL 'c'
-#define SC_CHANGEGROUP 'u'
-#define SC_CHECKFILE 'd'
-#define SC_DROP 'e'
-#define SC_FEEDINFO 'F'
-#define SC_FILTER 'T'
-#define SC_FLUSH 'f'
-#define SC_FLUSHLOGS 'g'
-#define SC_GO 'h'
-#define SC_HANGUP 'i'
-#define SC_LOGMODE 'E'
-#define SC_LOWMARK 'L'
-#define SC_MODE 's'
-#define SC_NAME 'j'
-#define SC_NEWGROUP 'k'
-#define SC_PARAM 'l'
-#define SC_PAUSE 'm'
-#define SC_PERL 'P'
-#define SC_PYTHON 'Y'
-#define SC_READERS 'v'
-#define SC_REJECT 'C'
-#define SC_RELOAD 'o'
-#define SC_RENUMBER 'n'
-#define SC_RESERVE 'z'
-#define SC_RMGROUP 'p'
-#define SC_SEND 'A'
-#define SC_SHUTDOWN 'q'
-#define SC_STATHIST 'H'
-#define SC_STATUS 'S'
-#define SC_SIGNAL 'B'
-#define SC_THROTTLE 'r'
-#define SC_TIMER 'Z'
-#define SC_TRACE 'w'
-#define SC_XABORT 'x'
-#define SC_XEXEC 'y'
-
- /* Yes, we don't want anyone to use this. */
-#define SC_FIRSTFREE G
-
-#define MAX_REASON_LEN 80
-
-
-extern void ICCsettimeout(int i);
-extern int ICCopen(void);
-extern int ICCclose(void);
-extern int ICCcommand(char cmd, const char *argv[], char **replyp);
-extern int ICCcancel(const char *msgid);
-extern int ICCgo(const char *why);
-extern int ICCpause(const char *why);
-extern int ICCreserve(const char *why);
-
-extern const char *ICCfailure;
-
-/* Use a read or recv call to read a descriptor. */
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-# define RECVorREAD(fd, p, s) recv((fd), (p), (s), 0)
-#else
-# define RECVorREAD(fd, p, s) read((fd), (p), (s))
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+++ /dev/null
-/* $Id: innperl.h 5302 2002-03-12 20:10:46Z rra $
-**
-** Declarations for embedded Perl.
-*/
-
-#ifndef INNPERL_H
-#define INNPERL_H 1
-
-/* Skip this entire file if DO_PERL (./configure --with-perl) isn't set. */
-#if DO_PERL
-
-#include "config.h"
-
-BEGIN_DECLS
-
-extern bool PerlFilterActive;
-
-extern bool PerlFilter(bool value);
-extern void PerlClose(void);
-extern void PERLsetup(char *startupfile, char *filterfile,
- const char *function);
-extern int PERLreadfilter(char *filterfile, const char *function);
-
-END_DECLS
-
-#endif /* DO_PERL */
-#endif /* !INNPERL_H */
+++ /dev/null
-/* $Id: libinn.h 6135 2003-01-19 01:15:40Z rra $
-**
-** Here be declarations of functions in the InterNetNews library.
-*/
-
-#ifndef LIBINN_H
-#define LIBINN_H 1
-
-#include "inn/defines.h"
-
-/* Eventually we don't want to include this, since this will be an installed
- header and we don't want to install config.h. */
-#include "config.h"
-
-#include <stdio.h> /* FILE */
-#include <sys/types.h> /* size_t and ssize_t */
-
-/* Forward declarations to avoid unnecessary includes. */
-struct stat;
-struct iovec;
-struct sockaddr;
-struct sockaddr_in;
-struct in_addr;
-
-BEGIN_DECLS
-
-/*
-** MEMORY MANAGEMENT
-*/
-
-/* The functions are actually macros so that we can pick up the file and line
- number information for debugging error messages without the user having to
- pass those in every time. */
-#define xcalloc(n, size) x_calloc((n), (size), __FILE__, __LINE__)
-#define xmalloc(size) x_malloc((size), __FILE__, __LINE__)
-#define xrealloc(p, size) x_realloc((p), (size), __FILE__, __LINE__)
-#define xstrdup(p) x_strdup((p), __FILE__, __LINE__)
-#define xstrndup(p, size) x_strndup((p), (size), __FILE__, __LINE__)
-
-/* Last two arguments are always file and line number. These are internal
- implementations that should not be called directly. ISO C99 says that
- identifiers beginning with _ and a lowercase letter are reserved for
- identifiers of file scope, so while the position of libraries in the
- standard isn't clear, it's probably not entirely kosher to use _xmalloc
- here. Use x_malloc instead. */
-extern void *x_calloc(size_t, size_t, const char *, int);
-extern void *x_malloc(size_t, const char *, int);
-extern void *x_realloc(void *, size_t, const char *, int);
-extern char *x_strdup(const char *, const char *, int);
-extern char *x_strndup(const char *, size_t, const char *, int);
-
-/* Failure handler takes the function, the size, the file, and the line. */
-typedef void (*xmalloc_handler_t)(const char *, size_t, const char *, int);
-
-/* The default error handler. */
-void xmalloc_fail(const char *, size_t, const char *, int);
-
-/* Assign to this variable to choose a handler other than the default, which
- just calls sysdie. */
-extern xmalloc_handler_t xmalloc_error_handler;
-
-
-/*
-** TIME AND DATE PARSING, GENERATION, AND HANDLING
-*/
-typedef struct _TIMEINFO {
- time_t time;
- long usec;
- long tzone;
-} TIMEINFO;
-
-extern int GetTimeInfo(TIMEINFO *Now);
-extern bool makedate(time_t, bool local, char *buff, size_t buflen);
-extern time_t parsedate(char *p, TIMEINFO *now);
-extern time_t parsedate_nntp(const char *, const char *, bool local);
-extern time_t parsedate_rfc2822(const char *);
-
-
-/*
-** VERSION INFORMATION
-*/
-extern const int inn_version[3];
-extern const char inn_version_extra[];
-extern const char inn_version_string[];
-
-/* Earlier versions of INN didn't have <inn/version.h> and some source is
- intended to be portable to different INN versions; it can use this macro
- to determine whether <inn/version.h> is available. */
-#define HAVE_INN_VERSION_H 1
-
-
-/*
-** WILDMAT MATCHING
-*/
-enum uwildmat {
- UWILDMAT_FAIL = 0,
- UWILDMAT_MATCH = 1,
- UWILDMAT_POISON
-};
-
-extern bool uwildmat(const char *text, const char *pat);
-extern bool uwildmat_simple(const char *text, const char *pat);
-extern enum uwildmat uwildmat_poison(const char *text, const char *pat);
-
-
-/*
-** FILE LOCKING
-*/
-enum inn_locktype {
- INN_LOCK_READ,
- INN_LOCK_WRITE,
- INN_LOCK_UNLOCK
-};
-
-extern bool inn_lock_file(int fd, enum inn_locktype type, bool block);
-extern bool inn_lock_range(int fd, enum inn_locktype type, bool block,
- off_t offset, off_t size);
-
-
-/*
-** MISCELLANEOUS UTILITY FUNCTIONS
-*/
-extern void close_on_exec(int fd, bool flag);
-extern char * concat(const char *first, ...);
-extern char * concatpath(const char *base, const char *name);
-extern void daemonize(const char *path);
-extern int getfdlimit(void);
-extern int nonblocking(int fd, bool flag);
-extern int setfdlimit(unsigned int limit);
-extern ssize_t xpwrite(int fd, const void *buffer, size_t size, off_t offset);
-extern void (*xsignal(int signum, void (*sigfunc)(int)))(int);
-extern void (*xsignal_norestart(int signum, void (*sigfunc)(int)))(int);
-extern ssize_t xwrite(int fd, const void *buffer, size_t size);
-extern ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt);
-
-
-/* Headers. */
-extern char * GenerateMessageID(char *domain);
-extern void HeaderCleanFrom(char *from);
-extern struct _DDHANDLE * DDstart(FILE *FromServer, FILE *ToServer);
-extern void DDcheck(struct _DDHANDLE *h, char *group);
-extern char * DDend(struct _DDHANDLE *h);
-
-/* NNTP functions. */
-extern int NNTPlocalopen(FILE **FromServerp, FILE **ToServerp,
- char *errbuff);
-extern int NNTPremoteopen(int port, FILE **FromServerp,
- FILE **ToServerp, char *errbuff);
-extern int NNTPconnect(char *host, int port, FILE **FromServerp,
- FILE **ToServerp, char *errbuff);
-extern int NNTPsendarticle(char *, FILE *F, bool Terminate);
-extern int NNTPsendpassword(char *server, FILE *FromServer,
- FILE *ToServer);
-
-/* clientlib compatibility functions. */
-extern char * getserverbyfile(char *file);
-extern int server_init(char *host, int port);
-extern int handle_server_response(int response, char *host);
-extern void put_server(const char *text);
-extern int get_server(char *buff, int buffsize);
-extern void close_server(void);
-
-/* Opening the active file on a client. */
-extern FILE * CAopen(FILE *FromServer, FILE *ToServer);
-extern FILE * CAlistopen(FILE *FromServer, FILE *ToServer,
- const char *request);
-extern FILE * CA_listopen(char *pathname, FILE *FromServer, FILE *ToServer,
- const char *request);
-extern void CAclose(void);
-
-extern char * GetFQDN(char *domain);
-extern char * GetModeratorAddress(FILE *FromServer, FILE *ToServer,
- char *group, char *moderatormailer);
-
-#define TEMPORARYOPEN 0
-#define INND_HISTORY 1
-#define INND_HISLOG 2
-#define DBZ_DIR 3
-#define DBZ_BASE 4
-
-/* Hash functions */
-typedef struct {
- char hash[16];
-} HASH;
-extern HASH Hash(const void *value, const size_t len);
-/* Return the hash of a case mapped message-id */
-extern HASH HashMessageID(const char *MessageID);
-extern bool HashEmpty(const HASH hash);
-extern void HashClear(HASH *hash);
-extern char * HashToText(const HASH hash);
-extern HASH TextToHash(const char *text);
-extern int HashCompare(const HASH *h1, const HASH *h2);
-
-/* Miscellaneous. */
-extern int dbzneedfilecount(void);
-extern bool MakeDirectory(char *Name, bool Recurse);
-extern int xread(int fd, char *p, off_t i);
-extern int GetResourceUsage(double *usertime, double *systime);
-extern void Radix32(unsigned long, char *buff);
-extern char * ReadInDescriptor(int fd, struct stat *Sbp);
-extern char * ReadInFile(const char *name, struct stat *Sbp);
-extern FILE * xfopena(const char *p);
-extern bool fdreserve(int fdnum);
-extern FILE * Fopen(const char *p, const char *type, int fd);
-extern int Fclose(FILE *fp);
-extern char * sprint_sockaddr(const struct sockaddr *sa);
-extern void make_sin(struct sockaddr_in *s, const struct in_addr *src);
-
-END_DECLS
-
-/* <ctype.h>'s isspace includes \n, which is not what we want. */
-#define ISWHITE(c) ((c) == ' ' || (c) == '\t')
-
-#endif /* LIBINN_H */
+++ /dev/null
-/* $Id: nntp.h 6070 2002-12-26 07:10:10Z rra $
-**
-** Here be a set of NNTP response codes as defined in RFC977 and elsewhere.
-** The reponse codes are three digits, RFI, defined like this:
-** R, Response:
-** 1xx Informative message
-** 2xx Command ok
-** 3xx Command ok so far, send the rest of it.
-** 4xx Command was correct, but couldn't be performed for
-** some reason.
-** 5xx Command unimplemented, or incorrect, or a serious
-** program error occurred.
-** F, Function:
-** x0x Connection, setup, and miscellaneous messages
-** x1x Newsgroup selection
-** x2x Article selection
-** x3x Distribution functions
-** x4x Posting
-** x8x Nonstandard extensions (AUTHINFO, XGTITLE)
-** x9x Debugging output
-** I, Information:
-** No defined semantics
-*/
-#define NNTP_HELPOK_VAL 100
-#define NNTP_BAD_COMMAND_VAL 500
-#define NNTP_BAD_COMMAND "500 Syntax error or bad command"
-#define NNTP_TEMPERR_VAL 503
-#define NNTP_ACCESS "502 Permission denied"
-#define NNTP_ACCESS_VAL 502
-#define NNTP_GOODBYE_ACK "205 ."
-#define NNTP_GOODBYE_ACK_VAL 205
-#define NNTP_GOODBYE "400"
-#define NNTP_GOODBYE_VAL 400
-#define NNTP_HAVEIT "435 Duplicate"
-#define NNTP_HAVEIT_BADID "435 Bad Message-ID"
-#define NNTP_HAVEIT_VAL 435
-#define NNTP_LIST_FOLLOWS "215"
-#define NNTP_LIST_FOLLOWS_VAL 215
-#define NNTP_HELP_FOLLOWS "100 Legal commands"
-#define NNTP_HELP_FOLLOWS_VAL 100
-#define NNTP_NOTHING_FOLLOWS_VAL 223
-#define NNTP_ARTICLE_FOLLOWS "220"
-#define NNTP_ARTICLE_FOLLOWS_VAL 220
-#define NNTP_NEWGROUPS_FOLLOWS_VAL 231
-#define NNTP_HEAD_FOLLOWS "221"
-#define NNTP_HEAD_FOLLOWS_VAL 221
-#define NNTP_BODY_FOLLOWS_VAL 222
-#define NNTP_OVERVIEW_FOLLOWS_VAL 224
-#define NNTP_DATE_FOLLOWS_VAL 111
-#define NNTP_POSTOK "200"
-#define NNTP_POSTOK_VAL 200
-#define NNTP_START_POST_VAL 340
-#define NNTP_NOPOSTOK_VAL 201
-#define NNTP_SLAVEOK_VAL 202
-#define NNTP_REJECTIT_VAL 437
-#define NNTP_REJECTIT_EMPTY "437 Empty article"
-#define NNTP_DONTHAVEIT "430"
-#define NNTP_DONTHAVEIT_VAL 430
-#define NNTP_RESENDIT_LATER "436 Retry later"
-#define NNTP_RESENDIT_VAL 436
-#define NNTP_POSTEDOK "240 Article posted"
-#define NNTP_POSTEDOK_VAL 240
-#define NNTP_POSTFAIL_VAL 441
-#define NNTP_GROUPOK_VAL 211
-#define NNTP_SENDIT "335"
-#define NNTP_SENDIT_VAL 335
-#define NNTP_SYNTAX_USE "501 Bad command use"
-#define NNTP_SYNTAX_VAL 501
-#define NNTP_BAD_SUBCMD "501 Bad subcommand"
-#define NNTP_TOOKIT "235"
-#define NNTP_TOOKIT_VAL 235
-#define NNTP_NOTINGROUP "412 Not in a newsgroup"
-#define NNTP_NOTINGROUP_VAL 412
-#define NNTP_NOSUCHGROUP "411 No such group"
-#define NNTP_NOSUCHGROUP_VAL 411
-#define NNTP_NEWNEWSOK "230 New news follows"
-#define NNTP_NOARTINGRP "423 Bad article number"
-#define NNTP_NOARTINGRP_VAL 423
-#define NNTP_NOCURRART "420 No current article"
-#define NNTP_NOCURRART_VAL 420
-#define NNTP_NONEXT_VAL 421
-#define NNTP_NOPREV_VAL 422
-#define NNTP_CANTPOST "440 Posting not allowed"
-#define NNTP_CANTPOST_VAL 440
-
-/* new entries for the "streaming" protocol */
-/* response to "mode stream" else 500 if stream not supported */
-#define NNTP_OK_STREAM_VAL 203 /* Streaming supported */
-
-/* response to "check <id>". Must include ID of article.
-** Example: "431 <1234@host.domain>"
-*/
-#define NNTP_OK_SENDID_VAL 238 /* I want article <id> */
-#define NNTP_RESENDID_VAL 431 /* try <id> again later */
-#define NNTP_ERR_GOTID_VAL 438 /* Got <id>, don't send */
-
-/* responses to "takethis <id>. Must include ID of article */
-#define NNTP_OK_RECID_VAL 239 /* Article <id> received OK */
-#define NNTP_ERR_FAILID_VAL 439 /* Transfer of <id> failed */
-
-/* End of new entries for the "streaming" protocol */
-
-/*
-** The first character of an NNTP reply can be used as a category class.
-*/
-#define NNTP_CLASS_OK '2'
-#define NNTP_CLASS_ERROR '4'
-#define NNTP_CLASS_FATAL '5'
-
-
-/*
-** Authentication commands from the RFC update (not official).
-*/
-#define NNTP_AUTH_NEEDED "480"
-#define NNTP_AUTH_NEEDED_VAL 480
-#define NNTP_AUTH_BAD "481"
-#define NNTP_AUTH_NEXT "381"
-#define NNTP_AUTH_NEXT_VAL 381
-#define NNTP_AUTH_OK "281"
-#define NNTP_AUTH_OK_VAL 281
-#define NNTP_AUTH_REJECT_VAL 482
-
-/*
-** Starttls commands (not official).
-*/
-#define NNTP_STARTTLS_NEXT "382"
-#define NNTP_STARTTLS_NEXT_VAL 382
-#define NNTP_STARTTLS_DONE "483"
-#define NNTP_STARTTLS_DONE_VAL 483
-#define NNTP_STARTTLS_BAD "580"
-#define NNTP_STARTTLS_BAD_VAL 580
-
-/*
-** XGTITLE, from ANU news.
-*/
-#define NNTP_XGTITLE_BAD 481 /* Yes, 481. */
-#define NNTP_XGTITLE_OK 282
-
-/*
-** MODE CANCEL extension.
-*/
-#define NNTP_OK_CANCEL_VAL 284
-#define NNTP_OK_CANCELLED "289"
-#define NNTP_ERR_CANCEL_VAL 484
-
-/*
-** XBATCH feed extension.
-*/
-#define NNTP_OK_XBATCHED_VAL 239 /* Batch transferred successfully */
-#define NNTP_OK_XBATCHED "239"
-#define NNTP_CONT_XBATCH_VAL 339 /* Continue to send batch */
-#define NNTP_CONT_XBATCH "339"
-/* and one more meaning for the 436 code NNTP_RESENDIT_VAL */
-#define NNTP_RESENDIT_XBATCHERR "436 xbatch failed: "
-/* and one more meaning for the 501 code NNTP_SYNTAX_USE */
-#define NNTP_XBATCH_BADSIZE "501 Invalid or missing size for xbatch"
-
-#define NNTP_STRLEN 512
-
-/* Consensus on the USEFOR mailing list in June of 2000 indicates that the
- next revision of the Usenet article standard will limit the length of the
- message ID to 250 characters. This is also the limit recommended by
- son-of-1036.
-
- You can increase this limit if you want, but don't increase it above 497.
- RFC 977 limits each line of the NNTP protocol to 512 octets, including
- the terminating CRLF. For a message ID to be passed using the TAKETHIS
- command, it can therefore be a maximum of 501 octets. The November 1999
- draft of the replacement RFC limits it to 497 octets.
-
- Both Cyclone and DNews are known to reject message IDs longer than 500
- octets as of June of 2000. DNews has been reported to have problems with
- message IDs of 494 octets. */
-
-#define NNTP_MSGID_MAXLEN 250
+++ /dev/null
-#ifndef _OV_H_
-#define _OV_H_
-
-#include "storage.h"
-#include "inn/history.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#define OV_READ 1
-#define OV_WRITE 2
-
-typedef enum {OVSPACE, OVSORT, OVCUTOFFLOW, OVGROUPBASEDEXPIRE, OVSTATICSEARCH, OVSTATALL, OVCACHEKEEP, OVCACHEFREE} OVCTLTYPE;
-#define OV_NOSPACE 100
-typedef enum {OVNEWSGROUP, OVARRIVED, OVNOSORT} OVSORTTYPE;
-typedef enum {OVADDCOMPLETED, OVADDFAILED, OVADDGROUPNOMATCH} OVADDRESULT;
-
-typedef struct _OVGE {
- bool delayrm; /* append tokens to filename if true */
- bool usepost; /* posting date is used to determine expiry
- time if true */
- bool quiet; /* statistics will be suppressed if true */
- bool keep; /* keep article so long as any of crossposted
- newsgroups is not expired if true */
- bool earliest; /* purge article any of crossposted
- newsgroups is expired if true */
- bool ignoreselfexpire; /* purge article even if storing method has
- self expiry */
- char *filename; /* used to append tokens to this file if
- delayrm is true */
- time_t now; /* used as current time */
- float timewarp; /* used to bias expiry time */
-} OVGE;
-
-extern bool OVstatall;
-bool OVopen(int mode);
-bool OVgroupstats(char *group, int *lo, int *hi, int *count, int *flag);
-bool OVgroupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag);
-bool OVgroupdel(char *group);
-OVADDRESULT OVadd(TOKEN token, char *data, int len, time_t arrived, time_t expires);
-bool OVcancel(TOKEN token);
-void *OVopensearch(char *group, int low, int high);
-bool OVsearch(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived);
-void OVclosesearch(void *handle);
-bool OVgetartinfo(char *group, ARTNUM artnum, TOKEN *token);
-bool OVexpiregroup(char *group, int *lo, struct history *h);
-bool OVctl(OVCTLTYPE type, void *val);
-void OVclose(void);
-
-/* Overview data manipulation functions. */
-const struct cvector *overview_fields(void);
-struct vector *overview_extra_fields(void);
-struct buffer *overview_build(ARTNUM number, const char *article,
- size_t length, const struct vector *extra,
- struct buffer *);
-bool overview_check(const char *data, size_t length, ARTNUM article);
-int overview_index(const char *field, const struct vector *extra);
-struct cvector *overview_split(const char *line, size_t length,
- ARTNUM *number, struct cvector *vector);
-char *overview_getheader(const struct cvector *vector, int element,
- const struct vector *extra);
-
-/* offsets into vectors for standard overview headers */
-enum {
- OVERVIEW_SUBJECT,
- OVERVIEW_FROM,
- OVERVIEW_DATE,
- OVERVIEW_MESSAGE_ID,
- OVERVIEW_REFERENCES,
- OVERVIEW_BYTES,
- OVERVIEW_LINES,
- OVERVIEW_MAX
-};
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _OV_H_ */
+++ /dev/null
-/* $Id: paths.h.in 4844 2001-06-30 03:54:06Z rra $ -*- c -*-
-** @configure_input@
-**
-** Here be #define's for filenames, socket names, environment variables,
-** and so on.
-*/
-
-/*
-** PATHS TO FILES AND SOCKETS
-**
-** Default prefixes can be overridden by defining the constant to a full
-** path. That magic is handled by concatpath. At some point all of these
-** defines will change to start with INN_PATH_ instead of _PATH_ because
-** identifiers beginning with an underscore and an uppercase letter are
-** reserved by the C standard. New ones should use INN_PATH_ for this
-** reason, to save eventual work.
-*/
-
-/* Default prefix path is pathbin. */
-#define _PATH_NNRPD "nnrpd"
-#define _PATH_NNTPD "nnrpd"
-#define _PATH_AUTHDIR "auth"
-#define _PATH_AUTHDIR_GENERIC "generic"
-#define _PATH_AUTHDIR_NOPASS "resolv"
-#define _PATH_AUTHDIR_PASSWD "passwd"
-#define _PATH_CTLINND "ctlinnd"
-#define _PATH_RNEWSPROGS "rnews.libexec"
-
-/* Default prefix path is pathfilter. */
-#define _PATH_TCL_STARTUP "startup.tcl"
-#define _PATH_TCL_FILTER "filter.tcl"
-#define _PATH_PERL_STARTUP_INND "startup_innd.pl"
-#define _PATH_PERL_FILTER_INND "filter_innd.pl"
-#define _PATH_PERL_FILTER_NNRPD "filter_nnrpd.pl"
-#define _PATH_PERL_AUTH "nnrpd_auth.pl"
-#define _PATH_PYTHON_STARTUP "filter_innd.py"
-#define _PATH_PYTHON_STARTUP_M "filter_innd"
-#define _PATH_PYTHON_AUTH_M "nnrpd_auth"
-
-/* Default prefix path is pathrun. */
-#define _PATH_NNTPCONNECT "nntpin"
-#define _PATH_NEWSCONTROL "control"
-#define _PATH_TEMPSOCK "ctlinndXXXXXX"
-#define _PATH_SERVERPID "innd.pid"
-
-/* Default prefix path is pathdb. */
-#define _PATH_HISTORY "history"
-#define _PATH_ACTIVE "active"
-#define _PATH_NEWACTIVE "active.tmp"
-#define _PATH_OLDACTIVE "active.old"
-#define _PATH_ACTIVETIMES "active.times"
-#define _PATH_NEWSGROUPS "newsgroups"
-
-/* Default prefix path is pathetc. */
-#define _PATH_NEWSFEEDS "newsfeeds"
-#define _PATH_INNDHOSTS "incoming.conf"
-#define _PATH_DISTPATS "distrib.pats"
-#define _PATH_NNRPDIST "distributions"
-#define _PATH_NNRPSUBS "subscriptions"
-#define _PATH_CONFIG "@ETCDIR@/inn.conf"
-#define _PATH_CLIENTACTIVE "active"
-#define _PATH_MODERATORS "moderators"
-#define _PATH_SERVER "server"
-#define _PATH_NNTPPASS "passwd.nntp"
-#define _PATH_NNRPACCESS "readers.conf"
-#define _PATH_EXPIRECTL "expire.ctl"
-#define _PATH_SCHEMA "overview.fmt"
-#define _PATH_MOTD "motd.news"
-#define _PATH_STORAGECTL "storage.conf"
-#define _PATH_RADIUS_CONFIG "radius.conf"
-#define _PATH_SASL_CONFIG "sasl.conf"
-#define INN_PATH_FILESYSTEMS "filesystems"
-
-/* Default prefix path is pathspool. */
-#define _PATH_SPOOL "articles"
-#define _PATH_BADNEWS "bad"
-
-/* Default prefix path is pathlog. */
-#define _PATH_LOGFILE "news"
-#define _PATH_ERRLOG "errlog"
-
-/* Paths to various programs. */
-#define _PATH_COMPRESS "@COMPRESS@"
-#define _PATH_GZIP "@GZIP@"
-#define _PATH_SH "@_PATH_SH@"
-#define _PATH_SORT "@_PATH_SORT@"
-
-/* Absolute paths. */
-#define _PATH_TMP "@tmpdir@"
-#define _PATH_RNEWS_DUP_LOG "/dev/null"
-
-/* Always relative to pathtmp. */
-#define _PATH_TEMPACTIVE "activeXXXXXX"
-#define _PATH_TEMPMODERATORS "moderatorsXXXXXX"
-
-/*
-** ENVIRONMENT VARIABLES
-*/
-
-/* The host name of the NNTP server, for client posting. */
-#define _ENV_NNTPSERVER "NNTPSERVER"
-
-/* The Organization header line, for client posting. */
-#define _ENV_ORGANIZATION "ORGANIZATION"
-
-/* What to put in the From line, for client posting. */
-#define _ENV_FROMHOST "FROMHOST"
-
-/* UUCP host, for rnews. */
-#define _ENV_UUCPHOST "UU_MACHINE"
-
-/* Interface to bind as, for sockets. */
-#define _ENV_INNBINDADDR "INND_BIND_ADDRESS"
+++ /dev/null
-/* $Id: mmap.h 6012 2002-12-16 11:19:21Z alexk $
-**
-** Portability wrapper around <sys/mman.h>.
-**
-** This header file includes <sys/mman.h> and then sets up various
-** additional defines and macros to permit a uniform API across platforms
-** with varying mmap implementations.
-*/
-
-#ifndef PORTABLE_MMAP_H
-#define PORTABLE_MMAP_H 1
-
-#include "config.h"
-#include <sys/mman.h>
-
-/* Make sure that the symbolic constant for the error return from mmap is
- defined (some platforms don't define it). */
-#ifndef MAP_FAILED
-# define MAP_FAILED ((void *) -1)
-#endif
-
-/* Solaris 8 (at least) prototypes munmap, msync, and madvise as taking char *
- (actually a caddr_t, which is a typedef for a char *) instead of void * as
- is required by the standard. This macro adds a cast that silences compiler
- warnings on Solaris 8 without adversely affecting other platforms. (ISO C
- allows macro definitions of this sort; this macro is not recursive.) */
-#define munmap(p, l) munmap((void *)(p), (l))
-
-/* On some platforms, msync only takes two arguments. (ANSI C allows macro
- definitions of this sort; this macro is not recursive.) */
-#if HAVE_MSYNC_3_ARG
-# define msync(p, l, f) msync((void *)(p), (l), (f))
-#else
-# define msync(p, l, f) msync((void *)(p), (l))
-#endif
-
-/* Turn calls to madvise into a no-op if that call isn't available. */
-#if HAVE_MADVISE
-# define madvise(p, l, o) madvise((void *)(p), (l), (o))
-#else
-# define madvise(p, l, o) /* empty */
-#endif
-
-/* Some platforms don't flush data written to a memory mapped region until
- msync or munmap; on those platforms, we sometimes need to force an msync
- so that other parts of INN will see the changed data. Some other
- platforms don't see writes to a file that's memory-mapped until the
- memory mappings have been flushed.
-
- These platforms can use mmap_flush to schedule a flush to disk and
- mmap_invalidate to force re-reading from disk. Note that all platforms
- should still periodically call msync so that data is written out in case
- of a crash. */
-#if MMAP_NEEDS_MSYNC
-# define mmap_flush(p, l) msync((p), (l), MS_ASYNC)
-#else
-# define mmap_flush(p, l) /* empty */
-#endif
-
-#if MMAP_MISSES_WRITES
-# define mmap_invalidate(p, l) msync((p), (l), MS_INVALIDATE)
-#else
-# define mmap_invalidate(p, l) /* empty */
-#endif
-
-#endif /* PORTABLE_MMAP_H */
+++ /dev/null
-/* $Id: setproctitle.h 5682 2002-08-29 05:17:56Z rra $
-**
-** Set things up for setproctitle portably.
-**
-** If the system supports setproctitle, we need to define away
-** setproctitle_init. Otherwise, we have to prototype setproctitle (which is
-** normally prototyped in stdlib.h).
-*/
-
-#ifndef PORTABLE_SETPROCTITLE_H
-#define PORTABLE_SETPROCTITLE_H 1
-
-#include "config.h"
-
-#if !HAVE_SETPROCTITLE
-void setproctitle(const char *format, ...);
-#endif
-
-#if HAVE_SETPROCTITLE || HAVE_PSTAT
-# define setproctitle_init(argc, argv) /* empty */
-#else
-void setproctitle_init(int argc, char *argv[]);
-#endif
-
-#endif /* !PORTABLE_SETPROCTITLE_H */
+++ /dev/null
-/* $Id: socket.h 5388 2002-04-01 07:03:01Z rra $
-**
-** Portability wrapper around <sys/socket.h> and friends.
-**
-** This header file is the equivalent of:
-**
-** #include <arpa/inet.h>
-** #include <netinet/in.h>
-** #include <sys/socket.h>
-**
-** but also cleans up various messes, mostly related to IPv6 support. It
-** ensures that inet_aton and inet_ntoa are available and properly
-** prototyped.
-*/
-
-#ifndef PORTABLE_SOCKET_H
-#define PORTABLE_SOCKET_H 1
-
-#include "config.h"
-#include <sys/types.h>
-
-/* BSDI needs <netinet/in.h> before <arpa/inet.h>. */
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-
-/* Provide prototypes for inet_aton and inet_ntoa if not prototyped in the
- system header files since they're occasionally available without proper
- prototypes. */
-#if NEED_DECLARATION_INET_ATON
-extern int inet_aton(const char *, struct in_addr *);
-#endif
-#if NEED_DECLARATION_INET_NTOA
-extern const char * inet_ntoa(const struct in_addr);
-#endif
-
-/* Defined by RFC 2553, used to store a generic address. Note that this
- doesn't do the alignment mangling that RFC 2553 does; it's not clear if
- that should be added.... */
-#if !HAVE_SOCKADDR_STORAGE
-# if HAVE_SOCKADDR_LEN
-struct sockaddr_storage {
- unsigned char ss_len;
- unsigned char ss_family;
- unsigned char __padding[128 - 2];
-};
-# else
-struct sockaddr_storage {
- unsigned short ss_family;
- unsigned char __padding[128 - 2];
-};
-# endif
-#endif
-
-/* Use convenient, non-uglified names for the fields since we use them quite a
- bit in code. */
-#if HAVE_2553_STYLE_SS_FAMILY
-# define ss_family __ss_family
-# define ss_len __ss_len
-#endif
-
-/* Define an SA_LEN macro that gives us the length of a sockaddr. */
-#if !HAVE_SA_LEN_MACRO
-# if HAVE_SOCKADDR_LEN
-# define SA_LEN(s) ((s)->sa_len)
-# else
-/* Hack courtesy of the USAGI project. */
-# if HAVE_INET6
-# define SA_LEN(s) \
- ((((struct sockaddr *)(s))->sa_family == AF_INET6) \
- ? sizeof(struct sockaddr_in6) \
- : ((((struct sockaddr *)(s))->sa_family == AF_INET) \
- ? sizeof(struct sockaddr_in) \
- : sizeof(struct sockaddr)))
-# else
-# define SA_LEN(s) \
- ((((struct sockaddr *)(s))->sa_family == AF_INET) \
- ? sizeof(struct sockaddr_in) \
- : sizeof(struct sockaddr))
-# endif
-# endif /* HAVE_SOCKADDR_LEN */
-#endif /* !HAVE_SA_LEN_MACRO */
-
-#endif /* PORTABLE_SOCKET_H */
+++ /dev/null
-/* $Id: time.h 4020 2000-10-03 01:27:13Z rra $
-**
-** Portability wrapper around <time.h> and <sys/time.h>.
-**
-** This header includes <time.h> and <sys/time.h> as applicable, handling
-** systems where one can't include both headers (per the autoconf manual).
-*/
-
-#ifndef PORTABLE_TIME_H
-#define PORTABLE_TIME_H 1
-
-#include "config.h"
-
-#if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#endif /* PORTABLE_TIME_H */
+++ /dev/null
-/* $Id: wait.h 5398 2002-04-09 07:21:58Z rra $
-**
-** Portability wrapper around <sys/wait.h>.
-**
-** This header includes <sys/wait.h> if it's available, and then makes sure
-** that the standard wait macros are defined and defines them if they
-** aren't.
-*/
-
-#ifndef PORTABLE_WAIT_H
-#define PORTABLE_WAIT_H 1
-
-#include "config.h"
-
-#ifdef HAVE_SYS_WAIT_H
-# include <sys/wait.h>
-#endif
-
-/* Per the autoconf documentation, just always check to see if the various
- macros are defined and define them ourselves if they aren't. These
- definitions are based on the approach taken by BSDI. */
-#ifndef WCOREDUMP
-# define WCOREDUMP(status) ((unsigned)(status) & 0x80)
-#endif
-#ifndef WEXITSTATUS
-# define WEXITSTATUS(status) (((unsigned)(status) >> 8) & 0xff)
-#endif
-#ifndef WTERMSIG
-# define WTERMSIG(status) ((unsigned)(status) & 0x7f)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(status) (((unsigned)(status) & 0xff) == 0)
-#endif
-#ifndef WIFSTOPPED
-# define WIFSTOPPED(status) (((unsigned)(status) & 0xff) == 0x7f)
-#endif
-#ifndef WIFSIGNALED
-# define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
-#endif
-
-#endif /* PORTABLE_WAIT_H */
+++ /dev/null
-
-#ifndef PPPORT_H
-#define PPPORT_H 1
-
-/* Perl/Pollution/Portability Version 1.0003 */
-
-/* Copyright (C) 1999, Kenneth Albanowski. This code may be used and
- distributed under the same license as any version of Perl. */
-
-/* For the latest version of this code, please contact the author at
- <kjahds@kjahds.com>, or check with the Perl maintainers. */
-
-/* If you needed to customize this file for your project, please mention
- your changes. */
-
-/*
- Modified for Perl 5.6.0 by Russ Allbery (use PERL_VERSION instead of
- PERL_PATCHLEVEL).
-*/
-
-
-/*
- In order for a Perl extension module to be as portable as possible
- across differing versions of Perl itself, certain steps need to be taken.
- Including this header is the first major one, then using dTHR is all the
- appropriate places and using a PL_ prefix to refer to global Perl
- variables is the second.
-*/
-
-
-/* If you use one of a few functions that were not present in earlier
- versions of Perl, please add a define before the inclusion of ppport.h
- for a static include, or use the GLOBAL request in a single module to
- produce a global definition that can be referenced from the other
- modules.
-
- Function: Static define: Extern define:
- newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
-
-*/
-
-
-/* To verify whether ppport.h is needed for your module, and whether any
- special defines should be used, ppport.h can be run through Perl to check
- your source code. Simply say:
-
- perl -x ppport.h *.c *.h *.xs foo/perl.c [etc]
-
- The result will be a list of patches suggesting changes that should at
- least be acceptable, if not necessarily the most efficient solution, or a
- fix for all possible problems. It won't catch where dTHR is needed, and
- doesn't attempt to account for global macro or function definitions,
- nested includes, typemaps, etc.
-
- In order to test for the need of dTHR, please try your module under a
- recent version of Perl that has threading compiled-in.
-
-*/
-
-
-/*
-#!/usr/bin/perl
-@ARGV = ("*.xs") if !@ARGV;
-%badmacros = %funcs = %macros = ();
-foreach (<DATA>) {
- $funcs{$1} = 1 if /Provide:\s+(\S+)/;
- $macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
- $badmacros{$2}=$1 if /^#\s*define\s+(PL_\S+)\s+(\S+)/;
-}
-foreach $filename (map(glob($_),@ARGV)) {
- unless (open(IN, "<$filename")) {
- warn "Unable to read from $file: $!\n";
- next;
- }
- print "Scanning $filename...\n";
- $c = ""; while (<IN>) { $c .= $_; } close(IN);
- $need_include = 0; %add_func = (); $changes = 0;
- $has_include = ($c =~ /#.*include.*ppport/m);
-
- foreach $func (keys %funcs) {
- if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
- if ($c !~ /\b$func\b/m) {
- print "If $func isn't needed, you don't need to request it.\n" if
- $changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
- } else {
- print "Uses $func\n";
- $need_include = 1;
- }
- } else {
- if ($c =~ /\b$func\b/m) {
- $add_func{$func} =1 ;
- print "Uses $func\n";
- $need_include = 1;
- }
- }
- }
-
- if (not $need_include) {
- foreach $macro (keys %macros) {
- if ($c =~ /\b$macro\b/m) {
- print "Uses $macro\n";
- $need_include = 1;
- }
- }
- }
-
- foreach $badmacro (keys %badmacros) {
- if ($c =~ /\b$badmacro\b/m) {
- $changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
- print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
- $need_include = 1;
- }
- }
-
- if (scalar(keys %add_func) or $need_include != $has_include) {
- if (!$has_include) {
- $inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
- "#include \"ppport.h\"\n";
- $c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
- } elsif (keys %add_func) {
- $inc = join('',map("#define NEED_$_\n", sort keys %add_func));
- $c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
- }
- if (!$need_include) {
- print "Doesn't seem to need ppport.h.\n";
- $c =~ s/^.*#.*include.*ppport.*\n//m;
- }
- $changes++;
- }
-
- if ($changes) {
- open(OUT,">/tmp/ppport.h.$$");
- print OUT $c;
- close(OUT);
- open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
- while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
- close(DIFF);
- unlink("/tmp/ppport.h.$$");
- } else {
- print "Looks OK\n";
- }
-}
-__DATA__
-*/
-
-
-#if !defined(PERL_VERSION) && !defined(PERL_PATCHLEVEL)
-# ifndef __PATCHLEVEL_H_INCLUDED__
-# include <patchlevel.h>
-# endif
-#endif
-#ifndef PERL_VERSION
-# define PERL_REVISION (5)
-# ifdef PERL_PATCHLEVEL
-# define PERL_VERSION PERL_PATCHLEVEL
-# else
-# define PERL_VERSION PATCHLEVEL
-# define PERL_SUBVERSION SUBVERSION
-# endif
-#endif
-
-#ifndef ERRSV
-# define ERRSV perl_get_sv("@",false)
-#endif
-
-#if (PERL_REVISION == 5) && ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 4)))
-# define PL_sv_undef sv_undef
-# define PL_sv_yes sv_yes
-# define PL_sv_no sv_no
-# define PL_na na
-# define PL_stdingv stdingv
-# define PL_hints hints
-# define PL_curcop curcop
-# define PL_curstash curstash
-# define PL_copline copline
-#endif
-
-#if (PERL_REVISION == 5) && (PERL_VERSION < 5)
-# undef dTHR
-# ifdef WIN32
-# define dTHR extern int Perl___notused
-# else
-# define dTHR extern int errno
-# endif
-#endif
-
-#ifndef boolSV
-# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
-#endif
-
-/* Perl tries to export a bunch of its own functions. Mutter. */
-#undef die
-#undef list
-#undef warn
-
-#endif /* !PPPORT_H */
+++ /dev/null
-## $Id: Makefile 7837 2008-05-19 17:14:15Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) $(TCLINC)
-
-ALL = innd inndstart
-
-SOURCES = art.c cc.c chan.c icd.c innd.c inndstart.c keywords.c lc.c \
- nc.c newsfeeds.c ng.c perl.c proc.c python.c rc.c site.c \
- status.c tcl.c util.c wip.c
-
-# The objects that are linked into innd. All SOURCES except inndstart.
-OBJECTS = art.o cc.o chan.o icd.o innd.o keywords.o lc.o nc.o \
- newsfeeds.o ng.o perl.o proc.o python.o rc.o site.o \
- status.o tcl.o util.o wip.o
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPRI) innd $D$(PATHBIN)/innd
- @ME=`$(WHOAMI)` ; \
- if [ x"$$ME" = xroot ] ; then \
- echo $(LI_SPRI) inndstart $D$(PATHBIN)/inndstart ; \
- $(LI_SPRI) inndstart $D$(PATHBIN)/inndstart ; \
- else \
- echo $(LI_XPRI) inndstart $D$(PATHBIN)/inndstart ; \
- $(LI_XPRI) inndstart $D$(PATHBIN)/inndstart ; \
- echo '' ; \
- echo '========================' ; \
- echo 'NOTE NOTE NOTE NOTE NOTE' ; \
- ls -l $D$(PATHBIN)/inndstart ; \
- echo '$D$(PATHBIN)/inndstart needs to be installed setuid root' ; \
- echo '' ; echo ; \
- fi
-
-clean:
- rm -f *.o $(ALL) inndp profiled
- rm -rf .libs
-
-clobber distclean: clean
- rm -f tags
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES) ../lib/*.c innd.h ../include/*.h
-
-
-## Compilation rules.
-
-INNDLIBS = $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) \
- $(PERLLIB) $(TCLLIB) $(PYTHONLIB) $(REGEXLIB) $(LIBS)
-
-perl.o: perl.c ; $(CC) $(CFLAGS) $(PERLINC) -c perl.c
-python.o: python.c ; $(CC) $(CFLAGS) $(PYTHONINC) -c python.c
-
-innd: $(OBJECTS) $(LIBSTORAGE) $(LIBHIST) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(OBJECTS) $(INNDLIBS)
-
-inndstart: inndstart.o $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ inndstart.o $(LIBINN) $(LIBS)
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSTORAGE): ; (cd ../storage ; $(MAKE))
-$(LIBHIST): ; (cd ../history ; $(MAKE))
-
-
-## Profiling. These rules have not been checked for a while and may need
-## some work.
-
-profiled: inndp
- date >$@
-
-inndp: $(SOURCES)
- rm -f $(OBJECTS)
- $(MAKEPROFILING) innd
- mv innd inndp
- rm -f $(OBJECTS)
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS) $(PERLINC) $(PYTHONINC) $(TCLINC)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-art.o: art.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/wire.h \
- ../include/inn/md5.h innd.h ../include/portable/time.h \
- ../include/config.h ../include/portable/socket.h \
- ../include/inn/buffer.h ../include/inn/history.h \
- ../include/inn/messages.h ../include/inn/timer.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h
-cc.o: cc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/qio.h \
- innd.h ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/inndcomm.h \
- ../include/innperl.h
-chan.o: chan.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-icd.o: icd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h ../include/inn/innconf.h \
- ../include/inn/defines.h innd.h ../include/portable/time.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h
-innd.o: innd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/innperl.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/timer.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h
-inndstart.o: inndstart.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/paths.h
-keywords.o: keywords.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h ../include/inn/innconf.h ../include/inn/defines.h \
- innd.h ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/nntp.h ../include/paths.h \
- ../include/storage.h
-lc.o: lc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-nc.o: nc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-newsfeeds.o: newsfeeds.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-ng.o: ng.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h
-perl.o: perl.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h
-proc.o: proc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/wait.h ../include/config.h innd.h \
- ../include/portable/time.h ../include/portable/socket.h \
- ../include/inn/buffer.h ../include/inn/defines.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-python.o: python.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-rc.o: rc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/vector.h innd.h ../include/portable/time.h \
- ../include/inn/buffer.h ../include/inn/history.h \
- ../include/inn/messages.h ../include/inn/timer.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h
-site.o: site.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-status.o: status.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/innperl.h
-tcl.o: tcl.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
-util.o: util.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- innd.h ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/nntp.h ../include/paths.h \
- ../include/storage.h
-wip.o: wip.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h innd.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/buffer.h \
- ../include/inn/history.h ../include/inn/messages.h \
- ../include/inn/timer.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h
+++ /dev/null
-/* $Id: art.c 7748 2008-04-06 13:49:56Z iulius $
-**
-** Article-processing.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <sys/uio.h>
-
-#include "inn/innconf.h"
-#include "inn/wire.h"
-#include "inn/md5.h"
-#include "innd.h"
-#include "ov.h"
-#include "storage.h"
-
-typedef struct iovec IOVEC;
-
-#define ARTIOVCNT 16
-
-extern bool DoCancels;
-
-#if defined(S_IXUSR)
-#define EXECUTE_BITS (S_IXUSR | S_IXGRP | S_IXOTH)
-#else
-#define EXECUTE_BITS 0111
-#endif /* defined(S_IXUSR) */
-
-/* Characters used in log messages indicating the disposition of messages. */
-#define ART_ACCEPT '+'
-#define ART_CANC 'c'
-#define ART_STRSTR '?'
-#define ART_JUNK 'j'
-#define ART_REJECT '-'
-
-/*
-** used to sort Xref, Bytes and Path pointers
-*/
-typedef struct _HEADERP {
- int index;
- char *p;
-} HEADERP;
-
-#define HPCOUNT 4
-
-/*
-** For speed we build a binary tree of the headers, sorted by their
-** name. We also store the header's Name fields in the tree to avoid
-** doing an extra indirection.
-*/
-typedef struct _TREE {
- const char *Name;
- const ARTHEADER *Header;
- struct _TREE *Before;
- struct _TREE *After;
-} TREE;
-
-static TREE *ARTheadertree;
-
-/*
-** For doing the overview database, we keep a list of the headers and
-** a flag saying if they're written in brief or full format.
-*/
-typedef struct _ARTOVERFIELD {
- const ARTHEADER *Header;
- bool NeedHeader;
-} ARTOVERFIELD;
-
-static ARTOVERFIELD *ARTfields;
-
-/*
-** General newsgroup we care about, and what we put in the Path line.
-*/
-static char ARTctl[] = "control";
-static char ARTjnk[] = "junk";
-static char *ARTpathme;
-
-/*
-** Different types of rejected articles.
-*/
-typedef enum {REJECT_DUPLICATE, REJECT_SITE, REJECT_FILTER, REJECT_DISTRIB,
- REJECT_GROUP, REJECT_UNAPP, REJECT_OTHER} Reject_type;
-
-/*
-** Flag array, indexed by character. Character classes for Message-ID's.
-*/
-static char ARTcclass[256];
-#define CC_MSGID_ATOM 01
-#define CC_MSGID_NORM 02
-#define CC_HOSTNAME 04
-#define ARTnormchar(c) ((ARTcclass[(unsigned char)(c)] & CC_MSGID_NORM) != 0)
-#define ARTatomchar(c) ((ARTcclass[(unsigned char)(c)] & CC_MSGID_ATOM) != 0)
-#define ARThostchar(c) ((ARTcclass[(unsigned char)(c)] & CC_HOSTNAME) != 0)
-
-#if defined(DO_PERL) || defined(DO_PYTHON)
-const char *filterPath;
-#endif /* DO_PERL || DO_PYTHON */
-
-
-\f
-/*
-** Trim '\r' from buffer.
-*/
-static void
-buffer_trimcr(struct buffer *bp)
-{
- char *p, *q;
- int trimmed = 0;
-
- for (p = q = bp->data ; p < bp->data + bp->left ; p++) {
- if (*p == '\r' && p+1 < bp->data + bp->left && p[1] == '\n') {
- trimmed++;
- continue;
- }
- *q++ = *p;
- }
- bp->left -= trimmed;
-}
-
-/*
-** Mark that the site gets this article.
-*/
-static void
-SITEmark(SITE *sp, NEWSGROUP *ngp)
-{
- SITE *funnel;
-
- sp->Sendit = true;
- if (sp->ng == NULL)
- sp->ng = ngp;
- if (sp->Funnel != NOSITE) {
- funnel = &Sites[sp->Funnel];
- if (funnel->ng == NULL)
- funnel->ng = ngp;
- }
-}
-
-/*
-**
-*/
-bool
-ARTreadschema(void)
-{
- static char *SCHEMA = NULL;
- FILE *F;
- int i;
- char *p;
- ARTOVERFIELD *fp;
- const ARTHEADER *hp;
- bool ok;
- char buff[SMBUF];
- bool foundxref = false;
- bool foundxreffull = false;
-
- if (ARTfields != NULL) {
- free(ARTfields);
- ARTfields = NULL;
- }
-
- /* Open file, count lines. */
- if (SCHEMA == NULL)
- SCHEMA = concatpath(innconf->pathetc, _PATH_SCHEMA);
- if ((F = Fopen(SCHEMA, "r", TEMPORARYOPEN)) == NULL)
- return false;
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
- fseeko(F, 0, SEEK_SET);
- ARTfields = xmalloc((i + 1) * sizeof(ARTOVERFIELD));
-
- /* Parse each field. */
- for (ok = true, fp = ARTfields ; fgets(buff, sizeof buff, F) != NULL ;) {
- /* Ignore blank and comment lines. */
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '#')) != NULL)
- *p = '\0';
- if (buff[0] == '\0')
- continue;
- if ((p = strchr(buff, ':')) != NULL) {
- *p++ = '\0';
- fp->NeedHeader = (strcmp(p, "full") == 0);
- } else
- fp->NeedHeader = false;
- if (strcasecmp(buff, "Xref") == 0) {
- foundxref = true;
- foundxreffull = fp->NeedHeader;
- }
- for (hp = ARTheaders; hp < ARRAY_END(ARTheaders); hp++) {
- if (strcasecmp(buff, hp->Name) == 0) {
- fp->Header = hp;
- break;
- }
- }
- if (hp == ARRAY_END(ARTheaders)) {
- syslog(L_ERROR, "%s bad_schema unknown header \"%s\"",
- LogName, buff);
- ok = false;
- continue;
- }
- fp++;
- }
- fp->Header = NULL;
-
- Fclose(F);
- if (!foundxref || !foundxreffull) {
- syslog(L_FATAL, "%s 'Xref:full' must be included in %s", LogName, SCHEMA);
- exit(1);
- }
- return ok;
-}
-
-
-/*
-** Build a balanced tree for the headers in subscript range [lo..hi).
-** This only gets called once, and the tree only has about 37 entries,
-** so we don't bother to unroll the recursion.
-*/
-static TREE *
-ARTbuildtree(const ARTHEADER **Table, int lo, int hi)
-{
- int mid;
- TREE *tp;
-
- mid = lo + (hi - lo) / 2;
- tp = xmalloc(sizeof(TREE));
- tp->Header = Table[mid];
- tp->Name = tp->Header->Name;
- if (mid == lo)
- tp->Before = NULL;
- else
- tp->Before = ARTbuildtree(Table, lo, mid);
- if (mid == hi - 1)
- tp->After = NULL;
- else
- tp->After = ARTbuildtree(Table, mid + 1, hi);
- return tp;
-}
-
-
-/*
-** Sorting predicate for qsort call in ARTsetup.
-*/
-static int
-ARTcompare(const void *p1, const void *p2)
-{
- return strcasecmp(((const ARTHEADER **)p1)[0]->Name,
- ((const ARTHEADER **)p2)[0]->Name);
-}
-
-
-/*
-** Setup the article processing.
-*/
-void
-ARTsetup(void)
-{
- const char * p;
- const ARTHEADER ** table;
- unsigned int i;
-
- /* Set up the character class tables. These are written a
- * little strangely to work around a GCC2.0 bug. */
- memset(ARTcclass, 0, sizeof ARTcclass);
- p = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- while ((i = *p++) != 0) {
- ARTcclass[i] = CC_HOSTNAME | CC_MSGID_ATOM | CC_MSGID_NORM;
- }
- p = "!#$%&'*+-/=?^_`{|}~";
- while ((i = *p++) != 0) {
- ARTcclass[i] = CC_MSGID_ATOM | CC_MSGID_NORM;
- }
- p = "\"(),.:;<@[\\]";
- while ((i = *p++) != 0) {
- ARTcclass[i] = CC_MSGID_NORM;
- }
-
- /* The RFC's don't require it, but we add underscore to the list of valid
- * hostname characters. */
- ARTcclass['.'] |= CC_HOSTNAME;
- ARTcclass['-'] |= CC_HOSTNAME;
- ARTcclass['_'] |= CC_HOSTNAME;
-
- /* Build the header tree. */
- table = xmalloc(ARRAY_SIZE(ARTheaders) * sizeof(ARTHEADER *));
- for (i = 0; i < ARRAY_SIZE(ARTheaders); i++)
- table[i] = &ARTheaders[i];
- qsort(table, ARRAY_SIZE(ARTheaders), sizeof *table, ARTcompare);
- ARTheadertree = ARTbuildtree(table, 0, ARRAY_SIZE(ARTheaders));
- free(table);
-
- /* Get our Path name, kill trailing !. */
- ARTpathme = xstrdup(Path.data);
- ARTpathme[Path.used - 1] = '\0';
-
- /* Set up database; ignore errors. */
- ARTreadschema();
-}
-
-
-static void
-ARTfreetree(TREE *tp)
-{
- TREE *next;
-
- for ( ; tp != NULL; tp = next) {
- if (tp->Before)
- ARTfreetree(tp->Before);
- next = tp->After;
- free(tp);
- }
-}
-
-
-void
-ARTclose(void)
-{
- if (ARTfields != NULL) {
- free(ARTfields);
- ARTfields = NULL;
- }
- ARTfreetree(ARTheadertree);
-}
-
-/*
-** Start a log message about an article.
-*/
-static void
-ARTlog(const ARTDATA *data, char code, const char *text)
-{
- const HDRCONTENT *hc = data->HdrContent;
- int i;
- bool Done;
-
- TMRstart(TMR_ARTLOG);
- /* We could be a bit faster by not dividing Now.usec by 1000,
- * but who really wants to log at the Microsec level? */
- Done = code == ART_ACCEPT || code == ART_JUNK;
- if (text)
- i = fprintf(Log, "%.15s.%03d %c %s %s %s%s",
- ctime(&Now.time) + 4, (int)(Now.usec / 1000), code, data->Feedsite,
- HDR_FOUND(HDR__MESSAGE_ID) ? HDR(HDR__MESSAGE_ID) : "(null)",
- text, Done ? "" : "\n");
- else
- i = fprintf(Log, "%.15s.%03d %c %s %s%s",
- ctime(&Now.time) + 4, (int)(Now.usec / 1000), code, data->Feedsite,
- HDR_FOUND(HDR__MESSAGE_ID) ? HDR(HDR__MESSAGE_ID) : "(null)",
- Done ? "" : "\n");
- if (i == EOF || (Done && !BufferedLogs && fflush(Log)) || ferror(Log)) {
- i = errno;
- syslog(L_ERROR, "%s cant write log_start %m", LogName);
- IOError("logging article", i);
- clearerr(Log);
- }
- TMRstop(TMR_ARTLOG);
-}
-
-/*
-** Parse a Path line, splitting it up into NULL-terminated array of strings.
-*/
-static int
-ARTparsepath(const char *p, int size, LISTBUFFER *list)
-{
- int i;
- char *q, **hp;
-
- /* setup buffer */
- SetupListBuffer(size, list);
-
- /* loop over text and copy */
- for (i = 0, q = list->Data, hp = list->List ; *p ; p++, *q++ = '\0') {
- /* skip leading separators. */
- for (; *p && !ARThostchar(*p) && ISWHITE(*p) ; p++)
- continue;
- if (*p == '\0')
- break;
-
- if (list->ListLength <= i) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- hp = &list->List[i];
- }
- /* mark the start of the host, move to the end of it while copying */
- for (*hp++ = q, i++ ; *p && ARThostchar(*p) && !ISWHITE(*p) ;)
- *q++ = *p++;
- if (*p == '\0')
- break;
- }
- *q = '\0';
- if (i == list->ListLength) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- hp = &list->List[i];
- }
- *hp = NULL;
- return i;
-}
-
-/*
-** Sorting pointer where header starts
-*/
-static int
-ARTheaderpcmp(const void *p1, const void *p2)
-{
- return (((const HEADERP *)p1)->p - ((const HEADERP *)p2)->p);
-}
-
-/* Write an article using the storage api. Put it together in memory and
- call out to the api. */
-static TOKEN
-ARTstore(CHANNEL *cp)
-{
- struct buffer *Article = &cp->In;
- ARTDATA *data = &cp->Data;
- HDRCONTENT *hc = data->HdrContent;
- const char *p;
- ARTHANDLE arth;
- int i, j, iovcnt = 0;
- long headersize = 0;
- TOKEN result;
- struct buffer *headers = &data->Headers;
- struct iovec iov[ARTIOVCNT];
- HEADERP hp[HPCOUNT];
-
- /* find Path, Bytes and Xref to be prepended/dropped/replaced */
- arth.len = i = 0;
- /* assumes Path header is required header */
- hp[i].p = HDR(HDR__PATH);
- hp[i++].index = HDR__PATH;
- if (HDR_FOUND(HDR__XREF)) {
- hp[i].p = HDR(HDR__XREF);
- hp[i++].index = HDR__XREF;
- }
- if (HDR_FOUND(HDR__BYTES)) {
- hp[i].p = HDR(HDR__BYTES);
- hp[i++].index = HDR__BYTES;
- }
- /* get the order of header appearance */
- qsort(hp, i, sizeof(HEADERP), ARTheaderpcmp);
- /* p always points where the next data should be written from */
- for (p = Article->data + cp->Start, j = 0 ; j < i ; j++) {
- switch (hp[j].index) {
- case HDR__PATH:
- if (!data->Hassamepath || data->AddAlias || Pathcluster.used) {
- /* write heading data */
- iov[iovcnt].iov_base = (char *) p;
- iov[iovcnt++].iov_len = HDR(HDR__PATH) - p;
- arth.len += HDR(HDR__PATH) - p;
- /* append clusterpath */
- if (Pathcluster.used) {
- iov[iovcnt].iov_base = Pathcluster.data;
- iov[iovcnt++].iov_len = Pathcluster.used;
- arth.len += Pathcluster.used;
- }
- /* now append new one */
- iov[iovcnt].iov_base = Path.data;
- iov[iovcnt++].iov_len = Path.used;
- arth.len += Path.used;
- if (data->AddAlias) {
- iov[iovcnt].iov_base = Pathalias.data;
- iov[iovcnt++].iov_len = Pathalias.used;
- arth.len += Pathalias.used;
- }
- /* next to write */
- p = HDR(HDR__PATH);
- if (data->Hassamecluster)
- p += Pathcluster.used;
- }
- break;
- case HDR__XREF:
- if (!innconf->xrefslave) {
- /* write heading data */
- iov[iovcnt].iov_base = (char *) p;
- iov[iovcnt++].iov_len = HDR(HDR__XREF) - p;
- arth.len += HDR(HDR__XREF) - p;
- /* replace with new one */
- iov[iovcnt].iov_base = data->Xref;
- iov[iovcnt++].iov_len = data->XrefLength - 2;
- arth.len += data->XrefLength - 2;
- /* next to write */
- /* this points where trailing "\r\n" of orginal Xref header exists */
- p = HDR(HDR__XREF) + HDR_LEN(HDR__XREF);
- }
- break;
- case HDR__BYTES:
- /* ditch whole Byte header */
- /* write heading data */
- iov[iovcnt].iov_base = (char *) p;
- iov[iovcnt++].iov_len = data->BytesHeader - p;
- arth.len += data->BytesHeader - p;
- /* next to write */
- /* need to skip trailing "\r\n" of Bytes header */
- p = HDR(HDR__BYTES) + HDR_LEN(HDR__BYTES) + 2;
- break;
- default:
- result.type = TOKEN_EMPTY;
- return result;
- }
- }
- /* in case Xref is not included in orignal article */
- if (!HDR_FOUND(HDR__XREF)) {
- /* write heading data */
- iov[iovcnt].iov_base = (char *) p;
- iov[iovcnt++].iov_len = Article->data + (data->Body - 2) - p;
- arth.len += Article->data + (data->Body - 2) - p;
- /* Xref needs to be inserted */
- iov[iovcnt].iov_base = (char *) "Xref: ";
- iov[iovcnt++].iov_len = sizeof("Xref: ") - 1;
- arth.len += sizeof("Xref: ") - 1;
- iov[iovcnt].iov_base = data->Xref;
- iov[iovcnt++].iov_len = data->XrefLength;
- arth.len += data->XrefLength;
- p = Article->data + (data->Body - 2);
- }
- /* write rest of data */
- iov[iovcnt].iov_base = (char *) p;
- iov[iovcnt++].iov_len = Article->data + cp->Next - p;
- arth.len += Article->data + cp->Next - p;
-
- /* revert trailing '\0\n' to '\r\n' of all system header */
- for (i = 0 ; i < MAX_ARTHEADER ; i++) {
- if (HDR_FOUND(i))
- HDR_PARSE_END(i);
- }
-
- arth.iov = iov;
- arth.iovcnt = iovcnt;
- arth.arrived = (time_t)0;
- arth.token = (TOKEN *)NULL;
- arth.expires = data->Expires;
- if (innconf->storeonxref) {
- arth.groups = data->Replic;
- arth.groupslen = data->ReplicLength;
- } else {
- arth.groups = HDR(HDR__NEWSGROUPS);
- arth.groupslen = HDR_LEN(HDR__NEWSGROUPS);
- }
-
- SMerrno = SMERR_NOERROR;
- result = SMstore(arth);
- if (result.type == TOKEN_EMPTY) {
- if (SMerrno == SMERR_NOMATCH)
- ThrottleNoMatchError();
- else if (SMerrno != SMERR_NOERROR)
- IOError("SMstore", SMerrno);
- return result;
- }
-
- /* calculate stored size */
- for (data->BytesValue = i = 0 ; i < iovcnt ; i++) {
- if (NeedHeaders && (i + 1 == iovcnt)) {
- /* body begins at last iov */
- headersize = data->BytesValue +
- Article->data + data->Body - (char *) iov[i].iov_base;
- }
- data->BytesValue += iov[i].iov_len;
- }
- /* "\r\n" is counted as 1 byte. trailing ".\r\n" and body delimitor are also
- substituted */
- data->BytesValue -= (data->HeaderLines + data->Lines + 4);
- /* Figure out how much space we'll need and get it. */
- snprintf(data->Bytes, sizeof(data->Bytes), "Bytes: %ld\r\n",
- data->BytesValue);
- /* does not include strlen("Bytes: \r\n") */
- data->BytesLength = strlen(data->Bytes) - 9;
-
- if (!NeedHeaders)
- return result;
-
- /* Add the data. */
- buffer_resize(headers, headersize);
- buffer_set(headers, data->Bytes, strlen(data->Bytes));
- for (i = 0 ; i < iovcnt ; i++) {
- if (i + 1 == iovcnt)
- buffer_append(headers, iov[i].iov_base,
- Article->data + data->Body - (char *) iov[i].iov_base);
- else
- buffer_append(headers, iov[i].iov_base, iov[i].iov_len);
- }
- buffer_trimcr(headers);
-
- return result;
-}
-
-/*
-** Parse a header that starts at header. size includes trailing "\r\n"
-*/
-static void
-ARTparseheader(CHANNEL *cp, int size)
-{
- ARTDATA *data = &cp->Data;
- char *header = cp->In.data + data->CurHeader;
- HDRCONTENT *hc = cp->Data.HdrContent;
- TREE *tp;
- const ARTHEADER *hp;
- char c, *p, *colon;
- int i;
-
- /* Find first colon */
- if ((colon = memchr(header, ':', size)) == NULL || !ISWHITE(colon[1])) {
- if ((p = memchr(header, '\r', size)) != NULL)
- *p = '\0';
- snprintf(cp->Error, sizeof(cp->Error),
- "%d No colon-space in \"%s\" header",
- NNTP_REJECTIT_VAL, MaxLength(header, header));
- if (p != NULL)
- *p = '\r';
- return;
- }
-
- /* See if this is a system header. A fairly tightly-coded binary search. */
- c = CTYPE(islower, *header) ? toupper(*header) : *header;
- for (*colon = '\0', tp = ARTheadertree; tp; ) {
- if ((i = c - tp->Name[0]) == 0 && (i = strcasecmp(header, tp->Name)) == 0)
- break;
- if (i < 0)
- tp = tp->Before;
- else
- tp = tp->After;
- }
- *colon = ':';
-
- if (tp == NULL) {
- /* Not a system header, make sure we have <word><colon><space>. */
- for (p = colon; --p > header; ) {
- if (ISWHITE(*p)) {
- c = *p;
- *p = '\0';
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Space before colon in \"%s\" header",
- NNTP_REJECTIT_VAL, MaxLength(header, header));
- *p = c;
- return;
- }
- }
- return;
- }
- hp = tp->Header;
- i = hp - ARTheaders;
- /* remember to ditch if it's Bytes: */
- if (i == HDR__BYTES)
- cp->Data.BytesHeader = header;
- hc = &hc[i];
- if (hc->Length != 0) {
- /* duplicated */
- hc->Length = -1;
- } else {
- for (p = colon + 1 ; (p < header + size - 2) &&
- (ISWHITE(*p) || *p == '\r' || *p == '\n'); p++);
- if (p < header + size - 2) {
- hc->Value = p;
- /* HDR_LEN() does not include trailing "\r\n" */
- hc->Length = header + size - 2 - p;
- } else {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Body of header is all blanks in \"%s\" header",
- NNTP_REJECTIT_VAL, MaxLength(hp->Name, hp->Name));
- }
- }
- return;
-}
-
-/*
-** Check Message-ID format based on RFC 822 grammar, except that (as per
-** RFC 1036) whitespace, non-printing, and '>' characters are excluded.
-** Based on code by Paul Eggert posted to news.software.b on 22-Nov-90
-** in <#*tyo2'~n@twinsun.com>, with additional email discussion.
-** Thanks, Paul.
-*/
-bool
-ARTidok(const char *MessageID)
-{
- int c;
- const char *p;
-
- /* Check the length of the message ID. */
- if (MessageID == NULL || strlen(MessageID) > NNTP_MSGID_MAXLEN)
- return false;
-
- /* Scan local-part: "< atom|quoted [ . atom|quoted]" */
- p = MessageID;
- if (*p++ != '<')
- return false;
- for (; ; p++) {
- if (ARTatomchar(*p))
- while (ARTatomchar(*++p))
- continue;
- else {
- if (*p++ != '"')
- return false;
- for ( ; ; ) {
- switch (c = *p++) {
- case '\\':
- c = *p++;
- /* FALLTHROUGH */
- default:
- if (ARTnormchar(c))
- continue;
- return false;
- case '"':
- break;
- }
- break;
- }
- }
- if (*p != '.')
- break;
- }
-
- /* Scan domain part: "@ atom|domain [ . atom|domain] > \0" */
- if (*p++ != '@')
- return false;
- for ( ; ; p++) {
- if (ARTatomchar(*p))
- while (ARTatomchar(*++p))
- continue;
- else {
- if (*p++ != '[')
- return false;
- for ( ; ; ) {
- switch (c = *p++) {
- case '\\':
- c = *p++;
- /* FALLTHROUGH */
- default:
- if (ARTnormchar(c))
- continue;
- /* FALLTHROUGH */
- case '[':
- return false;
- case ']':
- break;
- }
- break;
- }
- }
- if (*p != '.')
- break;
- }
-
- return *p == '>' && *++p == '\0';
-}
-
-/*
-** Clean up data field where article informations are stored.
-** This must be called before article processing.
-*/
-void
-ARTprepare(CHANNEL *cp)
-{
- ARTDATA *data = &cp->Data;
- HDRCONTENT *hc = data->HdrContent;
- int i;
-
- for (i = 0 ; i < MAX_ARTHEADER ; i++, hc++) {
- hc->Value = NULL;
- hc->Length = 0;
- }
- data->Lines = data->HeaderLines = data->CRwithoutLF = data->LFwithoutCR = 0;
- data->CurHeader = data->LastTerminator = data->LastCR = cp->Start - 1;
- data->LastCRLF = data->Body = cp->Start - 1;
- data->BytesHeader = NULL;
- data->Feedsite = "?";
- *cp->Error = '\0';
-}
-
-/*
-** Clean up an article. This is mainly copying in-place, stripping bad
-** headers. Also fill in the article data block with what we can find.
-** Return NULL if the article is okay, or a string describing the error.
-** Parse headers and end of article
-** This is called by NCproc().
-*/
-void
-ARTparse(CHANNEL *cp)
-{
- struct buffer *bp = &cp->In;
- ARTDATA *data = &cp->Data;
- long i, limit, fudge, size;
- int hopcount;
- char **hops;
- HDRCONTENT *hc = data->HdrContent;
-
- /* Read through the buffer to find header, body and end of article */
- /* this routine is designed not to refer data so long as possible for
- performance reason, so the code may look redundant at a glance */
- limit = bp->used;
- i = cp->Next;
- if (cp->State == CSgetheader) {
- /* header processing */
- for (; i < limit ;) {
- if (data->LastCRLF + 1 == i) {
- /* begining of the line */
- switch (bp->data[i]) {
- case '.':
- data->LastTerminator = i;
- data->NullHeader = false;
- break;
- case '\r':
- data->LastCR = i;
- data->NullHeader = false;
- break;
- case '\n':
- data->LFwithoutCR++;
- data->NullHeader = false;
- break;
- case '\t':
- case ' ':
- /* header is folded. NullHeader is untouched */
- break;
- case '\0':
- snprintf(cp->Error, sizeof(cp->Error), "%d Null Header",
- NNTP_REJECTIT_VAL);
- data->NullHeader = true;
- break;
- default:
- if (data->CurHeader >= cp->Start) {
- /* parse previous header */
- if (!data->NullHeader && (*cp->Error == '\0'))
- /* skip if already got an error */
- ARTparseheader(cp, i - data->CurHeader);
- }
- data->CurHeader = i;
- data->NullHeader = false;
- break;
- }
- i++;
- }
- for (; i < limit ;) {
- /* rest of the line */
- switch (bp->data[i]) {
- case '\0':
- snprintf(cp->Error, sizeof(cp->Error), "%d Null Header",
- NNTP_REJECTIT_VAL);
- data->NullHeader = true;
- break;
- case '\r':
- if (data->LastCR >= cp->Start)
- data->CRwithoutLF++;
- data->LastCR = i;
- break;
- case '\n':
- if (data->LastCR + 1 == i) {
- /* found CRLF */
- data->LastCR = cp->Start - 1;
- if (data->LastTerminator + 2 == i) {
- /* terminated still in header */
- if (cp->Start + 3 == i) {
- snprintf(cp->Error, sizeof(cp->Error), "%d Empty article",
- NNTP_REJECTIT_VAL);
- cp->State = CSnoarticle;
- } else {
- snprintf(cp->Error, sizeof(cp->Error), "%d No body",
- NNTP_REJECTIT_VAL);
- cp->State = CSgotarticle;
- }
- cp->Next = ++i;
- goto sizecheck;
- }
- if (data->LastCRLF + MAXHEADERSIZE < i)
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Too long line in header %ld bytes",
- NNTP_REJECTIT_VAL, i - data->LastCRLF);
- else if (data->LastCRLF + 2 == i) {
- /* header ends */
- /* parse previous header */
- if (data->CurHeader >= cp->Start) {
- if (!data->NullHeader && (*cp->Error == '\0'))
- /* skip if already got an error */
- ARTparseheader(cp, i - 1 - data->CurHeader);
- } else {
- snprintf(cp->Error, sizeof(cp->Error), "%d No header",
- NNTP_REJECTIT_VAL);
- }
- data->LastCRLF = i++;
- data->Body = i;
- cp->State = CSgetbody;
- goto bodyprocessing;
- }
- data->HeaderLines++;
- data->LastCRLF = i++;
- goto endofheaderline;
- } else {
- data->LFwithoutCR++;
- }
- break;
- default:
- break;
- }
- i++;
- }
-endofheaderline:
- ;
- }
- } else {
-bodyprocessing:
- /* body processing, or eating huge article */
- for (; i < limit ;) {
- if (data->LastCRLF + 1 == i) {
- /* begining of the line */
- switch (bp->data[i]) {
- case '.':
- data->LastTerminator = i;
- break;
- case '\r':
- data->LastCR = i;
- break;
- case '\n':
- data->LFwithoutCR++;
- break;
- default:
- break;
- }
- i++;
- }
- for (; i < limit ;) {
- /* rest of the line */
- switch (bp->data[i]) {
- case '\r':
- if (data->LastCR >= cp->Start)
- data->CRwithoutLF++;
- data->LastCR = i;
- break;
- case '\n':
- if (data->LastCR + 1 == i) {
- /* found CRLF */
- data->LastCR = cp->Start - 1;
- if (data->LastTerminator + 2 == i) {
- /* found end of article */
- if (cp->State == CSeatarticle) {
- cp->State = CSgotlargearticle;
- cp->Next = ++i;
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Article of %ld bytes exceeds local limit of %ld bytes",
- NNTP_REJECTIT_VAL, (unsigned long) i - cp->Start,
- innconf->maxartsize);
- } else {
- cp->State = CSgotarticle;
- i++;
- }
- if (*cp->Error != '\0' && HDR_FOUND(HDR__MESSAGE_ID)) {
- HDR_PARSE_START(HDR__MESSAGE_ID);
- if (HDR_FOUND(HDR__PATH)) {
- /* to record path into news log */
- HDR_PARSE_START(HDR__PATH);
- hopcount = ARTparsepath(HDR(HDR__PATH), HDR_LEN(HDR__PATH),
- &data->Path);
- HDR_PARSE_END(HDR__PATH);
- if (hopcount > 0) {
- hops = data->Path.List;
- if (innconf->logipaddr) {
- data->Feedsite = RChostname(cp);
- if (data->Feedsite == NULL)
- data->Feedsite = CHANname(cp);
- if (strcmp("0.0.0.0", data->Feedsite) == 0 ||
- data->Feedsite[0] == '\0')
- data->Feedsite =
- hops && hops[0] ? hops[0] : CHANname(cp);
- } else {
- data->Feedsite =
- hops && hops[0] ? hops[0] : CHANname(cp);
- }
- }
- }
- ARTlog(data, ART_REJECT, cp->Error);
- HDR_PARSE_END(HDR__MESSAGE_ID);
- }
- if (cp->State == CSgotlargearticle)
- return;
- goto sizecheck;
- }
-#if 0 /* this may be examined in the future */
- if (data->LastCRLF + MAXHEADERSIZE < i)
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Too long line in body %d bytes",
- NNTP_REJECTIT_VAL, i);
-#endif
- data->Lines++;
- data->LastCRLF = i++;
- goto endofline;
- } else {
- data->LFwithoutCR++;
- }
- break;
- default:
- break;
- }
- i++;
- }
-endofline:
- ;
- }
- }
-sizecheck:
- size = i - cp->Start;
- fudge = data->HeaderLines + data->Lines + 4;
- if (innconf->maxartsize > 0)
- if (size > fudge && size - fudge > innconf->maxartsize)
- cp->State = CSeatarticle;
- cp->Next = i;
- return;
-}
-
-/*
-** Clean up an article. This is mainly copying in-place, stripping bad
-** headers. Also fill in the article data block with what we can find.
-** Return true if the article has no error, or false which means the error.
-*/
-static bool
-ARTclean(ARTDATA *data, char *buff)
-{
- HDRCONTENT *hc = data->HdrContent;
- const ARTHEADER *hp = ARTheaders;
- int i;
- char *p;
- int delta;
-
- TMRstart(TMR_ARTCLEAN);
- data->Arrived = Now.time;
- data->Expires = 0;
-
- /* replace trailing '\r\n' with '\0\n' of all system header to be handled
- easily by str*() functions */
- for (i = 0 ; i < MAX_ARTHEADER ; i++) {
- if (HDR_FOUND(i))
- HDR_PARSE_START(i);
- }
-
- /* Make sure all the headers we need are there */
- for (i = 0; i < MAX_ARTHEADER ; i++) {
- if (hp[i].Type == HTreq) {
- if (HDR_FOUND(i))
- continue;
- if (hc[i].Length < 0) {
- sprintf(buff, "%d Duplicate \"%s\" header", NNTP_REJECTIT_VAL,
- hp[1].Name);
- } else {
- sprintf(buff, "%d Missing \"%s\" header", NNTP_REJECTIT_VAL,
- hp[i].Name);
- }
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
- }
-
- /* assumes Message-ID header is required header */
- if (!ARTidok(HDR(HDR__MESSAGE_ID))) {
- HDR_LEN(HDR__MESSAGE_ID) = 0;
- sprintf(buff, "%d Bad \"Message-ID\" header", NNTP_REJECTIT_VAL);
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
-
- if (innconf->linecountfuzz && HDR_FOUND(HDR__LINES)) {
- p = HDR(HDR__LINES);
- i = data->Lines;
- if ((delta = i - atoi(p)) != 0 && abs(delta) > innconf->linecountfuzz) {
- sprintf(buff, "%d Linecount %s != %d +- %ld", NNTP_REJECTIT_VAL,
- MaxLength(p, p), i, innconf->linecountfuzz);
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
- }
-
- /* Is article too old? */
- /* assumes Date header is required header */
- p = HDR(HDR__DATE);
- if ((data->Posted = parsedate(p, &Now)) == -1) {
- sprintf(buff, "%d Bad \"Date\" header -- \"%s\"", NNTP_REJECTIT_VAL,
- MaxLength(p, p));
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
- if (innconf->artcutoff) {
- long cutoff = innconf->artcutoff * 24 * 60 * 60;
-
- if (data->Posted < Now.time - cutoff) {
- sprintf(buff, "%d Too old -- \"%s\"", NNTP_REJECTIT_VAL,
- MaxLength(p, p));
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
- }
- if (data->Posted > Now.time + DATE_FUZZ) {
- sprintf(buff, "%d Article posted in the future -- \"%s\"",
- NNTP_REJECTIT_VAL, MaxLength(p, p));
- TMRstop(TMR_ARTCLEAN);
- return false;
- }
- if (HDR_FOUND(HDR__EXPIRES)) {
- p = HDR(HDR__EXPIRES);
- data->Expires = parsedate(p, &Now);
- }
-
- /* Colon or whitespace in the Newsgroups header? */
- /* assumes Newsgroups header is required header */
- if ((data->Groupcount =
- NGsplit(HDR(HDR__NEWSGROUPS), HDR_LEN(HDR__NEWSGROUPS),
- &data->Newsgroups)) == 0) {
- TMRstop(TMR_ARTCLEAN);
- sprintf(buff, "%d Unwanted character in \"Newsgroups\" header",
- NNTP_REJECTIT_VAL);
- return false;
- }
-
- /* Fill in other Data fields. */
- if (HDR_FOUND(HDR__SENDER))
- data->Poster = HDR(HDR__SENDER);
- else
- data->Poster = HDR(HDR__FROM);
- if (HDR_FOUND(HDR__REPLY_TO))
- data->Replyto = HDR(HDR__REPLY_TO);
- else
- data->Replyto = HDR(HDR__FROM);
-
- TMRstop(TMR_ARTCLEAN);
- return true;
-}
-
-/*
-** We are going to reject an article, record the reason and
-** and the article.
-*/
-static void
-ARTreject(Reject_type code, CHANNEL *cp, struct buffer *article UNUSED)
-{
- /* Remember why the article was rejected (for the status file) */
-
- switch (code) {
- case REJECT_DUPLICATE:
- cp->Duplicate++;
- cp->DuplicateSize += cp->Next - cp->Start;
- break;
- case REJECT_SITE:
- cp->Unwanted_s++;
- break;
- case REJECT_FILTER:
- cp->Unwanted_f++;
- break;
- case REJECT_DISTRIB:
- cp->Unwanted_d++;
- break;
- case REJECT_GROUP:
- cp->Unwanted_g++;
- break;
- case REJECT_UNAPP:
- cp->Unwanted_u++;
- break;
- case REJECT_OTHER:
- cp->Unwanted_o++;
- break;
- default:
- /* should never be here */
- syslog(L_NOTICE, "%s unknown reject type received by ARTreject()",
- LogName);
- break;
- }
- /* error */
-}
-
-/*
-** Verify if a cancel message is valid. If the user posting the cancel
-** matches the user who posted the article, return the list of filenames
-** otherwise return NULL.
-*/
-static bool
-ARTcancelverify(const ARTDATA *data, const char *MessageID, TOKEN *token)
-{
- const char *p;
- char *q, *q1;
- const char *local;
- char buff[SMBUF];
- ARTHANDLE *art;
- bool r;
-
- if (!HISlookup(History, MessageID, NULL, NULL, NULL, token))
- return false;
- if ((art = SMretrieve(*token, RETR_HEAD)) == NULL)
- return false;
- local = wire_findheader(art->data, art->len, "Sender");
- if (local == NULL) {
- local = wire_findheader(art->data, art->len, "From");
- if (local == NULL) {
- SMfreearticle(art);
- return false;
- }
- }
- for (p = local; p < art->data + art->len; p++) {
- if (*p == '\r' || *p == '\n')
- break;
- }
- if (p == art->data + art->len) {
- SMfreearticle(art);
- return false;
- }
- q = xmalloc(p - local + 1);
- memcpy(q, local, p - local);
- SMfreearticle(art);
- q[p - local] = '\0';
- HeaderCleanFrom(q);
-
- /* Compare canonical forms. */
- q1 = xstrdup(data->Poster);
- HeaderCleanFrom(q1);
- if (strcmp(q, q1) != 0) {
- r = false;
- sprintf(buff, "\"%.50s\" wants to cancel %s by \"%.50s\"",
- q1, MaxLength(MessageID, MessageID), q);
- ARTlog(data, ART_REJECT, buff);
- }
- else {
- r = true;
- }
- free(q1);
- free(q);
- return r;
-}
-
-/*
-** Process a cancel message.
-*/
-void
-ARTcancel(const ARTDATA *data, const char *MessageID, const bool Trusted)
-{
- char buff[SMBUF+16];
- TOKEN token;
- bool r;
-
- TMRstart(TMR_ARTCNCL);
- if (!DoCancels && !Trusted) {
- TMRstop(TMR_ARTCNCL);
- return;
- }
-
- if (!ARTidok(MessageID)) {
- syslog(L_NOTICE, "%s bad cancel Message-ID %s", data->Feedsite,
- MaxLength(MessageID, MessageID));
- TMRstop(TMR_ARTCNCL);
- return;
- }
-
- if (!HIScheck(History, MessageID)) {
- /* Article hasn't arrived here, so write a fake entry using
- * most of the information from the cancel message. */
- if (innconf->verifycancels && !Trusted) {
- TMRstop(TMR_ARTCNCL);
- return;
- }
- InndHisRemember(MessageID);
- snprintf(buff, sizeof(buff), "Cancelling %s",
- MaxLength(MessageID, MessageID));
- ARTlog(data, ART_CANC, buff);
- TMRstop(TMR_ARTCNCL);
- return;
- }
- if (Trusted || !innconf->verifycancels)
- r = HISlookup(History, MessageID, NULL, NULL, NULL, &token);
- else
- r = ARTcancelverify(data, MessageID, &token);
- if (r == false) {
- TMRstop(TMR_ARTCNCL);
- return;
- }
-
- /* Get stored message and zap them. */
- if (!SMcancel(token) && SMerrno != SMERR_NOENT && SMerrno != SMERR_UNINIT)
- syslog(L_ERROR, "%s cant cancel %s (SMerrno %d)", LogName,
- TokenToText(token), SMerrno);
- if (innconf->immediatecancel && !SMflushcacheddata(SM_CANCELEDART))
- syslog(L_ERROR, "%s cant cancel cached %s", LogName, TokenToText(token));
- snprintf(buff, sizeof(buff), "Cancelling %s",
- MaxLength(MessageID, MessageID));
- ARTlog(data, ART_CANC, buff);
- TMRstop(TMR_ARTCNCL);
-}
-
-/*
-** Process a control message. Cancels are handled here, but any others
-** are passed out to an external program in a specific directory that
-** has the same name as the first word of the control message.
-*/
-static void
-ARTcontrol(ARTDATA *data, char *Control, CHANNEL *cp UNUSED)
-{
- char *p, c;
-
- /* See if it's a cancel message. */
- c = *Control;
- if (c == 'c' && strncmp(Control, "cancel", 6) == 0) {
- for (p = &Control[6]; ISWHITE(*p); p++)
- continue;
- if (*p && ARTidok(p))
- ARTcancel(data, p, false);
- return;
- }
-}
-
-/*
-** Parse a Distribution line, splitting it up into NULL-terminated array of
-** strings.
-*/
-static void
-ARTparsedist(const char *p, int size, LISTBUFFER *list)
-{
- int i;
- char *q, **dp;
-
- /* setup buffer */
- SetupListBuffer(size, list);
-
- /* loop over text and copy */
- for (i = 0, q = list->Data, dp = list->List ; *p ; p++, *q++ = '\0') {
- /* skip leading separators. */
- for (; *p && ((*p == ',') || ISWHITE(*p)) ; p++)
- continue;
- if (*p == '\0')
- break;
-
- if (list->ListLength <= i) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- dp = &list->List[i];
- }
- /* mark the start of the host, move to the end of it while copying */
- for (*dp++ = q, i++ ; *p && (*p != ',') && !ISWHITE(*p) ;)
- *q++ = *p++;
- if (*p == '\0')
- break;
- }
- *q = '\0';
- if (i == list->ListLength) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- dp = &list->List[i];
- }
- *dp = NULL;
- return;
-}
-
-/*
-** A somewhat similar routine, except that this handles negated entries
-** in the list and is used to check the distribution sub-field.
-*/
-static bool
-DISTwanted(char **list, char *p)
-{
- char *q;
- char c;
- bool sawbang;
-
- for (sawbang = false, c = *p; (q = *list) != NULL; list++) {
- if (*q == '!') {
- sawbang = true;
- if (c == *++q && strcmp(p, q) == 0)
- return false;
- } else if (c == *q && strcmp(p, q) == 0)
- return true;
- }
-
- /* If we saw any !foo's and didn't match, then assume they are all negated
- distributions and return true, else return false. */
- return sawbang;
-}
-
-/*
-** See if any of the distributions in the article are wanted by the site.
-*/
-static bool
-DISTwantany(char **site, char **article)
-{
- for ( ; *article; article++)
- if (DISTwanted(site, *article))
- return true;
- return false;
-}
-
-/*
-** Send the current article to all sites that would get it if the
-** group were created.
-*/
-static void
-ARTsendthegroup(char *name)
-{
- SITE *sp;
- int i;
- NEWSGROUP *ngp;
-
- for (ngp = NGfind(ARTctl), sp = Sites, i = nSites; --i >= 0; sp++) {
- if (sp->Name != NULL && SITEwantsgroup(sp, name)) {
- SITEmark(sp, ngp);
- }
- }
-}
-
-/*
-** Check if site doesn't want this group even if it's crossposted
-** to a wanted group.
-*/
-static void
-ARTpoisongroup(char *name)
-{
- SITE *sp;
- int i;
-
- for (sp = Sites, i = nSites; --i >= 0; sp++) {
- if (sp->Name != NULL && (sp->PoisonEntry || ME.PoisonEntry) &&
- SITEpoisongroup(sp, name))
- sp->Poison = true;
- }
-}
-
-/*
-** Assign article numbers to the article and create the Xref line.
-** If we end up not being able to write the article, we'll get "holes"
-** in the directory and active file.
-*/
-static void
-ARTassignnumbers(ARTDATA *data)
-{
- char *p, *q;
- int i, len, linelen, buflen;
- NEWSGROUP *ngp;
-
- if (data->XrefBufLength == 0) {
- data->XrefBufLength = MAXHEADERSIZE * 2 + 1;
- data->Xref = xmalloc(data->XrefBufLength);
- strncpy(data->Xref, Path.data, Path.used - 1);
- }
- len = Path.used - 1;
- p = q = data->Xref + len;
- for (linelen = i = 0; (ngp = GroupPointers[i]) != NULL; i++) {
- /* If already went to this group (i.e., multiple groups are aliased
- * into it), then skip it. */
- if (ngp->PostCount > 0)
- continue;
-
- /* Bump the number. */
- ngp->PostCount++;
- ngp->Last++;
- if (!FormatLong(ngp->LastString, (long)ngp->Last, ngp->Lastwidth)) {
- syslog(L_ERROR, "%s cant update_active %s", LogName, ngp->Name);
- continue;
- }
- ngp->Filenum = ngp->Last;
- /* len ' ' "news_groupname" ':' "#" "\r\n" */
- if (len + 1 + ngp->NameLength + 1 + 10 + 2 > data->XrefBufLength) {
- data->XrefBufLength += MAXHEADERSIZE;
- data->Xref = xrealloc(data->Xref, data->XrefBufLength);
- p = data->Xref + len;
- }
- if (linelen + 1 + ngp->NameLength + 1 + 10 > MAXHEADERSIZE) {
- /* line exceeded */
- sprintf(p, "\r\n %s:%lu", ngp->Name, ngp->Filenum);
- buflen = strlen(p);
- linelen = buflen - 2;
- } else {
- sprintf(p, " %s:%lu", ngp->Name, ngp->Filenum);
- buflen = strlen(p);
- linelen += buflen;
- }
- len += buflen;
- p += buflen;
- }
- /* p[0] is replaced with '\r' to be wireformatted when stored. p[1] needs to
- be '\n' */
- p[0] = '\r';
- p[1] = '\n';
- /* data->XrefLength includes trailing "\r\n" */
- data->XrefLength = len + 2;
- data->Replic = q + 1;
- data->ReplicLength = len - (q + 1 - data->Xref);
-}
-
-/*
-** Parse the data from the xref header and assign the numbers.
-** This involves replacing the GroupPointers entries.
-*/
-static bool
-ARTxrefslave(ARTDATA *data)
-{
- char *p, *q, *name, *next, c = 0;
- NEWSGROUP *ngp;
- int i;
- bool nogroup = true;
- HDRCONTENT *hc = data->HdrContent;
-
- if (!HDR_FOUND(HDR__XREF))
- return false;
- /* skip server name */
- if ((p = strpbrk(HDR(HDR__XREF), " \t\r\n")) == NULL)
- return false;
- /* in case Xref is folded */
- while (*++p == ' ' || *p == '\t' || *p == '\r' || *p == '\n');
- if (*p == '\0')
- return false;
- data->Replic = p;
- data->ReplicLength = HDR_LEN(HDR__XREF) - (p - HDR(HDR__XREF));
- for (i = 0; (*p != '\0') && (p < HDR(HDR__XREF) + HDR_LEN(HDR__XREF)) ; p = next) {
- /* Mark end of this entry and where next one starts. */
- name = p;
- if ((q = next = strpbrk(p, " \t\r\n")) != NULL) {
- c = *q;
- *q = '\0';
- while (*++next == ' ' || *next == '\t' || *next == '\r' || *next == '\n');
- } else {
- q = NULL;
- next = "";
- }
-
- /* Split into news.group:# */
- if ((p = strchr(p, ':')) == NULL) {
- syslog(L_ERROR, "%s bad_format %s", LogName, name);
- if (q != NULL)
- *q = c;
- continue;
- }
- *p = '\0';
- if ((ngp = NGfind(name)) == NULL) {
- syslog(L_ERROR, "%s bad_newsgroup %s", LogName, name);
- *p = ':';
- if (q != NULL)
- *q = c;
- continue;
- }
- *p = ':';
- ngp->Filenum = atol(p + 1);
- if (q != NULL)
- *q = c;
-
- /* Update active file if we got a new high-water mark. */
- if (ngp->Last < ngp->Filenum) {
- ngp->Last = ngp->Filenum;
- if (!FormatLong(ngp->LastString, (long)ngp->Last, ngp->Lastwidth)) {
- syslog(L_ERROR, "%s cant update_active %s", LogName, ngp->Name);
- continue;
- }
- }
- /* Mark that this group gets the article. */
- ngp->PostCount++;
- GroupPointers[i++] = ngp;
- nogroup = false;
- }
- GroupPointers[i] = NULL;
- if (nogroup)
- return false;
- return true;
-}
-
-/*
-** Return true if a list of strings has a specific one. This is a
-** generic routine, but is used for seeing if a host is in the Path line.
-*/
-static bool
-ListHas(const char **list, const char *p)
-{
- const char *q;
- char c;
-
- for (c = *p; (q = *list) != NULL; list++)
- if (strcasecmp(p, q) == 0)
- return true;
- return false;
-}
-
-/*
-** Even though we have already calculated the Message-ID MD5sum,
-** we have to do it again since unfortunately HashMessageID()
-** lowercases the Message-ID first. We also need to remain
-** compatible with Diablo's hashfeed.
-*/
-
-static unsigned int
-HashFeedMD5(char *MessageID, unsigned int offset)
-{
- static char LastMessageID[128];
- static char *LastMessageIDPtr;
- static struct md5_context context;
- unsigned int ret;
-
- if (offset > 12)
- return 0;
-
- /* Some light caching. */
- if (MessageID != LastMessageIDPtr ||
- strcmp(MessageID, LastMessageID) != 0) {
- md5_init(&context);
- md5_update(&context, (unsigned char *)MessageID, strlen(MessageID));
- md5_final(&context);
- LastMessageIDPtr = MessageID;
- strncpy(LastMessageID, MessageID, sizeof(LastMessageID) - 1);
- LastMessageID[sizeof(LastMessageID) - 1] = 0;
- }
-
- memcpy(&ret, &context.digest[12 - offset], 4);
-
- return ntohl(ret);
-}
-
-/*
-** Old-style Diablo (< 5.1) quickhash.
-**
-*/
-static unsigned int
-HashFeedQH(char *MessageID, unsigned int *tmp)
-{
- unsigned char *p;
- int n;
-
- if (*tmp != (unsigned int)-1)
- return *tmp;
-
- p = (unsigned char *)MessageID;
- n = 0;
- while (*p)
- n += *p++;
- *tmp = (unsigned int)n;
-
- return *tmp;
-}
-
-/*
-** Return true if an element of the HASHFEEDLIST matches
-** the hash of the Message-ID.
-*/
-static bool
-HashFeedMatch(HASHFEEDLIST *hf, char *MessageID)
-{
- unsigned int qh = (unsigned int)-1;
- unsigned int h;
-
- while (hf) {
- if (hf->type == HASHFEED_MD5)
- h = HashFeedMD5(MessageID, hf->offset);
- else if (hf->type == HASHFEED_QH)
- h = HashFeedQH(MessageID, &qh);
- else
- continue;
- if ((h % hf->mod + 1) >= hf->begin &&
- (h % hf->mod + 1) <= hf->end)
- return true;
- hf = hf->next;
- }
-
- return false;
-}
-
-/*
-** Propagate an article to the sites have "expressed an interest."
-*/
-static void
-ARTpropagate(ARTDATA *data, const char **hops, int hopcount, char **list,
- bool ControlStore, bool OverviewCreated)
-{
- HDRCONTENT *hc = data->HdrContent;
- SITE *sp, *funnel;
- int i, j, Groupcount, Followcount, Crosscount;
- char *p, *q;
- struct buffer *bp;
- bool sendit;
-
- /* Work out which sites should really get it. */
- Groupcount = data->Groupcount;
- Followcount = data->Followcount;
- Crosscount = Groupcount + Followcount * Followcount;
- for (sp = Sites, i = nSites; --i >= 0; sp++) {
- if ((sp->IgnoreControl && ControlStore) ||
- (sp->NeedOverviewCreation && !OverviewCreated))
- sp->Sendit = false;
- if (sp->Seenit || !sp->Sendit)
- continue;
- sp->Sendit = false;
-
- if (sp->Originator) {
- if (!HDR_FOUND(HDR__XTRACE)) {
- if (!sp->FeedwithoutOriginator)
- continue;
- } else {
- if ((p = strchr(HDR(HDR__XTRACE), ' ')) != NULL) {
- *p = '\0';
- for (j = 0, sendit = false; (q = sp->Originator[j]) != NULL; j++) {
- if (*q == '@') {
- if (uwildmat(HDR(HDR__XTRACE), &q[1])) {
- *p = ' ';
- sendit = false;
- break;
- }
- } else {
- if (uwildmat(HDR(HDR__XTRACE), q))
- sendit = true;
- }
- }
- *p = ' ';
- if (!sendit)
- continue;
- } else
- continue;
- }
- }
-
- if (sp->Master != NOSITE && Sites[sp->Master].Seenit)
- continue;
-
- if (sp->MaxSize && data->BytesValue > sp->MaxSize)
- /* Too big for the site. */
- continue;
-
- if (sp->MinSize && data->BytesValue < sp->MinSize)
- /* Too small for the site. */
- continue;
-
- if ((sp->Hops && hopcount > sp->Hops)
- || (!sp->IgnorePath && ListHas(hops, sp->Name))
- || (sp->Groupcount && Groupcount > sp->Groupcount)
- || (sp->Followcount && Followcount > sp->Followcount)
- || (sp->Crosscount && Crosscount > sp->Crosscount))
- /* Site already saw the article; path too long; or too much
- * cross-posting. */
- continue;
-
- if (sp->HashFeedList &&
- !HashFeedMatch(sp->HashFeedList, HDR(HDR__MESSAGE_ID)))
- /* hashfeed doesn't match */
- continue;
-
- if (list && *list != NULL && sp->Distributions &&
- !DISTwantany(sp->Distributions, list))
- /* Not in the site's desired list of distributions. */
- continue;
- if (sp->DistRequired && (list == NULL || *list == NULL))
- /* Site requires Distribution header and there isn't one. */
- continue;
-
- if (sp->Exclusions) {
- for (j = 0; (p = sp->Exclusions[j]) != NULL; j++)
- if (ListHas(hops, p))
- break;
- if (p != NULL)
- /* A host in the site's exclusion list was in the Path. */
- continue;
- }
-
- /* Write that the site is getting it, and flag to send it. */
- if (innconf->logsitename) {
- if (fprintf(Log, " %s", sp->Name) == EOF || ferror(Log)) {
- j = errno;
- syslog(L_ERROR, "%s cant write log_site %m", LogName);
- IOError("logging site", j);
- clearerr(Log);
- }
- }
- sp->Sendit = true;
- sp->Seenit = true;
- if (sp->Master != NOSITE)
- Sites[sp->Master].Seenit = true;
- }
- if (putc('\n', Log) == EOF
- || (!BufferedLogs && fflush(Log))
- || ferror(Log)) {
- syslog(L_ERROR, "%s cant write log_end %m", LogName);
- clearerr(Log);
- }
-
- /* Handle funnel sites. */
- for (sp = Sites, i = nSites; --i >= 0; sp++) {
- if (sp->Sendit && sp->Funnel != NOSITE) {
- sp->Sendit = false;
- funnel = &Sites[sp->Funnel];
- funnel->Sendit = true;
- if (funnel->FNLwantsnames) {
- bp = &funnel->FNLnames;
- p = &bp->data[bp->used];
- if (bp->used) {
- *p++ = ' ';
- bp->used++;
- }
- bp->used += strlcpy(p, sp->Name, bp->size - bp->used);
- }
- }
- }
-}
-
-/*
-** Build up the overview data.
-*/
-static void
-ARTmakeoverview(CHANNEL *cp)
-{
- ARTDATA *data = &cp->Data;
- HDRCONTENT *hc = data->HdrContent;
- static char SEP[] = "\t";
- static char COLONSPACE[] = ": ";
- struct buffer *overview = &data->Overview;
- ARTOVERFIELD *fp;
- const ARTHEADER *hp;
- char *p, *q;
- int i, j, len;
- char *key_old_value = NULL;
- int key_old_length = 0;
-
- if (ARTfields == NULL) {
- /* User error. */
- return;
- }
-
- /* Setup. */
- buffer_resize(overview, MAXHEADERSIZE);
- buffer_set(overview, "", 0);
-
- /* Write the data, a field at a time. */
- for (fp = ARTfields; fp->Header; fp++) {
- if (fp != ARTfields)
- buffer_append(overview, SEP, strlen(SEP));
- hp = fp->Header;
- j = hp - ARTheaders;
-
- /* If requested, generate keywords from the body of the article and patch
- them into the apparent value of the Keywords header so that they make
- it into overview. */
- if (DO_KEYWORDS && innconf->keywords) {
- /* Ensure that there are Keywords: to shovel. */
- if (hp == &ARTheaders[HDR__KEYWORDS]) {
- key_old_value = HDR(HDR__KEYWORDS);
- key_old_length = HDR_LEN(HDR__KEYWORDS);
- KEYgenerate(&hc[HDR__KEYWORDS], cp->In.data + data->Body,
- key_old_value, key_old_length);
- }
- }
-
- switch (j) {
- case HDR__BYTES:
- p = data->Bytes + 7; /* skip "Bytes: " */
- len = data->BytesLength;
- break;
- case HDR__XREF:
- if (innconf->xrefslave) {
- p = HDR(j);
- len = HDR_LEN(j);
- } else {
- p = data->Xref;
- len = data->XrefLength - 2;
- }
- break;
- default:
- p = HDR(j);
- len = HDR_LEN(j);
- break;
- }
- if (len == 0)
- continue;
- if (fp->NeedHeader) {
- buffer_append(overview, hp->Name, hp->Size);
- buffer_append(overview, COLONSPACE, strlen(COLONSPACE));
- }
- if (overview->used + overview->left + len > overview->size)
- buffer_resize(overview, overview->size + len);
- for (i = 0, q = overview->data + overview->left; i < len; p++, i++) {
- if (*p == '\r' && i < len - 1 && p[1] == '\n') {
- p++;
- i++;
- continue;
- }
- if (*p == '\0' || *p == '\t' || *p == '\n' || *p == '\r')
- *q++ = ' ';
- else
- *q++ = *p;
- overview->left++;
- }
-
- /* Patch the old keywords back in. */
- if (DO_KEYWORDS && innconf->keywords) {
- if (key_old_value) {
- if (hc->Value)
- free(hc->Value); /* malloc'd within */
- hc->Value = key_old_value;
- hc->Length = key_old_length;
- key_old_value = NULL;
- }
- }
- }
-}
-
-/*
-** This routine is the heart of it all. Take a full article, parse it,
-** file or reject it, feed it to the other sites. Return the NNTP
-** message to send back.
-*/
-bool
-ARTpost(CHANNEL *cp)
-{
- char *p, **groups, ControlWord[SMBUF], **hops, *controlgroup;
- int i, j, *isp, hopcount, oerrno, canpost;
- NEWSGROUP *ngp, **ngptr;
- SITE *sp;
- ARTDATA *data = &cp->Data;
- HDRCONTENT *hc = data->HdrContent;
- bool Approved, Accepted, LikeNewgroup, ToGroup, GroupMissing;
- bool NoHistoryUpdate, artclean;
- bool ControlStore = false;
- bool NonExist = false;
- bool OverviewCreated = false;
- bool IsControl = false;
- bool Filtered = false;
- struct buffer *article;
- HASH hash;
- TOKEN token;
- char *groupbuff[2];
-#if defined(DO_PERL) || defined(DO_PYTHON)
- char *filterrc;
-#endif /* defined(DO_PERL) || defined(DO_PYTHON) */
- OVADDRESULT result;
-
- /* Preliminary clean-ups. */
- article = &cp->In;
- artclean = ARTclean(data, cp->Error);
-
- /* If we don't have Path or Message-ID, we can't continue. */
- if (!artclean && (!HDR_FOUND(HDR__PATH) || !HDR_FOUND(HDR__MESSAGE_ID)))
- return false;
- hopcount = ARTparsepath(HDR(HDR__PATH), HDR_LEN(HDR__PATH), &data->Path);
- if (hopcount == 0) {
- snprintf(cp->Error, sizeof(cp->Error), "%d illegal path element",
- NNTP_REJECTIT_VAL);
- return false;
- }
- hops = data->Path.List;
-
- if (innconf->logipaddr) {
- data->Feedsite = RChostname(cp);
- if (data->Feedsite == NULL)
- data->Feedsite = CHANname(cp);
- if (strcmp("0.0.0.0", data->Feedsite) == 0 || data->Feedsite[0] == '\0')
- data->Feedsite = hops && hops[0] ? hops[0] : CHANname(cp);
- } else {
- data->Feedsite = hops && hops[0] ? hops[0] : CHANname(cp);
- }
- data->FeedsiteLength = strlen(data->Feedsite);
-
- hash = HashMessageID(HDR(HDR__MESSAGE_ID));
- data->Hash = &hash;
- if (HIScheck(History, HDR(HDR__MESSAGE_ID))) {
- snprintf(cp->Error, sizeof(cp->Error), "%d Duplicate", NNTP_REJECTIT_VAL);
- ARTlog(data, ART_REJECT, cp->Error);
- ARTreject(REJECT_DUPLICATE, cp, article);
- return false;
- }
- if (!artclean) {
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_OTHER, cp, article);
- return false;
- }
-
- i = strlen(hops[0]);
- if (i == Path.used - 1 &&
- strncmp(Path.data, hops[0], Path.used - 1) == 0)
- data->Hassamepath = true;
- else
- data->Hassamepath = false;
- if (Pathcluster.data != NULL &&
- i == Pathcluster.used - 1 &&
- strncmp(Pathcluster.data, hops[0], Pathcluster.used - 1) == 0)
- data->Hassamecluster = true;
- else
- data->Hassamecluster = false;
- if (Pathalias.data != NULL &&
- !ListHas((const char **)hops, (const char *)innconf->pathalias))
- data->AddAlias = true;
- else
- data->AddAlias = false;
-
- /* And now check the path for unwanted sites -- Andy */
- for(j = 0 ; ME.Exclusions && ME.Exclusions[j] ; j++) {
- if (ListHas((const char **)hops, (const char *)ME.Exclusions[j])) {
- snprintf(cp->Error, sizeof(cp->Error), "%d Unwanted site %s in path",
- NNTP_REJECTIT_VAL, MaxLength(ME.Exclusions[j], ME.Exclusions[j]));
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_SITE, cp, article);
- return false;
- }
- }
-
-#if defined(DO_PERL) || defined(DO_PYTHON)
- filterPath = HDR(HDR__PATH);
-#endif /* DO_PERL || DO_PYHTON */
-
-#if defined(DO_PYTHON)
- TMRstart(TMR_PYTHON);
- filterrc = PYartfilter(data, article->data + data->Body,
- cp->Next - data->Body, data->Lines);
- TMRstop(TMR_PYTHON);
- if (filterrc != NULL) {
- if (innconf->dontrejectfiltered) {
- Filtered = true;
- } else {
- snprintf(cp->Error, sizeof(cp->Error), "%d %.200s", NNTP_REJECTIT_VAL,
- filterrc);
- syslog(L_NOTICE, "rejecting[python] %s %s", HDR(HDR__MESSAGE_ID),
- cp->Error);
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_FILTER, cp, article);
- return false;
- }
- }
-#endif /* DO_PYTHON */
-
- /* I suppose some masochist will run with Python and Perl in together */
-
-#if defined(DO_PERL)
- TMRstart(TMR_PERL);
- filterrc = PLartfilter(data, article->data + data->Body,
- cp->Next - data->Body, data->Lines);
- TMRstop(TMR_PERL);
- if (filterrc) {
- if (innconf->dontrejectfiltered) {
- Filtered = true;
- } else {
- snprintf(cp->Error, sizeof(cp->Error), "%d %.200s", NNTP_REJECTIT_VAL,
- filterrc);
- syslog(L_NOTICE, "rejecting[perl] %s %s", HDR(HDR__MESSAGE_ID),
- cp->Error);
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_FILTER, cp, article);
- return false;
- }
- }
-#endif /* DO_PERL */
-
- /* I suppose some masochist will run with both TCL and Perl in together */
-
-#if defined(DO_TCL)
- if (TCLFilterActive) {
- int code;
- const ARTHEADER *hp;
-
- /* make info available to Tcl */
-
- TCLCurrArticle = article;
- TCLCurrData = data;
- Tcl_UnsetVar(TCLInterpreter, "Body", TCL_GLOBAL_ONLY);
- Tcl_UnsetVar(TCLInterpreter, "Headers", TCL_GLOBAL_ONLY);
- for (i = 0 ; i < MAX_ARTHEADER ; i++, hc++) {
- if (HDR_FOUND(i)) {
- hp = &ARTheaders[i];
- Tcl_SetVar2(TCLInterpreter, "Headers", (char *) hp->Name, HDR(i),
- TCL_GLOBAL_ONLY);
- }
- }
- Tcl_SetVar(TCLInterpreter, "Body", article->data + data->Body,
- TCL_GLOBAL_ONLY);
- /* call filter */
-
- code = Tcl_Eval(TCLInterpreter, "filter_news");
- Tcl_UnsetVar(TCLInterpreter, "Body", TCL_GLOBAL_ONLY);
- Tcl_UnsetVar(TCLInterpreter, "Headers", TCL_GLOBAL_ONLY);
- if (code == TCL_OK) {
- if (strcmp(TCLInterpreter->result, "accept") != 0) {
- if (innconf->dontrejectfiltered) {
- Filtered = true;
- } else {
- snprintf(cp->Error, sizeof(cp->Error), "%d %.200s",
- NNTP_REJECTIT_VAL, TCLInterpreter->result);
- syslog(L_NOTICE, "rejecting[tcl] %s %s", HDR(HDR__MESSAGE_ID),
- cp->Error);
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m",
- LogName, HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_FILTER, cp, article);
- return false;
- }
- }
- } else {
- /* the filter failed: complain and then turn off filtering */
- syslog(L_ERROR, "TCL proc filter_news failed: %s",
- TCLInterpreter->result);
- TCLfilter(false);
- }
- }
-#endif /* defined(DO_TCL) */
-
- /* If we limit what distributions we get, see if we want this one. */
- if (HDR_FOUND(HDR__DISTRIBUTION)) {
- if (HDR(HDR__DISTRIBUTION)[0] == ',') {
- snprintf(cp->Error, sizeof(cp->Error), "%d bogus distribution \"%s\"",
- NNTP_REJECTIT_VAL,
- MaxLength(HDR(HDR__DISTRIBUTION), HDR(HDR__DISTRIBUTION)));
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && Mode == OMrunning &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_DISTRIB, cp, article);
- return false;
- } else {
- ARTparsedist(HDR(HDR__DISTRIBUTION), HDR_LEN(HDR__DISTRIBUTION),
- &data->Distribution);
- if (ME.Distributions &&
- !DISTwantany(ME.Distributions, data->Distribution.List)) {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Unwanted distribution \"%s\"", NNTP_REJECTIT_VAL,
- MaxLength(data->Distribution.List[0],
- data->Distribution.List[0]));
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m",
- LogName, HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_DISTRIB, cp, article);
- return false;
- }
- }
- } else {
- ARTparsedist("", 0, &data->Distribution);
- }
-
- for (i = nSites, sp = Sites; --i >= 0; sp++) {
- sp->Poison = false;
- sp->Sendit = false;
- sp->Seenit = false;
- sp->FNLnames.used = 0;
- sp->ng = NULL;
- }
-
- if (HDR_FOUND(HDR__FOLLOWUPTO)) {
- for (i = 0, p = HDR(HDR__FOLLOWUPTO) ; (p = strchr(p, ',')) != NULL ;
- i++, p++)
- continue;
- data->Followcount = i;
- }
- if (data->Followcount == 0)
- data->Followcount = data->Groupcount;
-
- groups = data->Newsgroups.List;
- /* Parse the Control header. */
- LikeNewgroup = false;
- if (HDR_FOUND(HDR__CONTROL)) {
- IsControl = true;
-
- /* Nip off the first word into lowercase. */
- strlcpy(ControlWord, HDR(HDR__CONTROL), sizeof(ControlWord));
- for (p = ControlWord; *p && !ISWHITE(*p); p++)
- if (CTYPE(isupper, *p))
- *p = tolower(*p);
- *p = '\0';
- LikeNewgroup = (strcmp(ControlWord, "newgroup") == 0
- || strcmp(ControlWord, "rmgroup") == 0);
-
- if (innconf->ignorenewsgroups && LikeNewgroup) {
- for (p++; *p && ISWHITE(*p); p++);
- groupbuff[0] = p;
- for (p++; *p; p++) {
- if (NG_ISSEP(*p)) {
- *p = '\0';
- break;
- }
- }
- p = groupbuff[0];
- for (p++; *p; p++) {
- if (ISWHITE(*p)) {
- *p = '\0';
- break;
- }
- }
- groupbuff[1] = NULL;
- groups = groupbuff;
- data->Groupcount = 2;
- if (data->Followcount == 0)
- data->Followcount = data->Groupcount;
- }
-
- LikeNewgroup = (LikeNewgroup || strcmp(ControlWord, "checkgroups") == 0);
-
- /* Control messages to "foo.ctl" are treated as if they were
- * posted to "foo". I should probably apologize for all the
- * side-effects in the if. */
- for (i = 0; (p = groups[i++]) != NULL; )
- if ((j = strlen(p) - 4) > 0 && *(p += j) == '.'
- && p[1] == 'c' && p[2] == 't' && p[3] == 'l')
- *p = '\0';
- }
-
- /* Loop over the newsgroups, see which ones we want, and get the
- * total space needed for the Xref line. At the end of this section
- * of code, j will have the needed length, the appropriate site
- * entries will have their Sendit and ng fields set, and GroupPointers
- * will have pointers to the relevant newsgroups. */
- ToGroup = NoHistoryUpdate = false;
- Approved = HDR_FOUND(HDR__APPROVED);
- ngptr = GroupPointers;
- for (GroupMissing = Accepted = false; (p = *groups) != NULL; groups++) {
- if ((ngp = NGfind(p)) == NULL) {
- GroupMissing = true;
- if (LikeNewgroup && Approved) {
- /* Checkgroups/newgroup/rmgroup being sent to a group that doesn't
- * exist. Assume it is being sent to the group being created or
- * removed (or to the admin group to which the checkgroups is posted),
- * and send it to all sites that would or would have had the group
- * if it were created. */
- ARTsendthegroup(*groups);
- Accepted = true;
- } else
- NonExist = true;
- ARTpoisongroup(*groups);
-
- if (innconf->mergetogroups) {
- /* Try to collapse all "to" newsgroups. */
- if (*p != 't' || *++p != 'o' || *++p != '.' || *++p == '\0')
- continue;
- ngp = NGfind("to");
- ToGroup = true;
- if ((sp = SITEfind(p)) != NULL) {
- SITEmark(sp, ngp);
- }
- } else {
- continue;
- }
- }
-
- ngp->PostCount = 0;
- /* Ignore this group? */
- if (ngp->Rest[0] == NF_FLAG_IGNORE) {
- /* See if any of this group's sites considers this group poison. */
- for (isp = ngp->Poison, i = ngp->nPoison; --i >= 0; isp++)
- if (*isp >= 0)
- Sites[*isp].Poison = true;
- continue;
- }
-
- /* Basic validity check. */
- if (ngp->Rest[0] == NF_FLAG_MODERATED && !Approved) {
- snprintf(cp->Error, sizeof(cp->Error), "%d Unapproved for \"%s\"",
- NNTP_REJECTIT_VAL, MaxLength(ngp->Name, ngp->Name));
- ARTlog(data, ART_REJECT, cp->Error);
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_UNAPP, cp, article);
- return false;
- }
-
- /* See if any of this group's sites considers this group poison. */
- for (isp = ngp->Poison, i = ngp->nPoison; --i >= 0; isp++)
- if (*isp >= 0)
- Sites[*isp].Poison = true;
-
- /* Check if we accept articles in this group from this peer, after
- poisoning. This means that articles that we accept from them will
- be handled correctly if they're crossposted. */
- canpost = RCcanpost(cp, p);
- if (!canpost) { /* At least one group cannot be fed by this peer.
- If we later reject the post as unwanted group,
- don't remember it. If we accept, do remember */
- NoHistoryUpdate = true;
- continue;
- } else if (canpost < 0) {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Won't accept posts in \"%s\"", NNTP_REJECTIT_VAL,
- MaxLength(p, p));
- ARTlog(data, ART_REJECT, cp->Error);
- ARTreject(REJECT_GROUP, cp, article);
- return false;
- }
-
- /* Valid group, feed it to that group's sites. */
- Accepted = true;
- for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++) {
- if (*isp >= 0) {
- sp = &Sites[*isp];
- if (!sp->Poison)
- SITEmark(sp, ngp);
- }
- }
-
- /* If it's excluded, don't file it. */
- if (ngp->Rest[0] == NF_FLAG_EXCLUDED)
- continue;
-
- /* Expand aliases, mark the article as getting filed in the group. */
- if (ngp->Alias != NULL)
- ngp = ngp->Alias;
- *ngptr++ = ngp;
- ngp->PostCount = 0;
- }
-
- /* Loop over sites to find Poisons/ControlOnly and undo Sendit flags. */
- for (i = nSites, sp = Sites; --i >= 0; sp++) {
- if (sp->Poison || (sp->ControlOnly && !IsControl)
- || (sp->DontWantNonExist && NonExist))
- sp->Sendit = false;
- }
-
- /* Control messages not filed in "to" get filed only in control.name
- * or control. */
- if (IsControl && Accepted && !ToGroup) {
- ControlStore = true;
- controlgroup = concat("control.", ControlWord, (char *) 0);
- if ((ngp = NGfind(controlgroup)) == NULL)
- ngp = NGfind(ARTctl);
- free(controlgroup);
- ngp->PostCount = 0;
- ngptr = GroupPointers;
- *ngptr++ = ngp;
- for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++) {
- if (*isp >= 0) {
- /* Checkgroups/newgroup/rmgroup posted to local.example
- * will still be sent with the newsfeeds patterns
- * "*,!local.*" and "*,@local.*". So as not to propagate
- * them, "!control,!control.*" should be added. */
- sp = &Sites[*isp];
- SITEmark(sp, ngp);
- }
- }
- }
-
- /* If !Accepted, then none of the article's newgroups exist in our
- * active file. Proper action is to drop the article on the floor.
- * If ngp == GroupPointers, then all the new articles newsgroups are
- * "j" entries in the active file. In that case, we have to file it
- * under junk so that downstream feeds can get it. */
- if (!Accepted || ngptr == GroupPointers) {
- if (!Accepted) {
- if (NoHistoryUpdate) {
- snprintf(cp->Error, sizeof(cp->Error), "%d Can't post to \"%s\"",
- NNTP_REJECTIT_VAL, MaxLength(data->Newsgroups.List[0],
- data->Newsgroups.List[0]));
- } else {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Unwanted newsgroup \"%s\"", NNTP_REJECTIT_VAL,
- MaxLength(data->Newsgroups.List[0],
- data->Newsgroups.List[0]));
- }
- ARTlog(data, ART_REJECT, cp->Error);
- if (!innconf->wanttrash) {
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !NoHistoryUpdate && !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m",
- LogName, HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_GROUP, cp, article);
- return false;
- } else {
- /* if !GroupMissing, then all the groups the article was posted
- * to have a flag of "x" in our active file, and therefore
- * we should throw the article away: if you have set
- * innconf->remembertrash true, then you want all trash except that
- * which you explicitly excluded in your active file. */
- if (!GroupMissing) {
- if (innconf->remembertrash && (Mode == OMrunning) &&
- !NoHistoryUpdate && !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m",
- LogName, HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_GROUP, cp, article);
- return false;
- }
- }
- }
- ngp = NGfind(ARTjnk);
- *ngptr++ = ngp;
- ngp->PostCount = 0;
-
- /* Junk can be fed to other sites. */
- for (isp = ngp->Sites, i = ngp->nSites; --i >= 0; isp++) {
- if (*isp >= 0) {
- sp = &Sites[*isp];
- if (!sp->Poison && !(sp->ControlOnly && !IsControl))
- SITEmark(sp, ngp);
- }
- }
- }
- *ngptr = NULL;
-
- if (innconf->xrefslave) {
- if (ARTxrefslave(data) == false) {
- if (HDR_FOUND(HDR__XREF)) {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Xref header \"%s\" invalid in xrefslave mode",
- NNTP_REJECTIT_VAL,
- MaxLength(HDR(HDR__XREF), HDR(HDR__XREF)));
- } else {
- snprintf(cp->Error, sizeof(cp->Error),
- "%d Xref header required in xrefslave mode",
- NNTP_REJECTIT_VAL);
- }
- ARTlog(data, ART_REJECT, cp->Error);
- ARTreject(REJECT_OTHER, cp, article);
- return false;
- }
- } else {
- ARTassignnumbers(data);
- }
-
- /* Now we can file it. */
- if (++ICDactivedirty >= innconf->icdsynccount) {
- ICDwriteactive();
- ICDactivedirty = 0;
- }
- TMRstart(TMR_ARTWRITE);
- for (i = 0; (ngp = GroupPointers[i]) != NULL; i++)
- ngp->PostCount = 0;
-
- token = ARTstore(cp);
- /* change trailing '\r\n' to '\0\n' of all system header */
- for (i = 0 ; i < MAX_ARTHEADER ; i++) {
- if (HDR_FOUND(i))
- HDR_PARSE_START(i);
- }
- if (token.type == TOKEN_EMPTY) {
- syslog(L_ERROR, "%s cant store article: %s", LogName, SMerrorstr);
- snprintf(cp->Error, sizeof(cp->Error), "%d cant store article",
- NNTP_RESENDIT_VAL);
- ARTlog(data, ART_REJECT, cp->Error);
- if ((Mode == OMrunning) && !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- ARTreject(REJECT_OTHER, cp, article);
- TMRstop(TMR_ARTWRITE);
- return false;
- }
- TMRstop(TMR_ARTWRITE);
- if ((innconf->enableoverview && !innconf->useoverchan) || NeedOverview) {
- TMRstart(TMR_OVERV);
- ARTmakeoverview(cp);
- if (innconf->enableoverview && !innconf->useoverchan) {
- if ((result = OVadd(token, data->Overview.data, data->Overview.left,
- data->Arrived, data->Expires)) == OVADDFAILED) {
- if (OVctl(OVSPACE, (void *)&i) && i == OV_NOSPACE)
- IOError("creating overview", ENOSPC);
- else
- IOError("creating overview", 0);
- syslog(L_ERROR, "%s cant store overview for %s", LogName,
- TokenToText(token));
- OverviewCreated = false;
- } else {
- if (result == OVADDCOMPLETED)
- OverviewCreated = true;
- else
- OverviewCreated = false;
- }
- }
- TMRstop(TMR_OVERV);
- }
- strlcpy(data->TokenText, TokenToText(token), sizeof(data->TokenText));
-
- /* Update history if we didn't get too many I/O errors above. */
- if ((Mode != OMrunning) ||
- !InndHisWrite(HDR(HDR__MESSAGE_ID), data->Arrived, data->Posted,
- data->Expires, &token)) {
- i = errno;
- syslog(L_ERROR, "%s cant write history %s %m", LogName,
- HDR(HDR__MESSAGE_ID));
- snprintf(cp->Error, sizeof(cp->Error), "%d cant write history, %s",
- NNTP_RESENDIT_VAL, strerror(errno));
- ARTlog(data, ART_REJECT, cp->Error);
- ARTreject(REJECT_OTHER, cp, article);
- return false;
- }
-
- if (NeedStoredGroup)
- data->StoredGroupLength = strlen(data->Newsgroups.List[0]);
-
- /* Start logging, then propagate the article. */
- if (data->CRwithoutLF > 0 || data->LFwithoutCR > 0) {
- if (data->CRwithoutLF > 0 && data->LFwithoutCR == 0)
- snprintf(cp->Error, sizeof(cp->Error),
- "%d article includes CR without LF(%d)",
- NNTP_REJECTIT_VAL, data->CRwithoutLF);
- else if (data->CRwithoutLF == 0 && data->LFwithoutCR > 0)
- snprintf(cp->Error, sizeof(cp->Error),
- "%d article includes LF without CR(%d)",
- NNTP_REJECTIT_VAL, data->LFwithoutCR);
- else
- snprintf(cp->Error, sizeof(cp->Error),
- "%d article includes CR without LF(%d) and LF withtout CR(%d)",
- NNTP_REJECTIT_VAL, data->CRwithoutLF, data->LFwithoutCR);
- ARTlog(data, ART_STRSTR, cp->Error);
- }
- ARTlog(data, Accepted ? ART_ACCEPT : ART_JUNK, (char *)NULL);
- if ((innconf->nntplinklog) &&
- (fprintf(Log, " (%s)", data->TokenText) == EOF || ferror(Log))) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write log_nntplink %m", LogName);
- IOError("logging nntplink", oerrno);
- clearerr(Log);
- }
- /* Calculate Max Article Time */
- i = Now.time - cp->ArtBeg;
- if(i > cp->ArtMax)
- cp->ArtMax = i;
- cp->ArtBeg = 0;
-
- cp->Size += data->BytesValue;
- if (innconf->logartsize) {
- if (fprintf(Log, " %ld", data->BytesValue) == EOF || ferror (Log)) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write artsize %m", LogName);
- IOError("logging artsize", oerrno);
- clearerr(Log);
- }
- }
-
- ARTpropagate(data, (const char **)hops, hopcount, data->Distribution.List,
- ControlStore, OverviewCreated);
-
- /* Now that it's been written, process the control message. This has
- * a small window, if we get a new article before the newgroup message
- * has been processed. We could pause ourselves here, but it doesn't
- * seem to be worth it. */
- if (Accepted) {
- if (IsControl) {
- ARTcontrol(data, HDR(HDR__CONTROL), cp);
- }
- if (DoCancels && HDR_FOUND(HDR__SUPERSEDES)) {
- if (ARTidok(HDR(HDR__SUPERSEDES)))
- ARTcancel(data, HDR(HDR__SUPERSEDES), false);
- }
- }
-
- /* And finally, send to everyone who should get it */
- for (sp = Sites, i = nSites; --i >= 0; sp++) {
- if (sp->Sendit) {
- if (!Filtered || !sp->DropFiltered) {
- TMRstart(TMR_SITESEND);
- SITEsend(sp, data);
- TMRstop(TMR_SITESEND);
- }
- }
- }
-
- return true;
-}
+++ /dev/null
-/* $Id: cc.c 7748 2008-04-06 13:49:56Z iulius $
-**
-** Routines for the control channel.
-**
-** Create a Unix-domain datagram socket that processes on the local server
-** send messages to. The control channel is used only by ctlinnd to tell
-** the server to perform special functions. We use datagrams so that we
-** don't need to do an accept() and tie up another descriptor. recvfrom
-** seems to be broken on several systems, so the client passes in the
-** socket name.
-**
-** This module completely rips away all pretense of software layering.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/qio.h"
-#include "innd.h"
-#include "inndcomm.h"
-#include "innperl.h"
-
-/*
-** An entry in the dispatch table. The name, and implementing function,
-** of every command we support.
-*/
-typedef struct _CCDISPATCH {
- char Name;
- int argc;
- const char * (*Function)(char *av[]);
-} CCDISPATCH;
-
-
-static const char * CCallow(char *av[]);
-static const char * CCbegin(char *av[]);
-static const char * CCchgroup(char *av[]);
-static const char * CCdrop(char *av[]);
-static const char * CCfeedinfo(char *av[]);
-static const char * CCflush(char *av[]);
-static const char * CCflushlogs(char *unused[]);
-static const char * CCgo(char *av[]);
-static const char * CChangup(char *av[]);
-static const char * CCreserve(char *av[]);
-static const char * CClogmode(char *unused[]);
-static const char * CCmode(char *unused[]);
-static const char * CCname(char *av[]);
-static const char * CCnewgroup(char *av[]);
-static const char * CCparam(char *av[]);
-static const char * CCpause(char *av[]);
-static const char * CCreaders(char *av[]);
-static const char * CCreject(char *av[]);
-static const char * CCreload(char *av[]);
-static const char * CCrenumber(char *av[]);
-static const char * CCrmgroup(char *av[]);
-static const char * CCsend(char *av[]);
-static const char * CCshutdown(char *av[]);
-static const char * CCsignal(char *av[]);
-static const char * CCstathist(char *av[]);
-static const char * CCstatus(char *av[]);
-static const char * CCthrottle(char *av[]);
-static const char * CCtimer(char *av[]);
-static const char * CCtrace(char *av[]);
-static const char * CCxabort(char *av[]);
-static const char * CCxexec(char *av[]);
-static const char * CCfilter(char *av[]);
-static const char * CCperl(char *av[]);
-static const char * CCpython(char *av[]);
-static const char * CClowmark(char *av[]);
-
-
-static char *CCpath = NULL;
-static char **CCargv;
-static char CCnosite[] = "1 No such site";
-static char CCwrongtype[] = "1 Wrong site type";
-static char CCnogroup[] = "1 No such group";
-static char CCnochannel[] = "1 No such channel";
-static char CCnoreason[] = "1 Empty reason";
-static char CCbigreason[] = "1 Reason too long";
-static char CCnotrunning[] = "1 Must be running";
-static struct buffer CCreply;
-static CHANNEL *CCchan;
-static int CCwriter;
-static CCDISPATCH CCcommands[] = {
- { SC_ADDHIST, 5, CCaddhist },
- { SC_ALLOW, 1, CCallow },
- { SC_BEGIN, 1, CCbegin },
- { SC_CANCEL, 1, CCcancel },
- { SC_CHANGEGROUP, 2, CCchgroup },
- { SC_CHECKFILE, 0, CCcheckfile },
- { SC_DROP, 1, CCdrop },
- { SC_FEEDINFO, 1, CCfeedinfo },
- { SC_FILTER, 1, CCfilter },
- { SC_PERL, 1, CCperl },
- { SC_PYTHON, 1, CCpython },
- { SC_FLUSH, 1, CCflush },
- { SC_FLUSHLOGS, 0, CCflushlogs },
- { SC_GO, 1, CCgo },
- { SC_HANGUP, 1, CChangup },
- { SC_LOGMODE, 0, CClogmode },
- { SC_MODE, 0, CCmode },
- { SC_NAME, 1, CCname },
- { SC_NEWGROUP, 3, CCnewgroup },
- { SC_PARAM, 2, CCparam },
- { SC_PAUSE, 1, CCpause },
- { SC_READERS, 2, CCreaders },
- { SC_REJECT, 1, CCreject },
- { SC_RENUMBER, 1, CCrenumber },
- { SC_RELOAD, 2, CCreload },
- { SC_RESERVE, 1, CCreserve },
- { SC_RMGROUP, 1, CCrmgroup },
- { SC_SEND, 2, CCsend },
- { SC_SHUTDOWN, 1, CCshutdown },
- { SC_SIGNAL, 2, CCsignal },
- { SC_STATHIST, 1, CCstathist },
- { SC_STATUS, 1, CCstatus },
- { SC_THROTTLE, 1, CCthrottle },
- { SC_TIMER, 1, CCtimer },
- { SC_TRACE, 2, CCtrace },
- { SC_XABORT, 1, CCxabort },
- { SC_LOWMARK, 1, CClowmark },
- { SC_XEXEC, 1, CCxexec }
-};
-
-static RETSIGTYPE CCresetup(int unused);
-\f
-
-void
-CCcopyargv(char *av[])
-{
- char **v;
- int i;
-
- /* Get the vector size. */
- for (i = 0; av[i]; i++)
- continue;
-
- /* Get the vector, copy each element. */
- for (v = CCargv = xmalloc((i + 1) * sizeof(char *)); *av; av++) {
- /* not to renumber */
- if (strncmp(*av, "-r", 2) == 0)
- continue;
- *v++ = xstrdup(*av);
- }
- *v = NULL;
-}
-
-
-/*
-** Return a string representing our operating mode.
-*/
-static const char *
-CCcurrmode(void)
-{
- static char buff[32];
-
- /* Server's mode. */
- switch (Mode) {
- default:
- snprintf(buff, sizeof(buff), "Unknown %d", Mode);
- return buff;
- case OMrunning:
- return "running";
- case OMpaused:
- return "paused";
- case OMthrottled:
- return "throttled";
- }
-}
-
-
-/*
-** Add <> around Message-ID if needed.
-*/
-static const char *
-CCgetid(char *p, const char **store)
-{
- static char NULLMESGID[] = "1 Empty Message-ID";
- static struct buffer Save = { 0, 0, 0, NULL };
- int i;
-
- if (*p == '\0')
- return NULLMESGID;
- if (*p == '<') {
- if (p[1] == '\0' || p[1] == '>')
- return NULLMESGID;
- *store = p;
- return NULL;
- }
-
- /* Make sure the Message-ID buffer has room. */
- i = 1 + strlen(p) + 1 + 1;
- buffer_resize(&Save, i);
- *store = Save.data;
- snprintf(Save.data, Save.size, "<%s>", p);
- return NULL;
-}
-
-
-/*
-** Abort and dump core.
-*/
-static const char *
-CCxabort(char *av[])
-{
- syslog(L_FATAL, "%s abort %s", LogName, av[0]);
- abort();
- syslog(L_FATAL, "%s cant abort %m", LogName);
- CleanupAndExit(1, av[0]);
- /* NOTREACHED */
-}
-
-
-/*
-** Do the work needed to add a history entry.
-*/
-const char *
-CCaddhist(char *av[])
-{
- static char DIGITS[] = "0123456789";
- ARTDATA Data;
- const char * p, *msgid;
- bool ok;
- TOKEN token;
-
- /* You must pass a <message-id> ID, the history API will hash it as it
- * wants */
- if ((p = CCgetid(av[0], &msgid)) != NULL)
- return p;
-
- /* If paused, don't try to use the history database since expire may be
- running */
- if (Mode == OMpaused)
- return "1 Server paused";
-
- /* If throttled by admin, briefly open the history database. */
- if (Mode != OMrunning) {
- if (ThrottledbyIOError)
- return "1 Server throttled";
- InndHisOpen();
- }
-
- if (HIScheck(History, msgid)) {
- if (Mode != OMrunning) InndHisClose();
- return "1 Duplicate";
- }
- if (Mode != OMrunning) InndHisClose();
- if (strspn(av[1], DIGITS) != strlen(av[1]))
- return "1 Bad arrival date";
- Data.Arrived = atol(av[1]);
- if (strspn(av[2], DIGITS) != strlen(av[2]))
- return "1 Bad expiration date";
- Data.Expires = atol(av[2]);
- if (strspn(av[3], DIGITS) != strlen(av[3]))
- return "1 Bad posted date";
- Data.Posted = atol(av[3]);
-
- token = TextToToken(av[4]);
- if (Mode == OMrunning)
- ok = InndHisWrite(msgid, Data.Arrived, Data.Posted,
- Data.Expires, &token);
- else {
- /* Possible race condition, but documented in ctlinnd manpage. */
- InndHisOpen();
- ok = InndHisWrite(msgid, Data.Arrived, Data.Posted,
- Data.Expires, &token);
- InndHisClose();
- }
- return ok ? NULL : "1 Write failed";
-}
-
-
-/*
-** Do the work to allow foreign connectiosn.
-*/
-static const char *
-CCallow(char *av[])
-{
- char *p;
-
- if (RejectReason == NULL)
- return "1 Already allowed";
- p = av[0];
- if (*p && strcmp(p, RejectReason) != 0)
- return "1 Wrong reason";
- free(RejectReason);
- RejectReason = NULL;
- return NULL;
-}
-
-
-/*
-** Do the work needed to start feeding a (new) site.
-*/
-static const char *
-CCbegin(char *av[])
-{
- SITE *sp;
- int i;
- int length;
- char *p;
- const char *p1;
- char **strings;
- NEWSGROUP *ngp;
- const char *error;
- char *subbed;
- char *poison;
-
- /* If site already exists, drop it. */
- if (SITEfind(av[0]) != NULL && (p1 = CCdrop(av)) != NULL)
- return p1;
-
- /* Find the named site. */
- length = strlen(av[0]);
- for (strings = SITEreadfile(true), i = 0; (p = strings[i]) != NULL; i++)
- if ((p[length] == NF_FIELD_SEP || p[length] == NF_SUBFIELD_SEP)
- && strncasecmp(p, av[0], length) == 0) {
- p = xstrdup(p);
- break;
- }
- if (p == NULL)
- return CCnosite;
-
- if (p[0] == 'M' && p[1] == 'E' && p[2] == NF_FIELD_SEP)
- sp = &ME;
- else {
- /* Get space for the new site entry, and space for it in all
- * the groups. */
- for (i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Name == NULL)
- break;
- if (i < 0) {
- nSites++;
- Sites = xrealloc(Sites, nSites * sizeof(SITE));
- sp = &Sites[nSites - 1];
- sp->Next = sp->Prev = NOSITE;
- for (i = nGroups, ngp = Groups; --i >= 0; ngp++) {
- ngp->Sites = xrealloc(ngp->Sites, nSites * sizeof(int));
- ngp->Poison = xrealloc(ngp->Poison, nSites * sizeof(int));
- }
- }
- }
-
- /* Parse. */
- subbed = xmalloc(nGroups);
- poison = xmalloc(nGroups);
- error = SITEparseone(p, sp, subbed, poison);
- free(subbed);
- free(poison);
- if (error != NULL) {
- free((void *)p);
- syslog(L_ERROR, "%s bad_newsfeeds %s", av[0], error);
- return "1 Parse error";
- }
-
- if (sp != &ME && (!SITEsetup(sp) || !SITEfunnelpatch()))
- return "1 Startup error";
- SITEforward(sp, "begin");
- return NULL;
-}
-
-
-/*
-** Common code to change a group's flags.
-*/
-static const char *
-CCdochange(NEWSGROUP *ngp, char *Rest)
-{
- int length;
- char *p;
-
- if (ngp->Rest[0] == Rest[0]) {
- length = strlen(Rest);
- if (ngp->Rest[length] == '\n' && strncmp(ngp->Rest, Rest, length) == 0)
- return "0 Group status unchanged";
- }
- if (Mode != OMrunning)
- return CCnotrunning;
-
- p = xstrdup(ngp->Name);
- if (!ICDchangegroup(ngp, Rest)) {
- syslog(L_NOTICE, "%s cant change_group %s to %s", LogName, p, Rest);
- free(p);
- return "1 Change failed (probably can't write active?)";
- }
- syslog(L_NOTICE, "%s change_group %s to %s", LogName, p, Rest);
- free(p);
- return NULL;
-}
-
-
-/*
-** Change the mode of a newsgroup.
-*/
-static const char *
-CCchgroup(char *av[])
-{
- NEWSGROUP *ngp;
- char *Rest;
-
- if ((ngp = NGfind(av[0])) == NULL)
- return CCnogroup;
- Rest = av[1];
- if (Rest[0] != NF_FLAG_ALIAS) {
- Rest[1] = '\0';
- if (CTYPE(isupper, Rest[0]))
- Rest[0] = tolower(Rest[0]);
- }
- return CCdochange(ngp, Rest);
-}
-
-
-/*
-** Cancel a message.
-*/
-const char *
-CCcancel(char *av[])
-{
- ARTDATA Data;
- const char * p, *msgid;
-
- Data.Posted = Data.Arrived = Now.time;
- Data.Expires = 0;
- Data.Feedsite = "?";
- if ((p = CCgetid(av[0], &msgid)) != NULL)
- return p;
-
- Data.HdrContent[HDR__MESSAGE_ID].Value = (char *)msgid;
- Data.HdrContent[HDR__MESSAGE_ID].Length = strlen(msgid);
- if (Mode == OMrunning)
- ARTcancel(&Data, msgid, true);
- else {
- /* If paused, don't try to use the history database since expire may be
- running */
- if (Mode == OMpaused)
- return "1 Server paused";
- if (ThrottledbyIOError)
- return "1 Server throttled";
- /* Possible race condition, but documented in ctlinnd manpage. */
- InndHisOpen();
- ARTcancel(&Data, msgid, true);
- InndHisClose();
- }
- if (innconf->logcancelcomm)
- syslog(L_NOTICE, "%s cancelled %s", LogName, msgid);
- return NULL;
-}
-
-
-/*
-** Syntax-check the newsfeeds file.
-*/
-const char *
-CCcheckfile(char *unused[])
-{
- char **strings;
- char *p;
- int i;
- int errors;
- const char * error;
- SITE fake;
- bool needheaders, needoverview, needpath, needstoredgroup;
- bool needreplicdata;
-
- unused = unused; /* ARGSUSED */
- /* Parse all site entries. */
- strings = SITEreadfile(false);
- fake.Buffer.size = 0;
- fake.Buffer.data = NULL;
- /* save global variables not to be changed */
- needheaders = NeedHeaders;
- needoverview = NeedOverview;
- needpath = NeedPath;
- needstoredgroup = NeedStoredGroup;
- needreplicdata = NeedReplicdata;
- for (errors = 0, i = 0; (p = strings[i]) != NULL; i++) {
- if ((error = SITEparseone(p, &fake, (char *)NULL, (char *)NULL)) != NULL) {
- syslog(L_ERROR, "%s bad_newsfeeds %s", MaxLength(p, p), error);
- errors++;
- }
- SITEfree(&fake);
- }
- free(strings);
- /* restore global variables not to be changed */
- NeedHeaders = needheaders;
- NeedOverview = needoverview;
- NeedPath = needpath;
- NeedStoredGroup = needstoredgroup;
- NeedReplicdata = needreplicdata;
-
- if (errors == 0)
- return NULL;
-
- buffer_resize(&CCreply, SMBUF);
- snprintf(CCreply.data, CCreply.size, "1 Found %d errors -- see syslog",
- errors);
- return CCreply.data;
-}
-
-
-/*
-** Drop a site.
-*/
-static const char *
-CCdrop(char *av[])
-{
- SITE *sp;
- NEWSGROUP *ngp;
- int *ip;
- int idx;
- int i;
- int j;
-
- if ((sp = SITEfind(av[0])) == NULL)
- return CCnosite;
-
- SITEdrop(sp);
-
- /* Loop over all groups, and if the site is in a group, clobber it. */
- for (idx = sp - Sites, i = nGroups, ngp = Groups; --i >= 0; ngp++) {
- for (j = ngp->nSites, ip = ngp->Sites; --j >= 0; ip++)
- if (*ip == idx)
- *ip = NOSITE;
- for (j = ngp->nPoison, ip = ngp->Poison; --j >= 0; ip++)
- if (*ip == idx)
- *ip = NOSITE;
- }
-
- return NULL;
-}
-
-/*
-** Return info on the feeds for one, or all, sites
-*/
-static const char *
-CCfeedinfo(char *av[])
-{
- SITE *sp;
- char *p;
- int i;
-
- buffer_set(&CCreply, "0 ", 2);
- p = av[0];
- if (*p != '\0') {
- if ((sp = SITEfind(p)) == NULL)
- return "1 No such site";
-
- SITEinfo(&CCreply, sp, true);
- while ((sp = SITEfindnext(p, sp)) != NULL)
- SITEinfo(&CCreply, sp, true);
- }
- else
- for (i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Name)
- SITEinfo(&CCreply, sp, false);
-
- buffer_append(&CCreply, "", 1);
- return CCreply.data;
-}
-
-
-static const char *
-CCfilter(char *av[] UNUSED)
-{
-#if defined(DO_TCL)
- char *p;
-
- switch (av[0][0]) {
- default:
- return "1 Bad flag";
- case 'y':
- if (TCLFilterActive)
- return "1 tcl filter already enabled";
- TCLfilter(true);
- break;
- case 'n':
- if (!TCLFilterActive)
- return "1 tcl filter already disabled";
- TCLfilter(false);
- break;
- }
- return NULL;
-#else /* defined(DO_TCL) */
- return "1 TCL filtering support not compiled in";
-#endif /* defined(DO_TCL) */
-}
-
-
-static const char *
-CCperl(char *av[])
-{
-#if defined(DO_PERL)
- switch (av[0][0]) {
- default:
- return "1 Bad flag";
- case 'y':
- if (PerlFilterActive)
- return "1 Perl filter already enabled";
- else if (!PerlFilter(true))
- return "1 Perl filter not defined";
- break;
- case 'n':
- if (!PerlFilterActive)
- return "1 Perl filter already disabled";
- PerlFilter(false);
- break;
- }
- return NULL;
-#else /* defined(DO_PERL) */
- return "1 Perl filtering support not compiled in";
-#endif /* defined(DO_PERL) */
-}
-
-
-static const char *
-CCpython(char *av[] UNUSED)
-{
-#if defined(DO_PYTHON)
- return PYcontrol(av);
-#else /* defined(DO_PYTHON) */
- return "1 Python filtering support not compiled in";
-#endif /* defined(DO_PYTHON) */
-}
-
-
-/*
-** Flush all sites or one site.
-*/
-static const char *
-CCflush(char *av[])
-{
- SITE *sp;
- int i;
- char *p;
-
- p = av[0];
- if (*p == '\0') {
- ICDwrite();
- for (sp = Sites, i = nSites; --i >= 0; sp++)
- SITEflush(sp, true);
- syslog(L_NOTICE, "%s flush_all", LogName);
- }
- else {
- if ((sp = SITEfind(p)) == NULL)
- return CCnosite;
- syslog(L_NOTICE, "%s flush", sp->Name);
- SITEflush(sp, true);
- }
- return NULL;
-}
-
-
-/*
-** Flush the log files.
-*/
-static const char *
-CCflushlogs(char *unused[])
-{
- unused = unused; /* ARGSUSED */
-
- if (Debug)
- return "1 In debug mode";
-
- ICDwrite();
- syslog(L_NOTICE, "%s flushlogs %s", LogName, CCcurrmode());
- ReopenLog(Log);
- ReopenLog(Errlog);
- return NULL;
-}
-
-
-/*
-** Leave paused or throttled mode.
-*/
-static const char *
-CCgo(char *av[])
-{
- static char YES[] = "y";
- char *p;
-
- p = av[0];
- if (Reservation && strcmp(p, Reservation) == 0) {
- free(Reservation);
- Reservation = NULL;
- }
- if (RejectReason && strcmp(p, RejectReason) == 0) {
- free(RejectReason);
- RejectReason = NULL;
- }
-
- if (Mode == OMrunning)
- return "1 Already running";
- if (*p && strcmp(p, ModeReason) != 0)
- return "1 Wrong reason";
-
-#if defined(DO_PERL)
- PLmode(Mode, OMrunning, p);
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- PYmode(Mode, OMrunning, p);
-#endif /* defined(DO_PYTHON) */
-
- free(ModeReason);
- ModeReason = NULL;
- Mode = OMrunning;
- ThrottledbyIOError = false;
-
- if (NNRPReason && !innconf->readerswhenstopped) {
- av[0] = YES;
- av[1] = p;
- CCreaders(av);
- }
- if (ErrorCount < 0)
- ErrorCount = IO_ERROR_COUNT;
- InndHisOpen();
- syslog(L_NOTICE, "%s running", LogName);
- if (ICDneedsetup)
- ICDsetup(true);
- SCHANwakeup(&Mode);
- return NULL;
-}
-
-
-/*
-** Hangup a channel.
-*/
-static const char *
-CChangup(char *av[])
-{
- CHANNEL *cp;
- int fd;
- char *p;
- int i;
-
- /* Parse the argument, a channel number. */
- for (p = av[0], fd = 0; *p; p++) {
- if (!CTYPE(isdigit, *p))
- return "1 Bad channel number";
- fd = fd * 10 + *p - '0';
- }
-
- /* Loop over all channels for the desired one. */
- for (i = 0; (cp = CHANiter(&i, CTany)) != NULL; )
- if (cp->fd == fd) {
- p = CHANname(cp);
- switch (cp->Type) {
- default:
- snprintf(CCreply.data, CCreply.size, "1 Can't close %s", p);
- return CCreply.data;
- case CTexploder:
- case CTprocess:
- case CTfile:
- case CTnntp:
- case CTreject:
- syslog(L_NOTICE, "%s hangup", p);
- CHANclose(cp, p);
- return NULL;
- }
- }
- return "1 Not active";
-}
-
-
-/*
-** Return our operating mode.
-*/
-static const char *
-CCmode(char *unused[] UNUSED)
-{
- char *p;
- int i;
- int h;
- char buff[BUFSIZ];
-#if defined(DO_PERL)
- char *stats;
-#endif /* defined(DO_PERL) */
-
- /* FIXME: We assume here that BUFSIZ is >= 512, and that none of
- * ModeReason, RejectReason, Reservation, NNRPReason, or the Perl filter
- * statistics are longer than MAX_REASON_LEN bytes (or actually, the
- * average of their lengths is <= MAX_REASON_LEN). If this is not true,
- * the sprintf's/strcpy's below are likely to overflow buff with somewhat
- * nasty consequences...
- */
-
- p = buff;
- p += strlen(strcpy(buff, "0 Server "));
-
- /* Server's mode. */
- switch (Mode) {
- default:
- sprintf(p, "Unknown %d", Mode);
- p += strlen(p);
- break;
- case OMrunning:
- p += strlen(strcpy(p, "running"));
- break;
- case OMpaused:
- p += strlen(strcpy(p, "paused "));
- p += strlen(strcpy(p, ModeReason));
- break;
- case OMthrottled:
- p += strlen(strcpy(p, "throttled "));
- p += strlen(strcpy(p, ModeReason));
- break;
- }
- *p++ = '\n';
- if (RejectReason) {
- p += strlen(strcpy(p, "Rejecting "));
- p += strlen(strcpy(p, RejectReason));
- }
- else
- p += strlen(strcpy(p, "Allowing remote connections"));
-
- /* Server parameters. */
- for (i = 0, h = 0; CHANiter(&h, CTnntp) != NULL; )
- i++;
- *p++ = '\n';
- sprintf(p, "Parameters c %ld i %ld (%d) l %ld o %d t %ld H %d T %d X %d %s %s",
- innconf->artcutoff, innconf->maxconnections, i,
- innconf->maxartsize, MaxOutgoing, (long)TimeOut.tv_sec,
- RemoteLimit, RemoteTotal, (int) RemoteTimer,
- innconf->xrefslave ? "slave" : "normal",
- AnyIncoming ? "any" : "specified");
- p += strlen(p);
-
- /* Reservation. */
- *p++ = '\n';
- if (Reservation) {
- sprintf(p, "Reserved %s", Reservation);
- p += strlen(p);
- }
- else
- p += strlen(strcpy(p, "Not reserved"));
-
- /* Newsreaders. */
- *p++ = '\n';
- p += strlen(strcpy(p, "Readers "));
- if (innconf->readerswhenstopped)
- p += strlen(strcpy(p, "independent "));
- else
- p += strlen(strcpy(p, "follow "));
- if (NNRPReason == NULL)
- p += strlen(strcpy(p, "enabled"));
- else {
- sprintf(p, "disabled %s", NNRPReason);
- p += strlen(p);
- }
-
-#if defined(DO_TCL)
- *p++ = '\n';
- p += strlen(strcpy(p, "Tcl filtering "));
- if (TCLFilterActive)
- p += strlen(strcpy(p, "enabled"));
- else
- p += strlen(strcpy(p, "disabled"));
-#endif /* defined(DO_TCL) */
-
-#if defined(DO_PERL)
- *p++ = '\n';
- p += strlen(strcpy(p, "Perl filtering "));
- if (PerlFilterActive)
- p += strlen(strcpy(p, "enabled"));
- else
- p += strlen(strcpy(p, "disabled"));
-
- /* Perl filter status. */
- stats = PLstats();
- if (stats != NULL) {
- *p++ = '\n';
- p += strlen(strcpy(p, "Perl filter stats: "));
- p += strlen(strcpy(p, stats));
- free(stats);
- }
-#endif /* defined(DO_PERL) */
-
-#if defined(DO_PYTHON)
- *p++ = '\n';
- p += strlen(strcpy(p, "Python filtering "));
- if (PythonFilterActive)
- p += strlen(strcpy(p, "enabled"));
- else
- p += strlen(strcpy(p, "disabled"));
-#endif /* defined(DO_PYTHON) */
-
- buffer_set(&CCreply, buff, strlen(buff) + 1);
- return CCreply.data;
-}
-
-
-/*
-** Log our operating mode (via syslog).
-*/
-static const char *
-CClogmode(char *unused[])
-{
- unused = unused; /* ARGSUSED */
- syslog(L_NOTICE, "%s servermode %s", LogName, CCcurrmode());
- return NULL;
-}
-
-
-/*
-** Name the channels. ("Name the bats -- simple names.")
-*/
-static const char *
-CCname(char *av[])
-{
- static char NL[] = "\n";
- static char NIL[] = "\0";
- char buff[SMBUF];
- CHANNEL *cp;
- char *p;
- int count;
- int i;
-
- p = av[0];
- if (*p != '\0') {
- if ((cp = CHANfromdescriptor(atoi(p))) == NULL)
- return xstrdup(CCnochannel);
- snprintf(CCreply.data, CCreply.size, "0 %s", CHANname(cp));
- return CCreply.data;
- }
- buffer_set(&CCreply, "0 ", 2);
- for (count = 0, i = 0; (cp = CHANiter(&i, CTany)) != NULL; ) {
- if (cp->Type == CTfree)
- continue;
- if (++count > 1)
- buffer_append(&CCreply, NL, 1);
- p = CHANname(cp);
- buffer_append(&CCreply, p, strlen(p));
- switch (cp->Type) {
- case CTremconn:
- sprintf(buff, ":remconn::");
- break;
- case CTreject:
- sprintf(buff, ":reject::");
- break;
- case CTnntp:
- sprintf(buff, ":%s:%ld:%s",
- cp->State == CScancel ? "cancel" : "nntp",
- (long) Now.time - cp->LastActive,
- (cp->MaxCnx > 0 && cp->ActiveCnx == 0) ? "paused" : "");
- break;
- case CTlocalconn:
- sprintf(buff, ":localconn::");
- break;
- case CTcontrol:
- sprintf(buff, ":control::");
- break;
- case CTfile:
- sprintf(buff, "::");
- break;
- case CTexploder:
- sprintf(buff, ":exploder::");
- break;
- case CTprocess:
- sprintf(buff, ":");
- break;
- default:
- sprintf(buff, ":unknown::");
- break;
- }
- p = buff;
- buffer_append(&CCreply, p, strlen(p));
- }
- buffer_append(&CCreply, NIL, 1);
- return CCreply.data;
-}
-
-
-/*
-** Create a newsgroup.
-*/
-static const char *
-CCnewgroup(char *av[])
-{
- static char *TIMES = NULL;
- static char WHEN[] = "updating active.times";
- int fd;
- char *p;
- NEWSGROUP *ngp;
- char *Name;
- char *Rest;
- const char * who;
- char *buff;
- int oerrno;
- size_t length;
-
- if (TIMES == NULL)
- TIMES = concatpath(innconf->pathdb, _PATH_ACTIVETIMES);
-
- Name = av[0];
- if (Name[0] == '.' || strspn(Name, "0123456789") == strlen(Name))
- return "1 Illegal newsgroup name";
- for (p = Name; *p; p++)
- if (*p == '.') {
- if (p[1] == '.' || p[1] == '\0')
- return "1 Double or trailing period in newsgroup name";
- }
- else if (ISWHITE(*p) || *p == ':' || *p == '!' || *p == '/')
- return "1 Illegal character in newsgroup name";
-
- Rest = av[1];
- if (Rest[0] != NF_FLAG_ALIAS) {
- Rest[1] = '\0';
- if (CTYPE(isupper, Rest[0]))
- Rest[0] = tolower(Rest[0]);
- }
- if (strlen(Name) + strlen(Rest) > SMBUF - 24)
- return "1 Name too long";
-
- if ((ngp = NGfind(Name)) != NULL)
- return CCdochange(ngp, Rest);
-
- if (Mode == OMthrottled && ThrottledbyIOError)
- return "1 server throttled";
-
- /* Update the log of groups created. Don't use stdio because SunOS
- * 4.1 has broken libc which can't handle fd's greater than 127. */
- if ((fd = open(TIMES, O_WRONLY | O_APPEND | O_CREAT, 0664)) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant open %s %m", LogName, TIMES);
- IOError(WHEN, oerrno);
- }
- else {
- who = av[2];
- if (*who == '\0')
- who = NEWSMASTER;
-
- length = snprintf(NULL, 0, "%s %ld %s\n", Name, (long) Now.time, who) + 1;
- buff = xmalloc(length);
- snprintf(buff, length, "%s %ld %s\n", Name, (long) Now.time, who);
- if (xwrite(fd, buff, strlen(buff)) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write %s %m", LogName, TIMES);
- IOError(WHEN, oerrno);
- }
-
- free(buff);
-
- if (close(fd) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant close %s %m", LogName, TIMES);
- IOError(WHEN, oerrno);
- }
- }
-
- /* Update the in-core data. */
- if (!ICDnewgroup(Name, Rest))
- return "1 Failed";
- syslog(L_NOTICE, "%s newgroup %s as %s", LogName, Name, Rest);
-
- return NULL;
-}
-
-
-/*
-** Parse and set a boolean flag.
-*/
-static bool
-CCparsebool(char name, bool *bp, char value)
-{
- switch (value) {
- default:
- return false;
- case 'y':
- *bp = false;
- break;
- case 'n':
- *bp = true;
- break;
- }
- syslog(L_NOTICE, "%s changed -%c %c", LogName, name, value);
- return true;
-}
-
-
-/*
-** Change a running parameter.
-*/
-static const char *
-CCparam(char *av[])
-{
- static char BADVAL[] = "1 Bad value";
- char *p;
- int temp;
-
- p = av[1];
- switch (av[0][0]) {
- default:
- return "1 Unknown parameter";
- case 'a':
- if (!CCparsebool('a', (bool *)&AnyIncoming, *p))
- return BADVAL;
- break;
- case 'c':
- innconf->artcutoff = atoi(p);
- syslog(L_NOTICE, "%s changed -c %ld", LogName, innconf->artcutoff);
- break;
- case 'i':
- innconf->maxconnections = atoi(p);
- syslog(L_NOTICE, "%s changed -i %ld", LogName, innconf->maxconnections);
- break;
- case 'l':
- innconf->maxartsize = atol(p);
- syslog(L_NOTICE, "%s changed -l %ld", LogName, innconf->maxartsize);
- break;
- case 'n':
- if (!CCparsebool('n', (bool *)&innconf->readerswhenstopped, *p))
- return BADVAL;
- break;
- case 'o':
- MaxOutgoing = atoi(p);
- syslog(L_NOTICE, "%s changed -o %d", LogName, MaxOutgoing);
- break;
- case 't':
- TimeOut.tv_sec = atol(p);
- syslog(L_NOTICE, "%s changed -t %ld", LogName, (long)TimeOut.tv_sec);
- break;
- case 'H':
- RemoteLimit = atoi(p);
- syslog(L_NOTICE, "%s changed -H %d", LogName, RemoteLimit);
- break;
- case 'T':
- temp = atoi(p);
- if (temp > REMOTETABLESIZE) {
- syslog(L_NOTICE, "%s -T must be lower than %d",
- LogName, REMOTETABLESIZE+1);
- temp = REMOTETABLESIZE;
- }
- syslog(L_NOTICE, "%s changed -T from %d to %d",
- LogName, RemoteTotal, temp);
- RemoteTotal = temp;
- break;
- case 'X':
- RemoteTimer = (time_t) atoi(p);
- syslog(L_NOTICE, "%s changed -X %d", LogName, (int) RemoteTimer);
- break;
- }
- return NULL;
-}
-
-
-/*
-** Common code to implement a pause or throttle.
-*/
-const char *
-CCblock(OPERATINGMODE NewMode, char *reason)
-{
- static char NO[] = "n";
- char * av[2];
-
- if (*reason == '\0')
- return CCnoreason;
-
- if (strlen(reason) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe */
- return CCbigreason;
-
- if (Reservation) {
- if (strcmp(reason, Reservation) != 0) {
- snprintf(CCreply.data, CCreply.size, "1 Reserved \"%s\"",
- Reservation);
- return CCreply.data;
- }
- free(Reservation);
- Reservation = NULL;
- }
-
-#if defined(DO_PERL)
- PLmode(Mode, NewMode, reason);
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- PYmode(Mode, NewMode, reason);
-#endif /* defined(DO_PYTHON) */
-
- ICDwrite();
- InndHisClose();
- Mode = NewMode;
- if (ModeReason)
- free(ModeReason);
- ModeReason = xstrdup(reason);
- if (NNRPReason == NULL && !innconf->readerswhenstopped) {
- av[0] = NO;
- av[1] = ModeReason;
- CCreaders(av);
- }
- syslog(L_NOTICE, "%s %s %s",
- LogName, NewMode == OMpaused ? "paused" : "throttled", reason);
- return NULL;
-}
-
-
-/*
-** Enter paused mode.
-*/
-static const char *
-CCpause(char *av[])
-{
- switch (Mode) {
- case OMrunning:
- return CCblock(OMpaused, av[0]);
- case OMpaused:
- return "1 Already paused";
- case OMthrottled:
- return "1 Already throttled";
- }
- return "1 Unknown mode";
-}
-
-
-/*
-** Allow or disallow newsreaders.
-*/
-static const char *
-CCreaders(char *av[])
-{
- const char *p;
-
- switch (av[0][0]) {
- default:
- return "1 Bad flag";
- case 'y':
- if (NNRPReason == NULL)
- return "1 Already allowing readers";
- p = av[1];
- if (*p && strcmp(p, NNRPReason) != 0)
- return "1 Wrong reason";
- free(NNRPReason);
- NNRPReason = NULL;
- break;
- case 'n':
- if (NNRPReason)
- return "1 Already not allowing readers";
- p = av[1];
- if (*p == '\0')
- return CCnoreason;
- if (strlen(p) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe */
- return CCbigreason;
- NNRPReason = xstrdup(p);
- break;
- }
- return NULL;
-}
-
-
-/*
-** Re-exec ourselves.
-*/
-static const char *
-CCxexec(char *av[])
-{
- char *inndstart;
- char *p;
- int i;
-
- if (CCargv == NULL)
- return "1 no argv!";
-
- inndstart = concatpath(innconf->pathbin, "inndstart");
- /* Get the pathname. */
- p = av[0];
- if (*p == '\0' || strcmp(p, "innd") == 0 || strcmp(p, "inndstart") == 0)
- CCargv[0] = inndstart;
- else
- return "1 Bad value";
-
- JustCleanup();
- syslog(L_NOTICE, "%s execv %s", LogName, CCargv[0]);
-
- /* Close all fds to protect possible fd leaking accross successive innds. */
- for (i=3; i<30; i++)
- close(i);
-
- execv(CCargv[0], CCargv);
- syslog(L_FATAL, "%s cant execv %s %m", LogName, CCargv[0]);
- _exit(1);
- /* NOTREACHED */
- return "1 Exit failed";
-}
-
-/*
-** Reject remote readers.
-*/
-static const char *
-CCreject(char *av[])
-{
- if (RejectReason)
- return "1 Already rejecting";
- if (strlen(av[0]) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe */
- return CCbigreason;
- RejectReason = xstrdup(av[0]);
- return NULL;
-}
-
-
-/*
-** Re-read all in-core data.
-*/
-static const char *
-CCreload(char *av[])
-{
- static char BADSCHEMA[] = "1 Can't read schema";
-#if defined(DO_PERL)
- static char BADPERLRELOAD[] = "1 Failed to define filter_art" ;
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- static char BADPYRELOAD[] = "1 Failed to reload filter_innd.py" ;
-#endif /* defined(DO_PYTHON) */
- const char *p;
- char *path;
-
- p = av[0];
- if (*p == '\0' || strcmp(p, "all") == 0) {
- SITEflushall(false);
- if (Mode == OMrunning)
- InndHisClose();
- RCreadlist();
- if (Mode == OMrunning)
- InndHisOpen();
- ICDwrite();
- ICDsetup(true);
- if (!ARTreadschema())
- return BADSCHEMA;
-#if defined(DO_TCL)
- TCLreadfilter();
-#endif /* defined(DO_TCL) */
-#if defined(DO_PERL)
- path = concatpath(innconf->pathfilter, _PATH_PERL_FILTER_INND);
- PERLreadfilter(path, "filter_art") ;
- free(path);
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- syslog(L_NOTICE, "reloading pyfilter");
- PYreadfilter();
- syslog(L_NOTICE, "reloaded pyfilter OK");
-#endif /* DO_PYTHON */
- p = "all";
- }
- else if (strcmp(p, "active") == 0 || strcmp(p, "newsfeeds") == 0) {
- SITEflushall(false);
- ICDwrite();
- ICDsetup(true);
- }
- else if (strcmp(p, "history") == 0) {
- if (Mode != OMrunning)
- return CCnotrunning;
- InndHisClose();
- InndHisOpen();
- }
- else if (strcmp(p, "incoming.conf") == 0)
- RCreadlist();
- else if (strcmp(p, "overview.fmt") == 0) {
- if (!ARTreadschema())
- return BADSCHEMA;
- }
-#if 0 /* we should check almost all innconf parameter, but the code
- is still incomplete for innd, so just commented out */
- else if (strcmp(p, "inn.conf") == 0) {
- struct innconf *saved;
-
- saved = innconf;
- innconf = NULL;
- if (innconf_read(NULL))
- innconf_free(saved);
- else {
- innconf = saved;
- return "1 Reload of inn.conf failed";
- }
- if (innconf->pathhost == NULL) {
- syslog(L_FATAL, "%s No pathhost set", LogName);
- exit(1);
- }
- free(Path.Data);
- Path.Used = strlen(innconf->pathhost) + 1;
- Path.Data = xmalloc(Path.Used + 1);
- sprintf(Path.Data, "%s!", innconf->pathhost);
- if (Pathalias.Used > 0)
- free(Pathalias.Data);
- if (innconf->pathalias == NULL) {
- Pathalias.Used = 0;
- Pathalias.Data = NULL;
- } else {
- Pathalias.Used = strlen(innconf->pathalias) + 1;
- Pathalias.Data = xmalloc(Pathalias.Used + 1);
- sprintf(Pathalias.Data, "%s!", innconf->pathalias);
- }
- if (Pathcluster.Used > 0)
- free(Pathcluster.Data);
- if (innconf->pathcluster == NULL) {
- Pathcluster.Used = 0;
- Pathcluster.Data = NULL;
- } else {
- Pathcluster.Used = strlen(innconf->pathcluster) + 1;
- Pathcluster.Data = xmalloc(Pathcluster.Used + 1);
- sprintf(Pathcluster.Data, "%s!", innconf->pathcluster);
- }
- }
-#endif
-#if defined(DO_TCL)
- else if (strcmp(p, "filter.tcl") == 0) {
- TCLreadfilter();
- }
-#endif /* defined(DO_TCL) */
-#if defined(DO_PERL)
- else if (strcmp(p, "filter.perl") == 0) {
- path = concatpath(innconf->pathfilter, _PATH_PERL_FILTER_INND);
- if (!PERLreadfilter(path, "filter_art"))
- return BADPERLRELOAD;
- }
-#endif /* defined(DO_PERL) */
-#if defined(DO_PYTHON)
- else if (strcmp(p, "filter.python") == 0) {
- if (!PYreadfilter())
- return BADPYRELOAD;
- }
-#endif /* defined(DO_PYTHON) */
- else
- return "1 Unknown reload type";
-
- syslog(L_NOTICE, "%s reload %s %s", LogName, p, av[1]);
- return NULL;
-}
-
-
-/*
-** Renumber the active file.
-*/
-static const char *
-CCrenumber(char *av[])
-{
- static char CANTRENUMBER[] = "1 Failed (see syslog)";
- char *p;
- NEWSGROUP *ngp;
-
- if (Mode != OMrunning)
- return CCnotrunning;
- if (ICDneedsetup)
- return "1 Must first reload newsfeeds";
- p = av[0];
- if (*p) {
- if ((ngp = NGfind(p)) == NULL)
- return CCnogroup;
- if (!NGrenumber(ngp))
- return CANTRENUMBER;
- }
- else if (!ICDrenumberactive())
- return CANTRENUMBER;
- return NULL;
-}
-
-
-/*
-** Reserve a lock.
-*/
-static const char *
-CCreserve(char *av[])
-{
- char *p;
-
- if (Mode != OMrunning)
- return CCnotrunning;
- p = av[0];
- if (*p) {
- /* Trying to make a reservation. */
- if (Reservation)
- return "1 Already reserved";
- if (strlen(p) > MAX_REASON_LEN) /* MAX_REASON_LEN is as big as is safe */
- return CCbigreason;
- Reservation = xstrdup(p);
- }
- else {
- /* Trying to remove a reservation. */
- if (Reservation == NULL)
- return "1 Not reserved";
- free(Reservation);
- Reservation = NULL;
- }
- return NULL;
-}
-
-
-/*
-** Remove a newsgroup.
-*/
-static const char *
-CCrmgroup(char *av[])
-{
- NEWSGROUP *ngp;
-
- if ((ngp = NGfind(av[0])) == NULL)
- return CCnogroup;
-
- if (Mode == OMthrottled && ThrottledbyIOError)
- return "1 server throttled";
-
- /* Update the in-core data. */
- if (!ICDrmgroup(ngp))
- return "1 Failed";
- syslog(L_NOTICE, "%s rmgroup %s", LogName, av[0]);
- return NULL;
-}
-
-
-/*
-** Send a command line to an exploder.
-*/
-static const char *
-CCsend(char *av[])
-{
- SITE *sp;
-
- if ((sp = SITEfind(av[0])) == NULL)
- return CCnosite;
- if (sp->Type != FTexploder)
- return CCwrongtype;
- SITEwrite(sp, av[1]);
- return NULL;
-}
-
-
-/*
-** Shut down the system.
-*/
-static const char *
-CCshutdown(char *av[])
-{
- syslog(L_NOTICE, "%s shutdown %s", LogName, av[0]);
- CleanupAndExit(0, av[0]);
- /* NOTREACHED */
- return "1 Exit failed";
-}
-
-
-/*
-** Send a signal to a site's feed.
-*/
-static const char *
-CCsignal(char *av[])
-{
- SITE *sp;
- char *p;
- int s;
- int oerrno;
-
- /* Parse the signal. */
- p = av[0];
- if (*p == '-')
- p++;
- if (strcasecmp(p, "HUP") == 0)
- s = SIGHUP;
- else if (strcasecmp(p, "INT") == 0)
- s = SIGINT;
- else if (strcasecmp(p, "TERM") == 0)
- s = SIGTERM;
- else if ((s = atoi(p)) <= 0)
- return "1 Invalid signal";
-
- /* Parse the site. */
- p = av[1];
- if ((sp = SITEfind(p)) == NULL)
- return CCnosite;
- if (sp->Type != FTchannel && sp->Type != FTexploder)
- return CCwrongtype;
- if (sp->Process < 0)
- return "1 Site has no process";
-
- /* Do it. */
- if (kill(sp->pid, s) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant kill %ld %d site %s, %m", LogName,
- (long) sp->pid, s, p);
- snprintf(CCreply.data, CCreply.size, "1 Can't signal process %ld, %s",
- (long) sp->pid, strerror(oerrno));
- return CCreply.data;
- }
-
- return NULL;
-}
-
-
-/*
-** Enter throttled mode.
-*/
-static const char *
-CCthrottle(char *av[])
-{
- char *p;
-
- p = av[0];
- switch (Mode) {
- case OMpaused:
- if (*p && strcmp(p, ModeReason) != 0)
- return "1 Already paused";
- /* FALLTHROUGH */
- case OMrunning:
- return CCblock(OMthrottled, p);
- case OMthrottled:
- return "1 Already throttled";
- }
- return "1 unknown mode";
-}
-
-/*
-** Turn on or off performance monitoring
-*/
-static const char *
-CCtimer(char *av[])
-{
- int value;
- char *p;
-
- if (strcmp(av[0], "off") == 0)
- value = 0;
- else {
- for (p = av[0]; *p; p++) {
- if (!CTYPE(isdigit, *p))
- return "1 parameter should be a number or 'off'";
- }
- value = atoi(av[0]);
- }
- innconf->timer = value;
- if (innconf->timer)
- TMRinit(TMR_MAX);
- else
- TMRinit(0);
- return NULL;
-}
-
-/*
-** Log into filename some history stats
-*/
-static const char *
-CCstathist(char *av[])
-{
- if (strcmp(av[0], "off") == 0)
- HISlogclose();
- else
- HISlogto(av[0]);
- return NULL;
-}
-
-/*
-** Turn innd status creation on or off
-*/
-static const char *
-CCstatus(char *av[])
-{
- int value;
- char *p;
-
- if (strcmp(av[0], "off") == 0)
- value = 0;
- else {
- for (p = av[0]; *p; p++) {
- if (!CTYPE(isdigit, *p))
- return "1 parameter should be a number or 'off'";
- }
- value = atoi(av[0]);
- }
- innconf->status = value;
- return NULL;
-}
-
-/*
-** Add or remove tracing.
-*/
-static const char *
-CCtrace(char *av[])
-{
- char *p;
- bool Flag;
- const char * word;
- CHANNEL *cp;
-
- /* Parse the flag. */
- p = av[1];
- switch (p[0]) {
- default: return "1 Bad trace flag";
- case 'y': case 'Y': Flag = true; word = "on"; break;
- case 'n': case 'N': Flag = false; word = "off"; break;
- }
-
- /* Parse what's being traced. */
- p = av[0];
- switch (*p) {
- default:
- return "1 Bad trace item";
- case 'i': case 'I':
- Tracing = Flag;
- syslog(L_NOTICE, "%s trace innd %s", LogName, word);
- break;
- case 'n': case 'N':
- NNRPTracing = Flag;
- syslog(L_NOTICE, "%s trace nnrpd %s", LogName, word);
- break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if ((cp = CHANfromdescriptor(atoi(p))) == NULL)
- return CCnochannel;
- CHANtracing(cp, Flag);
- break;
- }
- return NULL;
-}
-
-\f
-
-/*
-** Split up the text into fields and stuff them in argv. Return the
-** number of elements or -1 on error.
-*/
-static int
-CCargsplit(char *p, char *end, char **argv, int size)
-{
- char **save;
-
- for (save = argv, *argv++ = p, size--; p < end; p++)
- if (*p == SC_SEP) {
- if (--size <= 0)
- return -1;
- *p = '\0';
- *argv++ = p + 1;
- }
- *argv = NULL;
- return argv - save;
-}
-
-
-/*
-** Read function. Read and process the message.
-*/
-static void
-CCreader(CHANNEL *cp)
-{
- static char TOOLONG[] = "0 Reply too long for server to send";
- CCDISPATCH *dp;
- const char * p;
- char *q;
- ICC_MSGLENTYPE bufflen;
- ICC_PROTOCOLTYPE protocol ;
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- struct sockaddr_un client;
-#else
- int written;
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
- int i;
- char buff[BIG_BUFFER + 2];
- char copy[BIG_BUFFER + 2];
- char *argv[SC_MAXFIELDS + 2];
- int argc;
- int len;
- char *tbuff ;
-
- if (cp != CCchan) {
- syslog(L_ERROR, "%s internal CCreader wrong channel 0x%p not 0x%p",
- LogName, (void *)cp, (void *)CCchan);
- return;
- }
-
-#if defined (HAVE_UNIX_DOMAIN_SOCKETS)
-
- i = RECVorREAD(CCchan->fd, buff, BIG_BUFFER) ;
- if (i < 0) {
- syslog(L_ERROR, "%s cant recv CCreader %m", LogName);
- return;
- } else if (i == 0) {
- syslog(L_ERROR, "%s cant recv CCreader empty", LogName);
- return;
- } else if (i < (int)HEADER_SIZE) {
- syslog(L_ERROR, "%s cant recv CCreader header-length %m", LogName);
- return;
- }
-
- memcpy (&protocol,buff,sizeof (protocol)) ;
- memcpy (&bufflen,buff + sizeof (protocol),sizeof (bufflen)) ;
- bufflen = ntohs (bufflen) ;
-
- if (i != bufflen) {
- syslog(L_ERROR, "%s cant recv CCreader short-read %m", LogName);
- return;
- }
-
- i -= HEADER_SIZE ;
- memmove (buff,buff + HEADER_SIZE,i) ;
- buff[i] = '\0';
-
- if (protocol != ICC_PROTOCOL_1) {
- syslog(L_ERROR, "%s CCreader protocol mismatch", LogName) ;
- return ;
- }
-
-#else /* defined (HAVE_UNIX_DOMAIN_SOCKETS) */
-
- i = RECVorREAD(CCchan->fd, buff, HEADER_SIZE) ;
- if (i < 0) {
- syslog(L_ERROR, "%s cant read CCreader header %m", LogName);
- return;
- } else if (i == 0) {
- syslog(L_ERROR, "%s cant read CCreader header empty", LogName);
- return;
- } else if (i != HEADER_SIZE) {
- syslog(L_ERROR, "%s cant read CCreader header-length %m", LogName);
- return;
- }
-
- memcpy (&protocol,buff,sizeof (protocol)) ;
- memcpy (&bufflen,buff + sizeof (protocol),sizeof (bufflen)) ;
- bufflen = ntohs (bufflen);
- if (bufflen < HEADER_SIZE || bufflen > BIG_BUFFER) {
- syslog(L_ERROR, "%s cant read CCreader bad length", LogName);
- return;
- }
- bufflen -= HEADER_SIZE ;
-
- i = RECVorREAD(CCchan->fd, buff, bufflen) ;
-
- if (i < 0) {
- syslog(L_ERROR, "%s cant read CCreader buffer %m", LogName);
- return;
- } else if (i == 0) {
- syslog(L_ERROR, "%s cant read CCreader buffer empty", LogName);
- return;
- } else if (i != bufflen) {
- syslog(L_ERROR, "%s cant read CCreader buffer-length %m", LogName);
- return;
- }
-
- buff[i] = '\0';
-
- if (protocol != ICC_PROTOCOL_1) {
- syslog(L_ERROR, "%s CCreader protocol mismatch", LogName) ;
- return ;
- }
-
-#endif /* defined (HAVE_UNIX_DOMAIN_SOCKETS) */
-
- /* Copy to a printable buffer, and log. */
- strcpy(copy, buff);
- for (p = NULL, q = copy; *q; q++)
- if (*q == SC_SEP) {
- *q = ':';
- if (p == NULL)
- p = q + 1;
- }
- syslog(L_CC_CMD, "%s", p ? p : copy);
-
- /* Split up the fields, get the command letter. */
- if ((argc = CCargsplit(buff, &buff[i], argv, ARRAY_SIZE(argv))) < 2
- || argc == ARRAY_SIZE(argv)) {
- syslog(L_ERROR, "%s bad_fields CCreader", LogName);
- return;
- }
- p = argv[1];
- i = *p;
-
- /* Dispatch to the command function. */
- for (argc -= 2, dp = CCcommands; dp < ARRAY_END(CCcommands); dp++)
- if (i == dp->Name) {
- if (argc != dp->argc)
- p = "1 Wrong number of parameters";
- else
- p = (*dp->Function)(&argv[2]);
- break;
- }
- if (dp == ARRAY_END(CCcommands)) {
- syslog(L_NOTICE, "%s bad_message %c", LogName, i);
- p = "1 Bad command";
- }
- else if (p == NULL)
- p = "0 Ok";
-
- /* Build the reply address and send the reply. */
- len = strlen(p) + HEADER_SIZE ;
- tbuff = xmalloc(len + 1);
-
- protocol = ICC_PROTOCOL_1 ;
- memcpy (tbuff,&protocol,sizeof (protocol)) ;
- tbuff += sizeof (protocol) ;
-
- bufflen = htons (len) ;
- memcpy (tbuff,&bufflen,sizeof (bufflen)) ;
- tbuff += sizeof (bufflen) ;
-
- strcpy (tbuff,p) ;
- tbuff -= HEADER_SIZE ;
-
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- memset(&client, 0, sizeof client);
- client.sun_family = AF_UNIX;
- strcpy(client.sun_path, argv[0]);
- if (sendto(CCwriter, tbuff, len, 0,
- (struct sockaddr *) &client, SUN_LEN(&client)) < 0) {
- i = errno;
- syslog(i == ENOENT ? L_NOTICE : L_ERROR,
- "%s cant sendto CCreader bytes %d %m", LogName, len);
- if (i == EMSGSIZE)
- sendto(CCwriter, TOOLONG, strlen(TOOLONG), 0,
- (struct sockaddr *) &client, SUN_LEN(&client));
- }
-#else
- if ((i = open(argv[0], O_WRONLY | O_NDELAY)) < 0)
- syslog(L_ERROR, "%s cant open %s %m", LogName, argv[0]);
- else {
- if ((written = write(i, tbuff, len)) != len)
- if (written < 0)
- syslog(L_ERROR, "%s cant write %s %m", LogName, argv[0]);
- else
- syslog(L_ERROR, "%s cant write %s", LogName, argv[0]);
- if (close(i) < 0)
- syslog(L_ERROR, "%s cant close %s %m", LogName, argv[0]);
- }
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
- free (tbuff) ;
-}
-
-
-/*
-** Called when a write-in-progress is done on the channel. Shouldn't happen.
-*/
-static void
-CCwritedone(CHANNEL *unused)
-{
- unused = unused; /* ARGSUSED */
- syslog(L_ERROR, "%s internal CCwritedone", LogName);
-}
-
-
-/*
-** Create the channel.
-*/
-void
-CCsetup(void)
-{
- int i;
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- struct sockaddr_un server;
- int size = 65535;
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-
- if (CCpath == NULL)
- CCpath = concatpath(innconf->pathrun, _PATH_NEWSCONTROL);
- /* Remove old detritus. */
- if (unlink(CCpath) < 0 && errno != ENOENT) {
- syslog(L_FATAL, "%s cant unlink %s %m", LogName, CCpath);
- exit(1);
- }
-
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- /* Create a socket and name it. */
- if ((i = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- syslog(L_FATAL, "%s cant socket %s %m", LogName, CCpath);
- exit(1);
- }
- memset(&server, 0, sizeof server);
- server.sun_family = AF_UNIX;
- strcpy(server.sun_path, CCpath);
- if (bind(i, (struct sockaddr *) &server, SUN_LEN(&server)) < 0) {
- syslog(L_FATAL, "%s cant bind %s %m", LogName, CCpath);
- exit(1);
- }
-
- /* Create an unbound socket to reply on. */
- if ((CCwriter = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- syslog(L_FATAL, "%s cant socket unbound %m", LogName);
- exit(1);
- }
-
- /* Increase the buffer size for the Unix domain socket */
- if (setsockopt(CCwriter, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0)
- syslog(L_ERROR, "%s cant setsockopt %m", LogName);
-#else
- /* Create a named pipe and open it. */
- if (mkfifo(CCpath, 0666) < 0) {
- syslog(L_FATAL, "%s cant mkfifo %s %m", LogName, CCpath);
- exit(1);
- }
- if ((i = open(CCpath, O_RDWR)) < 0) {
- syslog(L_FATAL, "%s cant open %s %m", LogName, CCpath);
- exit(1);
- }
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-
- CCchan = CHANcreate(i, CTcontrol, CSwaiting, CCreader, CCwritedone);
- syslog(L_NOTICE, "%s ccsetup %s", LogName, CHANname(CCchan));
- RCHANadd(CCchan);
-
- buffer_resize(&CCreply, SMBUF);
-
- /*
- * Catch SIGUSR1 so that we can recreate the control channel when
- * needed (i.e. something has deleted our named socket.
- */
-#if defined(SIGUSR1)
- xsignal(SIGUSR1, CCresetup);
-#endif /* defined(SIGUSR1) */
-}
-
-
-/*
-** Cleanly shut down the channel.
-*/
-void
-CCclose(void)
-{
- CHANclose(CCchan, CHANname(CCchan));
- CCchan = NULL;
- if (unlink(CCpath) < 0)
- syslog(L_ERROR, "%s cant unlink %s %m", LogName, CCpath);
- free(CCpath);
- CCpath = NULL;
- free(CCreply.data);
- CCreply.data = NULL;
- CCreply.size = 0;
- CCreply.used = 0;
- CCreply.left = 0;
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- if (close(CCwriter) < 0)
- syslog(L_ERROR, "%s cant close unbound %m", LogName);
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-}
-
-
-/*
-** Restablish the control channel.
-*/
-static RETSIGTYPE
-CCresetup(int unused)
-{
-#ifndef HAVE_SIGACTION
- xsignal(s, CCresetup);
-#else
- unused = unused; /* ARGSUSED */
-#endif
- CCclose();
- CCsetup();
-}
-
-
-/*
- * Read a file containing lines of the form "newsgroup lowmark",
- * and reset the low article number for the specified groups.
- */
-static const char *
-CClowmark(char *av[])
-{
- long lo;
- char *line, *cp;
- const char *ret = NULL;
- QIOSTATE *qp;
- NEWSGROUP *ngp;
-
- if (Mode != OMrunning)
- return CCnotrunning;
- if (ICDneedsetup)
- return "1 Must first reload newsfeeds";
- if ((qp = QIOopen(av[0])) == NULL) {
- syslog(L_ERROR, "%s cant open %s %m", LogName, av[0]);
- return "1 Cannot read input file";
- }
- while ((line = QIOread(qp)) != NULL) {
- if (QIOerror(qp))
- break;
- if (QIOtoolong(qp)) {
- ret = "1 Malformed input line (too long)";
- break;
- }
- while (ISWHITE(*line))
- line++;
- for (cp = line; *cp && !ISWHITE(*cp); cp++)
- ;
- if (*cp == '\0') {
- ret = "1 Malformed input line (only one field)";
- break;
- }
- *cp++ = '\0';
- while (ISWHITE(*cp))
- cp++;
- if (strspn(cp, "0123456789") != strlen(cp)) {
- ret = "1 Malformed input line (non-digit in low mark)";
- break;
- }
- if ((lo = atol(cp)) == 0 && (cp[0] != '0' || cp[1] != '\0')) {
- ret = "1 Malformed input line (bad low mark)";
- break;
- }
- if ((ngp = NGfind(line)) == NULL) {
- /* ret = CCnogroup; break; */
- continue;
- }
- if (!NGlowmark(ngp, lo)) {
- ret = "1 Cannot set low mark - see syslog";
- break;
- }
- }
- if (ret == NULL && QIOerror(qp)) {
- syslog(L_ERROR, "%s cant read %s %m", LogName, av[0]);
- ret = "1 Error reading input file";
- }
- QIOclose(qp);
- ICDwrite();
- return ret;
-}
+++ /dev/null
-/* $Id: chan.c 6720 2004-05-16 20:54:25Z rra $
-**
-** I/O channel (and buffer) processing.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-/* These errno values don't exist on all systems, but may be returned as an
- (ignorable) error to setting the accept socket nonblocking. Define them
- to 0 if they don't exist so that we can unconditionally compare errno to
- them in the code. */
-#ifndef ENOTSOCK
-# define ENOTSOCK 0
-#endif
-#ifndef ENOTTY
-# define ENOTTY 0
-#endif
-
-static const char * const timer_name[] = {
- "idle", "artclean", "artwrite", "artcncl", "sitesend", "overv",
- "perl", "python", "nntpread", "artparse", "artlog", "datamove"
-};
-
-/* Minutes - basically, keep the connection open but idle */
-#define PAUSE_BEFORE_DROP 5
-
-/* Divisor of the BUFFER size. If the amount free at the beginning of the
- buffer is bigger than the quotient, then it is compacted in the
- readloop */
-#define COMP_THRESHOLD 10
-
-static fd_set RCHANmask;
-static fd_set SCHANmask;
-static fd_set WCHANmask;
-static int SCHANcount;
-static int CHANlastfd;
-static int CHANlastsleepfd;
-static int CHANccfd;
-static int CHANtablesize;
-static CHANNEL *CHANtable;
-static CHANNEL *CHANcc;
-static CHANNEL CHANnull = { CTfree, CSerror, -1 };
-
-#define PRIORITISE_REMCONN
-#ifdef PRIORITISE_REMCONN
-static int *CHANrcfd;
-static CHANNEL **CHANrc;
-static int chanlimit;
-#endif /* PRIORITISE_REMCONN */
-
-/*
-** Tear down our world
-*/
-void
-CHANshutdown(void)
-{
- CHANNEL *cp;
- int i;
-
- if (CHANtable) {
- for (i = CHANtablesize, cp = &CHANtable[0]; --i >= 0; cp++) {
- if (cp->In.data) {
- free(cp->In.data);
- }
- if (cp->Out.data) {
- free(cp->Out.data);
- }
- }
- free(CHANtable);
- CHANtable = NULL;
- }
-}
-
-/*
-** Initialize all the I/O channels.
-*/
-void
-CHANsetup(int i)
-{
- CHANNEL *cp;
-
- FD_ZERO(&RCHANmask);
- FD_ZERO(&SCHANmask);
- FD_ZERO(&WCHANmask);
- CHANshutdown();
- CHANtablesize = i;
- CHANtable = xcalloc(CHANtablesize, sizeof(CHANNEL));
- CHANnull.NextLog = innconf->chaninacttime;
- memset(&CHANnull.Address, 0, sizeof(CHANnull.Address));
- for (cp = CHANtable; --i >= 0; cp++)
- *cp = CHANnull;
-}
-
-
-/*
-** Create a channel from a descriptor.
-*/
-CHANNEL *
-CHANcreate(int fd, CHANNELTYPE Type, CHANNELSTATE State,
- innd_callback_t Reader, innd_callback_t WriteDone)
-{
- CHANNEL *cp;
- struct buffer in = { 0, 0, 0, NULL };
- struct buffer out = { 0, 0, 0, NULL };
-
- cp = &CHANtable[fd];
-
- /* Don't overwrite the buffers with CHANnull. */
- in = cp->In;
- buffer_resize(&in, START_BUFF_SIZE);
- in.used = 0;
- in.left = in.size;
- out = cp->Out;
- buffer_resize(&out, SMBUF);
- buffer_set(&out, "", 0);
-
- /* Set up the channel's info. */
- *cp = CHANnull;
- cp->fd = fd;
- cp->Type = Type;
- cp->State = State;
- cp->Streaming = false;
- cp->Skip = false;
- cp->NoResendId = false;
- cp->privileged = false;
- cp->Ihave = cp->Ihave_Duplicate = cp->Ihave_Deferred = cp->Ihave_SendIt = cp->Ihave_Cybercan = 0;
- cp->Check = cp->Check_send = cp->Check_deferred = cp->Check_got = cp->Check_cybercan = 0;
- cp->Takethis = cp->Takethis_Ok = cp->Takethis_Err = 0;
- cp->Size = cp->Duplicate = 0;
- cp->Unwanted_s = cp->Unwanted_f = cp->Unwanted_d = 0;
- cp->Unwanted_g = cp->Unwanted_u = cp->Unwanted_o = 0;
- cp->Reader = Reader;
- cp->WriteDone = WriteDone;
- cp->Started = cp->LastActive = Now.time;
- cp->In = in;
- cp->Out = out;
- cp->Tracing = Tracing;
- cp->Sendid.size = 0;
- cp->Next=0;
- cp->MaxCnx=0;
- cp->ActiveCnx=0;
- cp->ArtBeg = 0;
- cp->ArtMax = 0;
- cp->Start = 0;
- HashClear(&cp->CurrentMessageIDHash);
- memset(cp->PrecommitWIP, '\0', sizeof(cp->PrecommitWIP));
- cp->PrecommitiCachenext=0;
- ARTprepare(cp);
-
- close_on_exec(fd, true);
-
-#ifndef _HPUX_SOURCE
- /* Stupid HPUX 11.00 has a broken listen/accept where setting the listen
- socket to nonblocking prevents you from successfully setting the
- socket returned by accept(2) back to blocking mode, no matter what,
- resulting in all kinds of funny behaviour, data loss, etc. etc. */
- if (nonblocking(fd, true) < 0 && errno != ENOTSOCK && errno != ENOTTY)
- syslog(L_ERROR, "%s cant nonblock %d %m", LogName, fd);
-#endif
-
- /* Note control channel, for efficiency. */
- if (Type == CTcontrol) {
- CHANcc = cp;
- CHANccfd = fd;
- }
-#ifdef PRIORITISE_REMCONN
- /* Note remconn channel, for efficiency */
- if (Type == CTremconn) {
- int j;
- for (j = 0 ; j < chanlimit ; j++ ) {
- if (CHANrcfd[j] == -1) {
- break;
- }
- }
- if (j < chanlimit) {
- CHANrc[j] = cp;
- CHANrcfd[j] = fd;
- } else if (chanlimit == 0) {
- /* assuming two file descriptors(AF_INET and AF_INET6) */
- chanlimit = 2;
- CHANrc = xmalloc(chanlimit * sizeof(CHANNEL **));
- CHANrcfd = xmalloc(chanlimit * sizeof(int *));
- for (j = 0 ; j < chanlimit ; j++ ) {
- CHANrc[j] = NULL;
- CHANrcfd[j] = -1;
- }
- CHANrc[0] = cp;
- CHANrcfd[0] = fd;
- } else {
- /* extend to double size */
- CHANrc = xrealloc(CHANrc, chanlimit * 2 * sizeof(CHANNEL **));
- CHANrcfd = xrealloc(CHANrcfd, chanlimit * 2 * sizeof(int *));
- for (j = chanlimit ; j < chanlimit * 2 ; j++ ) {
- CHANrc[j] = NULL;
- CHANrcfd[j] = -1;
- }
- CHANrc[chanlimit] = cp;
- CHANrcfd[chanlimit] = fd;
- chanlimit *= 2;
- }
- }
-#endif /* PRIORITISE_REMCONN */
- return cp;
-}
-
-
-/*
-** Start tracing a channel.
-*/
-void
-CHANtracing(CHANNEL *cp, bool Flag)
-{
- char *p;
-
- p = CHANname(cp);
- syslog(L_NOTICE, "%s trace %s", p, Flag ? "on" : "off");
- cp->Tracing = Flag;
- if (Flag) {
- syslog(L_NOTICE, "%s trace badwrites %d blockwrites %d badreads %d",
- p, cp->BadWrites, cp->BlockedWrites, cp->BadReads);
- syslog(L_NOTICE, "%s trace address %s lastactive %ld nextlog %ld",
- p, sprint_sockaddr((struct sockaddr *)&cp->Address),
- (long) cp->LastActive, (long) cp->NextLog);
- if (FD_ISSET(cp->fd, &SCHANmask))
- syslog(L_NOTICE, "%s trace sleeping %ld 0x%p",
- p, (long)cp->Waketime, (void *)cp->Waker);
- if (FD_ISSET(cp->fd, &RCHANmask))
- syslog(L_NOTICE, "%s trace reading %lu %s",
- p, (unsigned long) cp->In.used,
- MaxLength(cp->In.data, cp->In.data));
- if (FD_ISSET(cp->fd, &WCHANmask))
- syslog(L_NOTICE, "%s trace writing %lu %s",
- p, (unsigned long) cp->Out.left,
- MaxLength(cp->Out.data, cp->Out.data));
- }
-}
-
-
-/*
-** Close a channel.
-*/
-void
-CHANclose(CHANNEL *cp, const char *name)
-{
- char *label, *tmplabel, buff[SMBUF];
-
- if (cp->Type == CTfree)
- syslog(L_ERROR, "%s internal closing free channel %d", name, cp->fd);
- else {
- if (cp->Type == CTnntp) {
- WIPprecomfree(cp);
- NCclearwip(cp);
- if (cp->State == CScancel)
- syslog(L_NOTICE,
- "%s closed seconds %ld cancels %ld",
- name, (long)(Now.time - cp->Started),
- cp->Received);
- else {
- snprintf(buff, sizeof(buff),
- "accepted size %.0f duplicate size %.0f", cp->Size,
- cp->DuplicateSize);
- syslog(L_NOTICE,
- "%s closed seconds %ld accepted %ld refused %ld rejected %ld duplicate %ld %s",
- name, (long)(Now.time - cp->Started),
- cp->Received, cp->Refused, cp->Rejected,
- cp->Duplicate, buff);
- }
- if (cp->Data.Newsgroups.Data != NULL) {
- free(cp->Data.Newsgroups.Data);
- cp->Data.Newsgroups.Data = NULL;
- }
- if (cp->Data.Newsgroups.List != NULL) {
- free(cp->Data.Newsgroups.List);
- cp->Data.Newsgroups.List = NULL;
- }
- if (cp->Data.Distribution.Data != NULL) {
- free(cp->Data.Distribution.Data);
- cp->Data.Distribution.Data = NULL;
- }
- if (cp->Data.Distribution.List != NULL) {
- free(cp->Data.Distribution.List);
- cp->Data.Distribution.List = NULL;
- }
- if (cp->Data.Path.Data != NULL) {
- free(cp->Data.Path.Data);
- cp->Data.Path.Data = NULL;
- }
- if (cp->Data.Path.List != NULL) {
- free(cp->Data.Path.List);
- cp->Data.Path.List = NULL;
- }
- if (cp->Data.Overview.size != 0) {
- free(cp->Data.Overview.data);
- cp->Data.Overview.data = NULL;
- cp->Data.Overview.size = 0;
- cp->Data.Overview.left = 0;
- cp->Data.Overview.used = 0;
- }
- if (cp->Data.XrefBufLength != 0) {
- free(cp->Data.Xref);
- cp->Data.Xref = NULL;
- cp->Data.XrefBufLength = 0;
- }
- } else if (cp->Type == CTreject)
- syslog(L_NOTICE, "%s %ld", name, cp->Rejected);
- else if (cp->Out.left)
- syslog(L_NOTICE, "%s closed lost %lu", name,
- (unsigned long) cp->Out.left);
- else
- syslog(L_NOTICE, "%s closed", name);
- WCHANremove(cp);
- RCHANremove(cp);
- SCHANremove(cp);
- if (cp->Argument != NULL)
- /* Set to NULL below. */
- free(cp->Argument);
- if (cp->fd >= 0 && close(cp->fd) < 0)
- syslog(L_ERROR, "%s cant close %s %m", LogName, name);
-
- if (cp->MaxCnx > 0 && cp->Type == CTnntp) {
- int tfd;
- CHANNEL *tempchan;
-
- cp->fd = -1;
- if ((label = RClabelname(cp)) != NULL) {
- for(tfd = 0; tfd <= CHANlastfd; tfd++) {
- tempchan = &CHANtable[tfd];
- if(tempchan->fd > 0 && tempchan->Type == CTnntp &&
- ((tmplabel = RClabelname(tempchan)) != NULL) &&
- strcmp(label, tmplabel) == 0 &&
- tempchan->ActiveCnx == 0) {
- tempchan->ActiveCnx = cp->ActiveCnx;
- RCHANadd(tempchan);
- break;
- }
- }
- }
- }
- }
-
- /* Mark it unused. */
- cp->Type = CTfree;
- cp->State = CSerror;
- cp->fd = -1;
- cp->Argument = NULL;
- cp->ActiveCnx = 0;
-
- /* Free the buffers if they got big. */
- if (cp->In.size > BIG_BUFFER) {
- cp->In.size = 0;
- cp->In.used = 0;
- cp->In.left = 0;
- free(cp->In.data);
- cp->In.data = NULL;
- }
- if (cp->Out.size > BIG_BUFFER) {
- cp->Out.size = 0;
- cp->Out.used = 0;
- cp->Out.left = 0;
- free(cp->Out.data);
- cp->Out.data = NULL;
- }
- if (cp->Sendid.size > 0) {
- cp->Sendid.size = 0;
- cp->Sendid.used = 0;
- cp->Sendid.left = 0;
- free(cp->Sendid.data);
- cp->Sendid.data = NULL;
- }
-}
-
-
-/*
-** Return a printable name for the channel.
-*/
-char *
-CHANname(const CHANNEL *cp)
-{
- static char buff[SMBUF];
- int i;
- SITE * sp;
- const char * p;
- pid_t pid;
-
- switch (cp->Type) {
- default:
- snprintf(buff, sizeof(buff), "?%d(#%d@%ld)?", cp->Type, cp->fd,
- (long) (cp - CHANtable));
- break;
- case CTany:
- snprintf(buff, sizeof(buff), "any:%d", cp->fd);
- break;
- case CTfree:
- snprintf(buff, sizeof(buff), "free:%d", cp->fd);
- break;
- case CTremconn:
- snprintf(buff, sizeof(buff), "remconn:%d", cp->fd);
- break;
- case CTreject:
- snprintf(buff, sizeof(buff), "%s rejected", RChostname(cp));
- break;
- case CTnntp:
- snprintf(buff, sizeof(buff), "%s:%d",
- cp->Address.ss_family == 0 ? "localhost" : RChostname(cp),
- cp->fd);
- break;
- case CTlocalconn:
- snprintf(buff, sizeof(buff), "localconn:%d", cp->fd);
- break;
- case CTcontrol:
- snprintf(buff, sizeof(buff), "control:%d", cp->fd);
- break;
- case CTexploder:
- case CTfile:
- case CTprocess:
- /* Find the site that has this channel. */
- for (p = "?", i = nSites, sp = Sites, pid = 0; --i >= 0; sp++)
- if (sp->Channel == cp) {
- p = sp->Name;
- if (cp->Type != CTfile)
- pid = sp->pid;
- break;
- }
- if (pid == 0)
- snprintf(buff, sizeof(buff), "%s:%d:%s",
- MaxLength(p, p), cp->fd,
- cp->Type == CTfile ? "file" : "proc");
- else
- snprintf(buff, sizeof(buff), "%s:%d:%s:%ld",
- MaxLength(p, p), cp->fd,
- cp->Type == CTfile ? "file" : "proc", (long)pid);
- break;
- }
- return buff;
-}
-
-
-/*
-** Return the channel for a specified descriptor.
-*/
-CHANNEL *
-CHANfromdescriptor(int fd)
-{
- if (fd <0 || fd > CHANtablesize)
- return NULL;
- return &CHANtable[fd];
-}
-
-
-/*
-** Iterate over all channels of a specified type.
-*/
-CHANNEL *
-CHANiter(int *ip, CHANNELTYPE Type)
-{
- CHANNEL *cp;
- int i;
-
- if ((i = *ip) >= 0 && i < CHANtablesize) {
- do {
- cp = &CHANtable[i];
- if (cp->Type == CTfree && cp->fd == -1)
- continue;
- if (Type == CTany || cp->Type == Type) {
- *ip = ++i;
- return cp;
- }
- } while (++i < CHANtablesize);
- }
- return NULL;
-}
-
-
-/*
-** Mark a channel as an active reader.
-*/
-void
-RCHANadd(CHANNEL *cp)
-{
- FD_SET(cp->fd, &RCHANmask);
- if (cp->fd > CHANlastfd)
- CHANlastfd = cp->fd;
-
- if (cp->Type != CTnntp)
- /* Start reading at the beginning of the buffer. */
- cp->In.used = 0;
-}
-
-
-/*
-** Remove a channel from the set of readers.
-*/
-void
-RCHANremove(CHANNEL *cp)
-{
- if (FD_ISSET(cp->fd, &RCHANmask)) {
- FD_CLR(cp->fd, &RCHANmask);
- if (cp->fd == CHANlastfd) {
- /* This was the highest descriptor, get a new highest. */
- while (!FD_ISSET(CHANlastfd, &RCHANmask)
- && !FD_ISSET(CHANlastfd, &WCHANmask)
- && CHANlastfd > 1)
- CHANlastfd--;
- }
- }
-}
-
-
-/*
-** Put a channel to sleep, call a function when it wakes.
-** Note that the Argument must be NULL or allocated memory!
-*/
-void
-SCHANadd(CHANNEL *cp, time_t Waketime, void *Event, innd_callback_t Waker,
- void *Argument)
-{
- if (!FD_ISSET(cp->fd, &SCHANmask)) {
- SCHANcount++;
- FD_SET(cp->fd, &SCHANmask);
- }
- if (cp->fd > CHANlastsleepfd)
- CHANlastsleepfd = cp->fd;
- cp->Waketime = Waketime;
- cp->Waker = Waker;
- if (cp->Argument != Argument) {
- free(cp->Argument);
- cp->Argument = Argument;
- }
- cp->Event = Event;
-}
-
-
-/*
-** Take a channel off the sleep list.
-*/
-void
-SCHANremove(CHANNEL *cp)
-{
- if (FD_ISSET(cp->fd, &SCHANmask)) {
- FD_CLR(cp->fd, &SCHANmask);
- SCHANcount--;
- cp->Waketime = 0;
- if (cp->fd == CHANlastsleepfd) {
- /* This was the highest descriptor, get a new highest. */
- while (!FD_ISSET(CHANlastsleepfd, &SCHANmask)
- && CHANlastsleepfd > 1)
- CHANlastsleepfd--;
- }
- }
-}
-
-
-/*
-** Is a channel on the sleep list?
-*/
-bool
-CHANsleeping(CHANNEL *cp)
-{
- return FD_ISSET(cp->fd, &SCHANmask);
-}
-
-
-/*
-** Wake up channels waiting for a specific event.
-*/
-void
-SCHANwakeup(void *Event)
-{
- CHANNEL *cp;
- int i;
-
- for (cp = CHANtable, i = CHANtablesize; --i >= 0; cp++)
- if (cp->Type != CTfree && cp->Event == Event && CHANsleeping(cp))
- cp->Waketime = 0;
-}
-
-
-/*
-** Mark a channel as an active writer. Don't reset the Out->left field
-** since we could have buffered I/O already in there.
-*/
-void
-WCHANadd(CHANNEL *cp)
-{
- if (cp->Out.left > 0) {
- FD_SET(cp->fd, &WCHANmask);
- if (cp->fd > CHANlastfd)
- CHANlastfd = cp->fd;
- }
-}
-
-
-/*
-** Remove a channel from the set of writers.
-*/
-void
-WCHANremove(CHANNEL *cp)
-{
- if (FD_ISSET(cp->fd, &WCHANmask)) {
- FD_CLR(cp->fd, &WCHANmask);
- if (cp->Out.left <= 0) {
- /* No data left -- reset used so we don't grow the buffer. */
- cp->Out.used = 0;
- cp->Out.left = 0;
- }
- if (cp->fd == CHANlastfd) {
- /* This was the highest descriptor, get a new highest. */
- while (!FD_ISSET(CHANlastfd, &RCHANmask)
- && !FD_ISSET(CHANlastfd, &WCHANmask)
- && CHANlastfd > 1)
- CHANlastfd--;
- }
- }
-}
-
-
-/*
-** Set a channel to start off with the contents of an existing channel.
-*/
-void
-WCHANsetfrombuffer(CHANNEL *cp, struct buffer *bp)
-{
- WCHANset(cp, &bp->data[bp->used], bp->left);
-}
-
-\f
-
-/*
-** Read in text data, return the amount we read.
-*/
-int
-CHANreadtext(CHANNEL *cp)
-{
- ptrdiff_t i, j;
- struct buffer *bp;
- char *p;
- int oerrno;
- int maxbyte;
- HDRCONTENT *hc = cp->Data.HdrContent;
-
- /* Grow buffer if we're getting close to current limit. FIXME: The In
- buffer doesn't use the normal meanings of .used and .left. */
- bp = &cp->In;
- bp->left = bp->size - bp->used;
- if (bp->left <= LOW_WATER) {
- i = GROW_AMOUNT(bp->size);
- bp->size += i;
- bp->left += i;
- p = bp->data;
- TMRstart(TMR_DATAMOVE);
- bp->data = xrealloc(bp->data, bp->size);
-
- /* Adjust offets of realloc moved the location of the memory region.
- FIXME: This is invalid C, although it will work on most (all?)
- common systems. The pointers need to be reduced to offets and then
- turned back into relative pointers rather than adjusting the
- pointers directly, since as soon as realloc is called, pointers
- into the old space become invalid and may not be used further. */
- if ((i = p - bp->data) != 0) {
- if (cp->State == CSgetheader || cp->State == CSgetbody ||
- cp->State == CSeatarticle) {
- /* adjust offset only in CSgetheader, CSgetbody or
- CSeatarticle */
- if (cp->Data.BytesHeader != NULL)
- cp->Data.BytesHeader -= i;
- for (j = 0 ; j < MAX_ARTHEADER ; j++, hc++) {
- if (hc->Value != NULL)
- hc->Value -= i;
- }
- }
- }
- TMRstop(TMR_DATAMOVE);
- }
-
- /* Read in whatever is there, up to some reasonable limit.
-
- We want to limit the amount of time devoted to processing the incoming
- data for any given channel. There's no easy way of doing that, though,
- so we restrict the data size instead.
-
- If the data is part of a single large article, then reading and
- processing many kilobytes at a time costs very little. If the data is
- a long list of CHECK commands from a streaming feed, then every line of
- data will require a history lookup, and we probably don't want to do
- more than about 10 of those per channel on each cycle of the main
- select() loop (otherwise we might take too long before giving other
- channels a turn). 10 lines of CHECK commands suggests a limit of about
- 1KB of data, or less. innconf->maxcmdreadsize (BUFSIZ by default) is
- often about 1KB, and is attractive for other reasons, so let's use that
- as our size limit. If innconf->maxcmdreadsize is 0, there is no limit.
-
- Reduce the read size only if we're reading commands.
-
- FIXME: A better approach would be to limit the number of commands we
- process for each channel. */
- if (innconf->maxcmdreadsize <= 0 || cp->State != CSgetcmd
- || bp->left < innconf->maxcmdreadsize)
- maxbyte = bp->left;
- else
- maxbyte = innconf->maxcmdreadsize;
- TMRstart(TMR_NNTPREAD);
- i = read(cp->fd, &bp->data[bp->used], maxbyte);
- TMRstop(TMR_NNTPREAD);
- if (i < 0) {
- /* Solaris (at least 2.4 through 2.6) will occasionally return
- EAGAIN in response to a read even if the file descriptor already
- selected true for reading, apparently due to some internal
- resource exhaustion. In that case, return -2, which will drop
- back out to the main loop and go on to the next file descriptor,
- as if the descriptor never selected true. This check will
- probably never trigger on platforms other than Solaris. */
- if (errno == EAGAIN)
- return -2;
- oerrno = errno;
- p = CHANname(cp);
- errno = oerrno;
- sysnotice("%s cant read", p);
- return -1;
- }
- if (i == 0) {
- p = CHANname(cp);
- notice("%s readclose", p);
- return 0;
- }
-
- bp->used += i;
- bp->left -= i;
- return i;
-}
-
-
-/*
-** If I/O backs up a lot, we can get EMSGSIZE on some systems. If that
-** happens we want to do the I/O in chunks. We assume stdio's BUFSIZ is
-** a good chunk value.
-*/
-static int
-CHANwrite(int fd, char *p, long length)
-{
- int i;
- char *save;
-
- do {
- /* Try the standard case -- write it all. */
- i = write(fd, p, length);
- if (i > 0 || (i < 0 && errno != EMSGSIZE && errno != EINTR))
- return i;
- } while (i < 0 && errno == EINTR);
-
- /* Write it in pieces. */
- for (save = p, i = 0; length; p += i, length -= i) {
- i = write(fd, p, (length > BUFSIZ ? BUFSIZ : length));
- if (i <= 0)
- break;
- }
-
- /* Return error, or partial results if we got something. */
- return p == save ? i : p - save;
-}
-
-
-/*
-** Try to flush out the buffer. Use this only on file channels!
-*/
-bool
-WCHANflush(CHANNEL *cp)
-{
- struct buffer *bp;
- int i;
-
- /* Write it. */
- for (bp = &cp->Out; bp->left > 0; bp->left -= i, bp->used += i) {
- i = CHANwrite(cp->fd, &bp->data[bp->used], bp->left);
- if (i < 0) {
- syslog(L_ERROR, "%s cant flush count %lu %m",
- CHANname(cp), (unsigned long) bp->left);
- return false;
- }
- if (i == 0) {
- syslog(L_ERROR, "%s cant flush count %lu",
- CHANname(cp), (unsigned long) bp->left);
- return false;
- }
- }
- WCHANremove(cp);
- return true;
-}
-
-\f
-
-/*
-** Wakeup routine called after a write channel was put to sleep.
-*/
-static void
-CHANwakeup(CHANNEL *cp)
-{
- syslog(L_NOTICE, "%s wakeup", CHANname(cp));
- WCHANadd(cp);
-}
-
-
-/*
-** Attempting to write would block; stop output or give up.
-*/
-static void
-CHANwritesleep(CHANNEL *cp, char *p)
-{
- int i;
-
- if ((i = ++(cp->BlockedWrites)) > innconf->badiocount)
- switch (cp->Type) {
- default:
- break;
- case CTreject:
- case CTnntp:
- case CTfile:
- case CTexploder:
- case CTprocess:
- syslog(L_ERROR, "%s blocked closing", p);
- SITEchanclose(cp);
- CHANclose(cp, p);
- return;
- }
- i *= innconf->blockbackoff;
- syslog(L_ERROR, "%s blocked sleeping %d", p, i);
- SCHANadd(cp, Now.time + i, NULL, CHANwakeup, NULL);
-}
-
-
-#if defined(INND_FIND_BAD_FDS)
-/*
-** We got an unknown error in select. Find out the culprit.
-** Not really ready for production use yet, and it's expensive, too.
-*/
-static void
-CHANdiagnose(void)
-{
- fd_set Test;
- int i;
- struct timeval t;
-
- FD_ZERO(&Test);
- for (i = CHANlastfd; i >= 0; i--) {
- if (FD_ISSET(i, &RCHANmask)) {
- FD_SET(i, &Test);
- t.tv_sec = 0;
- t.tv_usec = 0;
- if (select(i + 1, &Test, NULL, NULL, &t) < 0
- && errno != EINTR) {
- syslog(L_ERROR, "%s Bad Read File %d", LogName, i);
- FD_CLR(i, &RCHANmask);
- /* Probably do something about the file descriptor here; call
- * CHANclose on it? */
- }
- FD_CLR(i, &Test);
- }
- if (FD_ISSET(i, &WCHANmask)) {
- FD_SET(i, &Test);
- t.tv_sec = 0;
- t.tv_usec = 0;
- if (select(i + 1, NULL, &Test, NULL, &t) < 0
- && errno != EINTR) {
- syslog(L_ERROR, "%s Bad Write File %d", LogName, i);
- FD_CLR(i, &WCHANmask);
- /* Probably do something about the file descriptor here; call
- * CHANclose on it? */
- }
- FD_CLR(i, &Test);
- }
- }
-}
-#endif /* defined(INND_FIND_BAD_FDS) */
-
-void
-CHANsetActiveCnx(CHANNEL *cp) {
- int found;
- CHANNEL *tempchan;
- char *label, *tmplabel;
- int tfd;
-
- if((cp->fd > 0) && (cp->Type == CTnntp) && (cp->ActiveCnx == 0)) {
- found = 1;
- if ((label = RClabelname(cp)) != NULL) {
- for(tfd = 0; tfd <= CHANlastfd; tfd++) {
- tempchan = &CHANtable[tfd];
- if ((tmplabel = RClabelname(tempchan)) == NULL) {
- continue;
- }
- if(strcmp(label, tmplabel) == 0) {
- if(tempchan->ActiveCnx != 0)
- found++;
- }
- }
- }
- cp->ActiveCnx = found;
- }
-}
-
-/*
-** Main I/O loop. Wait for data, call the channel's handler when there is
-** something to read or when the queued write is finished. In order to
-** be fair (i.e., don't always give descriptor n priority over n+1), we
-** remember where we last had something and pick up from there.
-**
-** Yes, the main code has really wandered over to the side a lot.
-*/
-void
-CHANreadloop(void)
-{
- static char EXITING[] = "INND exiting because of signal\n";
- static int fd;
- ptrdiff_t i, j;
- int startpoint;
- int count;
- int lastfd;
- int oerrno;
- CHANNEL *cp;
- struct buffer *bp;
- fd_set MyRead;
- fd_set MyWrite;
- struct timeval MyTime;
- long silence;
- char *p;
- time_t LastUpdate;
- HDRCONTENT *hc;
-
- STATUSinit();
-
- LastUpdate = GetTimeInfo(&Now) < 0 ? 0 : Now.time;
- for ( ; ; ) {
- /* See if any processes died. */
- PROCscan();
-
- /* Wait for data, note the time. */
- MyRead = RCHANmask;
- MyWrite = WCHANmask;
- MyTime = TimeOut;
- if (innconf->timer) {
- unsigned long now = TMRnow();
-
- if (now >= 1000 * (unsigned long)(innconf->timer)) {
- TMRsummary("ME", timer_name);
- InndHisLogStats();
- MyTime.tv_sec = innconf->timer;
- }
- else {
- MyTime.tv_sec = innconf->timer - now / 1000;
- }
- }
- TMRstart(TMR_IDLE);
- count = select(CHANlastfd + 1, &MyRead, &MyWrite, NULL, &MyTime);
- TMRstop(TMR_IDLE);
-
- STATUSmainloophook();
- if (GotTerminate) {
- write(2, EXITING, strlen(EXITING));
- CleanupAndExit(0, (char *)NULL);
- }
- if (count < 0) {
- if (errno != EINTR) {
- syslog(L_ERROR, "%s cant select %m", LogName);
-#if defined(INND_FIND_BAD_FDS)
- CHANdiagnose();
-#endif /* defined(INND_FIND_BAD_FDS) */
- }
- continue;
- }
-
- /* Update the "reasonably accurate" time. */
- if (GetTimeInfo(&Now) < 0)
- syslog(L_ERROR, "%s cant gettimeinfo %m", LogName);
- if (Now.time > LastUpdate + TimeOut.tv_sec) {
- HISsync(History);
- if (ICDactivedirty) {
- ICDwriteactive();
- ICDactivedirty = 0;
- }
- LastUpdate = Now.time;
- }
-
- if (count == 0) {
- /* No channels active, so flush and skip if nobody's
- * sleeping. */
- if (Mode == OMrunning)
- ICDwrite();
- if (SCHANcount == 0)
- continue;
- }
-
- /* Try the control channel first. */
- if (FD_ISSET(CHANccfd, &RCHANmask) && FD_ISSET(CHANccfd, &MyRead)) {
- count--;
- if (count > 3)
- count = 3; /* might be more requests */
- (*CHANcc->Reader)(CHANcc);
- FD_CLR(CHANccfd, &MyRead);
- }
-
-#ifdef PRIORITISE_REMCONN
- /* Try the remconn channel next. */
- for (j = 0 ; (j < chanlimit) && (CHANrcfd[j] >= 0) ; j++) {
- if (FD_ISSET(CHANrcfd[j], &RCHANmask) && FD_ISSET(CHANrcfd[j], &MyRead)) {
- count--;
- if (count > 3)
- count = 3; /* might be more requests */
- (*CHANrc[j]->Reader)(CHANrc[j]);
- FD_CLR(CHANrcfd[j], &MyRead);
- }
- }
-#endif /* PRIORITISE_REMCONN */
-
- /* Loop through all active channels. Somebody could have closed
- * closed a channel so we double-check the global mask before
- * looking at what select returned. The code here is written so
- * that a channel could be reading and writing and sleeping at the
- * same time, even though that's not possible. (Just as well,
- * since in SysVr4 the count would be wrong.) */
- lastfd = CHANlastfd;
- if (lastfd < CHANlastsleepfd)
- lastfd = CHANlastsleepfd;
- if (fd > lastfd)
- fd = 0;
- startpoint = fd;
- do {
- cp = &CHANtable[fd];
-
- if (cp->MaxCnx > 0 && cp->HoldTime > 0) {
- CHANsetActiveCnx(cp);
- if((cp->ActiveCnx > cp->MaxCnx) && (cp->fd > 0)) {
- if(cp->Started + cp->HoldTime < Now.time) {
- CHANclose(cp, CHANname(cp));
- } else {
- if (fd >= lastfd)
- fd = 0;
- else
- fd++;
- cp->ActiveCnx = 0;
- RCHANremove(cp);
- }
- continue;
- }
- }
-
- /* Anything to read? */
- if (FD_ISSET(fd, &RCHANmask) && FD_ISSET(fd, &MyRead)) {
- count--;
- if (cp->Type == CTfree) {
- syslog(L_ERROR, "%s %d free but was in RMASK",
- CHANname(cp), fd);
- /* Don't call RCHANremove since cp->fd will be -1. */
- FD_CLR(fd, &RCHANmask);
- close(fd);
- }
- else {
- cp->LastActive = Now.time;
- (*cp->Reader)(cp);
- }
- }
-
- /* Check and see if the buffer is grossly overallocated and shrink
- if needed */
- if (cp->In.size > (BIG_BUFFER)) {
- if (cp->In.used != 0) {
- if ((cp->In.size / cp->In.used) > 10) {
- cp->In.size = (cp->In.used * 2) > START_BUFF_SIZE ? (cp->In.used * 2) : START_BUFF_SIZE;
- p = cp->In.data;
- TMRstart(TMR_DATAMOVE);
- cp->In.data = xrealloc(cp->In.data, cp->In.size);
- cp->In.left = cp->In.size - cp->In.used;
- /* do not move data, since xrealloc did it already */
- if ((i = p - cp->In.data) != 0) {
- if (cp->State == CSgetheader ||
- cp->State == CSgetbody ||
- cp->State == CSeatarticle) {
- /* adjust offset only in CSgetheader, CSgetbody
- or CSeatarticle */
- if (cp->Data.BytesHeader != NULL)
- cp->Data.BytesHeader -= i;
- hc = cp->Data.HdrContent;
- for (j = 0 ; j < MAX_ARTHEADER ; j++, hc++) {
- if (hc->Value != NULL)
- hc->Value -= i;
- }
- }
- }
- TMRstop(TMR_DATAMOVE);
- }
- } else {
- p = cp->In.data;
- TMRstart(TMR_DATAMOVE);
- cp->In.data = xrealloc(cp->In.data, START_BUFF_SIZE);
- cp->In.size = cp->In.left = START_BUFF_SIZE;
- if ((i = p - cp->In.data) != 0) {
- if (cp->State == CSgetheader ||
- cp->State == CSgetbody ||
- cp->State == CSeatarticle) {
- /* adjust offset only in CSgetheader, CSgetbody
- or CSeatarticle */
- if (cp->Data.BytesHeader != NULL)
- cp->Data.BytesHeader -= i;
- hc = cp->Data.HdrContent;
- for (j = 0 ; j < MAX_ARTHEADER ; j++, hc++) {
- if (hc->Value != NULL)
- hc->Value -= i;
- }
- }
- }
- TMRstop(TMR_DATAMOVE);
- }
- }
- /* Possibly recheck for dead children so we don't get SIGPIPE
- * on readerless channels. */
- if (PROCneedscan)
- PROCscan();
-
- /* Ready to write? */
- if (FD_ISSET(fd, &WCHANmask) && FD_ISSET(fd, &MyWrite)) {
- count--;
- if (cp->Type == CTfree) {
- syslog(L_ERROR, "%s %d free but was in WMASK",
- CHANname(cp), fd);
- /* Don't call WCHANremove since cp->fd will be -1. */
- FD_CLR(fd, &WCHANmask);
- close(fd);
- }
- else {
- bp = &cp->Out;
- if (bp->left) {
- cp->LastActive = Now.time;
- i = CHANwrite(fd, &bp->data[bp->used], bp->left);
- if (i <= 0) {
- oerrno = errno;
- p = CHANname(cp);
- errno = oerrno;
- if (i < 0)
- sysnotice("%s cant write", p);
- else
- notice("%s cant write", p);
- cp->BadWrites++;
- if (i < 0 && oerrno == EPIPE) {
- SITEchanclose(cp);
- CHANclose(cp, p);
- }
- else if (i < 0 &&
- (oerrno == EWOULDBLOCK
- || oerrno == EAGAIN)) {
- WCHANremove(cp);
- CHANwritesleep(cp, p);
- }
- else if (cp->BadWrites >= innconf->badiocount) {
- syslog(L_ERROR, "%s sleeping", p);
- WCHANremove(cp);
- SCHANadd(cp,
- Now.time + innconf->pauseretrytime,
- NULL, CHANwakeup, NULL);
- }
- }
- else {
- cp->BadWrites = 0;
- cp->BlockedWrites = 0;
- bp->left -= i;
- bp->used += i;
- if (bp->left <= 0) {
- WCHANremove(cp);
- (*cp->WriteDone)(cp);
- } else if (bp->used > (bp->size/COMP_THRESHOLD)) {
- /* compact the buffer, shoving the
- data back to the beginning.
- <rmtodd@mailhost.ecn.ou.edu> */
- buffer_set(bp, &bp->data[bp->used], bp->left);
- }
- }
- }
- else
- /* Should not be possible. */
- WCHANremove(cp);
- }
- }
-
- /* Coming off a sleep? */
- if (FD_ISSET(fd, &SCHANmask) && cp->Waketime <= Now.time) {
- if (cp->Type == CTfree) {
- syslog(L_ERROR,"%s ERROR s-select free %d",CHANname(cp),fd);
- FD_CLR(fd, &SCHANmask);
- close(fd);
- } else {
- cp->LastActive = Now.time;
- SCHANremove(cp);
- (*cp->Waker)(cp);
- }
- }
-
- /* Toss CTreject channel early if it's inactive. */
- if (cp->Type == CTreject
- && cp->LastActive + REJECT_TIMEOUT < Now.time) {
- p = CHANname(cp);
- syslog(L_NOTICE, "%s timeout reject", p);
- CHANclose(cp, p);
- }
-
- /* Has this channel been inactive very long? */
- if (cp->Type == CTnntp
- && cp->LastActive + cp->NextLog < Now.time) {
- p = CHANname(cp);
- silence = Now.time - cp->LastActive;
- cp->NextLog += innconf->chaninacttime;
- syslog(L_NOTICE, "%s inactive %ld", p, silence / 60L);
- if (silence > innconf->peertimeout) {
- syslog(L_NOTICE, "%s timeout", p);
- CHANclose(cp, p);
- }
- }
-
- /* Bump pointer, modulo the table size. */
- if (fd >= lastfd)
- fd = 0;
- else
- fd++;
-
- /* If there is nothing to do, break out. */
- if (count == 0 && SCHANcount == 0)
- break;
-
- } while (fd != startpoint);
- }
-}
+++ /dev/null
-/* $Id: icd.c 6156 2003-01-19 20:58:05Z rra $
-**
-** Routines to read and write the active file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <sys/uio.h>
-
-#include "inn/innconf.h"
-#include "innd.h"
-#include "ov.h"
-
-/* If we fork and exec under Cygwin, children hold onto the mmap */
-/* of active, and Windows won't let us resize or replace it. */
-#ifdef __CYGWIN__
-# undef HAVE_MMAP
-#endif
-
-static char *ICDactpath = NULL;
-static char *ICDactpointer;
-static int ICDactfd;
-static int ICDactsize;
-
-
-/*
-** Set and unset (or copy) IOVEC elements. We make copies to
-** avoid problems with mmap.
-*/
-#ifdef HAVE_MMAP
-static void
-ICDiovset(struct iovec *iovp, char *base, int len)
-{
- iovp->iov_len = len;
- iovp->iov_base = xmalloc(iovp->iov_len);
- memcpy(iovp->iov_base, base, iovp->iov_len);
-}
-#define ICDiovrelease(iovp) free((iovp)->iov_base)
-
-#else /* !HAVE_MMAP */
-
-#define ICDiovset(iovp, base, len) \
- (iovp)->iov_base = base, (iovp)->iov_len = len
-#define ICDiovrelease(iovp) /* NULL */
-
-#endif /* HAVE_MMAP */
-
-
-/*
-** Close the active file, releasing its resources.
-*/
-static void
-ICDcloseactive(void)
-{
- if (ICDactpointer) {
-#ifdef HAVE_MMAP
- if (munmap(ICDactpointer, ICDactsize) < 0)
- syslog(L_ERROR, "%s cant munmap %s %m", LogName, ICDactpath);
-#else
- free(ICDactpointer);
-#endif
- ICDactpointer = NULL;
- if (close(ICDactfd) < 0) {
- syslog(L_FATAL, "%s cant close %s %m", LogName, ICDactpath);
- exit(1);
- }
- }
-}
-
-
-/*
-** Set up the hash and in-core tables.
-*/
-void
-ICDsetup(StartSites)
- bool StartSites;
-{
- if (ICDneedsetup == true) {
- ICDneedsetup = false;
- }
- else {
- ICDcloseactive();
- NGparsefile();
- }
- if (NGfind("control") == NULL || NGfind("junk") == NULL) {
- syslog(L_FATAL, "%s internal no control and/or junk group", LogName);
- exit(1);
- }
- if (NGfind("control.cancel") == NULL) {
- syslog(L_FATAL, "%s internal no control.cancel group", LogName);
- exit(1);
- }
- if (innconf->mergetogroups && NGfind("to") == NULL) {
- syslog(L_FATAL, "%s internal no to group", LogName);
- exit(1);
- }
- SITEparsefile(StartSites);
-}
-
-
-/*
-** Write out all in-core data.
-*/
-void
-ICDwrite(void)
-{
- HISsync(History);
- SMflushcacheddata(SM_ALL);
-
- if (ICDactivedirty) {
- ICDwriteactive();
- ICDactivedirty = 0;
- }
-
- /* Flush log and error log. */
- if (fflush(Log) == EOF)
- syslog(L_ERROR, "%s cant fflush log %m", LogName);
- if (fflush(Errlog) == EOF)
- syslog(L_ERROR, "%s cant fflush errlog %m", LogName);
-}
-
-
-/*
-** Close things down.
-*/
-void
-ICDclose(void)
-{
- ICDwrite();
- ICDcloseactive();
-}
-
-
-/*
-** Scan the active file, and renumber the min/max counts.
-*/
-bool
-ICDrenumberactive(void)
-{
- int i;
- NEWSGROUP *ngp;
-
- for (i = nGroups, ngp = Groups; --i >= 0; ngp++)
- if (!NGrenumber(ngp))
- return false;
- if (i < 0)
- ICDwrite();
- return true;
-}
-
-
-/*
-** Use writev() to replace the active file.
-*/
-static bool
-ICDwritevactive(struct iovec *vp, int vpcount)
-{
- static char *BACKUP = NULL;
- static char *NEWACT = NULL;
- static char WHEN[] = "backup active";
- int fd;
- int oerrno;
-#ifdef __CYGWIN__
- size_t newactsize, padactsize, wrote;
- struct iovec *newvp;
- char *filler;
- int i;
-#endif
-
- if (BACKUP == NULL)
- BACKUP = concatpath(innconf->pathdb, _PATH_OLDACTIVE);
- if (NEWACT == NULL)
- NEWACT = concatpath(innconf->pathdb, _PATH_NEWACTIVE);
- /* Write the current file to a backup. */
- if (unlink(BACKUP) < 0 && errno != ENOENT) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant unlink %s %m", LogName, BACKUP);
- IOError(WHEN, oerrno);
- }
- if ((fd = open(BACKUP, O_WRONLY | O_TRUNC | O_CREAT, 0664)) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant open %s %m", LogName, BACKUP);
- IOError(WHEN, oerrno);
- }
- else if (xwrite(fd, ICDactpointer, ICDactsize) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write %s %m", LogName, BACKUP);
- IOError(WHEN, oerrno);
- close(fd);
- }
- else if (close(fd) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant close %s %m", LogName, BACKUP);
- IOError(WHEN, oerrno);
- }
-
-#ifdef __CYGWIN__
- /* If we are shrinking active, junk will be at the end between the */
- /* writev and ftruncate. Clobber it with values that overview and */
- /* nnrpd can ignore. */
- for (newactsize = 0, i = 0; i < vpcount; i++)
- newactsize += vp[i].iov_len;
- if (newactsize < ICDactsize) {
- padactsize = ICDactsize - newactsize;
- newvp = xmalloc((vpcount + 1) * sizeof(struct iovec));
- for (i = 0; i < vpcount; i++)
- newvp[i] = vp[i];
- filler = xcalloc(padactsize, 1);
- *filler = '.';
- filler[padactsize - 1] = '\n';
- newvp[vpcount].iov_base = filler;
- newvp[vpcount].iov_len = padactsize;
- vpcount++;
- }
- else {
- padactsize = 0;
- newvp = vp;
- }
- oerrno = 0;
- if (lseek(ICDactfd, 0, SEEK_SET) == -1) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant rewind %s %m", LogName, ICDactpath);
- IOError(WHEN, oerrno);
- goto bailout;
- }
- if (xwritev(ICDactfd, newvp, vpcount) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write %s %m", LogName, ICDactpath);
- IOError(WHEN, oerrno);
- goto bailout;
- }
- if (newactsize < ICDactsize && ftruncate(ICDactfd, newactsize) != 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant truncate %s", LogName, ICDactpath);
- }
-
-bailout:
- if (padactsize != 0) {
- free(filler);
- free(newvp);
- }
- if (oerrno != 0)
- return false;
-
-#else /* !__CYGWIN__, do it the Unix way. */
-
- /* Open the active file. */
- fd = open(NEWACT, O_WRONLY | O_TRUNC | O_CREAT, ARTFILE_MODE);
- if (fd < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant open %s %m", LogName, NEWACT);
- IOError(WHEN, oerrno);
- return false;
- }
-
- /* Write it. */
- if (xwritev(fd, vp, vpcount) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write %s %m", LogName, NEWACT);
- IOError(WHEN, oerrno);
- close(fd);
- return false;
- }
-
- /* Close it. */
- close(fd);
-
- /* Rename it to be the canonical active file */
- if (rename(NEWACT, ICDactpath) < 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant rename %s to %s %m",
- LogName, NEWACT, ICDactpath);
- IOError(WHEN, oerrno);
- return false;
- }
-
-#endif /* __CYGWIN__ */
-
- /* Invalidate in-core pointers. */
- ICDcloseactive();
-
- /* Restore in-core pointers. */
- if (Mode != OMrunning) {
- ICDneedsetup = true;
- /* Force the active file into memory. */
- NGparsefile();
- }
- else
- ICDsetup(true);
- return true;
-}
-
-
-/*
-** Change the flag on a newsgroup. Fairly easy.
-*/
-bool
-ICDchangegroup(NEWSGROUP *ngp, char *Rest)
-{
- static char NEWLINE[] = "\n";
- int i;
- struct iovec iov[3];
- bool ret;
- char *Name;
- long Last;
-
- /* Set up the scatter/gather vectors. */
- ICDiovset(&iov[0], ICDactpointer, ngp->Rest - ICDactpointer);
- ICDiovset(&iov[1], Rest, strlen(Rest));
- Name = xstrdup(ngp->Name);
- Last = ngp->Last;
- if (++ngp < &Groups[nGroups]) {
- /* Not the last group, keep the \n from the next line. */
- i = ngp->Start;
- ICDiovset(&iov[2], &ICDactpointer[i - 1], ICDactsize - i + 1);
- }
- else {
- /* Last group -- append a newline. */
- ICDiovset(&iov[2], NEWLINE, strlen(NEWLINE));
- }
- ret = ICDwritevactive(iov, 3);
- ICDiovrelease(&iov[0]);
- ICDiovrelease(&iov[1]);
- ICDiovrelease(&iov[2]);
-
- if (ret) {
- if (innconf->enableoverview && !OVgroupadd(Name, 0, Last, Rest)) {
- free(Name);
- return false;
- }
- }
- free(Name);
- return ret;
-}
-
-
-/*
-** Add a newsgroup. Append a line to the end of the active file and reload.
-*/
-bool
-ICDnewgroup(char *Name, char *Rest)
-{
- char buff[SMBUF];
- struct iovec iov[2];
- bool ret;
-
- /* Set up the scatter/gather vectors. */
- if (strlen(Name) + strlen(Rest) > SMBUF - 24) {
- syslog(L_ERROR, "%s too_long %s", LogName, MaxLength(Name, Name));
- return false;
- }
- snprintf(buff, sizeof(buff), "%s 0000000000 0000000001 %s\n", Name, Rest);
- ICDiovset(&iov[0], ICDactpointer, ICDactsize);
- ICDiovset(&iov[1], buff, strlen(buff));
-
- ret = ICDwritevactive(iov, 2);
- ICDiovrelease(&iov[0]);
- ICDiovrelease(&iov[1]);
- if (ret) {
- if (innconf->enableoverview && !OVgroupadd(Name, 1, 0, Rest))
- return false;
- }
- return ret;
-}
-
-
-/*
-** Remove a newsgroup. Splice the line out of the active file and reload.
-*/
-bool
-ICDrmgroup(NEWSGROUP *ngp)
-{
- struct iovec iov[2];
- int i;
- bool ret;
- char *Name;
-
- /* Don't let anyone remove newsgroups that INN requires exist. */
- if (strcmp(ngp->Name, "junk") == 0 || strcmp(ngp->Name, "control") == 0)
- return false;
- if (innconf->mergetogroups && strcmp(ngp->Name, "to") == 0)
- return false;
-
- Name = xstrdup(ngp->Name);
- /* If this is the first group in the file, write everything after. */
- if (ngp == &Groups[0]) {
- i = ngp[1].Start;
- ICDiovset(&iov[0], &ICDactpointer[i], ICDactsize - i);
- ret = ICDwritevactive(iov, 1);
- ICDiovrelease(&iov[0]);
- if (ret) {
- if (innconf->enableoverview && !OVgroupdel(Name)) {
- free(Name);
- return false;
- }
- }
- free(Name);
- return ret;
- }
-
- /* Write everything up to this group. */
- ICDiovset(&iov[0], ICDactpointer, ngp->Start);
-
- /* If this is the last group, that's all we have to write. */
- if (ngp == &Groups[nGroups - 1]) {
- ret = ICDwritevactive(iov, 1);
- ICDiovrelease(&iov[0]);
- if (ret) {
- if (innconf->enableoverview && !OVgroupdel(Name)) {
- free(Name);
- return false;
- }
- }
- free(Name);
- return ret;
- }
-
- /* Write everything after this group. */
- i = ngp[1].Start;
- ICDiovset(&iov[1], &ICDactpointer[i], ICDactsize - i);
- ret = ICDwritevactive(iov, 2);
- ICDiovrelease(&iov[0]);
- ICDiovrelease(&iov[1]);
- if (ret) {
- if (innconf->enableoverview && !OVgroupdel(Name)) {
- free(Name);
- return false;
- }
- }
- free(Name);
- return ret;
-}
-
-\f
-
-/*
-** Open the active file and "map" it into memory.
-*/
-char *
-ICDreadactive(endp)
- char **endp;
-{
- struct stat Sb;
-
- if (ICDactpointer) {
- *endp = ICDactpointer + ICDactsize;
- return ICDactpointer;
- }
- if (ICDactpath == NULL)
- ICDactpath = concatpath(innconf->pathdb, _PATH_ACTIVE);
- if ((ICDactfd = open(ICDactpath, O_RDWR)) < 0) {
- syslog(L_FATAL, "%s cant open %s %m", LogName, ICDactpath);
- exit(1);
- }
- close_on_exec(ICDactfd, true);
-
-#ifdef HAVE_MMAP
-
- if (fstat(ICDactfd, &Sb) < 0) {
- syslog(L_FATAL, "%s cant fstat %d %s %m",
- LogName, ICDactfd, ICDactpath);
- exit(1);
- }
- ICDactsize = Sb.st_size;
- ICDactpointer = mmap(NULL, ICDactsize, PROT_READ|PROT_WRITE,
- MAP_SHARED, ICDactfd, 0);
- if (ICDactpointer == (char *)-1) {
- syslog(L_FATAL, "%s cant mmap %d %s %m",
- LogName, ICDactfd, ICDactpath);
- exit(1);
- }
-
-#else /* !HAVE_MMAP */
-
- if ((ICDactpointer = ReadInDescriptor(ICDactfd, &Sb)) == NULL) {
- syslog(L_FATAL, "%s cant read %s %m", LogName, ICDactpath);
- exit(1);
- }
- ICDactsize = Sb.st_size;
-
-#endif /* HAVE_MMAP */
-
- *endp = ICDactpointer + ICDactsize;
- return ICDactpointer;
-}
-
-
-/*
-** Write the active file out.
-*/
-void
-ICDwriteactive(void)
-{
-#ifdef HAVE_MMAP
- if (msync(ICDactpointer, ICDactsize, MS_ASYNC) < 0) {
- syslog(L_FATAL, "%s msync failed %s %m", LogName, ICDactpath);
- exit(1);
- }
-#else /* !HAVE_MMAP */
- if (lseek(ICDactfd, 0, SEEK_SET) == -1) {
- syslog(L_FATAL, "%s cant rewind %s %m", LogName, ICDactpath);
- exit(1);
- }
- if (xwrite(ICDactfd, ICDactpointer, ICDactsize) < 0) {
- syslog(L_FATAL, "%s cant write %s %m", LogName, ICDactpath);
- exit(1);
- }
-#endif /* HAVE_MMAP */
-}
+++ /dev/null
-/* $Id: innd.c 7858 2008-06-05 18:51:20Z iulius $
-**
-** Variable definitions, miscellany, and main().
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "innperl.h"
-
-#define DEFINE_DATA
-#include "innd.h"
-#include "ov.h"
-
-
-bool Debug = false;
-bool NNRPTracing = false;
-bool StreamingOff = false ; /* default is we can stream */
-bool Tracing = false;
-bool DoCancels = true;
-char LogName[] = "SERVER";
-int ErrorCount = IO_ERROR_COUNT;
-OPERATINGMODE Mode = OMrunning;
-int RemoteLimit = REMOTELIMIT;
-time_t RemoteTimer = REMOTETIMER;
-int RemoteTotal = REMOTETOTAL;
-bool ThrottledbyIOError = false;
-
-static char *PID = NULL;
-
-/* Signal handling. If we receive a signal that should kill the server,
- killer_signal is set to the signal number that we received. This isn't
- what indicates that we should terminate; that's the separate global
- variable GotTerminate, used in CHANreadloop. */
-static volatile sig_atomic_t killer_signal = 0;
-
-/* Whether our self-maintained logs (stdout and stderr) are buffered, used
- to determine whether fflush is needed. Should be static. */
-bool BufferedLogs = true;
-
-/* FILEs for logs and error logs. Everything should just use stdout and
- stderr. */
-FILE *Log = NULL;
-FILE *Errlog = NULL;
-
-/* Some very old systems have a completely inadequate BUFSIZ buffer size, at
- least for our logging purposes. */
-#if BUFSIZ < 4096
-# define LOG_BUFSIZ 4096
-#else
-# define LOG_BUFSIZ BUFSIZ
-#endif
-
-/* Internal prototypes. */
-static RETSIGTYPE catch_terminate(int sig);
-static void xmalloc_abort(const char *what, size_t size,
- const char *file, int line);
-
-/* header table initialization */
-#define ARTHEADERINIT(name, type) {name, type, sizeof(name) - 1}
-const ARTHEADER ARTheaders[] = {
- /* Name Type */
- ARTHEADERINIT("Approved", HTstd),
-/* #define HDR__APPROVED 0 */
- ARTHEADERINIT("Control", HTstd),
-/* #define HDR__CONTROL 1 */
- ARTHEADERINIT("Date", HTreq),
-/* #define HDR__DATE 2 */
- ARTHEADERINIT("Distribution", HTstd),
-/* #define HDR__DISTRIBUTION 3 */
- ARTHEADERINIT("Expires", HTstd),
-/* #define HDR__EXPIRES 4 */
- ARTHEADERINIT("From", HTreq),
-/* #define HDR__FROM 5 */
- ARTHEADERINIT("Lines", HTstd),
-/* #define HDR__LINES 6 */
- ARTHEADERINIT("Message-ID", HTreq),
-/* #define HDR__MESSAGE_ID 7 */
- ARTHEADERINIT("Newsgroups", HTreq),
-/* #define HDR__NEWSGROUPS 8 */
- ARTHEADERINIT("Path", HTreq),
-/* #define HDR__PATH 9 */
- ARTHEADERINIT("Reply-To", HTstd),
-/* #define HDR__REPLY_TO 10 */
- ARTHEADERINIT("Sender", HTstd),
-/* #define HDR__SENDER 11 */
- ARTHEADERINIT("Subject", HTreq),
-/* #define HDR__SUBJECT 12 */
- ARTHEADERINIT("Supersedes", HTstd),
-/* #define HDR__SUPERSEDES 13 */
- ARTHEADERINIT("Bytes", HTstd),
-/* #define HDR__BYTES 14 */
- ARTHEADERINIT("Also-Control", HTobs),
-/* #define HDR__ALSOCONTROL 15 */
- ARTHEADERINIT("References", HTstd),
-/* #define HDR__REFERENCES 16 */
- ARTHEADERINIT("Xref", HTsav),
-/* #define HDR__XREF 17 */
- ARTHEADERINIT("Keywords", HTstd),
-/* #define HDR__KEYWORDS 18 */
- ARTHEADERINIT("X-Trace", HTstd),
-/* #define HDR__XTRACE 19 */
- ARTHEADERINIT("Date-Received", HTobs),
-/* #define HDR__DATERECEIVED 20 */
- ARTHEADERINIT("Posted", HTobs),
-/* #define HDR__POSTED 21 */
- ARTHEADERINIT("Posting-Version", HTobs),
-/* #define HDR__POSTINGVERSION 22 */
- ARTHEADERINIT("Received", HTobs),
-/* #define HDR__RECEIVED 23 */
- ARTHEADERINIT("Relay-Version", HTobs),
-/* #define HDR__RELAYVERSION 24 */
- ARTHEADERINIT("NNTP-Posting-Host", HTstd),
-/* #define HDR__NNTPPOSTINGHOST 25 */
- ARTHEADERINIT("Followup-To", HTstd),
-/* #define HDR__FOLLOWUPTO 26 */
- ARTHEADERINIT("Organization", HTstd),
-/* #define HDR__ORGANIZATION 27 */
- ARTHEADERINIT("Content-Type", HTstd),
-/* #define HDR__CONTENTTYPE 28 */
- ARTHEADERINIT("Content-Base", HTstd),
-/* #define HDR__CONTENTBASE 29 */
- ARTHEADERINIT("Content-Disposition", HTstd),
-/* #define HDR__CONTENTDISPOSITION 30 */
- ARTHEADERINIT("X-Newsreader", HTstd),
-/* #define HDR__XNEWSREADER 31 */
- ARTHEADERINIT("X-Mailer", HTstd),
-/* #define HDR__XMAILER 32 */
- ARTHEADERINIT("X-Newsposter", HTstd),
-/* #define HDR__XNEWSPOSTER 33 */
- ARTHEADERINIT("X-Cancelled-By", HTstd),
-/* #define HDR__XCANCELLEDBY 34 */
- ARTHEADERINIT("X-Canceled-By", HTstd),
-/* #define HDR__XCANCELEDBY 35 */
- ARTHEADERINIT("Cancel-Key", HTstd),
-/* #define HDR__CANCELKEY 36 */
- ARTHEADERINIT("User-Agent", HTstd),
-/* #define HDR__USER_AGENT 37 */
- ARTHEADERINIT("X-Original-Message-ID", HTstd),
-/* #define HDR__X_ORIGINAL_MESSAGE_ID 38 */
- ARTHEADERINIT("Cancel-Lock", HTstd),
-/* #define HDR__CANCEL_LOCK 39 */
- ARTHEADERINIT("Content-Transfer-Encoding", HTstd),
-/* #define HDR__CONTENT_TRANSFER_ENCODING 40 */
- ARTHEADERINIT("Face", HTstd),
-/* #define HDR__FACE 41 */
- ARTHEADERINIT("Injection-Info", HTstd),
-/* #define HDR__INJECTION_INFO 42 */
- ARTHEADERINIT("List-ID", HTstd),
-/* #define HDR__LIST_ID 43 */
- ARTHEADERINIT("MIME-Version", HTstd),
-/* #define HDR__MIME_VERSION 44 */
- ARTHEADERINIT("Originator", HTstd),
-/* #define HDR__ORIGINATOR 45 */
- ARTHEADERINIT("X-Auth", HTstd),
-/* #define HDR__X_AUTH 46 */
- ARTHEADERINIT("X-Complaints-To", HTstd),
-/* #define HDR__X_COMPLAINTS_TO 47 */
- ARTHEADERINIT("X-Face", HTstd),
-/* #define HDR__X_FACE 48 */
- ARTHEADERINIT("X-HTTP-UserAgent", HTstd),
-/* #define HDR__X_HTTP_USERAGENT 49 */
- ARTHEADERINIT("X-HTTP-Via", HTstd),
-/* #define HDR__X_HTTP_VIA 50 */
- ARTHEADERINIT("X-Modbot", HTstd),
-/* #define HDR__X_MODBOT 51 */
- ARTHEADERINIT("X-Modtrace", HTstd),
-/* #define HDR__X_MODTRACE 52 */
- ARTHEADERINIT("X-No-Archive", HTstd),
-/* #define HDR__X_NO_ARCHIVE 53 */
- ARTHEADERINIT("X-Original-Trace", HTstd),
-/* #define HDR__X_ORIGINAL_TRACE 54 */
- ARTHEADERINIT("X-Originating-IP", HTstd),
-/* #define HDR__X_ORIGINATING_IP 55 */
- ARTHEADERINIT("X-PGP-Key", HTstd),
-/* #define HDR__X_PGP_KEY 56 */
- ARTHEADERINIT("X-PGP-Sig", HTstd),
-/* #define HDR__X_PGP_SIG 57 */
- ARTHEADERINIT("X-Poster-Trace", HTstd),
-/* #define HDR__X_POSTER_TRACE 58 */
- ARTHEADERINIT("X-Postfilter", HTstd),
-/* #define HDR__X_POSTFILTER 59 */
- ARTHEADERINIT("X-Proxy-User", HTstd),
-/* #define HDR__X_PROXY_USER 60 */
- ARTHEADERINIT("X-Submissions-To", HTstd),
-/* #define HDR__X_SUBMISSIONS_TO 61 */
- ARTHEADERINIT("X-Usenet-Provider", HTstd),
-/* #define HDR__X_USENET_PROVIDER 62 */
- ARTHEADERINIT("In-Reply-To", HTstd),
-/* #define HDR__IN_REPLY_TO 63 */
- ARTHEADERINIT("Injection-Date", HTstd),
-/* #define HDR__INJECTION_DATE 64 */
- ARTHEADERINIT("NNTP-Posting-Date", HTstd)
-/* #define HDR__NNTP_POSTING_DATE 65 */
-};
-/* #define MAX_ARTHEADER 66 */
-\f
-
-/*
-** Signal handler to catch SIGTERM and similar signals and queue a clean
-** shutdown.
-*/
-static RETSIGTYPE
-catch_terminate(int sig)
-{
- GotTerminate = true;
- killer_signal = sig;
-
-#ifndef HAVE_SIGACTION
- xsignal(sig, catch_terminate);
-#endif
-}
-
-
-/*
-** Memory allocation failure handler. Instead of the default behavior of
-** just exiting, call abort to generate a core dump.
-*/
-static void
-xmalloc_abort(const char *what, size_t size, const char *file, int line)
-{
- fprintf(stderr, "SERVER cant %s %lu bytes at %s line %d: %s", what,
- (unsigned long) size, file, line, strerror(errno));
- syslog(LOG_CRIT, "SERVER cant %s %lu bytes at %s line %d: %m", what,
- (unsigned long) size, file, line);
- abort();
-}
-
-
-/*
-** The name is self-explanatory.
-*/
-void
-CleanupAndExit(int status, const char *why)
-{
- JustCleanup();
- if (why)
- syslog(LOG_WARNING, "SERVER shutdown %s", why);
- else
- syslog(LOG_WARNING, "SERVER shutdown received signal %d",
- killer_signal);
- exit(status);
-}
-
-
-/*
-** Close down all parts of the system (e.g., before calling exit or exec).
-*/
-void
-JustCleanup(void)
-{
- SITEflushall(false);
- CCclose();
- LCclose();
- NCclose();
- RCclose();
- ICDclose();
- InndHisClose();
- ARTclose();
- if (innconf->enableoverview)
- OVclose();
- NGclose();
- SMshutdown();
-
-#if DO_TCL
- TCLclose();
-#endif
-
-#if DO_PERL
- PerlFilter(false);
- PerlClose();
-#endif
-
-#if DO_PYTHON
- PYclose();
-#endif
-
- CHANshutdown();
- innconf_free(innconf);
- innconf = NULL;
-
- sleep(1);
-
- if (unlink(PID) < 0 && errno != ENOENT)
- syslog(LOG_ERR, "SERVER cant unlink %s: %m", PID);
-}
-
-
-/*
-** Flush one log file, re-establishing buffering if necessary. stdout is
-** block-buffered, stderr is line-buffered.
-*/
-void
-ReopenLog(FILE *F)
-{
- char *path, *oldpath;
- int mask;
-
- if (Debug)
- return;
-
- path = concatpath(innconf->pathlog,
- (F == stdout) ? _PATH_LOGFILE : _PATH_ERRLOG);
- oldpath = concat(path, ".old", (char *) 0);
- if (rename(path, oldpath) < 0)
- syswarn("SERVER cant rename %s to %s", path, oldpath);
- free(oldpath);
- mask = umask(033);
- if (freopen(path, "a", F) != F)
- sysdie("SERVER cant freopen %s", path);
- free(path);
- umask(mask);
- if (BufferedLogs)
- setvbuf(F, NULL, (F == stdout) ? _IOFBF : _IOLBF, LOG_BUFSIZ);
-}
-
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage error.\n");
- exit(1);
-}
-
-
-int
-main(int ac, char *av[])
-{
- const char *name, *p;
- char *path;
- char *t;
- bool flag;
- static char WHEN[] = "PID file";
- int i, j, fd[MAX_SOCKETS + 1];
- char buff[SMBUF], *path1, *path2;
- FILE *F;
- bool ShouldFork;
- bool ShouldRenumber;
- bool ShouldSyntaxCheck;
- bool filter = true;
- pid_t pid;
-#if defined(_DEBUG_MALLOC_INC)
- union malloptarg m;
-#endif /* defined(_DEBUG_MALLOC_INC) */
-
- /* Set up the pathname, first thing, and teach our error handlers about
- the name of the program. */
- name = av[0];
- if (name == NULL || *name == '\0')
- name = "innd";
- else {
- p = strrchr(name, '/');
- if (p != NULL)
- name = p + 1;
- }
- message_program_name = name;
- openlog(name, LOG_CONS | LOG_NDELAY, LOG_INN_SERVER);
- message_handlers_die(2, message_log_stderr, message_log_syslog_crit);
- message_handlers_warn(2, message_log_stderr, message_log_syslog_err);
- message_handlers_notice(1, message_log_syslog_notice);
-
- /* Make sure innd is not running as root. innd must be either started
- via inndstart or use a non-privileged port. */
- if (getuid() == 0 || geteuid() == 0)
- die("SERVER must be run as user news, not root (use inndstart)");
-
- /* Handle malloc debugging. */
-#if defined(_DEBUG_MALLOC_INC)
- m.i = M_HANDLE_ABORT;
- dbmallopt(MALLOC_WARN, &m);
- dbmallopt(MALLOC_FATAL, &m);
- m.i = 3;
- dbmallopt(MALLOC_FILLAREA, &m);
- m.i = 0;
- dbmallopt(MALLOC_CKCHAIN, &m);
- dbmallopt(MALLOC_CKDATA, &m);
-#endif /* defined(_DEBUG_MALLOC_INC) */
-
- /* Set defaults. */
- TimeOut.tv_sec = DEFAULT_TIMEOUT;
- TimeOut.tv_usec = 0;
- ShouldFork = true;
- ShouldRenumber = false;
- ShouldSyntaxCheck = false;
- fd[0] = fd[1] = -1;
-
- /* Set some options from inn.conf that can be overridden with
- command-line options if they exist, so read inn.conf first. */
- if (!innconf_read(NULL))
- exit(1);
-
- /* Parse JCL. */
- CCcopyargv(av);
- while ((i = getopt(ac, av, "ac:Cdfi:l:m:o:Nn:p:P:rst:uH:T:X:")) != EOF)
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'a':
- AnyIncoming = true;
- break;
- case 'c':
- innconf->artcutoff = atoi(optarg);
- break;
- case 'C':
- DoCancels = false;
- break;
- case 'd':
- Debug = true;
- break;
- case 'f':
- ShouldFork = false;
- break;
- case 'H':
- RemoteLimit = atoi(optarg);
- break;
- case 'i':
- innconf->maxconnections = atoi(optarg);
- break;
- case 'I':
- if (innconf->bindaddress) free(innconf->bindaddress);
- innconf->bindaddress = xstrdup(optarg);
- break;
- case 'l':
- innconf->maxartsize = atol(optarg);
- break;
- case 'm':
- if (ModeReason)
- free(ModeReason);
- switch (*optarg) {
- default:
- Usage();
- /* NOTREACHED */
- case 'g': Mode = OMrunning; break;
- case 'p': Mode = OMpaused; break;
- case 't': Mode = OMthrottled; break;
- }
- if (Mode != OMrunning)
- ModeReason = concat(OMpaused ? "Paus" : "Throttl",
- "ed from the command line", (char *) 0);
- break;
- case 'N':
- filter = false;
- break;
- case 'n':
- switch (*optarg) {
- default:
- Usage();
- /* NOTREACHED */
- case 'n': innconf->readerswhenstopped = false; break;
- case 'y': innconf->readerswhenstopped = true; break;
- }
- break;
- case 'o':
- MaxOutgoing = atoi(optarg);
- break;
- case 'p':
- /* Silently ignore multiple -p flags, in case ctlinnd xexec
- called inndstart. */
- if (fd[0] != -1)
- break;
- t = xstrdup(optarg);
- p = strtok(t, ",");
- j = 0;
- do {
- fd[j++] = atoi(p);
- if (j == MAX_SOCKETS)
- break;
- } while ((p = strtok(NULL, ",")) != NULL);
- fd[j] = -1;
- free(t);
- break;
- case 'P':
- innconf->port = atoi(optarg);
- break;
- case 'r':
- ShouldRenumber = true;
- break;
- case 's':
- ShouldSyntaxCheck = true;
- break;
- case 't':
- TimeOut.tv_sec = atol(optarg);
- break;
- case 'T':
- RemoteTotal = atoi(optarg);
- break;
- case 'u':
- BufferedLogs = false;
- break;
- case 'X':
- RemoteTimer = atoi(optarg);
- break;
- case 'Z':
- StreamingOff = true;
- break;
- }
- ac -= optind;
- if (ac != 0)
- Usage();
- if (ModeReason && !innconf->readerswhenstopped)
- NNRPReason = xstrdup(ModeReason);
-
- if (ShouldSyntaxCheck) {
- if ((p = CCcheckfile((char **)NULL)) == NULL)
- exit(0);
- fprintf(stderr, "%s\n", p + 2);
- exit(1);
- }
-
- /* Get the Path entry. */
- if (innconf->pathhost == NULL) {
- syslog(L_FATAL, "%s No pathhost set", LogName);
- exit(1);
- }
- Path.used = strlen(innconf->pathhost) + 1;
- Path.size = Path.used + 1;
- Path.data = xmalloc(Path.size);
- snprintf(Path.data, Path.size, "%s!", innconf->pathhost);
- if (innconf->pathalias == NULL) {
- Pathalias.used = 0;
- Pathalias.data = NULL;
- } else {
- Pathalias.used = strlen(innconf->pathalias) + 1;
- Pathalias.size = Pathalias.used + 1;
- Pathalias.data = xmalloc(Pathalias.size);
- snprintf(Pathalias.data, Pathalias.size, "%s!", innconf->pathalias);
- }
- if (innconf->pathcluster == NULL) {
- Pathcluster.used = 0;
- Pathcluster.data = NULL;
- } else {
- Pathcluster.used = strlen(innconf->pathcluster) + 1;
- Pathcluster.size = Pathcluster.used + 1;
- Pathcluster.data = xmalloc(Pathcluster.size);
- snprintf(Pathcluster.data, Pathcluster.size, "%s!", innconf->pathcluster);
- }
- /* Trace history ? */
- if (innconf->stathist != NULL) {
- syslog(L_NOTICE, "logging hist stats to %s", innconf->stathist);
- HISlogto(innconf->stathist);
- }
-
- i = dbzneedfilecount();
- if (!fdreserve(3 + i)) { /* TEMPORARYOPEN, history stats, INND_HISTORY and i */
- syslog(L_FATAL, "%s cant reserve file descriptors %m", LogName);
- exit(1);
- }
-
- /* Set up our permissions. */
- umask(NEWSUMASK);
-
- /* Become a daemon and initialize our log files. */
- if (Debug) {
- xsignal(SIGINT, catch_terminate);
- if (chdir(innconf->patharticles) < 0)
- sysdie("SERVER cant chdir to %s", innconf->patharticles);
- } else {
- if (ShouldFork)
- daemonize(innconf->patharticles);
-
- /* Open the logs. stdout is used to log information about incoming
- articles and stderr is used to log serious error conditions (as
- well as to capture stderr from embedded filters). Both are
- normally fully buffered. */
- path = concatpath(innconf->pathlog, _PATH_LOGFILE);
- if (freopen(path, "a", stdout) == NULL)
- sysdie("SERVER cant freopen stdout to %s", path);
- setvbuf(stdout, NULL, _IOFBF, LOG_BUFSIZ);
- free(path);
- path = concatpath(innconf->pathlog, _PATH_ERRLOG);
- if (freopen(path, "a", stderr) == NULL)
- sysdie("SERVER cant freopen stderr to %s", path);
- setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
- free(path);
- }
- Log = stdout;
- Errlog = stderr;
-
- /* Initialize overview if necessary. */
- if (innconf->enableoverview && !OVopen(OV_WRITE))
- die("SERVER cant open overview method");
-
- /* Always attempt to increase the number of open file descriptors. If
- we're not root, this may just fail quietly. */
- if (innconf->rlimitnofile > 0)
- setfdlimit(innconf->rlimitnofile);
-
- /* Get number of open channels. */
- i = getfdlimit();
- if (i < 0) {
- syslog(L_FATAL, "%s cant get file descriptor limit: %m", LogName);
- exit(1);
- }
-
- /* There is no file descriptor limit on some hosts; for those, cap at
- MaxOutgoing plus maxconnections plus 20, or 5000, whichever is larger.
- Otherwise, we use insane amounts of memory for the channel table.
- FIXME: Get rid of this hard-coded constant. */
- if (i > 5000) {
- int max;
-
- max = innconf->maxconnections + MaxOutgoing + 20;
- if (max < 5000)
- max = 5000;
- i = max;
- }
- syslog(L_NOTICE, "%s descriptors %d", LogName, i);
- if (MaxOutgoing == 0) {
- /* getfdlimit() - (stdio + dbz + cc + lc + rc + art + fudge) */
- MaxOutgoing = i - ( 3 + 3 + 2 + 1 + 1 + 1 + 2 );
- syslog(L_NOTICE, "%s outgoing %d", LogName, MaxOutgoing);
- }
-
- /* See if another instance is alive. */
- if (PID == NULL)
- PID = concatpath(innconf->pathrun, _PATH_SERVERPID);
- if ((F = fopen(PID, "r")) != NULL) {
- if (fgets(buff, sizeof buff, F) != NULL
- && ((pid = (pid_t) atol(buff)) > 0)
- && (kill(pid, 0) > 0 || errno != ESRCH)) {
- syslog(L_FATAL, "%s already_running pid %ld", LogName,
- (long) pid);
- exit(1);
- }
- fclose(F);
- }
-
- if (GetTimeInfo(&Now) < 0)
- syslog(L_ERROR, "%s cant gettimeinfo %m", LogName);
-
- /* Set up signal and error handlers. */
- xmalloc_error_handler = xmalloc_abort;
- xsignal(SIGHUP, catch_terminate);
- xsignal(SIGTERM, catch_terminate);
-
- /* Set up the various parts of the system. Channel feeds start
- processes so call PROCsetup before ICDsetup. NNTP needs to know if
- it's a slave, so call RCsetup before NCsetup. */
- CHANsetup(i);
- PROCsetup(10);
- if (Mode == OMrunning)
- InndHisOpen();
- CCsetup();
- LCsetup();
- RCsetup(fd[0]);
- for (i = 1; fd[i] != -1; i++)
- RCsetup(fd[i]);
- WIPsetup();
- NCsetup();
- ARTsetup();
- ICDsetup(true);
- if (innconf->timer)
- TMRinit(TMR_MAX);
-
- /* Initialize the storage subsystem. */
- flag = true;
- if (!SMsetup(SM_RDWR, &flag) || !SMsetup(SM_PREOPEN, &flag))
- die("SERVER cant set up storage manager");
- if (!SMinit())
- die("SERVER cant initalize storage manager: %s", SMerrorstr);
-
-#if defined(_DEBUG_MALLOC_INC)
- m.i = 1;
- dbmallopt(MALLOC_CKCHAIN, &m);
- dbmallopt(MALLOC_CKDATA, &m);
-#endif /* defined(_DEBUG_MALLOC_INC) */
-
- /* Record our PID. */
- pid = getpid();
- if ((F = fopen(PID, "w")) == NULL) {
- i = errno;
- syslog(L_ERROR, "%s cant fopen %s %m", LogName, PID);
- IOError(WHEN, i);
- }
- else {
- if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F)) {
- i = errno;
- syslog(L_ERROR, "%s cant fprintf %s %m", LogName, PID);
- IOError(WHEN, i);
- }
- if (fclose(F) == EOF) {
- i = errno;
- syslog(L_ERROR, "%s cant fclose %s %m", LogName, PID);
- IOError(WHEN, i);
- }
- if (chmod(PID, 0664) < 0) {
- i = errno;
- syslog(L_ERROR, "%s cant chmod %s %m", LogName, PID);
- IOError(WHEN, i);
- }
- }
-
-#if DO_TCL
- TCLsetup();
- if (!filter)
- TCLfilter(false);
-#endif /* DO_TCL */
-
-#if DO_PERL
- /* Load the Perl code */
- path1 = concatpath(innconf->pathfilter, _PATH_PERL_STARTUP_INND);
- path2 = concatpath(innconf->pathfilter, _PATH_PERL_FILTER_INND);
- PERLsetup(path1, path2, "filter_art");
- free(path1);
- free(path2);
- PLxsinit();
- if (filter)
- PerlFilter(true);
-#endif /* DO_PERL */
-
-#if DO_PYTHON
- PYsetup();
- if (!filter)
- PYfilter(false);
-#endif /* DO_PYTHON */
-
- /* And away we go... */
- if (ShouldRenumber) {
- syslog(LOG_NOTICE, "SERVER renumbering");
- if (!ICDrenumberactive())
- die("SERVER cant renumber");
- }
- syslog(LOG_NOTICE, "SERVER starting");
- CHANreadloop();
-
- /* CHANreadloop should never return. */
- CleanupAndExit(1, "CHANreadloop returned");
- return 1;
-}
+++ /dev/null
-/* $Id: innd.h 7858 2008-06-05 18:51:20Z iulius $
-**
-** Many of the data types used here have abbreviations, such as CT
-** for CHANNELTYPE. Here are a list of the conventions and meanings:
-**
-** ART A news article
-** CHAN An I/O channel
-** CS Channel state
-** CT Channel type
-** FNL Funnel, into which other feeds pour
-** FT Feed type -- how a site gets told about new articles
-** ICD In-core data (primarily the active and sys files)
-** LC Local NNTP connection-receiving channel
-** CC Control channel (used by ctlinnd)
-** NC NNTP client channel
-** NG Newsgroup
-** NGH Newgroup hashtable
-** PROC A process (used to feed a site)
-** PS Process state
-** RC Remote NNTP connection-receiving channel
-** RCHAN A channel in "read" state
-** SITE Something that gets told when we get an article
-** WCHAN A channel in "write" state
-** WIP Work-In-Progress, keeps track of articles before committed.
-*/
-
-#ifndef INND_H
-#define INND_H 1
-
-#include "config.h"
-#include "portable/time.h"
-#include "portable/socket.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/buffer.h"
-#include "inn/history.h"
-#include "inn/messages.h"
-#include "inn/timer.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "storage.h"
-
-/* TCL defines EXTERN, so undef it after inclusion since we use it. */
-#if DO_TCL
-# include <tcl.h>
-# undef EXTERN
-#endif
-
-BEGIN_DECLS
-
-typedef short SITEIDX;
-#define NOSITE ((SITEIDX) -1)
-
-/*
-** Various constants.
-*/
-
-/* Used for storing group subscriptions for feeds. */
-#define SUB_DEFAULT false
-#define SUB_NEGATE '!'
-#define SUB_POISON '@'
-
-/* Special characters for newsfeeds entries. */
-#define NF_FIELD_SEP ':'
-#define NF_SUBFIELD_SEP '/'
-
-
-/*
-** Server's operating mode.
-*/
-typedef enum _OPERATINGMODE {
- OMrunning,
- OMpaused,
- OMthrottled
-} OPERATINGMODE;
-
-
-typedef struct _LISTBUFFER {
- char * Data;
- int DataLength;
- char ** List;
- int ListLength;
-} LISTBUFFER;
-
-/*
-** What program to handoff a connection to.
-*/
-typedef enum _HANDOFF {
- HOnnrpd,
- HOnntpd
-} HANDOFF;
-
-
-/*
-** Header types.
-*/
-typedef enum _ARTHEADERTYPE {
- HTreq, /* Drop article if this is missing */
- HTobs, /* obsolete header but keep untouched */
- HTstd, /* Standard optional header */
- HTsav /* Save header, but may be deleted from article */
-} ARTHEADERTYPE;
-
-
-/*
-** Entry in the header table.
-*/
-typedef struct _ARTHEADER {
- const char * Name;
- ARTHEADERTYPE Type;
- int Size; /* Length of Name. */
-} ARTHEADER;
-
-
-/*
-** Header content
-*/
-typedef struct _HDRCONTENT {
- char * Value; /* don't copy, shows where it begins */
- int Length; /* Length of Value(tailing CRLF is not
- included. -1 if duplicated */
-} HDRCONTENT;
-
-
-/*
-** A way to index into the header table.
-*/
-#define HDR_FOUND(_x) (hc[(_x)].Length > 0)
-#define HDR_PARSE_START(_x) hc[(_x)].Value[hc[_x].Length] = '\0'
-#define HDR(_x) (hc[(_x)].Value)
-/* HDR_LEN does not includes trailing "\r\n" */
-#define HDR_LEN(_x) (hc[(_x)].Length)
-#define HDR_PARSE_END(_x) hc[(_x)].Value[hc[_x].Length] = '\r'
-
-
-#define HDR__APPROVED 0
-#define HDR__CONTROL 1
-#define HDR__DATE 2
-#define HDR__DISTRIBUTION 3
-#define HDR__EXPIRES 4
-#define HDR__FROM 5
-#define HDR__LINES 6
-#define HDR__MESSAGE_ID 7
-#define HDR__NEWSGROUPS 8
-#define HDR__PATH 9
-#define HDR__REPLY_TO 10
-#define HDR__SENDER 11
-#define HDR__SUBJECT 12
-#define HDR__SUPERSEDES 13
-#define HDR__BYTES 14
-#define HDR__ALSOCONTROL 15
-#define HDR__REFERENCES 16
-#define HDR__XREF 17
-#define HDR__KEYWORDS 18
-#define HDR__XTRACE 19
-#define HDR__DATERECEIVED 20
-#define HDR__POSTED 21
-#define HDR__POSTINGVERSION 22
-#define HDR__RECEIVED 23
-#define HDR__RELAYVERSION 24
-#define HDR__NNTPPOSTINGHOST 25
-#define HDR__FOLLOWUPTO 26
-#define HDR__ORGANIZATION 27
-#define HDR__CONTENTTYPE 28
-#define HDR__CONTENTBASE 29
-#define HDR__CONTENTDISPOSITION 30
-#define HDR__XNEWSREADER 31
-#define HDR__XMAILER 32
-#define HDR__XNEWSPOSTER 33
-#define HDR__XCANCELLEDBY 34
-#define HDR__XCANCELEDBY 35
-#define HDR__CANCELKEY 36
-#define HDR__USER_AGENT 37
-#define HDR__X_ORIGINAL_MESSAGE_ID 38
-#define HDR__CANCEL_LOCK 39
-#define HDR__CONTENT_TRANSFER_ENCODING 40
-#define HDR__FACE 41
-#define HDR__INJECTION_INFO 42
-#define HDR__LIST_ID 43
-#define HDR__MIME_VERSION 44
-#define HDR__ORIGINATOR 45
-#define HDR__X_AUTH 46
-#define HDR__X_COMPLAINTS_TO 47
-#define HDR__X_FACE 48
-#define HDR__X_HTTP_USERAGENT 49
-#define HDR__X_HTTP_VIA 50
-#define HDR__X_MODBOT 51
-#define HDR__X_MODTRACE 52
-#define HDR__X_NO_ARCHIVE 53
-#define HDR__X_ORIGINAL_TRACE 54
-#define HDR__X_ORIGINATING_IP 55
-#define HDR__X_PGP_KEY 56
-#define HDR__X_PGP_SIG 57
-#define HDR__X_POSTER_TRACE 58
-#define HDR__X_POSTFILTER 59
-#define HDR__X_PROXY_USER 60
-#define HDR__X_SUBMISSIONS_TO 61
-#define HDR__X_USENET_PROVIDER 62
-#define HDR__IN_REPLY_TO 63
-#define HDR__INJECTION_DATE 64
-#define HDR__NNTP_POSTING_DATE 65
-
-#define MAX_ARTHEADER 66
-
-/*
-** Miscellaneous data we want to keep on an article. All the fields
-** are not always valid.
-*/
-typedef struct _ARTDATA {
- int Body; /* where body begins in article
- it indicates offset from bp->Data */
- char * Poster; /* Sender otherwise From in article */
- char * Replyto; /* Reply-To otherwise From in article */
- time_t Posted; /* when article posted */
- time_t Arrived; /* when article arrived */
- time_t Expires; /* when article should be expired */
- int Lines; /* number of body lines */
- int HeaderLines; /* number of header lines */
- long BytesValue; /* size of stored article, "\r\n" is
- counted as 1 byte */
- char Bytes[16]; /* generated Bytes header */
- int BytesLength; /* generated Bytes header length */
- char * BytesHeader; /* where Bytes header begins in
- received article */
- char TokenText[(sizeof(TOKEN) * 2) + 3];
- /* token of stored article */
- LISTBUFFER Newsgroups; /* newsgroup list */
- int Groupcount; /* number of newsgroups */
- int Followcount; /* number of folloup to newsgroups */
- char * Xref; /* generated Xref header */
- int XrefLength; /* generated Xref header length */
- int XrefBufLength; /* buffer length of generated Xref
- header */
- LISTBUFFER Distribution; /* distribution list */
- const char * Feedsite; /* who gives me this article */
- int FeedsiteLength; /* length of Feedsite */
- LISTBUFFER Path; /* path name list */
- int StoredGroupLength; /* 1st newsgroup name in Xref */
- char * Replic; /* replication data */
- int ReplicLength; /* length of Replic */
- HASH * Hash; /* Message-ID hash */
- struct buffer Headers; /* buffer for headers which will be sent
- to site */
- struct buffer Overview; /* buffer for overview data */
- int CRwithoutLF; /* counter for '\r' without '\n' */
- int LFwithoutCR; /* counter for '\n' without '\r' */
- long CurHeader; /* where current header starts.
- this is used for folded header
- it indicates offset from bp->Data */
- bool NullHeader; /* contains NULL in current header */
- long LastTerminator; /* where last '.' exists. only set if
- it exists at the begining of line
- it indicates offset from bp->Data */
- long LastCR; /* where last CR exists
- it indicates offset from bp->Data */
- long LastCRLF; /* where last CRLF exists.
- indicates where last LF exists
- it indicates offset from bp->Data */
- HDRCONTENT HdrContent[MAX_ARTHEADER];
- /* includes system headers info */
- bool AddAlias; /* Whether Pathalias should be added
- to this article */
- bool Hassamepath; /* Whether this article matches Path */
- bool Hassamecluster; /* Whether this article matches
- Pathcluster */
-} ARTDATA;
-
-/*
-** Set of channel types.
-*/
-typedef enum _CHANNELTYPE {
- CTany,
- CTfree,
- CTremconn,
- CTreject,
- CTnntp,
- CTlocalconn,
- CTcontrol,
- CTfile,
- CTexploder,
- CTprocess
-} CHANNELTYPE;
-
-
-/*
-** The state a channel is in. Interpretation of this depends on the
-** channel's type. Used mostly by CTnntp channels.
-*/
-typedef enum _CHANNELSTATE {
- CSerror,
- CSwaiting,
- CSgetcmd,
- CSgetauth,
- CSwritegoodbye,
- CSwriting,
- CSpaused,
- CSgetheader,
- CSgetbody,
- CSgotarticle,
- CSgotlargearticle,
- CSnoarticle,
- CSeatarticle,
- CSeatcommand,
- CSgetxbatch,
- CScancel
-} CHANNELSTATE;
-
-#define SAVE_AMT 10 /* used for eating article/command */
-
-/*
-** I/O channel, the heart of the program. A channel has input and output
-** buffers, and functions to call when there is input to be read, or when
-** all the output was been written. Many callback functions take a
-** pointer to a channel, so set up a typedef for that.
-*/
-#define PRECOMMITCACHESIZE 128
-struct _CHANNEL;
-typedef void (*innd_callback_t)(struct _CHANNEL *);
-
-typedef struct _CHANNEL {
- CHANNELTYPE Type;
- CHANNELSTATE State;
- int fd;
- bool Skip;
- bool Streaming;
- bool NoResendId;
- bool privileged;
- bool Nolist;
- unsigned long Duplicate;
- unsigned long Unwanted_s;
- unsigned long Unwanted_f;
- unsigned long Unwanted_d;
- unsigned long Unwanted_g;
- unsigned long Unwanted_u;
- unsigned long Unwanted_o;
- float Size;
- float DuplicateSize;
- unsigned long Check;
- unsigned long Check_send;
- unsigned long Check_deferred;
- unsigned long Check_got;
- unsigned long Check_cybercan;
- unsigned long Takethis;
- unsigned long Takethis_Ok;
- unsigned long Takethis_Err;
- unsigned long Ihave;
- unsigned long Ihave_Duplicate;
- unsigned long Ihave_Deferred;
- unsigned long Ihave_SendIt;
- unsigned long Ihave_Cybercan;
- int Reported;
- long Received;
- long Refused;
- long Rejected;
- int BadWrites;
- int BadReads;
- int BlockedWrites;
- int BadCommands;
- time_t LastActive;
- time_t NextLog;
- struct sockaddr_storage Address;
- innd_callback_t Reader;
- innd_callback_t WriteDone;
- time_t Waketime;
- time_t Started;
- innd_callback_t Waker;
- void * Argument;
- void * Event;
- struct buffer In;
- struct buffer Out;
- bool Tracing;
- struct buffer Sendid;
- HASH CurrentMessageIDHash;
- struct _WIP * PrecommitWIP[PRECOMMITCACHESIZE];
- int PrecommitiCachenext;
- int XBatchSize;
- int LargeArtSize;
- int LargeCmdSize;
- int ActiveCnx;
- int MaxCnx;
- int HoldTime;
- time_t ArtBeg;
- int ArtMax;
- long Start; /* where current cmd/article starts
- it indicates offset from bp->Data */
- long Next; /* next pointer to read
- it indicates offset from bp->Data */
- char Error[SMBUF]; /* error buffer */
- ARTDATA Data; /* used for processing article */
- struct _CHANNEL *nextcp; /* linked list for each incoming site */
-} CHANNEL;
-
-#define DEFAULTNGBOXSIZE 64
-
-/*
-** A newsgroup has a name in different formats, and a high-water count,
-** also kept in different formats. It also has a list of sites that
-** get this group.
-*/
-typedef struct _NEWSGROUP {
- long Start; /* Offset into the active file */
- char * Name;
- int NameLength;
- ARTNUM Last;
- ARTNUM Filenum; /* File name to use */
- int Lastwidth;
- int PostCount; /* Have we already put it here? */
- char * LastString;
- char * Rest; /* Flags, NOT NULL TERMINATED */
- SITEIDX nSites;
- int * Sites;
- SITEIDX nPoison;
- int * Poison;
- struct _NEWSGROUP * Alias;
-} NEWSGROUP;
-
-
-/*
-** How a site is fed.
-*/
-typedef enum _FEEDTYPE {
- FTerror,
- FTfile,
- FTchannel,
- FTexploder,
- FTfunnel,
- FTlogonly,
- FTprogram
-} FEEDTYPE;
-
-
-/*
-** Diablo-style hashed feeds or hashfeeds.
-*/
-#define HASHFEED_QH 1
-#define HASHFEED_MD5 2
-
-typedef struct _HASHFEEDLIST {
- int type;
- unsigned int begin;
- unsigned int end;
- unsigned int mod;
- unsigned int offset;
- struct _HASHFEEDLIST *next;
-} HASHFEEDLIST;
-
-
-/*
-** A site may reject something in its subscription list if it has
-** too many hops, or a bad distribution.
-*/
-typedef struct _SITE {
- const char * Name;
- char * Entry;
- int NameLength;
- char ** Exclusions;
- char ** Distributions;
- char ** Patterns;
- bool Poison;
- bool PoisonEntry;
- bool Sendit;
- bool Seenit;
- bool IgnoreControl;
- bool DistRequired;
- bool IgnorePath;
- bool ControlOnly;
- bool DontWantNonExist;
- bool NeedOverviewCreation;
- bool FeedwithoutOriginator;
- bool DropFiltered;
- int Hops;
- int Groupcount;
- int Followcount;
- int Crosscount;
- FEEDTYPE Type;
- NEWSGROUP * ng;
- bool Spooling;
- char * SpoolName;
- bool Working;
- long StartWriting;
- long StopWriting;
- long StartSpooling;
- char * Param;
- char FileFlags[FEED_MAXFLAGS + 1];
- long MaxSize;
- long MinSize;
- int Nice;
- CHANNEL * Channel;
- bool IsMaster;
- int Master;
- int Funnel;
- bool FNLwantsnames;
- struct buffer FNLnames;
- int Process;
- pid_t pid;
- long Flushpoint;
- struct buffer Buffer;
- bool Buffered;
- char ** Originator;
- HASHFEEDLIST * HashFeedList;
- int Next;
- int Prev;
-} SITE;
-
-
-/*
-** A process is something we start up to send articles.
-*/
-typedef enum _PROCSTATE {
- PSfree,
- PSrunning,
- PSdead
-} PROCSTATE;
-
-
-/*
-** We track our children and collect them synchronously.
-*/
-typedef struct _PROCESS {
- PROCSTATE State;
- pid_t Pid;
- int Status;
- time_t Started;
- time_t Collected;
- int Site;
-} PROCESS;
-
-/*
-** A work in progress entry, an article that we've been offered but haven't
-** received yet.
-*/
-typedef struct _WIP {
- HASH MessageID; /* Hash of the messageid. Doing it like
- this saves us from haveing to allocate
- and deallocate memory a lot, and also
- means lookups are faster. */
- time_t Timestamp; /* Time we last looked at this MessageID */
- CHANNEL *Chan; /* Channel that this message is associated
- with */
- struct _WIP *Next; /* Next item in this bucket */
-} WIP;
-
-/*
-** Supported timers. If you add new timers to this list, also add them to
-** the list of tags in chan.c.
-*/
-enum timer {
- TMR_IDLE = TMR_APPLICATION, /* Server is completely idle. */
- TMR_ARTCLEAN, /* Analyzing an incoming article. */
- TMR_ARTWRITE, /* Writing an article. */
- TMR_ARTCNCL, /* Processing a cancel message. */
- TMR_SITESEND, /* Sending an article to feeds. */
- TMR_OVERV, /* Generating overview information. */
- TMR_PERL, /* Perl filter. */
- TMR_PYTHON, /* Python filter. */
- TMR_NNTPREAD, /* Reading NNTP data from the network. */
- TMR_ARTPARSE, /* Parsing an article. */
- TMR_ARTLOG, /* Logging article disposition. */
- TMR_DATAMOVE, /* Moving data. */
- TMR_MAX
-};
-
-\f
-
-/*
-** In-line macros for efficiency.
-**
-** Set or append data to a channel's output buffer.
-*/
-#define WCHANset(cp, p, l) buffer_set(&(cp)->Out, (p), (l))
-#define WCHANappend(cp, p, l) buffer_append(&(cp)->Out, (p), (l))
-
-/*
-** Mark that an I/O error occurred, and block if we got too many.
-*/
-#define IOError(WHEN, e) \
- do { \
- if (--ErrorCount <= 0 || (e) == ENOSPC) \
- ThrottleIOError(WHEN); \
- } while (0)
-\f
-
-/*
-** Global data.
-**
-** Do not change "extern" to "EXTERN" in the Global data. The ones
-** marked with "extern" are initialized in innd.c. The ones marked
-** with "EXTERN" are not explicitly initialized in innd.c.
-*/
-#if defined(DEFINE_DATA)
-# define EXTERN /* NULL */
-#else
-# define EXTERN extern
-#endif
-extern const ARTHEADER ARTheaders[MAX_ARTHEADER];
-extern bool BufferedLogs;
-EXTERN bool AnyIncoming;
-extern bool Debug;
-EXTERN bool ICDneedsetup;
-EXTERN bool NeedHeaders;
-EXTERN bool NeedOverview;
-EXTERN bool NeedPath;
-EXTERN bool NeedStoredGroup;
-EXTERN bool NeedReplicdata;
-extern bool NNRPTracing;
-extern bool StreamingOff;
-extern bool Tracing;
-EXTERN struct buffer Path;
-EXTERN struct buffer Pathalias;
-EXTERN struct buffer Pathcluster;
-EXTERN char * ModeReason; /* NNTP reject message */
-EXTERN char * NNRPReason; /* NNRP reject message */
-EXTERN char * Reservation; /* Reserved lock message */
-EXTERN char * RejectReason; /* NNTP reject message */
-EXTERN FILE * Errlog;
-EXTERN FILE * Log;
-extern char LogName[];
-extern int ErrorCount;
-EXTERN int ICDactivedirty;
-EXTERN int MaxOutgoing;
-EXTERN int nGroups;
-EXTERN SITEIDX nSites;
-EXTERN int PROCneedscan;
-EXTERN NEWSGROUP ** GroupPointers;
-EXTERN NEWSGROUP * Groups;
-extern OPERATINGMODE Mode;
-EXTERN sig_atomic_t GotTerminate;
-EXTERN SITE * Sites;
-EXTERN SITE ME;
-EXTERN struct timeval TimeOut;
-EXTERN TIMEINFO Now; /* Reasonably accurate time */
-EXTERN bool ThrottledbyIOError;
-EXTERN char * NCgreeting;
-EXTERN struct history *History;
-
-/*
-** Table size for limiting incoming connects. Do not change the table
-** size unless you look at the code manipulating it in rc.c.
-*/
-#define REMOTETABLESIZE 128
-
-/*
-** Setup the default values. The REMOTETIMER being zero turns off the
-** code to limit incoming connects.
-*/
-#define REMOTELIMIT 2
-#define REMOTETIMER 0
-#define REMOTETOTAL 60
-#define REJECT_TIMEOUT 10
-extern int RemoteLimit; /* Per host limit. */
-extern time_t RemoteTimer; /* How long to remember connects. */
-extern int RemoteTotal; /* Total limit. */
-
-
-/*
-** Function declarations.
-*/
-extern void InndHisOpen(void);
-extern void InndHisClose(void);
-extern bool InndHisWrite(const char *key, time_t arrived,
- time_t posted, time_t expires,
- TOKEN *token);
-extern bool InndHisRemember(const char *key);
-extern void InndHisLogStats(void);
-extern bool FormatLong(char *p, unsigned long value, int width);
-extern bool NeedShell(char *p, const char **av, const char **end);
-extern char ** CommaSplit(char *text);
-extern void SetupListBuffer(int size, LISTBUFFER *list);
-extern char * MaxLength(const char *p, const char *q);
-extern pid_t Spawn(int niceval, int fd0, int fd1, int fd2,
- char * const av[]);
-extern void CleanupAndExit(int x, const char *why);
-extern void FileGlue(char *p, const char *n1, char c, const char *n2);
-extern void JustCleanup(void);
-extern void ThrottleIOError(const char *when);
-extern void ThrottleNoMatchError(void);
-extern void ReopenLog(FILE *F);
-extern void xchown(char *p);
-
-extern bool ARTidok(const char *MessageID);
-extern bool ARTreadschema(void);
-extern const char * ARTreadarticle(char *files);
-extern char * ARTreadheader(char *files);
-extern bool ARTpost(CHANNEL *cp);
-extern void ARTcancel(const ARTDATA *Data,
- const char *MessageID, bool Trusted);
-extern void ARTclose(void);
-extern void ARTsetup(void);
-extern void ARTprepare(CHANNEL *cp);
-extern void ARTparse(CHANNEL *cp);
-
-extern bool CHANsleeping(CHANNEL *cp);
-extern CHANNEL * CHANcreate(int fd, CHANNELTYPE Type,
- CHANNELSTATE State,
- innd_callback_t Reader,
- innd_callback_t WriteDone);
-extern CHANNEL * CHANiter(int *cp, CHANNELTYPE Type);
-extern CHANNEL * CHANfromdescriptor(int fd);
-extern char * CHANname(const CHANNEL *cp);
-extern int CHANreadtext(CHANNEL *cp);
-extern void CHANclose(CHANNEL *cp, const char *name);
-extern void CHANreadloop(void);
-extern void CHANsetup(int i);
-extern void CHANshutdown(void);
-extern void CHANtracing(CHANNEL *cp, bool Flag);
-extern void CHANsetActiveCnx(CHANNEL *cp);
-
-extern void RCHANadd(CHANNEL *cp);
-extern void RCHANremove(CHANNEL *cp);
-
-extern void SCHANadd(CHANNEL *cp, time_t Waketime, void *Event,
- innd_callback_t Waker, void *Argument);
-extern void SCHANremove(CHANNEL *cp);
-extern void SCHANwakeup(void *Event);
-
-extern bool WCHANflush(CHANNEL *cp);
-extern void WCHANadd(CHANNEL *cp);
-extern void WCHANremove(CHANNEL *cp);
-extern void WCHANsetfrombuffer(CHANNEL *cp, struct buffer *bp);
-
-extern void CCcopyargv(char *av[]);
-extern const char * CCaddhist(char *av[]);
-extern const char * CCblock(OPERATINGMODE NewMode, char *reason);
-extern const char * CCcancel(char *av[]);
-extern const char * CCcheckfile(char *av[]);
-
-extern bool ICDnewgroup(char *Name, char *Rest);
-extern char * ICDreadactive(char **endp);
-extern bool ICDchangegroup(NEWSGROUP *ngp, char *Rest);
-extern void ICDclose(void);
-extern bool ICDrenumberactive(void);
-extern bool ICDrmgroup(NEWSGROUP *ngp);
-extern void ICDsetup(bool StartSites);
-extern void ICDwrite(void);
-extern void ICDwriteactive(void);
-
-extern void CCclose(void);
-extern void CCsetup(void);
-
-extern void KEYgenerate(HDRCONTENT *, const char *body,
- const char *orig, size_t length);
-
-extern void LCclose(void);
-extern void LCsetup(void);
-
-extern int NGsplit(char *p, int size, LISTBUFFER *List);
-extern NEWSGROUP * NGfind(const char *Name);
-extern void NGclose(void);
-extern CHANNEL * NCcreate(int fd, bool MustAuthorize, bool IsLocal);
-extern void NGparsefile(void);
-extern bool NGrenumber(NEWSGROUP *ngp);
-extern bool NGlowmark(NEWSGROUP *ngp, long lomark);
-
-extern void NCclearwip(CHANNEL *cp);
-extern void NCclose(void);
-extern void NCsetup(void);
-extern void NCwritereply(CHANNEL *cp, const char *text);
-extern void NCwriteshutdown(CHANNEL *cp, const char *text);
-
-/* perl.c */
-extern char * PLartfilter(const ARTDATA *Data, char *artBody, long artLen, int lines);
-extern char * PLmidfilter(char *messageID);
-extern void PLmode(OPERATINGMODE mode, OPERATINGMODE NewMode,
- char *reason);
-extern char * PLstats(void);
-extern void PLxsinit(void);
-
-extern int PROCwatch(pid_t pid, int site);
-extern void PROCunwatch(int process);
-/* extern void PROCclose(bool Quickly); */
-extern void PROCscan(void);
-extern void PROCsetup(int i);
-
-extern int RClimit(CHANNEL *cp);
-extern bool RCnolimit(CHANNEL *cp);
-extern bool RCauthorized(CHANNEL *cp, char *pass);
-extern int RCcanpost(CHANNEL *cp, char *group);
-extern char * RChostname(const CHANNEL *cp);
-extern char * RClabelname(CHANNEL *cp);
-extern void RCclose(void);
-extern void RChandoff(int fd, HANDOFF h);
-extern void RCreadlist(void);
-extern void RCsetup(int i);
-
-extern bool SITEfunnelpatch(void);
-extern bool SITEsetup(SITE *sp);
-extern bool SITEwantsgroup(SITE *sp, char *name);
-extern bool SITEpoisongroup(SITE *sp, char *name);
-extern char ** SITEreadfile(const bool ReadOnly);
-extern SITE * SITEfind(const char *p);
-extern SITE * SITEfindnext(const char *p, SITE *sp);
-extern const char * SITEparseone(char *Entry, SITE *sp,
- char *subbed, char *poison);
-extern void SITEchanclose(CHANNEL *cp);
-extern void SITEdrop(SITE *sp);
-extern void SITEflush(SITE *sp, const bool Restart);
-extern void SITEflushall(const bool Restart);
-extern void SITEforward(SITE *sp, const char *text);
-extern void SITEfree(SITE *sp);
-extern void SITEinfo(struct buffer *bp, SITE *sp, bool Verbose);
-extern void SITEparsefile(bool StartSite);
-extern void SITEprocdied(SITE *sp, int process, PROCESS *pp);
-extern void SITEsend(SITE *sp, ARTDATA *Data);
-extern void SITEwrite(SITE *sp, const char *text);
-
-extern void STATUSinit(void);
-extern void STATUSmainloophook(void);
-
-extern void WIPsetup(void);
-extern WIP * WIPnew(const char *messageid, CHANNEL *cp);
-extern void WIPprecomfree(CHANNEL *cp);
-extern void WIPfree(WIP *wp);
-extern bool WIPinprogress(const char *msgid, CHANNEL *cp,
- bool Add);
-extern WIP * WIPbyid(const char *mesageid);
-extern WIP * WIPbyhash(const HASH hash);
-
-/*
-** TCL globals and functions
-*/
-#if DO_TCL
-extern Tcl_Interp * TCLInterpreter;
-extern bool TCLFilterActive;
-extern struct buffer * TCLCurrArticle;
-extern ARTDATA * TCLCurrData;
-
-extern void TCLfilter(bool value);
-extern void TCLreadfilter(void);
-extern void TCLsetup(void);
-extern void TCLclose(void);
-#endif /* DO_TCL */
-
-/*
-** Python globals and functions
-*/
-#if DO_PYTHON
-extern bool PythonFilterActive;
-
-void PYfilter(bool value);
-extern const char * PYcontrol(char **av);
-extern int PYreadfilter(void);
-extern char * PYartfilter(const ARTDATA *Data, char *artBody, long artLen, int lines);
-extern char * PYmidfilter(char *messageID, int msglen);
-extern void PYmode(OPERATINGMODE mode, OPERATINGMODE newmode,
- char *reason);
-extern void PYsetup(void);
-extern void PYclose(void);
-#endif /* DO_PYTHON */
-
-END_DECLS
-
-#endif /* INND_H */
+++ /dev/null
-/* $Id: inndstart.c 7749 2008-04-06 14:15:04Z iulius $
-**
-** Open the privileged port, then exec innd.
-**
-** inndstart, in a normal INN installation, is installed setuid root and
-** executable only by users in the news group. Because it is setuid root,
-** it's very important to ensure that it be as simple and secure as
-** possible so that news access can't be leveraged into root access.
-**
-** Fighting against this desire, as much of INN's operation as possible
-** should be configurable at run-time using inn.conf, and the news system
-** should be able to an alternate inn.conf by setting INNCONF to the path
-** to that file before starting any programs. The configuration data
-** therefore can't be trusted.
-**
-** Our security model is therefore:
-**
-** - The only three operations performed while privileged are determining
-** the UID and GID of NEWSUSER and NEWSGRP, setting system limits, and
-** opening the privileged port we're binding to.
-**
-** - We can only be executed by the NEWSUSER and NEWSGRP, both compile-
-** time constants; otherwise, we exit. Similarly, we will only setuid()
-** to the NEWSUSER. This is to prevent someone other than the NEWSUSER
-** but still able to execute inndstart for whatever reason from using it
-** to run innd as the news user with bogus configuration information,
-** thereby possibly compromising the news account.
-**
-** - The only ports < 1024 that we'll bind to are 119 and 433, or a port
-** given at configure time with --with-innd-port. This is to prevent
-** the news user from taking over a service such as telnet or POP and
-** potentially gaining access to user passwords.
-**
-** This program therefore gives the news user the ability to revoke system
-** file descriptor limits and bind to the news port, and nothing else.
-**
-** Note that we do use getpwnam() to determine the UID of NEWSUSER, which
-** potentially opens an exploitable hole on those systems that don't
-** correctly prevent a user running a setuid program from interfering with
-** the running process (replacing system calls, for example, or using
-** things like LD_PRELOAD).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <grp.h>
-#include <pwd.h>
-#include <syslog.h>
-
-#ifdef HAVE_INET6
-# include <netdb.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-
-/* Fake up a do-nothing setgroups for Cygwin. */
-#if !HAVE_SETGROUPS
-# define setgroups(n, list) 0
-#endif
-
-/* To run innd under the debugger, uncomment this and fix the path. */
-/* #define DEBUGGER "/usr/ucb/dbx" */
-
-
-int
-main(int argc, char *argv[])
-{
- struct passwd *pwd;
- struct group *grp;
- uid_t news_uid, real_uid;
- gid_t news_gid;
- int snum = 0;
- int port, s[MAX_SOCKETS + 1], i, j;
-#ifdef HAVE_INET6
- struct in6_addr address6;
- bool addr6_specified = false;
-#endif
- struct in_addr address;
- bool addr_specified = false;
- char *p;
- char **innd_argv;
- char pflag[SMBUF];
-#ifdef PURIFY
- char *innd_env[11];
-#else
- char *innd_env[9];
-#endif
-
- /* Set up the error handlers. Always print to stderr, and for warnings
- also syslog with a priority of LOG_ERR. For fatal errors, also
- syslog with a priority of LOG_CRIT. These priority levels are a
- little high, but they're chosen to match innd. */
- openlog("inndstart", LOG_CONS, LOG_INN_PROG);
- message_handlers_warn(2, message_log_stderr, message_log_syslog_err);
- message_handlers_die(2, message_log_stderr, message_log_syslog_crit);
- message_program_name = "inndstart";
-
- /* Convert NEWSUSER and NEWSGRP to a UID and GID. getpwnam() and
- getgrnam() don't set errno normally, so don't print strerror() on
- failure; it probably contains garbage.*/
- pwd = getpwnam(NEWSUSER);
- if (!pwd)
- die("can't getpwnam(%s)", NEWSUSER);
- news_uid = pwd->pw_uid;
- grp = getgrnam(NEWSGRP);
- if (!grp)
- die("can't getgrnam(%s)", NEWSGRP);
- news_gid = grp->gr_gid;
-
- /* Exit if run by any other user or group. */
- real_uid = getuid();
- if (real_uid != news_uid)
- die("must be run by user %s (%lu), not %lu", NEWSUSER,
- (unsigned long)news_uid, (unsigned long)real_uid);
-
- /* Drop all supplemental groups and drop privileges to read inn.conf.
- setgroups() can only be invoked by root, so if inndstart isn't setuid
- root this is where we fail. */
- if (setgroups(1, &news_gid) < 0)
- syswarn("can't setgroups (is inndstart setuid root?)");
- if (seteuid(news_uid) < 0)
- sysdie("can't seteuid to %lu", (unsigned long)news_uid);
- if (!innconf_read(NULL))
- exit(1);
-
- /* Check for a bind address specified in inn.conf. "any" or "all" will
- cause inndstart to bind to INADDR_ANY. */
- address.s_addr = htonl(INADDR_ANY);
- p = innconf->bindaddress;
- if (p && strcmp(p, "all") != 0 && strcmp(p, "any") != 0) {
- if (!inet_aton(p, &address))
- die("invalid bindaddress in inn.conf (%s)", p);
- addr_specified = true;
- }
-#ifdef HAVE_INET6
- address6 = in6addr_any;
- p = innconf->bindaddress6;
- if (p && strcmp(p, "all") != 0 && strcmp(p, "any") != 0) {
- if (inet_pton(AF_INET6, p, &address6) < 1)
- die("invalid bindaddress6 in inn.conf (%s)", p);
- addr6_specified = true;
- }
-#endif
-
- /* Parse our command-line options. The only options we take are -P,
- which specifies what port number to bind to, and -I, which specifies
- what IP address to bind to. Both override inn.conf. Support both
- "-P <port>" and "-P<port>". All other options are passed through to
- innd. */
- port = innconf->port;
- for (i = 1; i < argc; i++) {
- if (strncmp("-P", argv[i], 2) == 0) {
- if (strlen(argv[i]) > 2) {
- port = atoi(&argv[i][2]);
- } else {
- i++;
- if (argv[i] == NULL)
- die("missing port after -P");
- port = atoi(argv[i]);
- }
- if (port == 0)
- die("invalid port %s (must be a number)", argv[i]);
-#ifdef HAVE_INET6
- } else if (strncmp("-6", argv[i], 2) == 0) {
- if (strlen(argv[i]) > 2) {
- p = &argv[i][2];
- } else {
- i++;
- if (argv[i] == NULL)
- die("missing address after -6");
- p = argv[i];
- }
- if (inet_pton(AF_INET6, p, &address6) < 1)
- die("invalid address %s", p);
- addr6_specified = true;
-#endif
- } else if (strncmp("-I", argv[i], 2) == 0) {
- if (strlen(argv[i]) > 2) {
- p = &argv[i][2];
- } else {
- i++;
- if (argv[i] == NULL)
- die("missing address after -I");
- p = argv[i];
- }
- if (!inet_aton(p, &address))
- die("invalid address %s", p);
- addr_specified = true;
- }
- }
-
- /* Make sure that the requested port is legitimate. */
- if (port < 1024 && port != 119
-#ifdef INND_PORT
- && port != INND_PORT
-#endif
- && port != 433)
- die("can't bind to restricted port %d", port);
-
- /* Now, regain privileges so that we can change system limits and bind
- to our desired port. */
- if (seteuid(0) < 0)
- sysdie("can't seteuid to 0");
-
- /* innconf->rlimitnofile <= 0 says to leave it alone. */
- if (innconf->rlimitnofile > 0 && setfdlimit(innconf->rlimitnofile) < 0)
- syswarn("can't set file descriptor limit to %ld",
- innconf->rlimitnofile);
-
-#if defined(HAVE_INET6) && defined(IPV6_V6ONLY)
- /* If we have the IPV6_V6ONLY socket option, and it works,
- always open separate IPv4 and IPv6 sockets. */
- if (addr_specified == 0 && addr6_specified == 0) {
- j = socket(PF_INET6, SOCK_STREAM, 0);
- if (j >= 0) {
- i = 1;
- if (setsockopt (j, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i,
- sizeof i) == 0) {
- addr_specified = 1;
- addr6_specified = 1;
- }
- close (j);
- }
- }
-#endif
-
- /* Create a socket and name it. */
-#ifdef HAVE_INET6
- if( ! (addr_specified || addr6_specified) ) {
- struct addrinfo hints, *addr, *ressave;
- char service[16];
- int error;
-
- memset(&hints, 0, sizeof hints);
- hints.ai_family = PF_UNSPEC;
- hints.ai_flags = AI_PASSIVE;
- hints.ai_socktype = SOCK_STREAM;
- snprintf(service, sizeof(service), "%d", port);
- error = getaddrinfo(NULL, service, &hints, &addr);
- if (error < 0)
- die("getaddrinfo: %s", gai_strerror(error));
-
- for (ressave = addr; addr; addr = addr->ai_next) {
- if ((i = socket(addr->ai_family, addr->ai_socktype,
- addr->ai_protocol)) < 0)
- continue; /* ignore */
-#ifdef SO_REUSEADDR
- j = 1;
- if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR, (char *)&j,
- sizeof j) < 0)
- syswarn("can't set SO_REUSEADDR");
-#endif
- if (bind(i, addr->ai_addr, addr->ai_addrlen) < 0) {
- j = errno;
- close(i);
- errno = j;
- continue; /* ignore */
- }
- s[snum++] = i;
- if (snum == MAX_SOCKETS)
- break;
- }
- freeaddrinfo(ressave);
-
- if (snum == 0)
- sysdie("can't bind socket");
- } else {
- if ( addr6_specified ) {
- struct sockaddr_in6 server6;
-
- s[snum] = socket(PF_INET6, SOCK_STREAM, 0);
- if (s[snum] < 0)
- sysdie("can't open inet6 socket");
-#ifdef SO_REUSEADDR
- i = 1;
- if (setsockopt(s[snum], SOL_SOCKET, SO_REUSEADDR, (char *)&i,
- sizeof i) < 0)
- syswarn("can't set SO_REUSEADDR");
-#endif
-#ifdef IPV6_V6ONLY
- i = 1;
- if (setsockopt(s[snum], IPPROTO_IPV6, IPV6_V6ONLY, (char *)&i,
- sizeof i) < 0)
- syswarn("can't set IPV6_V6ONLY");
-#endif
- memset(&server6, 0, sizeof server6);
- server6.sin6_port = htons(port);
- server6.sin6_family = AF_INET6;
- server6.sin6_addr = address6;
-#ifdef HAVE_SOCKADDR_LEN
- server6.sin6_len = sizeof server6;
-#endif
- if (bind(s[snum], (struct sockaddr *)&server6, sizeof server6) < 0)
- sysdie("can't bind inet6 socket");
- snum++;
- }
- if ( addr_specified )
-#endif /* HAVE_INET6 */
- {
- struct sockaddr_in server;
-
- s[snum] = socket(PF_INET, SOCK_STREAM, 0);
- if (s[snum] < 0)
- sysdie("can't open inet socket");
-#ifdef SO_REUSEADDR
- i = 1;
- if (setsockopt(s[snum], SOL_SOCKET, SO_REUSEADDR, (char *) &i,
- sizeof i) < 0)
- syswarn("can't set SO_REUSEADDR");
-#endif
- memset(&server, 0, sizeof server);
- server.sin_port = htons(port);
- server.sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_LEN
- server.sin_len = sizeof server;
-#endif
- server.sin_addr = address;
- if (bind(s[snum], (struct sockaddr *)&server, sizeof server) < 0)
- sysdie("can't bind inet socket");
- snum++;
- }
-#ifdef HAVE_INET6
- }
-#endif
- s[snum] = -1;
-
- /* Now, permanently drop privileges. */
- if (setgid(news_gid) < 0 || getgid() != news_gid)
- sysdie("can't setgid to %lu", (unsigned long)news_gid);
- if (setuid(news_uid) < 0 || getuid() != news_uid)
- sysdie("can't setuid to %lu", (unsigned long)news_uid);
-
- /* Build the argument vector for innd. Pass -p<port> to innd to tell it
- what port we just created and bound to for it. */
- innd_argv = xmalloc((1 + argc + 1) * sizeof(char *));
- i = 0;
- strlcpy(pflag, "-p ", sizeof(pflag));
- for (j = 0; s[j] > 0; j++) {
- char temp[16];
-
- snprintf(temp, sizeof(temp), "%d,", s[j]);
- strlcat(pflag, temp, sizeof(pflag));
- }
- /* chop off the trailing , */
- j = strlen(pflag) - 1;
- pflag[j] = '\0';
-#ifdef DEBUGGER
- innd_argv[i++] = DEBUGGER;
- innd_argv[i++] = concatpath(innconf->pathbin, "innd");
- innd_argv[i] = 0;
- printf("When starting innd, use -d %s\n", s, pflag);
-#else /* DEBUGGER */
- innd_argv[i++] = concatpath(innconf->pathbin, "innd");
- innd_argv[i++] = pflag;
-
- /* Don't pass along -p, -P, or -I. Check the length of the argument
- string, and if it == 2 (meaning there's nothing after the -p or -P or
- -I), skip the next argument too, to support leaving a space between
- the argument and the value. */
- for (j = 1; j < argc; j++) {
- if (argv[j][0] == '-' && strchr("pP6I", argv[j][1])) {
- if (strlen(argv[j]) == 2)
- j++;
- continue;
- } else {
- innd_argv[i++] = argv[j];
- }
- }
- innd_argv[i] = 0;
-#endif /* !DEBUGGER */
-
- /* Set up the environment. Note that we're trusting BIND_INADDR and TZ;
- everything else is either from inn.conf or from configure. These
- should be sanity-checked before being propagated, but that requires
- knowledge of the range of possible values. Just limiting their
- length doesn't necessarily do anything to prevent exploits and may
- stop things from working that should. We have to pass BIND_INADDR so
- that it's set for programs, such as innfeed, that innd may spawn. */
- innd_env[0] = concat("PATH=", innconf->pathbin, ":", innconf->pathetc,
- ":/bin:/usr/bin:/usr/ucb", (char *) 0);
- innd_env[1] = concat( "TMPDIR=", innconf->pathtmp, (char *) 0);
- innd_env[2] = concat( "SHELL=", _PATH_SH, (char *) 0);
- innd_env[3] = concat("LOGNAME=", NEWSMASTER, (char *) 0);
- innd_env[4] = concat( "USER=", NEWSMASTER, (char *) 0);
- innd_env[5] = concat( "HOME=", innconf->pathnews, (char *) 0);
- i = 6;
- p = getenv("BIND_INADDR");
- if (p != NULL)
- innd_env[i++] = concat("BIND_INADDR=", p, (char *) 0);
- p = getenv("TZ");
- if (p != NULL)
- innd_env[i++] = concat("TZ=", p, (char *) 0);
-#ifdef PURIFY
- /* you have to compile with `purify cc -DPURIFY' to get this */
- p = getenv("DISPLAY");
- if (p != NULL)
- innd_env[i++] = concat("DISPLAY=", p, (char *) 0);
- p = getenv("PURIFYOPTIONS");
- if (p != NULL)
- innd_env[i++] = concat("PURIFYOPTIONS=", p, (char *) 0);
-#endif
- innd_env[i] = 0;
-
- /* Go exec innd. */
- execve(innd_argv[0], innd_argv, innd_env);
- sysdie("can't exec %s", innd_argv[0]);
-
- /* Not reached. */
- return 1;
-}
+++ /dev/null
-/* $Id: keywords.c 6269 2003-03-28 01:52:36Z rra $
-**
-** Optional keyword generation code.
-**
-** Additional code for sake of manufacturing Keywords: headers out of air in
-** order to provide better (scorable) XOVER data, containing bits of article
-** body content which have a reasonable expectation of utility.
-**
-** Basic idea: Simple word-counting. We find words in the article body,
-** separated by whitespace. Remove punctuation. Sort words, count unique
-** words, sort those counts. Write the resulting Keywords: header containing
-** the poster's original Keywords: (if any) followed by a magic cookie
-** separator and then the sorted list of words.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "libinn.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-/* If keyword support wasn't requested, stub out the main function provided by
- this file. */
-#if !DO_KEYWORDS
-void
-KEYgenerate(HDRCONTENT *header UNUSED, const char *body UNUSED,
- const char *orig UNUSED, size_t length UNUSED)
-{
-}
-
-#else
-
-/* For regex-based common word elimination. */
-#include <regex.h>
-
-#define MIN_WORD_LENGTH 3 /* 1- and 2-char words don't count. */
-#define MAX_WORD_LENGTH 28 /* fits "antidisestablishmentarianism". */
-
-/*
-** A trivial structure for keeping track of words via both
-** index to the overall word list and their counts.
-*/
-struct word_entry {
- int index;
- int length;
- int count;
-};
-
-/*
-** Wrapper for qsort(3) comparison of word_entry (frequency).
-*/
-
-static int
-wvec_freq_cmp(const void *p1, const void *p2)
-{
- return ((const struct word_entry *)p2)->count - /* decreasing sort */
- ((const struct word_entry *)p1)->count;
-}
-
-/*
-** Wrapper for qsort(3) comparison of word_entry (word length).
-*/
-
-static int
-wvec_length_cmp(const void *p1, const void *p2)
-{
- return ((const struct word_entry *)p2)->length - /* decreasing sort */
- ((const struct word_entry *)p1)->length;
-}
-
-/*
-** Wrapper for qsort(3), for pointer-to-pointer strings.
-*/
-
-static int
-ptr_strcmp(const void *p1, const void *p2)
-{
- int cdiff;
-
- cdiff = (**(const char **)p1) - (**(const char **)p2);
- if (cdiff)
- return cdiff;
- return strcmp((*(const char **)p1)+1, (*(const char **)p2)+1);
-}
-
-/*
-** Build new Keywords.
-*/
-
-void
-KEYgenerate(
- HDRCONTENT *hc, /* header data */
- const char *body, /* article body */
- const char *v, /* old kw value */
- size_t l) /* old kw length */
-{
-
- int word_count, word_length, bodylen, word_index, distinct_words;
- int last;
- char *text, *orig_text, *text_end, *this_word, *chase, *punc;
- static struct word_entry *word_vec;
- static char **word;
- static const char *whitespace = " \t\r\n";
-
- /* ---------------------------------------------------------------- */
- /* Prototype setup: Regex match preparation. */
- static int regex_lib_init = 0;
- static regex_t preg;
- static const char *elim_regexp = "^\\([-+/0-9][-+/0-9]*\\|.*1st\\|.*2nd\\|.*3rd\\|.*[04-9]th\\|about\\|after\\|ago\\|all\\|already\\|also\\|among\\|and\\|any\\|anybody\\|anyhow\\|anyone\\|anywhere\\|are\\|bad\\|because\\|been\\|before\\|being\\|between\\|but\\|can\\|could\\|did\\|does\\|doing\\|done\\|dont\\|during\\|eight\\|eighth\\|eleven\\|else\\|elsewhere\\|every\\|everywhere\\|few\\|five\\|fifth\\|first\\|for\\|four\\|fourth\\|from\\|get\\|going\\|gone\\|good\\|got\\|had\\|has\\|have\\|having\\|he\\|her\\|here\\|hers\\|herself\\|him\\|himself\\|his\\|how\\|ill\\|into\\|its\\|ive\\|just\\|kn[eo]w\\|least\\|less\\|let\\|like\\|look\\|many\\|may\\|more\\|m[ou]st\\|myself\\|next\\|nine\\|ninth\\|not\\|now\\|off\\|one\\|only\\|onto\\|our\\|out\\|over\\|really\\|said\\|saw\\|says\\|second\\|see\\|set\\|seven\\|seventh\\|several\\|shall\\|she\\|should\\|since\\|six\\|sixth\\|some\\|somehow\\|someone\\|something\\|somewhere\\|such\\|take\\|ten\\|tenth\\|than\\|that\\|the\\|their\\!|them\\|then\\|there\\|therell\\|theres\\|these\\|they\\|thing\\|things\\|third\\|this\\|those\\|three\\|thus\\|together\\|told\\|too\\|twelve\\|two\\|under\\|upon\\|very\\|via\\|want\\|wants\\|was\\|wasnt\\|way\\|were\\|weve\\|what\\|whatever\\|when\\|where\\|wherell\\|wheres\\|whether\\|which\\|while\\|who\\|why\\|will\\|will\\|with\\|would\\|write\\|writes\\|wrote\\|yes\\|yet\\|you\\|your\\|youre\\|yourself\\)$";
-
- if (word_vec == 0) {
- word_vec = xmalloc(innconf->keymaxwords * sizeof(struct word_entry));
- if (word_vec == 0)
- return;
- word = xmalloc(innconf->keymaxwords * sizeof(char *));
- if (word == NULL) {
- free(word_vec);
- return;
- }
- }
-
- if (regex_lib_init == 0) {
- regex_lib_init++;
-
- if (regcomp(&preg, elim_regexp, REG_ICASE|REG_NOSUB) != 0) {
- syslog(L_FATAL, "%s regcomp failure", LogName);
- abort();
- }
- }
- /* ---------------------------------------------------------------- */
-
- /* first re-init kw from original value. */
- if (l > innconf->keylimit - (MAX_WORD_LENGTH+5)) /* mostly arbitrary cutoff: */
- l = innconf->keylimit - (MAX_WORD_LENGTH+5); /* room for minimal word vec */
- hc->Value = xmalloc(innconf->keylimit+1);
- if ((v != NULL) && (*v != '\0')) {
- memcpy(hc->Value, v, l);
- hc->Value[l] = '\0';
- } else
- *hc->Value = '\0';
- l = hc->Length = strlen(hc->Value);
-
- /*
- * now figure acceptable extents, and copy body to working string.
- * (Memory-intensive for hefty articles: limit to non-ABSURD articles.)
- */
- bodylen = strlen(body);
- if ((bodylen < 100) || (bodylen > innconf->keyartlimit)) /* too small/big to bother */
- return;
-
- orig_text = text = xstrdup(body); /* orig_text is for free() later on */
-
- text_end = text + bodylen;
-
- /* abusive punctuation stripping: turn it all into SPCs. */
- for (punc = text; *punc; punc++)
- if (!CTYPE(isalpha, *punc))
- *punc = ' ';
-
- /* move to first word. */
- text += strspn(text, whitespace);
- word_count = 0;
-
- /* hunt down words */
- while ((text < text_end) && /* while there might be words... */
- (*text != '\0') &&
- (word_count < innconf->keymaxwords)) {
-
- /* find a word. */
- word_length = strcspn(text, whitespace);
- if (word_length == 0)
- break; /* no words left */
-
- /* bookkeep to save word location, then move through text. */
- word[word_count++] = this_word = text;
- text += word_length;
- *(text++) = '\0';
- text += strspn(text, whitespace); /* move to next word. */
-
- /* 1- and 2-char words don't count, nor do excessively long ones. */
- if ((word_length < MIN_WORD_LENGTH) ||
- (word_length > MAX_WORD_LENGTH)) {
- word_count--;
- continue;
- }
-
- /* squash to lowercase. */
- for (chase = this_word; *chase; chase++)
- if (CTYPE(isupper, *chase))
- *chase = tolower(*chase);
- }
-
- /* If there were no words, we're done. */
- if (word_count < 1)
- goto out;
-
- /* Sort the words. */
- qsort(word, word_count, sizeof(word[0]), ptr_strcmp);
-
- /* Count unique words. */
- distinct_words = 0; /* the 1st word is "pre-figured". */
- word_vec[0].index = 0;
- word_vec[0].length = strlen(word[0]);
- word_vec[0].count = 1;
-
- for (word_index = 1; /* we compare (N-1)th and Nth words. */
- word_index < word_count;
- word_index++) {
- if (strcmp(word[word_index-1], word[word_index]) == 0)
- word_vec[distinct_words].count++;
- else {
- distinct_words++;
- word_vec[distinct_words].index = word_index;
- word_vec[distinct_words].length = strlen(word[word_index]);
- word_vec[distinct_words].count = 1;
- }
- }
-
- /* Sort the counts. */
- distinct_words++; /* we were off-by-1 until this. */
- qsort(word_vec, distinct_words, sizeof(struct word_entry), wvec_freq_cmp);
-
- /* Sub-sort same-frequency words on word length. */
- for (last = 0, word_index = 1; /* again, (N-1)th and Nth entries. */
- word_index < distinct_words;
- word_index++) {
- if (word_vec[last].count != word_vec[word_index].count) {
- if ((word_index - last) != 1) /* 2+ entries to sub-sort. */
- qsort(&word_vec[last], word_index - last,
- sizeof(struct word_entry), wvec_length_cmp);
- last = word_index;
- }
- }
- /* do it one last time for the only-one-appearance words. */
- if ((word_index - last) != 1)
- qsort(&word_vec[last], word_index - last,
- sizeof(struct word_entry), wvec_length_cmp);
-
- /* Scribble onto end of Keywords:. */
- strcpy(hc->Value + l, ",\377"); /* magic separator, 'ÿ' */
- for (chase = hc->Value + l + 2, word_index = 0;
- word_index < distinct_words;
- word_index++) {
- /* ---------------------------------------------------------------- */
- /* "noise" words don't count */
- if (regexec(&preg, word[word_vec[word_index].index], 0, NULL, 0) == 0)
- continue;
- /* ---------------------------------------------------------------- */
-
- /* add to list. */
- *chase++ = ',';
- strcpy(chase, word[word_vec[word_index].index]);
- chase += word_vec[word_index].length;
-
- if (chase - hc->Value > (innconf->keylimit - (MAX_WORD_LENGTH + 4)))
- break;
- }
- /* note #words we didn't get to add. */
- /* This code can potentially lead to a buffer overflow if the number of
- ignored words is greater than 100, under some circumstances. It's
- temporarily disabled until fixed. */
- hc->Length = strlen(hc->Value);
-
-out:
- /* We must dispose of the original strdup'd text area. */
- free(orig_text);
-}
-
-#endif /* DO_KEYWORDS */
+++ /dev/null
-/* $Id: lc.c 6155 2003-01-19 19:58:25Z rra $
-**
-** Routines for the local connect channel. Create a Unix-domain stream
-** socket that processes on the local server connect to. Once the
-** connection is set up, we speak NNTP. The connect channel is used only
-** by rnews to feed in articles from the UUCP sites.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-
-#if HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-
-static char *LCpath = NULL;
-static CHANNEL *LCchan;
-
-
-/*
-** Read function. Accept the connection and create an NNTP channel.
-*/
-static void
-LCreader(CHANNEL *cp)
-{
- int fd;
- CHANNEL *new;
-
- if (cp != LCchan) {
- syslog(L_ERROR, "%s internal LCreader wrong channel 0x%p not 0x%p",
- LogName, (void *)cp, (void *)LCchan);
- return;
- }
-
- if ((fd = accept(cp->fd, NULL, NULL)) < 0) {
- syslog(L_ERROR, "%s cant accept CCreader %m", LogName);
- return;
- }
- if ((new = NCcreate(fd, false, true)) != NULL) {
- memset( &new->Address, 0, sizeof( new->Address ) );
- syslog(L_NOTICE, "%s connected %d", "localhost", new->fd);
- NCwritereply(new, (char *)NCgreeting);
- }
-}
-
-
-/*
-** Write-done function. Shouldn't happen.
-*/
-static void
-LCwritedone(CHANNEL *unused)
-{
- unused = unused; /* ARGSUSED */
- syslog(L_ERROR, "%s internal LCwritedone", LogName);
-}
-
-#endif /* HAVE_UNIX_DOMAIN_SOCKETS */
-
-
-/*
-** Create the channel.
-*/
-void
-LCsetup(void)
-{
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- int i;
- struct sockaddr_un server;
-
- if (LCpath == NULL)
- LCpath = concatpath(innconf->pathrun, _PATH_NNTPCONNECT);
- /* Remove old detritus. */
- if (unlink(LCpath) < 0 && errno != ENOENT) {
- syslog(L_FATAL, "%s cant unlink %s %m", LogName, LCpath);
- exit(1);
- }
-
- /* Create a socket and name it. */
- if ((i = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- syslog(L_FATAL, "%s cant socket %s %m", LogName, LCpath);
- exit(1);
- }
- memset(&server, 0, sizeof server);
- server.sun_family = AF_UNIX;
- strlcpy(server.sun_path, LCpath, sizeof(server.sun_path));
- if (bind(i, (struct sockaddr *) &server, SUN_LEN(&server)) < 0) {
- syslog(L_FATAL, "%s cant bind %s %m", LogName, LCpath);
- exit(1);
- }
-
- /* Set it up to wait for connections. */
- if (listen(i, MAXLISTEN) < 0) {
- syslog(L_FATAL, "%s cant listen %s %m", LogName, LCpath);
- exit(1);
- }
- LCchan = CHANcreate(i, CTlocalconn, CSwaiting, LCreader, LCwritedone);
- syslog(L_NOTICE, "%s lcsetup %s", LogName, CHANname(LCchan));
- RCHANadd(LCchan);
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-}
-
-
-/*
-** Cleanly shut down the channel.
-*/
-void
-LCclose(void)
-{
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- CHANclose(LCchan, CHANname(LCchan));
- LCchan = NULL;
- if (unlink(LCpath) < 0)
- syslog(L_ERROR, "%s cant unlink %s %m", LogName, LCpath);
- free(LCpath);
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-}
+++ /dev/null
-/* $Id: nc.c 7418 2005-10-09 04:37:05Z eagle $
-**
-** Routines for the NNTP channel. Other channels get the descriptors which
-** we turn into NNTP channels, and over which we speak NNTP.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-#define BAD_COMMAND_COUNT 10
-
-
-/*
-** An entry in the dispatch table. The name, and implementing function,
-** of every command we support.
-*/
-typedef struct _NCDISPATCH {
- const char * Name;
- innd_callback_t Function;
- int Size;
-} NCDISPATCH;
-
-/* The functions that implement the various commands. */
-static void NCauthinfo(CHANNEL *cp);
-static void NCcancel(CHANNEL *cp);
-static void NCcheck(CHANNEL *cp);
-static void NChead(CHANNEL *cp);
-static void NChelp(CHANNEL *cp);
-static void NCihave(CHANNEL *cp);
-static void NClist(CHANNEL *cp);
-static void NCmode(CHANNEL *cp);
-static void NCquit(CHANNEL *cp);
-static void NCstat(CHANNEL *cp);
-static void NCtakethis(CHANNEL *cp);
-static void NCxbatch(CHANNEL *cp);
-
-/* Handlers for unimplemented commands. We need two handlers so that we can
- return the right status code; reader commands that are required by the
- standard must return a 502 error rather than a 500 error. */
-static void NC_reader(CHANNEL *cp);
-static void NC_unimp(CHANNEL *cp);
-
-/* Supporting functions. */
-static void NCwritedone(CHANNEL *cp);
-
-/* Set up the dispatch table for all of the commands. */
-#define COMMAND(name, func) { name, func, sizeof(name) - 1 }
-static NCDISPATCH NCcommands[] = {
- COMMAND("authinfo", NCauthinfo),
- COMMAND("check", NCcheck),
- COMMAND("head", NChead),
- COMMAND("help", NChelp),
- COMMAND("ihave", NCihave),
- COMMAND("list", NClist),
- COMMAND("mode", NCmode),
- COMMAND("quit", NCquit),
- COMMAND("stat", NCstat),
- COMMAND("takethis", NCtakethis),
- COMMAND("xbatch", NCxbatch),
-
- /* Unimplemented reader commands which may become available after a MODE
- READER command. */
- COMMAND("article", NC_reader),
- COMMAND("body", NC_reader),
- COMMAND("group", NC_reader),
- COMMAND("last", NC_reader),
- COMMAND("newgroups", NC_reader),
- COMMAND("newnews", NC_reader),
- COMMAND("next", NC_reader),
- COMMAND("post", NC_reader),
-
- /* Other unimplemented standard commands. */
- COMMAND("date", NC_unimp),
- COMMAND("slave", NC_unimp)
-};
-#undef COMMAND
-
-/* Number of open connections. */
-static int NCcount;
-
-static char *NCquietlist[] = { INND_QUIET_BADLIST };
-static const char NCterm[] = "\r\n";
-static const char NCdot[] = "." ;
-static const char NCbadcommand[] = NNTP_BAD_COMMAND;
-static const char NCbadsubcommand[] = NNTP_BAD_SUBCMD;
-
-/*
-** Clear the WIP entry for the given channel
-*/
-void
-NCclearwip(CHANNEL *cp)
-{
- WIPfree(WIPbyhash(cp->CurrentMessageIDHash));
- HashClear(&cp->CurrentMessageIDHash);
- cp->ArtBeg = 0;
-}
-
-/*
-** Write an NNTP reply message.
-**
-** Tries to do the actual write immediately if it will not block and if there
-** is not already other buffered output. Then, if the write is successful,
-** calls NCwritedone (which does whatever is necessary to accommodate state
-** changes). Else, NCwritedone will be called from the main select loop
-** later.
-**
-** If the reply that we are writing now is associated with a state change,
-** then cp->State must be set to its new value *before* NCwritereply is
-** called.
-*/
-void
-NCwritereply(CHANNEL *cp, const char *text)
-{
- struct buffer *bp;
- int i;
-
- /* XXX could do RCHANremove(cp) here, as the old NCwritetext() used to
- * do, but that would be wrong if the channel is sreaming (because it
- * would zap the channell's input buffer). There's no harm in
- * never calling RCHANremove here. */
-
- bp = &cp->Out;
- i = bp->left;
- WCHANappend(cp, text, strlen(text)); /* text in buffer */
- WCHANappend(cp, NCterm, strlen(NCterm)); /* add CR NL to text */
-
- if (i == 0) { /* if only data then try to write directly */
- i = write(cp->fd, &bp->data[bp->used], bp->left);
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s NCwritereply %d=write(%d, \"%.15s\", %lu)",
- CHANname(cp), i, cp->fd, &bp->data[bp->used],
- (unsigned long) bp->left);
- if (i > 0)
- bp->used += i;
- if (bp->used == bp->left) {
- /* all the data was written */
- bp->used = bp->left = 0;
- NCwritedone(cp);
- } else {
- bp->left -= i;
- i = 0;
- }
- } else i = 0;
- if (i <= 0) { /* write failed, queue it for later */
- WCHANadd(cp);
- }
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s > %s", CHANname(cp), text);
-}
-
-/*
-** Tell the NNTP channel to go away.
-*/
-void
-NCwriteshutdown(CHANNEL *cp, const char *text)
-{
- cp->State = CSwritegoodbye;
- RCHANremove(cp); /* we're not going to read anything more */
- WCHANappend(cp, NNTP_GOODBYE, strlen(NNTP_GOODBYE));
- WCHANappend(cp, " ", 1);
- WCHANappend(cp, text, (int)strlen(text));
- WCHANappend(cp, NCterm, strlen(NCterm));
- WCHANadd(cp);
-}
-
-
-/*
-** If a Message-ID is bad, write a reject message and return true.
-*/
-static bool
-NCbadid(CHANNEL *cp, char *p)
-{
- if (ARTidok(p))
- return false;
-
- NCwritereply(cp, NNTP_HAVEIT_BADID);
- syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp), MaxLength(p, p));
- return true;
-}
-
-
-/*
-** We have an entire article collected; try to post it. If we're
-** not running, drop the article or just pause and reschedule.
-*/
-static void
-NCpostit(CHANNEL *cp)
-{
- bool postok;
- const char *response;
- char buff[SMBUF];
-
- /* Note that some use break, some use return here. */
- if ((postok = ARTpost(cp)) != 0) {
- cp->Received++;
- if (cp->Sendid.size > 3) { /* We be streaming */
- cp->Takethis_Ok++;
- snprintf(buff, sizeof(buff), "%d", NNTP_OK_RECID_VAL);
- cp->Sendid.data[0] = buff[0];
- cp->Sendid.data[1] = buff[1];
- cp->Sendid.data[2] = buff[2];
- response = cp->Sendid.data;
- } else
- response = NNTP_TOOKIT;
- } else {
- cp->Rejected++;
- if (cp->Sendid.size)
- response = cp->Sendid.data;
- else
- response = cp->Error;
- }
- cp->Reported++;
- if (cp->Reported >= innconf->nntpactsync) {
- snprintf(buff, sizeof(buff), "accepted size %.0f duplicate size %.0f",
- cp->Size, cp->DuplicateSize);
- syslog(L_NOTICE,
- "%s checkpoint seconds %ld accepted %ld refused %ld rejected %ld duplicate %ld %s",
- CHANname(cp), (long)(Now.time - cp->Started),
- cp->Received, cp->Refused, cp->Rejected,
- cp->Duplicate, buff);
- cp->Reported = 0;
- }
- if (Mode == OMthrottled) {
- NCwriteshutdown(cp, ModeReason);
- return;
- }
- cp->State = CSgetcmd;
- NCwritereply(cp, response);
-}
-
-
-/*
-** Write-done function. Close down or set state for what we expect to
-** read next.
-*/
-static void
-NCwritedone(CHANNEL *cp)
-{
- switch (cp->State) {
- default:
- syslog(L_ERROR, "%s internal NCwritedone state %d",
- CHANname(cp), cp->State);
- break;
-
- case CSwritegoodbye:
- if (NCcount > 0)
- NCcount--;
- CHANclose(cp, CHANname(cp));
- break;
-
- case CSgetcmd:
- case CSgetauth:
- case CSgetheader:
- case CSgetbody:
- case CSgetxbatch:
- case CSgotlargearticle:
- case CScancel:
- RCHANadd(cp);
- break;
- }
-}
-
-\f
-
-/*
-** The "head" command.
-*/
-static void
-NChead(CHANNEL *cp)
-{
- char *p;
- TOKEN token;
- ARTHANDLE *art;
-
- /* Snip off the Message-ID. */
- for (p = cp->In.data + cp->Start + strlen("head"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- if (NCbadid(cp, p))
- return;
-
- /* Get the article token and retrieve it. */
- if (!HISlookup(History, p, NULL, NULL, NULL, &token)) {
- NCwritereply(cp, NNTP_DONTHAVEIT);
- return;
- }
- if ((art = SMretrieve(token, RETR_HEAD)) == NULL) {
- NCwritereply(cp, NNTP_DONTHAVEIT);
- return;
- }
-
- /* Write it. */
- WCHANappend(cp, NNTP_HEAD_FOLLOWS, strlen(NNTP_HEAD_FOLLOWS));
- WCHANappend(cp, " 0 ", 3);
- WCHANappend(cp, p, strlen(p));
- WCHANappend(cp, NCterm, strlen(NCterm));
- WCHANappend(cp, art->data, art->len);
-
- /* Write the terminator. */
- NCwritereply(cp, NCdot);
- SMfreearticle(art);
-}
-
-
-/*
-** The "stat" command.
-*/
-static void
-NCstat(CHANNEL *cp)
-{
- char *p;
- TOKEN token;
- ARTHANDLE *art;
- char *buff;
- size_t length;
-
- /* Snip off the Message-ID. */
- for (p = cp->In.data + cp->Start + strlen("stat"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- if (NCbadid(cp, p))
- return;
-
- /* Get the article filenames; open the first file (to make sure
- * the article is still here). */
- if (!HISlookup(History, p, NULL, NULL, NULL, &token)) {
- NCwritereply(cp, NNTP_DONTHAVEIT);
- return;
- }
- if ((art = SMretrieve(token, RETR_STAT)) == NULL) {
- NCwritereply(cp, NNTP_DONTHAVEIT);
- return;
- }
- SMfreearticle(art);
-
- /* Write the message. */
- length = snprintf(NULL, 0, "%d 0 %s", NNTP_NOTHING_FOLLOWS_VAL, p) + 1;
- buff = xmalloc(length);
- snprintf(buff, length, "%d 0 %s", NNTP_NOTHING_FOLLOWS_VAL, p);
- NCwritereply(cp, buff);
- free(buff);
-}
-
-
-/*
-** The "authinfo" command. Actually, we come in here whenever the
-** channel is in CSgetauth state and we just got a command.
-*/
-static void
-NCauthinfo(CHANNEL *cp)
-{
- static char AUTHINFO[] = "authinfo ";
- static char PASS[] = "pass ";
- static char USER[] = "user ";
- char *p;
-
- p = cp->In.data + cp->Start;
- cp->Start = cp->Next;
-
- /* Allow the poor sucker to quit. */
- if (strcasecmp(p, "quit") == 0) {
- NCquit(cp);
- return;
- }
-
- /* Otherwise, make sure we're only getting "authinfo" commands. */
- if (strncasecmp(p, AUTHINFO, strlen(AUTHINFO)) != 0) {
- NCwritereply(cp, NNTP_AUTH_NEEDED);
- return;
- }
- for (p += strlen(AUTHINFO); ISWHITE(*p); p++)
- continue;
-
- /* Ignore "authinfo user" commands, since we only care about the
- * password. */
- if (strncasecmp(p, USER, strlen(USER)) == 0) {
- NCwritereply(cp, NNTP_AUTH_NEXT);
- return;
- }
-
- /* Now make sure we're getting only "authinfo pass" commands. */
- if (strncasecmp(p, PASS, strlen(PASS)) != 0) {
- NCwritereply(cp, NNTP_AUTH_NEEDED);
- return;
- }
- for (p += strlen(PASS); ISWHITE(*p); p++)
- continue;
-
- /* Got the password -- is it okay? */
- if (!RCauthorized(cp, p)) {
- cp->State = CSwritegoodbye;
- NCwritereply(cp, NNTP_AUTH_BAD);
- } else {
- cp->State = CSgetcmd;
- NCwritereply(cp, NNTP_AUTH_OK);
- }
-}
-
-/*
-** The "help" command.
-*/
-static void
-NChelp(CHANNEL *cp)
-{
- static char LINE1[] = "For more information, contact \"";
- static char LINE2[] = "\" at this machine.";
- NCDISPATCH *dp;
-
- WCHANappend(cp, NNTP_HELP_FOLLOWS,strlen(NNTP_HELP_FOLLOWS));
- WCHANappend(cp, NCterm,strlen(NCterm));
- for (dp = NCcommands; dp < ARRAY_END(NCcommands); dp++)
- if (dp->Function != NC_unimp) {
- if ((!StreamingOff && cp->Streaming) ||
- (dp->Function != NCcheck && dp->Function != NCtakethis)) {
- WCHANappend(cp, "\t", 1);
- WCHANappend(cp, dp->Name, dp->Size);
- WCHANappend(cp, NCterm, strlen(NCterm));
- }
- }
- WCHANappend(cp, LINE1, strlen(LINE1));
- WCHANappend(cp, NEWSMASTER, strlen(NEWSMASTER));
- WCHANappend(cp, LINE2, strlen(LINE2));
- WCHANappend(cp, NCterm, strlen(NCterm));
- NCwritereply(cp, NCdot) ;
- cp->Start = cp->Next;
-}
-
-/*
-** The "ihave" command. Check the Message-ID, and see if we want the
-** article or not. Set the state appropriately.
-*/
-static void
-NCihave(CHANNEL *cp)
-{
- char *p;
-#if defined(DO_PERL) || defined(DO_PYTHON)
- char *filterrc;
- int msglen;
-#endif /*defined(DO_PERL) || defined(DO_PYTHON) */
-
- cp->Ihave++;
- /* Snip off the Message-ID. */
- for (p = cp->In.data + cp->Start + strlen("ihave"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- if (NCbadid(cp, p))
- return;
-
- if ((innconf->refusecybercancels) && (strncmp(p, "<cancel.", 8) == 0)) {
- cp->Refused++;
- cp->Ihave_Cybercan++;
- NCwritereply(cp, NNTP_HAVEIT);
- return;
- }
-
-#if defined(DO_PERL)
- /* Invoke a perl message filter on the message ID. */
- filterrc = PLmidfilter(p);
- if (filterrc) {
- cp->Refused++;
- msglen = strlen(p) + 5; /* 3 digits + space + id + null */
- if (cp->Sendid.size < msglen) {
- if (cp->Sendid.size > 0) free(cp->Sendid.data);
- if (msglen > MAXHEADERSIZE)
- cp->Sendid.size = msglen;
- else
- cp->Sendid.size = MAXHEADERSIZE;
- cp->Sendid.data = xmalloc(cp->Sendid.size);
- }
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %.200s",
- NNTP_HAVEIT_VAL, filterrc);
- NCwritereply(cp, cp->Sendid.data);
- free(cp->Sendid.data);
- cp->Sendid.size = 0;
- return;
- }
-#endif
-
-#if defined(DO_PYTHON)
- /* invoke a Python message filter on the message id */
- msglen = strlen(p);
- TMRstart(TMR_PYTHON);
- filterrc = PYmidfilter(p, msglen);
- TMRstop(TMR_PYTHON);
- if (filterrc) {
- cp->Refused++;
- msglen += 5; /* 3 digits + space + id + null */
- if (cp->Sendid.size < msglen) {
- if (cp->Sendid.size > 0)
- free(cp->Sendid.data);
- if (msglen > MAXHEADERSIZE)
- cp->Sendid.size = msglen;
- else
- cp->Sendid.size = MAXHEADERSIZE;
- cp->Sendid.data = xmalloc(cp->Sendid.size);
- }
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %.200s",
- NNTP_HAVEIT_VAL, filterrc);
- NCwritereply(cp, cp->Sendid.data);
- free(cp->Sendid.data);
- cp->Sendid.size = 0;
- return;
- }
-#endif
-
- if (HIScheck(History, p)) {
- cp->Refused++;
- cp->Ihave_Duplicate++;
- NCwritereply(cp, NNTP_HAVEIT);
- }
- else if (WIPinprogress(p, cp, false)) {
- cp->Ihave_Deferred++;
- if (cp->NoResendId) {
- cp->Refused++;
- NCwritereply(cp, NNTP_HAVEIT);
- } else {
- NCwritereply(cp, NNTP_RESENDIT_LATER);
- }
- }
- else {
- if (cp->Sendid.size > 0) {
- free(cp->Sendid.data);
- cp->Sendid.size = 0;
- }
- cp->Ihave_SendIt++;
- NCwritereply(cp, NNTP_SENDIT);
- cp->ArtBeg = Now.time;
- cp->State = CSgetheader;
- ARTprepare(cp);
- }
-}
-
-/*
-** The "xbatch" command. Set the state appropriately.
-*/
-
-static void
-NCxbatch(CHANNEL *cp)
-{
- char *p;
-
- /* Snip off the batch size */
- for (p = cp->In.data + cp->Start + strlen("xbatch"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
-
- if (cp->XBatchSize) {
- syslog(L_FATAL, "NCxbatch(): oops, cp->XBatchSize already set to %d",
- cp->XBatchSize);
- }
-
- cp->XBatchSize = atoi(p);
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s will read batch of size %d",
- CHANname(cp), cp->XBatchSize);
-
- if (cp->XBatchSize <= 0 || ((innconf->maxartsize != 0) && (innconf->maxartsize < cp->XBatchSize))) {
- syslog(L_NOTICE, "%s got bad xbatch size %d",
- CHANname(cp), cp->XBatchSize);
- NCwritereply(cp, NNTP_XBATCH_BADSIZE);
- return;
- }
-
- /* we prefer not to touch the buffer, NCreader() does enough magic
- * with it
- */
- cp->State = CSgetxbatch;
- NCwritereply(cp, NNTP_CONT_XBATCH);
-}
-
-/*
-** The "list" command. Send the active file.
-*/
-static void
-NClist(CHANNEL *cp)
-{
- char *p, *q, *trash, *end, *path;
-
- for (p = cp->In.data + cp->Start + strlen("list"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- if (cp->Nolist) {
- NCwritereply(cp, NCbadcommand);
- return;
- }
- if (strcasecmp(p, "newsgroups") == 0) {
- path = concatpath(innconf->pathdb, _PATH_NEWSGROUPS);
- trash = p = ReadInFile(path, NULL);
- free(path);
- if (p == NULL) {
- NCwritereply(cp, NCdot);
- return;
- }
- end = p + strlen(p);
- }
- else if (strcasecmp(p, "active.times") == 0) {
- path = concatpath(innconf->pathdb, _PATH_ACTIVETIMES);
- trash = p = ReadInFile(path, NULL);
- free(path);
- if (p == NULL) {
- NCwritereply(cp, NCdot);
- return;
- }
- end = p + strlen(p);
- }
- else if (*p == '\0' || (strcasecmp(p, "active") == 0)) {
- p = ICDreadactive(&end);
- trash = NULL;
- }
- else {
- NCwritereply(cp, NCbadsubcommand);
- return;
- }
-
- /* Loop over all lines, sending the text and \r\n. */
- WCHANappend(cp, NNTP_LIST_FOLLOWS,strlen(NNTP_LIST_FOLLOWS));
- WCHANappend(cp, NCterm, strlen(NCterm)) ;
- for (; p < end && (q = strchr(p, '\n')) != NULL; p = q + 1) {
- WCHANappend(cp, p, q - p);
- WCHANappend(cp, NCterm, strlen(NCterm));
- }
- NCwritereply(cp, NCdot);
- if (trash)
- free(trash);
-}
-
-
-/*
-** The "mode" command. Hand off the channel.
-*/
-static void
-NCmode(CHANNEL *cp)
-{
- char *p;
- HANDOFF h;
-
- /* Skip the first word, get the argument. */
- for (p = cp->In.data + cp->Start + strlen("mode"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
-
- if (strcasecmp(p, "reader") == 0 && !innconf->noreader)
- h = HOnnrpd;
- else if (strcasecmp(p, "stream") == 0 &&
- (!StreamingOff && cp->Streaming)) {
- char buff[16];
-
- snprintf(buff, sizeof(buff), "%d StreamOK.", NNTP_OK_STREAM_VAL);
- NCwritereply(cp, buff);
- syslog(L_NOTICE, "%s NCmode \"mode stream\" received",
- CHANname(cp));
- return;
- } else if (strcasecmp(p, "cancel") == 0 && cp->privileged) {
- char buff[16];
-
- cp->State = CScancel;
- snprintf(buff, sizeof(buff), "%d CancelOK.", NNTP_OK_CANCEL_VAL);
- NCwritereply(cp, buff);
- syslog(L_NOTICE, "%s NCmode \"mode cancel\" received",
- CHANname(cp));
- return;
- } else {
- NCwritereply(cp, NCbadsubcommand);
- return;
- }
- RChandoff(cp->fd, h);
- if (NCcount > 0)
- NCcount--;
- CHANclose(cp, CHANname(cp));
-}
-
-
-/*
-** The "quit" command. Acknowledge, and set the state to closing down.
-*/
-static void
-NCquit(CHANNEL *cp)
-{
- cp->State = CSwritegoodbye;
- NCwritereply(cp, NNTP_GOODBYE_ACK);
-}
-
-
-/*
-** The catch-all for reader commands, which should return a different status
-** than just "unrecognized command" since a change of state may make them
-** available.
-*/
-static void
-NC_reader(CHANNEL *cp)
-{
- cp->Start = cp->Next;
- NCwritereply(cp, NNTP_ACCESS);
-}
-
-
-/*
-** The catch-all for inimplemented commands.
-*/
-static void
-NC_unimp(CHANNEL *cp)
-{
- char *p, *q;
- char buff[SMBUF];
-
- /* Nip off the first word. */
- for (p = q = cp->In.data + cp->Start; *p && !ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- *p = '\0';
- snprintf(buff, sizeof(buff), "%d \"%s\" not implemented; try \"help\".",
- NNTP_BAD_COMMAND_VAL, MaxLength(q, q));
- NCwritereply(cp, buff);
-}
-
-\f
-
-/*
-** Check whatever data is available on the channel. If we got the
-** full amount (i.e., the command or the whole article) process it.
-*/
-static void
-NCproc(CHANNEL *cp)
-{
- char *p, *q;
- NCDISPATCH *dp;
- struct buffer *bp;
- char buff[SMBUF];
- int i, j;
- bool readmore, movedata;
- ARTDATA *data = &cp->Data;
- HDRCONTENT *hc = data->HdrContent;
-
- readmore = movedata = false;
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s NCproc Used=%lu", CHANname(cp),
- (unsigned long) cp->In.used);
-
- bp = &cp->In;
- if (bp->used == 0)
- return;
-
- for ( ; ; ) {
- if (Tracing || cp->Tracing) {
- syslog(L_TRACE, "%s cp->Start=%lu cp->Next=%lu bp->Used=%lu",
- CHANname(cp), (unsigned long) cp->Start, (unsigned long) cp->Next,
- (unsigned long) bp->used);
- if (bp->used > 15)
- syslog(L_TRACE, "%s NCproc state=%d next \"%.15s\"", CHANname(cp),
- cp->State, &bp->data[cp->Next]);
- }
- switch (cp->State) {
- default:
- syslog(L_ERROR, "%s internal NCproc state %d", CHANname(cp), cp->State);
- movedata = false;
- readmore = true;
- break;
-
- case CSwritegoodbye:
- movedata = false;
- readmore = true;
- break;
-
- case CSgetcmd:
- case CSgetauth:
- case CScancel:
- /* Did we get the whole command, terminated with "\r\n"? */
- for (i = cp->Next; (i < bp->used) && (bp->data[i] != '\n'); i++) ;
- if (i == bp->used) {
- /* Check for too long command. */
- if ((j = bp->used - cp->Start) > NNTP_STRLEN) {
- /* Make some room, saving only the last few bytes. */
- for (p = bp->data, i = 0; i < SAVE_AMT; i++)
- p[i] = p[bp->used - SAVE_AMT + i];
- cp->LargeCmdSize += j - SAVE_AMT;
- bp->used = cp->Next = SAVE_AMT;
- bp->left = bp->size - SAVE_AMT;
- cp->Start = 0;
- cp->State = CSeatcommand;
- /* above means moving data already */
- movedata = false;
- } else {
- cp->Next = bp->used;
- /* move data to the begining anyway */
- movedata = true;
- }
- readmore = true;
- break;
- }
- /* i points where '\n" and go forward */
- cp->Next = ++i;
- /* never move data so long as "\r\n" is found, since subsequent
- data may also include command line */
- movedata = false;
- readmore = false;
- if (i - cp->Start < 3) {
- break;
- }
- p = &bp->data[i];
- if (p[-2] != '\r') { /* probably in an article */
- char *tmpstr;
-
- tmpstr = xmalloc(i - cp->Start + 1);
- memcpy(tmpstr, bp->data + cp->Start, i - cp->Start);
- tmpstr[i - cp->Start] = '\0';
-
- syslog(L_NOTICE, "%s bad_command %s", CHANname(cp),
- MaxLength(tmpstr, tmpstr));
- free(tmpstr);
-
- if (++(cp->BadCommands) >= BAD_COMMAND_COUNT) {
- cp->State = CSwritegoodbye;
- NCwritereply(cp, NCbadcommand);
- break;
- }
- NCwritereply(cp, NCbadcommand);
- /* still some data left, go for it */
- cp->Start = cp->Next;
- break;
- }
-
- q = &bp->data[cp->Start];
- /* Ignore blank lines. */
- if (*q == '\0' || i - cp->Start == 2) {
- cp->Start = cp->Next;
- break;
- }
- p[-2] = '\0';
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s < %s", CHANname(cp), q);
-
- /* We got something -- stop sleeping (in case we were). */
- SCHANremove(cp);
- if (cp->Argument != NULL) {
- free(cp->Argument);
- cp->Argument = NULL;
- }
-
- if (cp->State == CSgetauth) {
- if (strncasecmp(q, "mode", 4) == 0)
- NCmode(cp);
- else
- NCauthinfo(cp);
- break;
- } else if (cp->State == CScancel) {
- NCcancel(cp);
- break;
- }
-
- /* Loop through the command table. */
- for (p = q, dp = NCcommands; dp < ARRAY_END(NCcommands); dp++) {
- if (strncasecmp(p, dp->Name, dp->Size) == 0) {
- /* ignore the streaming commands if necessary. */
- if (!StreamingOff || cp->Streaming ||
- (dp->Function != NCcheck && dp->Function != NCtakethis)) {
- (*dp->Function)(cp);
- cp->BadCommands = 0;
- break;
- }
- }
- }
- if (dp == ARRAY_END(NCcommands)) {
- if (++(cp->BadCommands) >= BAD_COMMAND_COUNT)
- cp->State = CSwritegoodbye;
- NCwritereply(cp, NCbadcommand);
- cp->Start = cp->Next;
-
- /* Channel could have been freed by above NCwritereply if
- we're writing-goodbye */
- if (cp->Type == CTfree)
- return;
- for (i = 0; (p = NCquietlist[i]) != NULL; i++)
- if (strcasecmp(p, q) == 0)
- break;
- if (p == NULL)
- syslog(L_NOTICE, "%s bad_command %s", CHANname(cp),
- MaxLength(q, q));
- }
- break;
-
- case CSgetheader:
- case CSgetbody:
- case CSeatarticle:
- TMRstart(TMR_ARTPARSE);
- ARTparse(cp);
- TMRstop(TMR_ARTPARSE);
- if (cp->State == CSgetbody || cp->State == CSgetheader ||
- cp->State == CSeatarticle) {
- if (cp->Next - cp->Start > innconf->datamovethreshold ||
- (innconf->maxartsize > 0 && cp->Size > innconf->maxartsize)) {
- /* avoid buffer extention for ever */
- movedata = true;
- } else {
- movedata = false;
- }
- readmore = true;
- break;
- }
-
- if (cp->State == CSgotlargearticle) {
- syslog(L_NOTICE, "%s internal rejecting huge article (%d > %ld)",
- CHANname(cp), cp->Next - cp->Start, innconf->maxartsize);
- if (cp->Sendid.size)
- NCwritereply(cp, cp->Sendid.data);
- else {
- snprintf(buff, sizeof(buff),
- "%d Article exceeds local limit of %ld bytes",
- NNTP_REJECTIT_VAL, innconf->maxartsize);
- NCwritereply(cp, buff);
- }
- cp->State = CSgetcmd;
- cp->Rejected++;
- cp->Start = cp->Next;
-
- /* Write a local cancel entry so nobody else gives it to us. */
- if (HDR_FOUND(HDR__MESSAGE_ID)) {
- HDR_PARSE_START(HDR__MESSAGE_ID);
- if (!HIScheck(History, HDR(HDR__MESSAGE_ID)) &&
- !InndHisRemember(HDR(HDR__MESSAGE_ID)))
- syslog(L_ERROR, "%s cant write %s", LogName, HDR(HDR__MESSAGE_ID));
- }
- /* Clear the work-in-progress entry. */
- NCclearwip(cp);
- readmore = false;
- movedata = false;
- break;
- }
-
- if (*cp->Error != '\0') {
- cp->Rejected++;
- cp->State = CSgetcmd;
- cp->Start = cp->Next;
- NCclearwip(cp);
- if (cp->Sendid.size > 3)
- NCwritereply(cp, cp->Sendid.data);
- else
- NCwritereply(cp, cp->Error);
- readmore = false;
- movedata = false;
- break;
- }
-
- if (cp->State == CSnoarticle) {
- /* this should happen when parsing header */
- cp->Rejected++;
- cp->State = CSgetcmd;
- cp->Start = cp->Next;
- /* Clear the work-in-progress entry. */
- NCclearwip(cp);
- if (cp->Sendid.size > 3) { /* We be streaming */
- cp->Takethis_Err++;
- snprintf(buff, sizeof(buff), "%d", NNTP_ERR_FAILID_VAL);
- cp->Sendid.data[0] = buff[0];
- cp->Sendid.data[1] = buff[1];
- cp->Sendid.data[2] = buff[2];
- NCwritereply(cp, cp->Sendid.data);
- } else
- NCwritereply(cp, NNTP_REJECTIT_EMPTY);
- readmore = false;
- movedata = false;
- break;
- }
- case CSgotarticle: /* in case caming back from pause */
- /* never move data so long as "\r\n.\r\n" is found, since subsequent data
- may also include command line */
- readmore = false;
- movedata = false;
- if (Mode == OMpaused) { /* defer processing while paused */
- RCHANremove(cp); /* don't bother trying to read more for now */
- SCHANadd(cp, Now.time + innconf->pauseretrytime, &Mode, NCproc, NULL);
- return;
- } else if (Mode == OMthrottled) {
- /* Clear the work-in-progress entry. */
- NCclearwip(cp);
- NCwriteshutdown(cp, ModeReason);
- cp->Rejected++;
- return;
- }
-
- SCHANremove(cp);
- if (cp->Argument != NULL) {
- free(cp->Argument);
- cp->Argument = NULL;
- }
- NCpostit(cp);
- /* Clear the work-in-progress entry. */
- NCclearwip(cp);
- if (cp->State == CSwritegoodbye)
- break;
- cp->State = CSgetcmd;
- cp->Start = cp->Next;
- break;
-
- case CSeatcommand:
- /* Eat the command line and then complain that it was too large */
- /* Reading a line; look for "\r\n" terminator. */
- /* cp->Next should be SAVE_AMT(10) */
- for (i = cp->Next ; i < bp->used; i++) {
- if ((bp->data[i - 1] == '\r') && (bp->data[i] == '\n')) {
- cp->Next = i + 1;
- break;
- }
- }
- if (i < bp->used) { /* did find terminator */
- /* Reached the end of the command line. */
- SCHANremove(cp);
- if (cp->Argument != NULL) {
- free(cp->Argument);
- cp->Argument = NULL;
- }
- i += cp->LargeCmdSize;
- syslog(L_NOTICE, "%s internal rejecting too long command line (%d > %d)",
- CHANname(cp), i, NNTP_STRLEN);
- cp->LargeCmdSize = 0;
- snprintf(buff, sizeof(buff), "%d command exceeds limit of %d bytes",
- NNTP_BAD_COMMAND_VAL, NNTP_STRLEN);
- cp->State = CSgetcmd;
- cp->Start = cp->Next;
- NCwritereply(cp, buff);
- readmore = false;
- movedata = false;
- } else {
- cp->LargeCmdSize += bp->used - cp->Next;
- bp->used = cp->Next = SAVE_AMT;
- bp->left = bp->size - SAVE_AMT;
- cp->Start = 0;
- readmore = true;
- movedata = false;
- }
- break;
-
- case CSgetxbatch:
- /* if the batch is complete, write it out into the in.coming
- * directory with an unique timestamp, and start rnews on it.
- */
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s CSgetxbatch: now %lu of %d bytes", CHANname(cp),
- (unsigned long) bp->used, cp->XBatchSize);
-
- if (cp->Next != 0) {
- /* data must start from the begining of the buffer */
- movedata = true;
- readmore = false;
- break;
- }
- if (bp->used < cp->XBatchSize) {
- movedata = false;
- readmore = true;
- break; /* give us more data */
- }
- movedata = false;
- readmore = false;
-
- /* now do something with the batch */
- {
- char buff2[SMBUF];
- int fd, oerrno, failed;
- long now;
-
- now = time(NULL);
- failed = 0;
- /* time+channel file descriptor should make an unique file name */
- snprintf(buff, sizeof(buff), "%s/%ld%d.tmp", innconf->pathincoming,
- now, cp->fd);
- fd = open(buff, O_WRONLY|O_CREAT|O_EXCL, ARTFILE_MODE);
- if (fd < 0) {
- oerrno = errno;
- failed = 1;
- syslog(L_ERROR, "%s cannot open outfile %s for xbatch: %m",
- CHANname(cp), buff);
- snprintf(buff, sizeof(buff), "%s cant create file: %s",
- NNTP_RESENDIT_XBATCHERR, strerror(oerrno));
- NCwritereply(cp, buff);
- } else {
- if (write(fd, cp->In.data, cp->XBatchSize) != cp->XBatchSize) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant write batch to file %s: %m", CHANname(cp),
- buff);
- snprintf(buff, sizeof(buff), "%s cant write batch to file: %s",
- NNTP_RESENDIT_XBATCHERR, strerror(oerrno));
- NCwritereply(cp, buff);
- failed = 1;
- }
- }
- if (fd >= 0 && close(fd) != 0) {
- oerrno = errno;
- syslog(L_ERROR, "%s error closing batch file %s: %m", CHANname(cp),
- failed ? "" : buff);
- snprintf(buff, sizeof(buff), "%s error closing batch file: %s",
- NNTP_RESENDIT_XBATCHERR, strerror(oerrno));
- NCwritereply(cp, buff);
- failed = 1;
- }
- snprintf(buff2, sizeof(buff2), "%s/%ld%d.x", innconf->pathincoming,
- now, cp->fd);
- if (rename(buff, buff2)) {
- oerrno = errno;
- syslog(L_ERROR, "%s cant rename %s to %s: %m", CHANname(cp),
- failed ? "" : buff, buff2);
- snprintf(buff, sizeof(buff), "%s cant rename batch to %s: %s",
- NNTP_RESENDIT_XBATCHERR, buff2, strerror(oerrno));
- NCwritereply(cp, buff);
- failed = 1;
- }
- cp->Reported++;
- if (!failed) {
- NCwritereply(cp, NNTP_OK_XBATCHED);
- cp->Received++;
- } else
- cp->Rejected++;
- }
- syslog(L_NOTICE, "%s accepted batch size %d", CHANname(cp),
- cp->XBatchSize);
- cp->State = CSgetcmd;
- cp->Start = cp->Next = cp->XBatchSize;
- break;
- }
- if (cp->State == CSwritegoodbye || cp->Type == CTfree)
- break;
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s NCproc state=%d Start=%lu Next=%lu Used=%lu",
- CHANname(cp), cp->State, (unsigned long) cp->Start,
- (unsigned long) cp->Next, (unsigned long) bp->used);
-
- if (movedata) { /* move data rather than extend buffer */
- TMRstart(TMR_DATAMOVE);
- movedata = false;
- if (cp->Start > 0)
- memmove(bp->data, &bp->data[cp->Start], bp->used - cp->Start);
- bp->used -= cp->Start;
- bp->left += cp->Start;
- cp->Next -= cp->Start;
- if (cp->State == CSgetheader || cp->State == CSgetbody ||
- cp->State == CSeatarticle) {
- /* adjust offset only in CSgetheader, CSgetbody or CSeatarticle */
- data->CurHeader -= cp->Start;
- data->LastTerminator -= cp->Start;
- data->LastCR -= cp->Start;
- data->LastCRLF -= cp->Start;
- data->Body -= cp->Start;
- if (data->BytesHeader != NULL)
- data->BytesHeader -= cp->Start;
- for (i = 0 ; i < MAX_ARTHEADER ; i++, hc++) {
- if (hc->Value != NULL)
- hc->Value -= cp->Start;
- }
- }
- cp->Start = 0;
- TMRstop(TMR_DATAMOVE);
- }
- if (readmore)
- /* need to read more */
- break;
- }
-}
-
-
-/*
-** Read whatever data is available on the channel. If we got the
-** full amount (i.e., the command or the whole article) process it.
-*/
-static void
-NCreader(CHANNEL *cp)
-{
- int i;
-
- if (Tracing || cp->Tracing)
- syslog(L_TRACE, "%s NCreader Used=%lu",
- CHANname(cp), (unsigned long) cp->In.used);
-
- /* Read any data that's there; ignore errors (retry next time it's our
- * turn) and if we got nothing, then it's EOF so mark it closed. */
- if ((i = CHANreadtext(cp)) <= 0) {
- /* Return of -2 indicates we got EAGAIN even though the descriptor
- selected true for reading, probably due to the Solaris select
- bug. Drop back out to the main loop as if the descriptor never
- selected true. */
- if (i == -2) {
- return;
- }
- if (i == 0 || cp->BadReads++ >= innconf->badiocount) {
- if (NCcount > 0)
- NCcount--;
- CHANclose(cp, CHANname(cp));
- }
- return;
- }
-
- NCproc(cp); /* check and process data */
-}
-
-
-
-/*
-** Set up the NNTP channel state.
-*/
-void
-NCsetup(void)
-{
- char *p;
- char buff[SMBUF];
-
- /* Set the greeting message. */
- p = innconf->pathhost;
- if (p == NULL)
- /* Worked in main, now it fails? Curious. */
- p = Path.data;
- snprintf(buff, sizeof(buff), "%d %s InterNetNews server %s ready",
- NNTP_POSTOK_VAL, p, inn_version_string);
- NCgreeting = xstrdup(buff);
-}
-
-
-/*
-** Tear down our state.
-*/
-void
-NCclose(void)
-{
- CHANNEL *cp;
- int j;
-
- /* Close all incoming channels. */
- for (j = 0; (cp = CHANiter(&j, CTnntp)) != NULL; ) {
- if (NCcount > 0)
- NCcount--;
- CHANclose(cp, CHANname(cp));
- }
-}
-
-
-/*
-** Create an NNTP channel and print the greeting message.
-*/
-CHANNEL *
-NCcreate(int fd, bool MustAuthorize, bool IsLocal)
-{
- CHANNEL *cp;
- int i;
-
- /* Create the channel. */
- cp = CHANcreate(fd, CTnntp, MustAuthorize ? CSgetauth : CSgetcmd,
- NCreader, NCwritedone);
-
- NCclearwip(cp);
- cp->privileged = IsLocal;
-#if defined(SOL_SOCKET) && defined(SO_SNDBUF) && defined(SO_RCVBUF)
- if (!IsLocal) {
- i = 24 * 1024;
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&i, sizeof i) < 0)
- syslog(L_ERROR, "%s cant setsockopt(SNDBUF) %m", CHANname(cp));
- if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&i, sizeof i) < 0)
- syslog(L_ERROR, "%s cant setsockopt(RCVBUF) %m", CHANname(cp));
- }
-#endif /* defined(SOL_SOCKET) && defined(SO_SNDBUF) && defined(SO_RCVBUF) */
-
-#if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
- if (!IsLocal) {
- /* Set KEEPALIVE to catch broken socket connections. */
- i = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof i) < 0)
- syslog(L_ERROR, "%s cant setsockopt(KEEPALIVE) %m", CHANname(cp));
- }
-#endif /* defined(SOL_SOCKET) && defined(SO_KEEPALIVE) */
-
- /* Now check our operating mode. */
- NCcount++;
- if (Mode == OMthrottled) {
- NCwriteshutdown(cp, ModeReason);
- return NULL;
- }
- if (RejectReason) {
- NCwriteshutdown(cp, RejectReason);
- return NULL;
- }
-
- /* See if we have too many channels. */
- if (!IsLocal && innconf->maxconnections &&
- NCcount >= innconf->maxconnections && !RCnolimit(cp)) {
- /* Recount, just in case we got out of sync. */
- for (NCcount = 0, i = 0; CHANiter(&i, CTnntp) != NULL; )
- NCcount++;
- if (NCcount >= innconf->maxconnections) {
- NCwriteshutdown(cp, "Too many connections");
- return NULL;
- }
- }
- cp->BadReads = 0;
- cp->BadCommands = 0;
- return cp;
-}
-
-
-
-/* These modules support the streaming option to tranfer articles
-** faster.
-*/
-
-/*
-** The "check" command. Check the Message-ID, and see if we want the
-** article or not. Stay in command state.
-*/
-static void
-NCcheck(CHANNEL *cp)
-{
- char *p;
- int idlen, msglen;
-#if defined(DO_PERL) || defined(DO_PYTHON)
- char *filterrc;
-#endif /* DO_PERL || DO_PYTHON */
-
- cp->Check++;
- /* Snip off the Message-ID. */
- for (p = cp->In.data + cp->Start; *p && !ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- for ( ; ISWHITE(*p); p++)
- continue;
- idlen = strlen(p);
- msglen = idlen + 5; /* 3 digits + space + id + null */
- if (cp->Sendid.size < msglen) {
- if (cp->Sendid.size > 0) free(cp->Sendid.data);
- if (msglen > MAXHEADERSIZE) cp->Sendid.size = msglen;
- else cp->Sendid.size = MAXHEADERSIZE;
- cp->Sendid.data = xmalloc(cp->Sendid.size);
- }
- if (!ARTidok(p)) {
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp), MaxLength(p, p));
- return;
- }
-
- if ((innconf->refusecybercancels) && (strncmp(p, "<cancel.", 8) == 0)) {
- cp->Refused++;
- cp->Check_cybercan++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- return;
- }
-
-#if defined(DO_PERL)
- /* Invoke a perl message filter on the message ID. */
- filterrc = PLmidfilter(p);
- if (filterrc) {
- cp->Refused++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- return;
- }
-#endif /* defined(DO_PERL) */
-
-#if defined(DO_PYTHON)
- /* invoke a python message filter on the message id */
- filterrc = PYmidfilter(p, idlen);
- if (filterrc) {
- cp->Refused++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- return;
- }
-#endif /* defined(DO_PYTHON) */
-
- if (HIScheck(History, p)) {
- cp->Refused++;
- cp->Check_got++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- } else if (WIPinprogress(p, cp, true)) {
- cp->Check_deferred++;
- if (cp->NoResendId) {
- cp->Refused++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_ERR_GOTID_VAL, p);
- } else {
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_RESENDID_VAL, p);
- }
- NCwritereply(cp, cp->Sendid.data);
- } else {
- cp->Check_send++;
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s",
- NNTP_OK_SENDID_VAL, p);
- NCwritereply(cp, cp->Sendid.data);
- }
- /* stay in command mode */
-}
-
-/*
-** The "takethis" command. Article follows.
-** Remember <id> for later ack.
-*/
-static void
-NCtakethis(CHANNEL *cp)
-{
- char *p;
- int msglen;
- WIP *wp;
-
- cp->Takethis++;
- /* Snip off the Message-ID. */
- for (p = cp->In.data + cp->Start + strlen("takethis"); ISWHITE(*p); p++)
- continue;
- cp->Start = cp->Next;
- for ( ; ISWHITE(*p); p++)
- continue;
- if (!ARTidok(p)) {
- syslog(L_NOTICE, "%s bad_messageid %s", CHANname(cp), MaxLength(p, p));
- }
- msglen = strlen(p) + 5; /* 3 digits + space + id + null */
- if (cp->Sendid.size < msglen) {
- if (cp->Sendid.size > 0) free(cp->Sendid.data);
- if (msglen > MAXHEADERSIZE) cp->Sendid.size = msglen;
- else cp->Sendid.size = MAXHEADERSIZE;
- cp->Sendid.data = xmalloc(cp->Sendid.size);
- }
- /* save ID for later NACK or ACK */
- snprintf(cp->Sendid.data, cp->Sendid.size, "%d %s", NNTP_ERR_FAILID_VAL,
- p);
-
- cp->ArtBeg = Now.time;
- cp->State = CSgetheader;
- ARTprepare(cp);
- /* set WIP for benefit of later code in NCreader */
- if ((wp = WIPbyid(p)) == (WIP *)NULL)
- wp = WIPnew(p, cp);
- cp->CurrentMessageIDHash = wp->MessageID;
-}
-
-/*
-** Process a cancel ID from a "mode cancel" channel.
-*/
-static void
-NCcancel(CHANNEL *cp)
-{
- char *av[2] = { NULL, NULL };
- const char *res;
-
- ++cp->Received;
- av[0] = cp->In.data + cp->Start;
- cp->Start = cp->Next;
- res = CCcancel(av);
- if (res) {
- char buff[SMBUF];
-
- snprintf(buff, sizeof(buff), "%d %s", NNTP_ERR_CANCEL_VAL,
- MaxLength(res, res));
- syslog(L_NOTICE, "%s cant_cancel %s", CHANname(cp),
- MaxLength(res, res));
- NCwritereply(cp, buff);
- } else {
- NCwritereply(cp, NNTP_OK_CANCELLED);
- }
-}
+++ /dev/null
-/* $Id: newsfeeds.c 7730 2008-04-06 08:27:16Z iulius $
-**
-** Routines for the in-core data structures for the newsfeeds file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-/*
-** List of variables assigned in the configuration file.
-*/
-typedef struct _SITEVARIABLES {
- char *Name;
- char *Value;
- int Elements;
- struct _SITEVARIABLES *Next;
-} SITEVARIABLES;
-
-/* The character which introduces a variable assignment or reference. */
-#define VARIABLE_CHAR '$'
-
-static SITE SITEnull;
-static char *SITEfeedspath = NULL;
-static SITEVARIABLES *SITEvariables = NULL;
-
-
-/*
-** Return a copy of an array of strings.
-*/
-static char **
-SITEcopystrings(char **av)
-{
- char **new;
- char **pp;
- char **save;
-
- for (pp = av; *pp; pp++)
- continue;
- for (new = save = xmalloc((pp - av + 1) * sizeof(char *)), pp = av; *pp; pp++)
- *new++ = xstrdup(*pp);
- *new = NULL;
- return save;
-}
-
-/*
-** Adds a variable from a line.
-*/
-static bool
-SITEaddvariable(char *line)
-{
- char *p, *q;
- SITEVARIABLES *v, *w;
-
- if (*line != VARIABLE_CHAR)
- return false;
-
- for (p = line + 1; *p != '\0' && CTYPE(isalnum, *p); p++)
- ;
- if (*p != '=')
- return false;
- if (p - line > 32) {
- syslog(L_FATAL, "%s bad_newsfeed variable name '%s' too long",
- LogName, line+1);
- return false;
- }
-
- /* Chop off trailing spaces. */
- q = p + strlen(p) - 1;
- while (q > p && (*q == ' ' || *q == '\t'))
- *q-- = '\0';
-
- /* Seperate variable name from contents. */
- *p++ = '\0';
- if (*p == '\0')
- return false;
-
- /* Is variable already defined? Free and reassign. */
- w = NULL;
- v = SITEvariables;
- while (v && strcmp(line + 1, v->Name)) {
- w = v;
- v = v->Next;
- }
- if (v)
- free(v->Value);
- else {
- v = xmalloc(sizeof(SITEVARIABLES));
- if (!SITEvariables)
- SITEvariables = v;
- if (w)
- w->Next = v;
- v->Name = xstrdup(line + 1);
- v->Next = NULL;
- }
-
- /* Add variable's contents. */
- v->Elements = 1;
- for (q = v->Value = xmalloc(strlen(p) + 1); *p != '\0'; p++) {
- if (*p != ' ' && *p != '\t')
- *q++ = *p;
- if (*p == ',')
- v->Elements++;
- }
- *q = '\0';
- return true;
-}
-
-static void
-SITEclearvariables(void)
-{
- SITEVARIABLES *v, *w;
-
- v = SITEvariables;
- while (v) {
- free(v->Name);
- free(v->Value);
- w = v;
- v = v->Next;
- free(w);
- }
- SITEvariables = NULL;
-}
-
-static SITEVARIABLES *
-SITEfindvariable(char *name)
-{
- SITEVARIABLES *v;
-
- v = SITEvariables;
- while (v && strcmp(v->Name, name) != 0)
- v = v->Next;
- return v;
-}
-
-static char *
-SITEexpandvariables(char *site)
-{
- char *p, *r, *s;
- char *q = NULL;
- int c = 0;
- char modifier;
- char varname[64];
- SITEVARIABLES *v;
-
- /* Count characters. */
- *varname = '\0';
- modifier = '\0';
- for (p = site; p <= site + strlen(site); p++) {
- /* In variable name. */
- if (*varname) {
- if (CTYPE(isalnum, *p)) {
- if (q - varname > 32) {
- /* Add ignored modifier. */
- if (modifier)
- c++;
- /* Add ignored $ and characters. */
- c += strlen(varname);
- /* Add this character. */
- c++;
- *varname = '\0';
- modifier = '\0';
- continue;
- }
- /* Append to variable name. */
- *q++ = *p;
- continue;
- } else {
- v = SITEfindvariable(varname + 1);
- if (v != NULL) {
- /* Add length of contents. */
- c += strlen(v->Value);
- /* If modified add number of mods. */
- if (modifier)
- c += v->Elements;
- } else {
- /* Add ignored modifier. */
- if (modifier)
- c++;
- c += strlen(varname); /* add ignored $ and characters */
- }
- *varname = '\0';
- modifier = '\0';
- }
- }
- /* New variable starts */
- if (*p == VARIABLE_CHAR) {
- q = varname;
- memset(varname, 0, sizeof(varname));
- *q++ = VARIABLE_CHAR;
- continue;
- }
- if (modifier) {
- /* Add last modifier */
- c++;
- modifier = '\0';
- }
- if (*p == SUB_NEGATE || *p == SUB_POISON) {
- modifier = *p;
- } else {
- /* Add this character. */
- c++;
- }
- }
-
- /* Copy contents. */
- s = r = xmalloc(c + 1);
- *varname = '\0';
- modifier = '\0';
- for (p = site; p <= site + strlen(site); p++) {
- /* In variable name. */
- if (*varname) {
- if (CTYPE(isalnum, *p)) {
- if (q - varname > 32) {
- if (modifier)
- *s++ = modifier;
- for (q = varname; *q; q++)
- *s++ = *q;
- *s++ = *p;
- *varname = '\0';
- modifier = '\0';
- continue;
- }
- *q++ = *p;
- continue;
- } else {
- v = SITEfindvariable(varname + 1);
- if (v != NULL) {
- if (modifier)
- *s++ = modifier;
- for (q = v->Value; *q; q++) {
- *s++ = *q;
- if (*q == ',' && modifier)
- *s++ = modifier;
- }
- } else {
- if (modifier)
- *s++ = modifier;
- for (q = varname; *q; q++)
- *s++ = *q;
- }
- *varname = '\0';
- modifier = '\0';
- }
- }
- /* New variable starts. */
- if (*p == VARIABLE_CHAR) {
- q = varname;
- memset(varname, 0, sizeof(varname));
- *q++ = VARIABLE_CHAR;
- continue;
- }
- if (modifier) {
- *s++ = modifier;
- modifier = '\0';
- }
- if (*p == SUB_NEGATE || *p == SUB_POISON)
- modifier = *p;
- else
- *s++ = *p;
- }
- *s++ = '\0';
-
- return r;
-}
-
-/*
-** Read the newsfeeds file, return a string array of entries.
-*/
-char **
-SITEreadfile(const bool ReadOnly)
-{
- static char **old_strings;
- static time_t old_mtime;
- static ino_t old_ino;
- static off_t old_size;
- char *p;
- char *to;
- char *site;
- int i;
- struct stat Sb;
- char *data;
-
- if (SITEfeedspath == NULL)
- SITEfeedspath = concatpath(innconf->pathetc, _PATH_NEWSFEEDS);
- if (old_strings != NULL) {
- /* If the file hasn't changed, return a copy of the old data. */
- if (stat(SITEfeedspath, &Sb) >= 0
- && Sb.st_ino == old_ino
- && Sb.st_size == old_size
- && Sb.st_mtime == old_mtime)
- return ReadOnly ? old_strings : SITEcopystrings(old_strings);
-
- /* Data's bad, toss it. */
- for (i = 0; old_strings[i] != NULL; i++)
- free(old_strings[i]);
- free(old_strings);
- }
-
- /* Read in the file, note its statistics. */
- if ((data = ReadInFile(SITEfeedspath, &Sb)) == NULL) {
- syslog(L_FATAL, "%s cant read %s %m", LogName, SITEfeedspath);
- exit(1);
- }
- old_mtime = Sb.st_mtime;
- old_ino = Sb.st_ino;
- old_size = Sb.st_size;
-
- /* Get a gross count of the number of sites. */
- for (p = data, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)
- continue;
-
- /* Scan the file, parse all multi-line entries. */
- for (old_strings = xmalloc((i + 1) * sizeof(char *)), i = 0, to = p = data; *p; ) {
- for (site = to; *p; ) {
- if (*p == '\n') {
- p++;
- *to = '\0';
- break;
- }
- if (*p == '\\' && p[1] == '\n')
- while (*++p && CTYPE(isspace, *p))
- continue;
- else
- *to++ = *p++;
- }
- *to++ = '\0';
- if (*site == '#' || *site == '\0')
- continue ;
- if (*site == VARIABLE_CHAR && SITEaddvariable(site))
- continue ;
- if (strspn(site," \t") == strlen (site))
- continue;
- if (SITEvariables)
- old_strings[i++] = SITEexpandvariables(site);
- else
- old_strings[i++] = xstrdup(site);
- }
- old_strings[i] = NULL;
-
- SITEclearvariables();
- free(data);
- return ReadOnly ? old_strings : SITEcopystrings(old_strings);
-}
-
-
-/*
-** Modify "subbed" according to the patterns in "patlist."
-*/
-static void
-SITEsetlist(char **patlist, char *subbed, char *poison, bool *poisonEntry)
-{
- char *pat;
- char *p;
- char *u;
- char subvalue;
- char poisonvalue;
- NEWSGROUP *ngp;
- int i;
-
- while ((pat = *patlist++) != NULL) {
- subvalue = *pat != SUB_NEGATE && *pat != SUB_POISON;
- poisonvalue = *pat == SUB_POISON;
- if (!subvalue)
- pat++;
- if (!*pat)
- continue;
- if (!*poisonEntry && poisonvalue)
- *poisonEntry = true;
-
- /* See if pattern is a simple newsgroup name. If so, set the
- * right subbed element for that one group (if found); if not,
- * pattern-match against all the groups. */
- for (p = pat; *p; p++)
- if (*p == '?' || *p == '*' || *p == '[')
- break;
- if (*p == '\0') {
- /* Simple string; look it up, set it. */
- if ((ngp = NGfind(pat)) != NULL) {
- subbed[ngp - Groups] = subvalue;
- poison[ngp - Groups] = poisonvalue;
- }
- }
- else
- for (p = subbed, u = poison, ngp = Groups, i = nGroups;
- --i >= 0; ngp++, p++, u++)
- if (uwildmat(ngp->Name, pat)) {
- *p = subvalue;
- *u = poisonvalue;
- }
- }
-}
-
-/*
-** Split text into slash-separated fields. Return an allocated
-** NULL-terminated array of the fields within the modified argument that
-** the caller is expected to save or free. We don't use strchr() since
-** the text is expected to be either relatively short or "slash-dense."
-*/
-static char **
-SlashSplit(char *text)
-{
- int i;
- char *p;
- char **av;
- char **save;
-
- /* How much space do we need? */
- for (i = 2, p = text; *p; p++)
- if (*p == '/')
- i++;
-
- for (av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
- if (*p == '/') {
- *p++ = '\0';
- *av++ = p;
- }
- else
- p++;
- *av = NULL;
- return save;
-}
-
-/*
-** Parse an individual site entry. Subbed is used to build the subscription
-** list. Since this routine is called once for each site, the caller
-** allocates subbed once, and frees it after the last site has been parsed.
-** If subbed is NULL, we don't update the SITE array, since we're just
-** doing syntax checking.
-*/
-const char *
-SITEparseone(char *Entry, SITE *sp, char *subbed, char *poison)
-{
- int i;
- int j;
- NEWSGROUP *ngp;
- char *p;
- char *u;
- char *f2;
- char *f3;
- char *f4;
- char **save;
- char **argv;
- bool JustModerated;
- bool JustUnmoderated;
- int isp;
- SITE *nsp;
- struct buffer b;
- HASHFEEDLIST *hf;
-
- b = sp->Buffer;
- *sp = SITEnull;
- sp->Buffer = b;
- sp->Master = NOSITE;
- sp->Funnel = NOSITE;
- sp->PoisonEntry = false;
- sp->Process = -1;
- sp->Next = sp->Prev = NOSITE;
- sp->Entry = Entry;
- sp->Originator = NULL;
- sp->FileFlags[0] = FEED_NAME;
- sp->FileFlags[1] = '\0';
- sp->Nice = innconf->nicekids;
- sp->ControlOnly = false;
- sp->DontWantNonExist = false;
- sp->NeedOverviewCreation = false;
- sp->FeedwithoutOriginator = false;
- sp->DropFiltered = false;
- sp->HashFeedList = NULL;
-
- /* Nip off the first field, the site name. */
- if ((f2 = strchr(Entry, NF_FIELD_SEP)) == NULL)
- return "missing field 2";
- *f2++ = '\0';
- sp->Name = Entry;
- if ((p = strchr(sp->Name, NF_SUBFIELD_SEP)) != NULL) {
- /* Exclusions within the site field. */
- *p++ = '\0';
- if (*p)
- sp->Exclusions = CommaSplit(p);
- }
- sp->NameLength = strlen(sp->Name);
-
- /* Parse the second field, the subscriptions. */
- if ((f3 = strchr(f2, NF_FIELD_SEP)) == NULL)
- return "missing field 3";
- *f3++ = '\0';
- if ((p = strchr(f2, NF_SUBFIELD_SEP)) != NULL) {
- /* Distributions within the subscription field. */
- *p++ = '\0';
- if (*p)
- sp->Distributions = CommaSplit(p);
- }
- if (f2)
- sp->Patterns = CommaSplit(f2);
-
- if (subbed) {
- /* Read the subscription patterns and set the bits. */
- memset(subbed, SUB_DEFAULT, nGroups);
- memset(poison, SUB_DEFAULT, nGroups);
- if (ME.Patterns)
- SITEsetlist(ME.Patterns, subbed, poison, &ME.PoisonEntry);
- SITEsetlist(sp->Patterns, subbed, poison, &sp->PoisonEntry);
- }
-
- /* Get the third field, the flags. */
- if ((f4 = strchr(f3, NF_FIELD_SEP)) == NULL)
- return "missing field 4";
- *f4++ = '\0';
- JustModerated = false;
- JustUnmoderated = false;
- sp->Type = FTfile;
- for (save = argv = CommaSplit(f3); (p = *argv++) != NULL; )
- switch (*p) {
- default:
- return "unknown field 3 flag";
- case '\0':
- break;
- case '<':
- if (*++p && CTYPE(isdigit, *p))
- sp->MaxSize = atol(p);
- break;
- case '>':
- if (*++p && CTYPE(isdigit, *p))
- sp->MinSize = atol(p);
- break;
- case 'A':
- while (*++p)
- switch (*p) {
- default:
- return "unknown A param in field 3";
- case 'c': sp->IgnoreControl = true;
- sp->ControlOnly = false;
- break;
- case 'C': sp->ControlOnly = true;
- sp->IgnoreControl = false;
- break;
- case 'd': sp->DistRequired = true; break;
- case 'e': sp->DontWantNonExist = true; break;
- case 'f': sp->DropFiltered = true; break;
- case 'o': sp->NeedOverviewCreation = true; break;
- case 'O': sp->FeedwithoutOriginator = true; break;
- case 'p': sp->IgnorePath = true; break;
- }
- break;
- case 'B':
- if (*++p && CTYPE(isdigit, *p)) {
- sp->StartWriting = atoi(p);
- if ((p = strchr(p, NF_SUBFIELD_SEP)) != NULL
- && *++p
- && CTYPE(isdigit, *p))
- sp->StopWriting = atoi(p);
- }
- break;
- case 'C':
- if (*++p && CTYPE(isdigit, *p))
- sp->Crosscount = atoi(p);
- else
- sp->Crosscount = 1;
- break;
- case 'F':
- if (*++p == '\0')
- return "missing file name for F param in field 3";
- else if (*p == '/')
- sp->SpoolName = xstrdup(p);
- else {
- sp->SpoolName = xmalloc(strlen(innconf->pathoutgoing) + 1 +
- strlen(p) + 1);
- FileGlue(sp->SpoolName, innconf->pathoutgoing, '/', p);
- }
- break;
- case 'G':
- if (*++p && CTYPE(isdigit, *p))
- sp->Groupcount = atoi(p);
- else
- sp->Groupcount = 1;
- break;
- case 'H':
- if (*++p && CTYPE(isdigit, *p))
- sp->Hops = atoi(p);
- else
- sp->Hops = 1;
- break;
- case 'I':
- if (*++p && CTYPE(isdigit, *p))
- sp->Flushpoint = atol(p);
- break;
- case 'N':
- while (*++p)
- switch (*p) {
- default:
- return "unknown N param in field 3";
- case 'm': JustModerated = true; break;
- case 'u': JustUnmoderated = true; break;
- }
- break;
- case 'O':
- if (*++p == '\0')
- return "missing originator name for O param in field 3";
- sp->Originator = SlashSplit(p);
- break;
- case 'P':
- if (*++p && CTYPE(isdigit, *p))
- sp->Nice = atoi(p);
- break;
- case 'Q':
- hf = xmalloc(sizeof(HASHFEEDLIST));
- p++;
- /* Check whether it is a quickhash or a MD5 hashfeed. */
- if (*p == '@') {
- p++;
- hf->type = HASHFEED_QH;
- } else
- hf->type = HASHFEED_MD5;
- /* Check the presence of a starting byte-offset for hashfeed. */
- if ((u = strchr(p, '_')) != NULL) {
- if (sscanf(u + 1, "%u", &hf->offset) != 1 || hf->offset > 12) {
- free(hf);
- return "invalid hash offset for Q param in field 3";
- }
- } else
- hf->offset = 0;
- if (sscanf(p, "%u/%u", &hf->begin, &hf->mod) == 2) {
- hf->end = hf->begin;
- } else if (sscanf(p, "%u-%u/%u", &hf->begin, &hf->end,
- &hf->mod) != 3) {
- free(hf);
- return "hash not in x/z or x-y/z format for Q param in field 3";
- }
- if (hf->begin > hf->end || hf->end > hf->mod) {
- free(hf);
- return "incorrect hash values for Q param in field 3";
- }
- hf->next = sp->HashFeedList;
- sp->HashFeedList = hf;
- break;
- case 'S':
- if (*++p && CTYPE(isdigit, *p))
- sp->StartSpooling = atol(p);
- break;
- case 'T':
- switch (*++p) {
- default:
- return "unknown T param in field 3";
- case 'c': sp->Type = FTchannel; break;
- case 'l': sp->Type = FTlogonly; break;
- case 'f': sp->Type = FTfile; break;
- case 'm': sp->Type = FTfunnel; break;
- case 'p': sp->Type = FTprogram; break;
- case 'x': sp->Type = FTexploder; break;
- }
- break;
- case 'U':
- if (*++p && CTYPE(isdigit, *p))
- sp->Followcount = atoi(p);
- else
- sp->Followcount = 1;
- break;
- case 'W':
- for (i = 0; *++p && i < FEED_MAXFLAGS; ) {
- switch (*p) {
- default:
- return "unknown W param in field 3";
- case FEED_FNLNAMES: /* Funnel feed names */
- sp->FNLwantsnames = true;
- break;
- case FEED_HEADERS: /* Article headers */
- NeedHeaders = true;
- break;
- case FEED_OVERVIEW:
- NeedOverview = true; /* Overview data */
- break;
- case FEED_PATH: /* Path */
- NeedPath = true;
- break;
- case FEED_BYTESIZE: /* Size in bytes */
- case FEED_FULLNAME: /* Full filename */
- case FEED_HASH: /* Hash */
- case FEED_HDR_DISTRIB: /* Distribution header */
- case FEED_STOREDGROUP: /* stored newsgroup */
- NeedStoredGroup = true;
- break;
- case FEED_HDR_NEWSGROUP: /* Newsgroup header */
- case FEED_MESSAGEID: /* Message-ID */
- case FEED_NAME: /* Filename */
- case FEED_NEWSGROUP: /* Newsgroup */
- case FEED_REPLIC: /* Replication data */
- NeedReplicdata = true;
- break;
- case FEED_SITE: /* Site that gave it */
- case FEED_TIMERECEIVED: /* When received */
- case FEED_TIMEPOSTED: /* When posted */
- case FEED_TIMEEXPIRED: /* When will be expired */
- break;
- }
- sp->FileFlags[i++] = *p;
- }
- if (*p)
- return "too many W param values";
- sp->FileFlags[i] = '\0';
- break;
- }
- free(save);
- if (sp->Flushpoint && sp->Type != FTfile)
- return "I param with non-file feed";
- if (sp->Flushpoint == 0 && sp->Type == FTfile)
- sp->Flushpoint = SITE_BUFFER_SIZE;
-
- if (subbed) {
- /* Modify the subscription list based on the flags. */
- if (JustModerated)
- for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++, p++)
- if (ngp->Rest[0] != NF_FLAG_MODERATED)
- *p = false;
- if (JustUnmoderated)
- for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++, p++)
- if (ngp->Rest[0] == NF_FLAG_MODERATED)
- *p = false;
- }
-
- /* Get the fourth field, the param. */
- if (*f4 == '\0' && sp != &ME) {
- if (sp->Type != FTfile && sp->Type != FTlogonly)
- return "empty field 4";
- sp->Param = xmalloc(strlen(innconf->pathoutgoing) + 1 +
- sp->NameLength + 1);
- FileGlue(sp->Param, innconf->pathoutgoing, '/', sp->Name);
- }
- else if (sp->Type == FTfile && *f4 != '/') {
- sp->Param = xmalloc(strlen(innconf->pathoutgoing) + 1 +
- strlen(f4) + 1);
- FileGlue(sp->Param, innconf->pathoutgoing, '/', f4);
- }
- else
- sp->Param = xstrdup(f4);
-
- if (sp->SpoolName == NULL) {
- sp->SpoolName = xmalloc(strlen(innconf->pathoutgoing) + 1 +
- strlen(sp->Name) + 1);
- FileGlue(sp->SpoolName, innconf->pathoutgoing, '/', sp->Name);
- }
-
- /* Make sure there is only one %s, and only one *. */
- if (sp->Type == FTprogram) {
- f3 = NULL;
- for (f2 = sp->Param; *f2; f2 = p + 1) {
- p = strchr(f2, '%');
- if (p == NULL)
- break;
- if (p[1] == '%') {
- p++;
- continue;
- }
- if (f3 != NULL)
- return "bad (extra) sprintf format for field 4";
- f3 = p;
- while (*++p && *p != '*' && !CTYPE(isalpha, *p))
- continue;
- if (*p != 's')
- return "bad sprintf format for field 4";
- }
- if (sp->FNLwantsnames
- && ((p = strchr(sp->Param, '*')) == NULL
- || strchr(++p, '*') != NULL))
- return "multiple or no *'s in field 4";
- }
-
- /* Now tell the groups this site gets that they should feed this site. */
- if (sp != &ME && subbed) {
- isp = sp - Sites;
- for (p = subbed, u = poison, ngp = Groups, i = nGroups;
- --i >= 0; ngp++) {
- if (*p++) {
- for (j = 0; j < ngp->nSites; j++)
- if (ngp->Sites[j] == NOSITE) {
- ngp->Sites[j] = isp;
- break;
- }
- if (j == ngp->nSites)
- ngp->Sites[ngp->nSites++] = isp;
- }
- if (*u++) {
- for (j = 0; j < ngp->nPoison; j++)
- if (ngp->Poison[j] == NOSITE) {
- ngp->Poison[j] = isp;
- break;
- }
- if (j == ngp->nPoison)
- ngp->Poison[ngp->nPoison++] = isp;
- }
- }
- }
-
- /* If this is a duplicate name, find the master. */
- nsp = SITEfind(sp->Name);
- if (nsp == sp)
- nsp = SITEfindnext(sp->Name, nsp);
- if (nsp != NULL) {
- if (nsp->Master != NOSITE)
- nsp = &Sites[nsp->Master];
- if (nsp != sp) {
- sp->Master = nsp - Sites;
- nsp->IsMaster = true;
- }
- }
-
- return NULL;
-}
-
-
-/*
-** Patch up the funnel references.
-*/
-bool
-SITEfunnelpatch(void)
-{
- int i;
- int length;
- SITE *sp;
- SITE *funnel;
- bool result;
-
- /* Get worst-case length of all sitenames. */
- for (length = 0, i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Name != NULL)
- length += 1 + strlen(sp->Name);
-
- /* Loop over all funnel feeds. */
- for (result = true, i = nSites, sp = Sites; --i >= 0; sp++) {
- if (sp->Name == NULL || sp->Type != FTfunnel)
- continue;
-
- /* Find the entry they feed in to, give that entry a buffer. */
- if (sp->Param == NULL) {
- syslog(L_FATAL, "%s funnel NULL", sp->Name);
- SITEfree(sp);
- result = false;
- continue;
- }
- if ((funnel = SITEfind(sp->Param)) == NULL) {
- syslog(L_FATAL, "%s funnel_bad", sp->Name);
- SITEfree(sp);
- result = false;
- continue;
- }
- if (funnel->Type == FTfunnel) {
- syslog(L_FATAL, "%s funnels to funnel %s", sp->Name, funnel->Name);
- SITEfree(sp);
- result = false;
- continue;
- }
- if (funnel->FNLnames.data == NULL) {
- funnel->FNLnames.size = length;
- funnel->FNLnames.data = xmalloc(length);
- }
- else if (funnel->FNLnames.size != length) {
- funnel->FNLnames.size = length;
- funnel->FNLnames.data = xrealloc(funnel->FNLnames.data, length);
- }
- sp->Funnel = funnel - Sites;
- }
-
- return result;
-}
-
-
-/*
-** Read the entries in the newsfeeds file, and parse them one at a time.
-*/
-void
-SITEparsefile(bool StartSite)
-{
- int i;
- char * p;
- char ** strings;
- SITE * sp;
- char * subbed;
- char * poison;
- const char * error;
- int errors;
- int setuperrors;
-
- /* Free old sites info. */
- if (Sites) {
- for (i = nSites, sp = Sites; --i >= 0; sp++) {
- SITEflush(sp, false);
- SITEfree(sp);
- }
- free(Sites);
- SITEfree(&ME);
- }
-
- /* Count the number of sites. */
- for (strings = SITEreadfile(false), nSites = 0; strings[nSites]; nSites++)
- continue;
- Sites = xcalloc(nSites, sizeof(SITE));
-
- /* Set up scratch subscription list. */
- subbed = xmalloc(nGroups);
- poison = xmalloc(nGroups);
- /* reset global variables */
- NeedHeaders = NeedOverview = NeedPath = NeedStoredGroup = NeedReplicdata
- = false;
-
- ME.Prev = 0; /* Used as a flag to ensure exactly one ME entry */
- for (sp = Sites, errors = 0, setuperrors = 0, i = 0; i < nSites; i++) {
- p = strings[i];
- if (p[0] == 'M' && p[1] == 'E' &&
- ((p[2] == NF_FIELD_SEP) || (p[2] == NF_SUBFIELD_SEP))) {
- if (ME.Prev == NOSITE) {
- syslog(L_FATAL, "bad_newsfeeds. Must have exactly one ME entry");
- errors++;
- } else if ((error = SITEparseone(p, &ME, subbed, poison)) != NULL) {
- syslog(L_FATAL, "%s bad_newsfeeds %s", MaxLength(p, p), error);
- errors++;
- }
- continue;
- }
- if ((error = SITEparseone(p, sp, subbed, poison)) != NULL) {
- syslog(L_FATAL, "%s bad_newsfeeds %s", MaxLength(p, p), error);
- errors++;
- continue;
- }
- if (StartSite && !SITEsetup(sp)) {
- syslog(L_FATAL, "%s cant setup %m", sp->Name);
- setuperrors++;
- continue;
- }
- sp->Working = true;
- sp++;
- }
- if (ME.Prev != NOSITE) {
- syslog(L_FATAL, "bad_newsfeeds. Must have exactly one ME entry");
- errors++;
- }
-
- if (errors || setuperrors) {
- if (errors)
- syslog(L_FATAL, "%s syntax_error %s", LogName, SITEfeedspath);
- if (setuperrors)
- syslog(L_FATAL, "%s setup_error %s", LogName, SITEfeedspath);
- JustCleanup();
- exit(1);
- }
-
- /* Free our scratch array, set up the funnel links. */
- nSites = sp - Sites;
- free(subbed);
- free(poison);
- free(strings);
- if (!SITEfunnelpatch()) {
- JustCleanup();
- exit(1);
- }
-}
+++ /dev/null
-/* $Id: ng.c 6494 2003-10-20 01:12:50Z rra $
-**
-** Routine for the in-core data structures for the active and newsfeeds
-** files.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <dirent.h>
-
-#include "inn/innconf.h"
-#include "innd.h"
-#include "ov.h"
-
-
-/*
-** Hash function taken from Chris Torek's hash package posted to
-** comp.lang.c on 18-Oct-90 in <27038@mimsy.umd.edu>. Thanks, Chris.
-*/
-#define NGH_HASH(Name, p, j) \
- for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++
-
-
-/*
-** Size of hash table. Change NGH_BUCKET if not a power of two.
-*/
-#define NGH_SIZE 2048
-#define NGH_BUCKET(j) &NGHtable[j & (NGH_SIZE - 1)]
-
-
-/*
-** Newsgroup hash entry, which is really a hash bucket -- pointers
-** to all the groups with this hash code.
-*/
-typedef struct _NGHASH {
- int Size;
- int Used;
- NEWSGROUP **Groups;
-} NGHASH;
-
-
-static struct buffer NGnames;
-static NGHASH NGHtable[NGH_SIZE];
-static int NGHbuckets;
-static int NGHcount;
-
-\f
-
-/*
-** Sorting predicate for qsort call in NGparsefile. Put newsgroups in
-** rough order of their activity. Will be better if we write a "counts"
-** file sometime.
-*/
-static int
-NGcompare(const void *p1, const void *p2)
-{
- return ((const NEWSGROUP **)p1)[0]->Last -
- ((const NEWSGROUP **)p2)[0]->Last;
-}
-
-
-/*
-** Parse a single line from the active file, filling in ngp. Be careful
-** not to write NUL's into the in-core copy, since we're either mmap(2)'d,
-** or we want to just blat it out to disk later.
-*/
-static bool
-NGparseentry(NEWSGROUP *ngp, const char *p, char *end)
-{
- char *q;
- unsigned int j;
- NGHASH *htp;
- NEWSGROUP **ngpp;
- int i;
- ARTNUM lo;
-
- if ((q = strchr(p, ' ')) == NULL)
- return false;
- i = q - p;
-
- ngp->NameLength = i;
- ngp->Name = &NGnames.data[NGnames.used];
- strncpy(ngp->Name, p, i);
- ngp->Name[i] = '\0';
- NGnames.used += i + 1;
-
- ngp->LastString = ++q;
- if ((q = strchr(q, ' ')) == NULL || q > end)
- return false;
- ngp->Lastwidth = q - ngp->LastString;
- if ((q = strchr(q, ' ')) == NULL || q > end)
- return false;
- lo = (ARTNUM)atol(q + 1);
- if ((q = strchr(q + 1, ' ')) == NULL || q > end)
- return false;
- ngp->Rest = ++q;
- /* We count on atoi() to stop at the space after the digits! */
- ngp->Last = atol(ngp->LastString);
- ngp->nSites = 0;
- ngp->Sites = xmalloc(NGHcount * sizeof(int));
- ngp->nPoison = 0;
- ngp->Poison = xmalloc(NGHcount * sizeof(int));
- ngp->Alias = NULL;
-
- /* Find the right bucket for the group, make sure there is room. */
- NGH_HASH(ngp->Name, p, j);
- htp = NGH_BUCKET(j);
- for (p = ngp->Name, ngpp = htp->Groups, i = htp->Used; --i >= 0; ngpp++)
- if (*p == ngpp[0]->Name[0] && strcmp(p, ngpp[0]->Name) == 0) {
- syslog(L_ERROR, "%s duplicate_group %s", LogName, p);
- return false;
- }
- if (htp->Used >= htp->Size) {
- htp->Size += NGHbuckets;
- htp->Groups = xrealloc(htp->Groups, htp->Size * sizeof(NEWSGROUP *));
- }
- htp->Groups[htp->Used++] = ngp;
-
- if (innconf->enableoverview && !OVgroupadd(ngp->Name, lo, ngp->Last, ngp->Rest))
- return false;
-
- return true;
-}
-
-
-/*
-** Parse the active file, building the initial Groups global.
-*/
-void
-NGparsefile(void)
-{
- char *p;
- char *q;
- int i;
- bool SawMe;
- NEWSGROUP *ngp;
- NGHASH *htp;
- char **strings;
- char *active;
- char *end;
-
- /* If re-reading, remove anything we might have had. */
- NGclose();
-
- /* Get active file and space for group entries. */
- active = ICDreadactive(&end);
- for (p = active, i = 0; p < end; p++)
- if (*p == '\n') i++;
- if ((nGroups = i) == 0) {
- syslog(L_FATAL, "%s empty active file", LogName);
- exit(1);
- }
- Groups = xmalloc(nGroups * sizeof(NEWSGROUP));
- GroupPointers = xmalloc(nGroups * sizeof(NEWSGROUP *));
-
- /* Get space to hold copies of the names. This might take more space
- * than individually allocating each element, but it is definitely easier
- * on the system. */
- i = end - active;
- NGnames.size = i;
- NGnames.data = xmalloc(NGnames.size + 1);
- NGnames.used = 0;
-
- /* Set up the default hash buckets. */
- NGHbuckets = nGroups / NGH_SIZE;
- if (NGHbuckets == 0)
- NGHbuckets = 1;
- if (NGHtable[0].Groups)
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++)
- htp->Used = 0;
- else
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++) {
- htp->Size = NGHbuckets;
- htp->Groups = xmalloc(htp->Size * sizeof(NEWSGROUP *));
- htp->Used = 0;
- }
-
- /* Count the number of sites. */
- SawMe = false;
- for (strings = SITEreadfile(true), i = 0; (p = strings[i]) != NULL; i++)
- if (*p == 'M' && *++p == 'E' && *++p == ':')
- SawMe = true;
- if (i == 0 || (i == 1 && SawMe)) {
- syslog(L_ERROR, "%s bad_newsfeeds no feeding sites", LogName);
- NGHcount = 1;
- }
- else
- NGHcount = i;
-
- /* Loop over all lines in the active file, filling in the fields of
- * the Groups array. */
- for (p = active, ngp = Groups, i = nGroups; --i >= 0; ngp++, p = q + 1) {
- ngp->Start = p - active;
- if ((q = strchr(p, '\n')) == NULL || !NGparseentry(ngp, p, q)) {
- syslog(L_FATAL, "%s bad_active %s...", LogName, MaxLength(p, q));
- exit(1);
- }
- }
-
- /* Sort each bucket. */
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++)
- if (htp->Used > 1)
- qsort(htp->Groups, htp->Used, sizeof htp->Groups[0], NGcompare);
-
- /* Chase down any alias flags. */
- for (ngp = Groups, i = nGroups; --i >= 0; ngp++)
- if (ngp->Rest[0] == NF_FLAG_ALIAS) {
- ngp->Alias = ngp;
- if ((p = strchr(ngp->Alias->Rest, '\n')) != NULL)
- *p = '\0';
- ngp->Alias = NGfind(&ngp->Alias->Rest[1]);
- if (p)
- *p = '\n';
- if (ngp->Alias != NULL && ngp->Alias->Rest[0] == NF_FLAG_ALIAS)
- syslog(L_NOTICE, "%s alias_error %s too many levels",
- LogName, ngp->Name);
- }
-}
-
-/*
-** Free allocated memory
-*/
-void
-NGclose(void)
-{
- int i;
- NEWSGROUP *ngp;
- NGHASH *htp;
-
- if (Groups) {
- for (i = nGroups, ngp = Groups; --i >= 0; ngp++) {
- free(ngp->Sites);
- free(ngp->Poison);
- }
- free(Groups);
- Groups = NULL;
- free(GroupPointers);
- free(NGnames.data);
- }
-
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++) {
- htp->Size = NGHbuckets;
- if (htp->Groups) {
- free(htp->Groups);
- htp->Used = 0;
- htp->Groups = NULL;
- }
- }
-}
-
-/*
-** Hash a newsgroup and see if we get it.
-*/
-NEWSGROUP *
-NGfind(const char *Name)
-{
- const char *p;
- int i;
- unsigned int j;
- NEWSGROUP **ngp;
- char c;
- NGHASH *htp;
-
- NGH_HASH(Name, p, j);
- htp = NGH_BUCKET(j);
- for (c = *Name, ngp = htp->Groups, i = htp->Used; --i >= 0; ngp++)
- if (c == ngp[0]->Name[0] && strcmp(Name, ngp[0]->Name) == 0)
- return ngp[0];
- return NULL;
-}
-
-
-/*
-** Split a newsgroups header line into the groups we get. Return the
-** number of newsgroups. ' ' and '\t' are dropped when copying.
-*/
-int
-NGsplit(char *p, int size, LISTBUFFER *list)
-{
- char **gp, *q;
- int i;
-
- /* setup buffer */
- SetupListBuffer(size, list);
-
- /* loop over and copy */
- for (i = 0, q = list->Data, gp = list->List ; *p ; p++, *q++ = '\0') {
- /* skip leading separators and white spaces. */
- for (; *p && (NG_ISSEP(*p) || ISWHITE(*p)) ; p++)
- continue;
- if (*p == '\0')
- break;
-
- if (i == list->ListLength) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- gp = &list->List[i];
- }
- /* mark the start of the newsgroup, move to the end of it while copying */
- for (*gp++ = q, i++ ; *p && !NG_ISSEP(*p) && !ISWHITE(*p) ;) {
- if (*p == ':')
- /* reject if ':' is included */
- return 0;
- *q++ = *p++;
- continue;
- }
- if (*p == '\0')
- break;
- }
- *q = '\0';
- if (i == list->ListLength) {
- list->ListLength += DEFAULTNGBOXSIZE;
- list->List = xrealloc(list->List, list->ListLength * sizeof(char *));
- gp = &list->List[i];
- }
- *gp = NULL;
- return i;
-}
-
-
-/*
-** Renumber a group.
-*/
-static char NORENUMBER[] = "%s cant renumber %s %s too wide";
-static char RENUMBER[] = "%s renumber %s %s from %ld to %ld";
-
-bool
-NGrenumber(NEWSGROUP *ngp)
-{
- int low, high, count,flag;
- char *f2;
- char *f3;
- char *f4;
- char *start;
- long lomark, himark;
- long l;
- char *dummy;
-
- if (!innconf->enableoverview) return true; /* can't do anything w/o overview */
-
- /* Get a valid offset into the active file. */
- if (ICDneedsetup) {
- syslog(L_ERROR, "%s unsynched must reload before renumber", LogName);
- return false;
- }
- start = ICDreadactive(&dummy) + ngp->Start;
-
- /* Check the file format. */
- if ((f2 = strchr(start, ' ')) == NULL
- || (f3 = strchr(++f2, ' ')) == NULL
- || (f4 = strchr(++f3, ' ')) == NULL) {
- syslog(L_ERROR, "%s bad_format active %s",
- LogName, MaxLength(start, start));
- return false;
- }
- himark = atol(f2);
- lomark = himark + 1;
- /* note these will be the low and himarks if the group turns out to be empty. */
-
- /* Check overview data for the group. */
- if (!OVgroupstats(ngp->Name, &low, &high, &count, &flag)) return false;
- if (count != 0) {
- /* non-empty group, so set low/himarks from overview. */
- lomark = low;
- himark = high;
- }
- l = atol(f2);
- if (himark > l) {
- syslog(L_NOTICE, RENUMBER, LogName, ngp->Name, "hi", l, himark);
- if (!FormatLong(f2, himark, f3 - f2 - 1)) {
- syslog(L_ERROR, NORENUMBER, LogName, ngp->Name, "hi");
- return false;
- }
- ngp->Last = himark;
- ICDactivedirty++;
- } else if (himark < l) {
- syslog(L_NOTICE, "%s renumber %s hi not decreasing %ld to %ld",
- LogName, ngp->Name, l, himark);
- }
- l = atol(f3);
- if (lomark != l) {
- if (lomark < l)
- syslog(L_NOTICE, RENUMBER, LogName, ngp->Name, "lo", l, lomark);
- if (!FormatLong(f3, lomark, f4 - f3)) {
- syslog(L_ERROR, NORENUMBER, LogName, ngp->Name, "lo");
- return false;
- }
- ICDactivedirty++;
- }
- return true;
-}
-
-/*
- * Set the low article count for the given group.
- * Like NGrenumber(), but we don't scan the spool,
- * and the himark is ignored.
- */
-bool
-NGlowmark(NEWSGROUP *ngp, long lomark)
-{
- long l;
- char *f2, *f3, *f4;
- char *start;
-
- start = ICDreadactive(&f2) + ngp->Start;
- /* Check the file format. */
- if ((f2 = strchr(start, ' ')) == NULL
- || (f3 = strchr(++f2, ' ')) == NULL
- || (f4 = strchr(++f3, ' ')) == NULL) {
- syslog(L_ERROR, "%s bad_format active %s",
- LogName, MaxLength(start, start));
- return false;
- }
- l = atol(f3);
- if (lomark != l) {
- if (lomark < l)
- syslog(L_NOTICE, RENUMBER, LogName, ngp->Name, "lo", l, lomark);
- if (!FormatLong(f3, lomark, f4 - f3)) {
- syslog(L_ERROR, NORENUMBER, LogName, ngp->Name, "lo");
- return false;
- }
- ICDactivedirty++;
- }
- return true;
-}
+++ /dev/null
-/* $Id: perl.c 7815 2008-05-05 08:43:58Z iulius $
-**
-** Perl filtering support for innd.
-**
-** Originally written by Christophe Wolfhugel <wolf@pasteur.fr> (although
-** he wouldn't recognise it anymore so don't blame him) and modified,
-** expanded and tweaked since by James Brister, Jeremy Nixon, Ed Mooring,
-** Russell Vincent, and Russ Allbery.
-**
-** This file should contain all innd-specific Perl linkage. Linkage
-** applicable to both innd and nnrpd should go into lib/perl.c instead.
-**
-** We are assuming Perl 5.004 or later.
-**
-** Future work:
-**
-** - What we're doing with Path headers right now doesn't work for folded
-** headers. It's also kind of gross. There has to be a better way of
-** handling this.
-**
-** - The breakdown between this file, lib/perl.c, and nnrpd/perl.c should
-** be rethought, ideally in the light of supporting multiple filters in
-** different languages.
-**
-** - We're still calling strlen() on artBody, which should be avoidable
-** since we've already walked it several times. We should just cache
-** the length somewhere for speed.
-**
-** - Variable and key names should be standardized between this and nnrpd.
-**
-** - The XS code is still calling CC* functions. The common code between
-** the two control interfaces should be factored out into the rest of
-** innd instead.
-**
-** - There's a needless perl_get_cv() call for *every message ID* offered
-** to the server right now. We need to stash whether that filter is
-** active.
-*/
-
-#include "config.h"
-
-/* Skip this entire file if DO_PERL (./configure --with-perl) isn't set. */
-#if DO_PERL
-
-#include "clibrary.h"
-#include "innd.h"
-
-#include <EXTERN.h>
-#include <perl.h>
-#include <XSUB.h>
-#include "ppport.h"
-
-#include "innperl.h"
-
-/* From art.c. Ew. Need header parsing that doesn't use globals. */
-extern char *filterPath;
-
-/*
-** Run an incoming article through the Perl article filter. Returns NULL
-** accept the article or a rejection message to reject it.
-*/
-char *
-PLartfilter(const ARTDATA *data, char *artBody, long artLen, int lines)
-{
- dSP;
- const ARTHEADER * hp;
- const HDRCONTENT *hc = data->HdrContent;
- HV * hdr;
- CV * filter;
- int i, rc;
- char * p;
- static char buf[256];
-
- if (!PerlFilterActive) return NULL;
- filter = perl_get_cv("filter_art", 0);
- if (!filter) return NULL;
-
- /* Create %hdr and stash a copy of every known header. Path has to be
- handled separately since it's been munged by article processing. */
- hdr = perl_get_hv("hdr", 1);
- for (i = 0 ; i < MAX_ARTHEADER ; i++) {
- if (HDR_FOUND(i)) {
- hp = &ARTheaders[i];
- hv_store(hdr, (char *) hp->Name, hp->Size, newSVpv(HDR(i), 0), 0);
- }
- }
-
- /* Store the article body. We don't want to make another copy of it,
- * since it could potentially be quite large. In testing, this produced
- * a 17% speed improvement over making a copy of the article body
- * for a fairly heavy filter.
- * Available since Perl 5.7.1, newSVpvn_share allows to avoid such
- * a copy (getting round its use for older versions of Perl leads
- * to unreliable SV * bodies as for regexps). And for Perl not to
- * compute a hash for artBody, we give it "42". */
- if (artBody) {
-#if (PERL_REVISION == 5) && ((PERL_VERSION < 7) || ((PERL_VERSION == 7) && (PERL_SUBVERSION < 1)))
- hv_store(hdr, "__BODY__", 8, newSVpv(artBody, artLen), 0);
-#else
- hv_store(hdr, "__BODY__", 8, newSVpvn_share(artBody, artLen, 42), 0);
-#endif /* Perl < 5.7.1 */
- }
-
- hv_store(hdr, "__LINES__", 9, newSViv(lines), 0);
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- rc = perl_call_sv((SV *) filter, G_EVAL|G_SCALAR|G_NOARGS);
- SPAGAIN;
-
- hv_undef(hdr);
-
- /* Check $@, which will be set if the sub died. */
- buf[0] = '\0';
- if (SvTRUE(ERRSV)) {
- syslog(L_ERROR, "Perl function filter_art died on article %s: %s",
- HDR_FOUND(HDR__MESSAGE_ID) ? HDR(HDR__MESSAGE_ID) : "?",
- SvPV(ERRSV, PL_na));
- (void) POPs;
- PerlFilter(false);
- } else if (rc == 1) {
- p = POPp;
- if (p && *p)
- strlcpy(buf, p, sizeof(buf));
- }
-
- PUTBACK;
- FREETMPS;
- LEAVE;
- return (buf[0] != '\0') ? buf : NULL;
-}
-
-
-/*
-** Run an incoming message ID from CHECK or IHAVE through the Perl filter.
-** Returns NULL to accept the article or a rejection message to reject it.
-*/
-char *
-PLmidfilter(char *messageID)
-{
- dSP;
- CV *filter;
- int rc;
- char *p;
- static char buf[256];
-
- if (!PerlFilterActive) return NULL;
- filter = perl_get_cv("filter_messageid", 0);
- if (!filter) return NULL;
-
- /* Pass filter_messageid() the message ID on the Perl stack. */
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- XPUSHs(sv_2mortal(newSVpv(messageID, 0)));
- PUTBACK;
- rc = perl_call_sv((SV *) filter, G_EVAL|G_SCALAR);
- SPAGAIN;
-
- /* Check $@, which will be set if the sub died. */
- buf[0] = '\0';
- if (SvTRUE(ERRSV)) {
- syslog(L_ERROR, "Perl function filter_messageid died on id %s: %s",
- messageID, SvPV(ERRSV, PL_na));
- (void) POPs;
- PerlFilter(false);
- } else if (rc == 1) {
- p = POPp;
- if (p && *p)
- strlcpy(buf, p, sizeof(buf));
- }
-
- PUTBACK;
- FREETMPS;
- LEAVE;
- return (buf[0] != '\0') ? buf : NULL;
-}
-
-
-/*
-** Call a Perl sub on any change in INN's mode, passing in the old and new
-** mode and the reason.
-*/
-void
-PLmode(OPERATINGMODE Mode, OPERATINGMODE NewMode, char *reason)
-{
- dSP;
- HV *mode;
- CV *filter;
-
- filter = perl_get_cv("filter_mode", 0);
- if (!filter) return;
-
- /* Current mode goes into $mode{Mode}, new mode in $mode{NewMode}, and
- the reason in $mode{reason}. */
- mode = perl_get_hv("mode", 1);
-
- if (Mode == OMrunning)
- hv_store(mode, "Mode", 4, newSVpv("running", 0), 0);
- if (Mode == OMpaused)
- hv_store(mode, "Mode", 4, newSVpv("paused", 0), 0);
- if (Mode == OMthrottled)
- hv_store(mode, "Mode", 4, newSVpv("throttled", 0), 0);
-
- if (NewMode == OMrunning)
- hv_store(mode, "NewMode", 7, newSVpv("running", 0), 0);
- if (NewMode == OMpaused)
- hv_store(mode, "NewMode", 7, newSVpv("paused", 0), 0);
- if (NewMode == OMthrottled)
- hv_store(mode, "NewMode", 7, newSVpv("throttled", 0), 0);
-
- hv_store(mode, "reason", 6, newSVpv(reason, 0), 0);
-
- PUSHMARK(SP);
- perl_call_sv((SV *) filter, G_EVAL|G_DISCARD|G_NOARGS);
-
- /* Check $@, which will be set if the sub died. */
- if (SvTRUE(ERRSV)) {
- syslog(L_ERROR, "Perl function filter_mode died: %s",
- SvPV(ERRSV, PL_na));
- (void) POPs;
- PerlFilter(false);
- }
-}
-
-
-/*
-** Called by CCmode, this returns the Perl filter statistics if a Perl
-** function to generate such statistics has been defined, or NULL otherwise.
-** If a string is returned, it's in newly allocated memory that must be freed
-** by the caller.
-*/
-char *
-PLstats(void)
-{
- dSP;
- char *argv[] = { NULL };
-
- if (perl_get_cv("filter_stats", false) == NULL)
- return NULL;
- else {
- char *stats = NULL;
- char *result;
-
- ENTER;
- SAVETMPS;
- perl_call_argv("filter_stats", G_EVAL | G_NOARGS, argv);
- SPAGAIN;
- result = POPp;
- if (result != NULL && *result)
- stats = xstrdup(result);
- PUTBACK;
- FREETMPS;
- LEAVE;
-
- return stats;
- }
-}
-
-
-/*
-** The remainder of this file are XS callbacks visible to embedded Perl
-** code to perform various innd functions. They were originally written by
-** Ed Mooring (mooring@acm.org) on May 14, 1998, and have since been split
-** between this file and lib/perl.c (which has the ones that can also be
-** used in nnrpd). The function that registers them at startup is at the
-** end.
-*/
-
-/*
-** Add an entry to history. Takes message ID and optionally arrival,
-** article, and expire times and storage API token. If the times aren't
-** given, they default to now. If the token isn't given, that field will
-** be left empty. Returns boolean success.
-*/
-XS(XS_INN_addhist)
-{
- dXSARGS;
- int i;
- char tbuff[32];
- char* parambuf[6];
-
- if (items < 1 || items > 5)
- croak("Usage INN::addhist(msgid,[arrival,articletime,expire,token])");
-
- for (i = 0; i < items; i++)
- parambuf[i] = (char *) SvPV(ST(0), PL_na);
-
- /* If any of the times are missing, they should default to now. */
- if (i < 4) {
- snprintf(tbuff, sizeof(tbuff), "%ld", (long) time(NULL));
- for (; i < 4; i++)
- parambuf[i] = tbuff;
- }
-
- /* The token defaults to an empty string. */
- if (i == 4)
- parambuf[4] = "";
-
- parambuf[5] = NULL;
-
- /* CCaddhist returns NULL on success. */
- if (CCaddhist(parambuf))
- XSRETURN_NO;
- else
- XSRETURN_YES;
-}
-
-
-/*
-** Takes the message ID of an article and returns the full article as a
-** string or undef if the article wasn't found. It will be converted from
-** wire format to native format. Note that this call isn't particularly
-** optimized or cheap.
-*/
-XS(XS_INN_article)
-{
- dXSARGS;
- char * msgid;
- TOKEN token;
- ARTHANDLE * art;
- char * p;
- size_t len;
-
- if (items != 1)
- croak("Usage: INN::article(msgid)");
-
- /* Get the article token from the message ID and the history file. */
- msgid = (char *) SvPV(ST(0), PL_na);
- if (!HISlookup(History, msgid, NULL, NULL, NULL, &token)) XSRETURN_UNDEF;
-
- /* Retrieve the article and convert it from wire format. */
- art = SMretrieve(token, RETR_ALL);
- if (art == NULL) XSRETURN_UNDEF;
- p = FromWireFmt(art->data, art->len, &len);
- SMfreearticle(art);
-
- /* Push a copy of the article onto the Perl stack, free our temporary
- memory allocation, and return the article to Perl. */
- ST(0) = sv_2mortal(newSVpv(p, len));
- free(p);
- XSRETURN(1);
-}
-
-
-/*
-** Cancel a message by message ID; returns boolean success. Equivalent to
-** ctlinnd cancel <message>.
-*/
-XS(XS_INN_cancel)
-{
- dXSARGS;
- char *msgid;
- char *parambuf[2];
-
- if (items != 1)
- croak("Usage: INN::cancel(msgid)");
-
- msgid = (char *) SvPV(ST(0), PL_na);
- parambuf[0] = msgid;
- parambuf[1] = NULL;
-
- /* CCcancel returns NULL on success. */
- if (CCcancel(parambuf))
- XSRETURN_NO;
- else
- XSRETURN_YES;
-}
-
-
-/*
-** Return the files for a given message ID, taken from the history file.
-** This function should really be named INN::token() and probably will be
-** some day.
-*/
-XS(XS_INN_filesfor)
-{
- dXSARGS;
- char *msgid;
- TOKEN token;
-
- if (items != 1)
- croak("Usage: INN::filesfor(msgid)");
-
- msgid = (char *) SvPV(ST(0), PL_na);
- if (HISlookup(History, msgid, NULL, NULL, NULL, &token)) {
- XSRETURN_PV(TokenToText(token));
- } else {
- XSRETURN_UNDEF;
- }
-}
-
-
-/*
-** Whether message ID is in the history file; returns boolean.
-*/
-XS(XS_INN_havehist)
-{
- dXSARGS;
- char *msgid;
-
- if (items != 1)
- croak("Usage: INN::havehist(msgid)");
-
- msgid = (char *) SvPV(ST(0), PL_na);
- if (HIScheck(History, msgid))
- XSRETURN_YES;
- else
- XSRETURN_NO;
-}
-
-
-/*
-** Takes the message ID of an article and returns the article headers as
-** a string or undef if the article wasn't found. Each line of the header
-** will end with \n.
-*/
-XS(XS_INN_head)
-{
- dXSARGS;
- char * msgid;
- TOKEN token;
- ARTHANDLE * art;
- char * p;
- size_t len;
-
- if (items != 1)
- croak("Usage: INN::head(msgid)");
-
- /* Get the article token from the message ID and the history file. */
- msgid = (char *) SvPV(ST(0), PL_na);
- if (!HISlookup(History, msgid, NULL, NULL, NULL, &token)) XSRETURN_UNDEF;
-
- /* Retrieve the article header and convert it from wire format. */
- art = SMretrieve(token, RETR_HEAD);
- if (art == NULL) XSRETURN_UNDEF;
- p = FromWireFmt(art->data, art->len, &len);
- SMfreearticle(art);
-
- /* Push a copy of the article header onto the Perl stack, free our
- temporary memory allocation, and return the header to Perl. */
- ST(0) = sv_2mortal(newSVpv(p, len));
- free(p);
- XSRETURN(1);
-}
-
-
-/*
-** Returns the active file flag for a newsgroup or undef if it isn't in the
-** active file.
-*/
-XS(XS_INN_newsgroup)
-{
- dXSARGS;
- char * newsgroup;
- NEWSGROUP * ngp;
- char * end;
- int size;
-
- if (items != 1)
- croak("Usage: INN::newsgroup(group)");
- newsgroup = (char *) SvPV(ST(0), PL_na);
-
- ngp = NGfind(newsgroup);
- if (!ngp) {
- XSRETURN_UNDEF;
- } else {
- /* ngp->Rest is newline-terminated; find the end. */
- end = strchr(ngp->Rest, '\n');
- if (end == NULL) {
- size = strlen(ngp->Rest);
- } else {
- size = end - ngp->Rest;
- }
- ST(0) = sv_2mortal(newSVpv(ngp->Rest, size));
- XSRETURN(1);
- }
-}
-
-
-/*
-** Initialize the XS callbacks defined in this file.
-*/
-void
-PLxsinit(void)
-{
- newXS("INN::addhist", XS_INN_addhist, "perl.c");
- newXS("INN::article", XS_INN_article, "perl.c");
- newXS("INN::cancel", XS_INN_cancel, "perl.c");
- newXS("INN::havehist", XS_INN_havehist, "perl.c");
- newXS("INN::head", XS_INN_head, "perl.c");
- newXS("INN::newsgroup", XS_INN_newsgroup, "perl.c");
- newXS("INN::filesfor", XS_INN_filesfor, "perl.c");
-}
-
-#endif /* defined(DO_PERL) */
+++ /dev/null
-/* $Id: proc.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Process control routines.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-
-#include "innd.h"
-
-
-static PROCESS *PROCtable;
-static int PROCtablesize;
-static PROCESS PROCnull = { PSfree, 0, 0, 0, 0, 0 };
-
-
-/*
-** Collect dead processes.
-*/
-static void
-PROCreap(void)
-{
- int status;
- PROCESS *pp;
- int i;
- pid_t pid;
-
- for ( ; ; ) {
- pid = waitpid(-1, &status, WNOHANG);
- if (pid == 0)
- break;
- if (pid < 0) {
- if (errno != ECHILD)
- syslog(L_ERROR, "%s cant wait %m", LogName);
- break;
- }
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++)
- if (pp->Pid == pid) {
- PROCneedscan = true;
- pp->Status = WEXITSTATUS(status);
- pp->State = PSdead;
- pp->Collected = Now.time;
- break;
- }
- }
-}
-
-
-/*
-** Signal handler that collects the processes, then resets the signal.
-*/
-static RETSIGTYPE
-PROCcatchsignal(int s)
-{
- PROCreap();
-
-#ifndef HAVE_SIGACTION
- xsignal(s, PROCcatchsignal);
-#else
- s = s; /* ARGSUSED */
-#endif
-}
-
-
-/*
-** Synchronous version that notifies a site when its process went away.
-*/
-void
-PROCscan(void)
-{
- PROCESS *pp;
- int i;
-
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++)
- if (pp->State == PSdead) {
- if (pp->Site >= 0)
- SITEprocdied(&Sites[pp->Site], pp - PROCtable, pp);
- pp->State = PSfree;
- }
- PROCneedscan = false;
-}
-
-
-#if 0
-/*
-** Close down all processes.
-*/
-void
-PROCclose(Quickly)
- bool Quickly;
-{
- int sig;
- PROCESS *pp;
- int i;
-
- /* What signal are we sending? */
- sig = Quickly ? SIGKILL : SIGTERM;
-
- /* Send the signal to all living processes. */
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++) {
- if (pp->State != PSrunning)
- continue;
- if (kill(pp->Pid, sig) < 0 && errno != ESRCH)
- syslog(L_ERROR, "%s cant kill %s %ld %m",
- LogName, Quickly ? "KILL" : "TERM", (long) pp->Pid);
- }
-
- /* Collect any who might have died. */
- PROCreap();
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++)
- if (pp->State == PSdead)
- *pp = PROCnull;
-}
-#endif /* 0 */
-
-
-/*
-** Stop watching a process -- we don't care about it any more.
-*/
-void
-PROCunwatch(int process)
-{
- if (process < 0 || process >= PROCtablesize) {
- syslog(L_ERROR, "%s internal PROCunwatch %d", LogName, process);
- return;
- }
- PROCtable[process].Site = -1;
-}
-
-
-/*
-** Add a pid to the list of processes we watch.
-*/
-int
-PROCwatch(pid_t pid, int site)
-{
- PROCESS *pp;
- int i;
-
- /* Find a free slot for this process. */
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++)
- if (pp->State == PSfree)
- break;
- if (i < 0) {
- /* Ran out of room -- grow the table. */
- PROCtable = xrealloc(PROCtable, (PROCtablesize + 20) * sizeof(PROCESS));
- for (pp = &PROCtable[PROCtablesize], i=20; --i >= 0; pp++)
- *pp = PROCnull;
- pp = &PROCtable[PROCtablesize];
- PROCtablesize += 20;
- }
-
- pp->State = PSrunning;
- pp->Pid = pid;
- pp->Started = Now.time;
- pp->Site = site;
- return pp - PROCtable;
-}
-
-
-/*
-** Setup.
-*/
-void
-PROCsetup(int i)
-{
- PROCESS *pp;
-
- if (PROCtable)
- free(PROCtable);
- PROCtablesize = i;
- PROCtable = xmalloc(PROCtablesize * sizeof(PROCESS));
- for (pp = PROCtable, i = PROCtablesize; --i >= 0; pp++)
- *pp = PROCnull;
-
-#if defined(SIGCHLD)
- xsignal(SIGCHLD, PROCcatchsignal);
-#endif /* defined(SIGCHLD) */
- xsignal(SIGPIPE, PROCcatchsignal);
-}
+++ /dev/null
-/* $Id: python.c 7891 2008-06-22 09:59:11Z iulius $
-**
-** python.c: Embed Python in the style of innd's TCL and Perl stuff.
-**
-** Written by G.J. Andruk <meowing@banet.net> patterned after
-** TCL/Perl work by Bob Heiney and Christophe Wolfhugel and a whole
-** bunch of other people mentioned in the docs and sources for the
-** other filters.
-**
-** The astute reader may notice the commission of blatant atrocities
-** against Python's OO model here. Don't tell Guido.
-**
-** A quick note regarding Python exceptions: functions like
-** PyObject_GetAttrString(PyObject *o, const char *attr_name)
-** raise an exception when they fail, even though they return NULL.
-** And as exceptions accumulate from caller to caller and so on,
-** it generates weird issues with Python scripts afterwards. So such
-** uses should be checked before. For instance with:
-** PyObject_HasAttrString(PyObject *o, const char *attr_name).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-
-#if defined(DO_PYTHON)
-
-#include "Python.h"
-
-
-bool PythonFilterActive;
-char *filterPath; /* this gets set in art.c */
-PyObject *PYFilterObject = NULL;
-PyObject *PYFilterModule = NULL;
-
-/* article filter bits and pieces */
-PyObject *PYheaders = NULL;
-PyObject **PYheaditem;
-PyObject **PYheadkey;
-PyObject *PYpathkey, *PYlineskey, *PYbodykey;
-
-/* external functions */
-PyObject *msgid_method = NULL;
-PyObject *art_method = NULL;
-PyObject *mode_method = NULL;
-PyObject *pre_reload_method = NULL;
-PyObject *close_method = NULL;
-
-
-
-/*
-** Turn filtering on or off.
-*/
-void
-PYfilter(value)
- bool value;
-{
- PythonFilterActive = value;
- syslog(L_NOTICE, "%s Python filtering %s", LogName,
- PythonFilterActive ? "enabled" : "disabled");
-}
-
-
-
-/*
-** Front end for PYfilter()
-*/
-const char *
-PYcontrol(char **av)
-{
- char *p;
- extern bool PythonFilterActive;
-
- switch (av[0][0]) {
- default:
- return "1 Bad flag";
- case 'y':
- if (PythonFilterActive)
- return "1 Python filter already enabled";
- else if (PYFilterObject == NULL)
- return "1 Python filter not defined" ;
- PYfilter(true);
- break;
- case 'n':
- if (!PythonFilterActive)
- return "1 Python filter already disabled";
- PYfilter(false);
- break;
- }
- return NULL;
-}
-
-
-
-
-/*
-** Reject articles we don't like.
-*/
-char *
-PYartfilter(const ARTDATA *data, char *artBody, long artLen, int lines)
-{
- const ARTHEADER *hp;
- const HDRCONTENT *hc = data->HdrContent;
- int hdrnum;
- int i;
- char *p, save;
- static char buf[256];
- PyObject *result;
-
- if (!PythonFilterActive || PYFilterObject == NULL || art_method == NULL)
- return NULL;
-
- /* Add headers to the dictionary... */
- hdrnum = 0;
- for (i = 0 ; i < MAX_ARTHEADER ; i++) {
- if (HDR_FOUND(i)) {
- hp = &ARTheaders[i];
- PYheaditem[hdrnum] = PyBuffer_FromMemory(HDR(i), HDR_LEN(i));
- } else
- PYheaditem[hdrnum] = Py_None;
- PyDict_SetItem(PYheaders, PYheadkey[hdrnum], PYheaditem[hdrnum]);
- hdrnum++;
- }
-
- /* ...then the body... */
- if (artLen && artBody != NULL)
- PYheaditem[hdrnum] = PyBuffer_FromMemory(artBody, --artLen);
- else
- PYheaditem[hdrnum] = Py_None;
- PyDict_SetItem(PYheaders, PYbodykey, PYheaditem[hdrnum++]);
-
- /* ...and finally, the line count. */
- PYheaditem[hdrnum] = PyInt_FromLong((long) lines);
- PyDict_SetItem(PYheaders, PYlineskey, PYheaditem[hdrnum++]);
-
- /* Now see if the filter likes it. */
- result = PyObject_CallFunction(art_method, "O", PYheaders);
- if ((result != NULL) && PyObject_IsTrue(result))
- strlcpy(buf, PyString_AS_STRING(result), sizeof(buf));
- else
- *buf = '\0';
- Py_XDECREF(result);
-
- /* Clean up after ourselves */
- PyDict_Clear(PYheaders);
- for (i = 0; i < hdrnum; i++)
- if (PYheaditem[i] != Py_None)
- Py_DECREF(PYheaditem[i]);
-
- if (*buf != '\0')
- return buf;
- return NULL;
-}
-
-
-
-/*
-** Refuse message IDs offered thru CHECK or IHAVE that we don't like.
-*/
-char *
-PYmidfilter(messageID, msglen)
- char *messageID;
- int msglen;
-{
- static char buf[256];
- PyObject *result;
-
- if (!PythonFilterActive || PYFilterObject == NULL || msgid_method == NULL)
- return NULL;
-
- result = PyObject_CallFunction(msgid_method, "s#", messageID, msglen);
- if ((result != NULL) && PyObject_IsTrue(result))
- strlcpy(buf, PyString_AS_STRING(result), sizeof(buf));
- else
- *buf = '\0';
- Py_XDECREF(result);
-
- if (*buf != '\0')
- return buf;
- return NULL;
-}
-
-
-
-/*
-** Tell the external module about innd's state.
-*/
-void
-PYmode(Mode, NewMode, reason)
- OPERATINGMODE Mode, NewMode;
- char *reason;
-{
- PyObject *result;
- char oldmode[10], newmode[10];
-
- if (!PythonFilterActive || PYFilterObject == NULL || mode_method == NULL)
- return;
-
- switch (Mode) {
- default: strlcpy(oldmode, "unknown", 10); break;
- case OMrunning: strlcpy(oldmode, "running", 10); break;
- case OMpaused: strlcpy(oldmode, "paused", 10); break;
- case OMthrottled: strlcpy(oldmode, "throttled", 10); break;
- }
-
- switch (NewMode) {
- default: strlcpy(newmode, "unknown", 10); break;
- case OMrunning: strlcpy(newmode, "running", 10); break;
- case OMpaused: strlcpy(newmode, "paused", 10); break;
- case OMthrottled: strlcpy(newmode, "throttled", 10); break;
- }
-
- result = PyObject_CallFunction(mode_method, "sss",
- oldmode, newmode, reason);
- Py_XDECREF(result);
-}
-
-
-
-/*
-** Called by the external module so it can register itself with innd.
-*/
-static PyObject *
-PY_set_filter_hook(dummy, args)
- PyObject *dummy, *args;
-{
- PyObject *result = NULL;
- PyObject *temp;
-
- if (PyArg_ParseTuple(args, "O:set_filter_hook", &temp)) {
- Py_XINCREF(temp);
- Py_XDECREF(PYFilterObject);
- PYFilterObject = temp;
- Py_INCREF(Py_None);
- result = Py_None;
- }
- return result;
-}
-
-
-
-/*
-** Allow external module to ask innd if an ID is in history.
-*/
-static PyObject *
-PY_havehist(self, args)
- PyObject *self, *args;
-{
- char *msgid;
- int msgidlen;
-
- if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen))
- return NULL;
-
- if (HIScheck(History, msgid))
- return PyInt_FromLong(1);
- return PyInt_FromLong(0);
-}
-
-
-
-/*
-** Allow external module to locally delete an article.
-*/
-static PyObject *
-PY_cancel(self, args)
- PyObject *self, *args;
-{
- char *msgid;
- int msgidlen;
- char *parambuf[2];
-
- if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen))
- return NULL;
-
- parambuf[0]= msgid;
- parambuf[1]= 0;
-
- if (!CCcancel(parambuf))
- return PyInt_FromLong(1);
- return PyInt_FromLong(0);
-}
-
-
-
-/*
-** Stuff an ID into history so that it will be refused later.
-*/
-static PyObject *
-PY_addhist(self, args)
- PyObject *self, *args;
-{
- char *msgid;
- int msgidlen;
- char *articlepaths = "";
- char tbuff[12];
- char *parambuf[6];
-
- if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen))
- return NULL;
-
- snprintf(tbuff, sizeof(tbuff), "%d", time(NULL));
-
- parambuf[0] = msgid;
- parambuf[1] = parambuf[2] = parambuf[3] = tbuff;
- parambuf[4] = articlepaths;
- parambuf[5] = 0;
-
- if (!CCaddhist(parambuf))
- return PyInt_FromLong(1);
- return PyInt_FromLong(0);
-}
-
-
-
-/*
-** Get a newsgroup's status flag (j, m, n, x, y, =other.group)
-*/
-static PyObject *
-PY_newsgroup(self, args)
- PyObject *self, *args;
-{
- char *newsgroup;
- int nglen;
- NEWSGROUP *ngp;
- char *end;
- char *rest;
- int size;
-
- if (!PyArg_ParseTuple(args, "s#", &newsgroup, &nglen))
- return NULL;
-
- ngp = NGfind(newsgroup);
- if (ngp == NULL)
- return PyString_FromStringAndSize(NULL, 0);
-
- /* ngp->Rest is newline-terminated; find the end. */
- end = strchr(ngp->Rest, '\n');
- if (end == NULL)
- size = strlen(ngp->Rest);
- else
- size = end - ngp->Rest;
-
- /* If an alias is longer than this, active is probably broken. */
- if (size > MAXHEADERSIZE) {
- syslog(L_ERROR, "too-long flag field in active for %s", newsgroup);
- size = MAXHEADERSIZE;
- }
-
- return PyString_FromStringAndSize(ngp->Rest, size);
-}
-
-
-
-/*
-** Return an article header to the external module as a string. We
-** don't use a buffer object here because that would make it harder,
-** for example, to compare two on-spool articles.
-*/
-static PyObject *
-PY_head(self, args)
- PyObject *self, *args;
-{
- char *msgid;
- int msgidlen;
- char *p;
- TOKEN token;
- ARTHANDLE *art;
- PyObject *header;
- int headerlen;
-
- if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen))
- return NULL;
-
- if (! HISlookup(History, msgid, NULL, NULL, NULL, &token))
- return Py_BuildValue("s", "");
- if ((art = SMretrieve(token, RETR_HEAD)) == NULL)
- return Py_BuildValue("s", "");
- p = FromWireFmt(art->data, art->len, &headerlen);
- SMfreearticle(art);
- header = PyString_FromStringAndSize(p, headerlen);
- free(p);
-
- return header;
-}
-
-
-
-/*
-** Return a whole article to the external module as a string.
-*/
-static PyObject *
-PY_article(self, args)
- PyObject *self, *args;
-{
- char *msgid;
- int msgidlen;
- char *p;
- TOKEN token;
- ARTHANDLE *arth;
- PyObject *art;
- int artlen;
-
- if (!PyArg_ParseTuple(args, "s#", &msgid, &msgidlen))
- return NULL;
-
- if (! HISlookup(History, msgid, NULL, NULL, NULL, &token))
- return Py_BuildValue("s", "");
- if ((arth = SMretrieve(token, RETR_ALL)) == NULL)
- return Py_BuildValue("s", "");
- p = FromWireFmt(arth->data, arth->len, &artlen);
- SMfreearticle(arth);
- art = PyString_FromStringAndSize(p, artlen);
- free(p);
-
- return art;
-}
-
-
-
-/*
-** Python's syslog module isn't compiled in by default. It's easier
-** to do it this way, and the switch block looks pretty in a color
-** editor).
-*/
-static PyObject *
-PY_syslog(self, args)
- PyObject *self, *args;
-{
- char *loglevel;
- int levellen;
- char *logmsg;
- int msglen;
- int priority;
-
- if (!PyArg_ParseTuple(args, "s#s#",
- &loglevel, &levellen, &logmsg, &msglen))
- return NULL;
-
- switch (*loglevel) {
- default: priority = LOG_NOTICE ;
- case 'd': case 'D': priority = LOG_DEBUG ; break;
- case 'i': case 'I': priority = LOG_INFO ; break;
- case 'n': case 'N': priority = LOG_NOTICE ; break;
- case 'w': case 'W': priority = LOG_WARNING ; break;
- case 'e': case 'E': priority = LOG_ERR ; break;
- case 'c': case 'C': priority = LOG_CRIT ; break;
- case 'a': case 'A': priority = LOG_ALERT ; break;
- }
-
- syslog(priority, "python: %s", logmsg);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-
-
-/*
-** Compute a hash digest for a string.
-*/
-static PyObject *
-PY_hashstring(self, args)
- PyObject *self, *args;
-{
- char *instring, *wpos, *p, *q;
- char *workstring = NULL;
- int insize, worksize, newsize, i, wasspace;
- int lines = 0;
- HASH myhash;
-
- if (!PyArg_ParseTuple(args, "s#|i", &instring, &insize, &lines))
- return NULL;
-
- /* If a linecount is provided, munge before hashing. */
- if (lines > 0) {
- worksize = insize;
-
- /* chop leading whitespace */
- for (p=instring ; worksize>0 && isspace(*p) ; p++) {
- if (*p == '\n')
- lines--;
- worksize--;
- }
- wpos = p;
-
- /* and trailing */
- for (p=&wpos[worksize] ; worksize>0 && isspace(*p) ; p--) {
- if (*p == '\n')
- lines--;
- worksize--;
- }
-
- /* chop last 3 lines if we have >= 5. From above chop the
- * last line has no CR so we use 1 less here. */
- if (lines >= 4) {
- for (i=0, p=wpos+worksize ; i<2 ; p--)
- if (*p == '\n')
- i++;
- worksize = p - wpos;
- }
-
- /* Compress out multiple whitespace in the trimmed string. We
- * do a copy because this is probably an original art
- * buffer. */
- workstring = memcpy(xmalloc(worksize), wpos, worksize);
- newsize = wasspace = 0;
- p = wpos;
- q = workstring;
- for (i=0 ; i<worksize ; i++) {
- if (isspace(*p)) {
- if (!wasspace)
- *q++ = ' ';
- wasspace = 1;
- }
- else {
- *q++ = tolower(*p);
- wasspace = 0;
- }
- p++;
- }
- worksize = q - workstring;
- myhash = Hash(workstring, worksize);
- free(workstring);
- }
- else
- myhash = Hash(instring, insize);
-
- return PyString_FromStringAndSize((const char *)&myhash, sizeof(myhash));
-}
-
-
-
-/*
-** Make the internal INN module's functions visible to Python.
-*/
-static PyMethodDef INNPyMethods[] = {
- {"set_filter_hook", PY_set_filter_hook, METH_VARARGS},
- {"havehist", PY_havehist, METH_VARARGS},
- {"addhist", PY_addhist, METH_VARARGS},
- {"cancel", PY_cancel, METH_VARARGS},
- {"newsgroup", PY_newsgroup, METH_VARARGS},
- {"head", PY_head, METH_VARARGS},
- {"article", PY_article, METH_VARARGS},
- {"syslog", PY_syslog, METH_VARARGS},
- {"hashstring", PY_hashstring, METH_VARARGS},
- {NULL, NULL}
-};
-
-
-
-/*
-** This runs when innd shuts down.
-*/
-void
-PYclose(void)
-{
- PyObject *result;
-
- if (close_method != NULL) {
- result = PyObject_CallFunction(close_method, NULL);
- Py_XDECREF(result);
- }
-}
-
-
-
-/*
-** Check that a method exists and is callable. Set a pointer to
-** the corresponding PyObject, or NULL if not found.
-*/
-void
-PYdefonemethod(methptr, methname)
- PyObject **methptr;
- char *methname;
-{
- Py_XDECREF(*methptr);
-
- /* We check with HasAttrString() the existence of the method because
- * otherwise, in case it does not exist, an exception is raised by Python,
- * although the result of the function is NULL. */
- if (PyObject_HasAttrString(PYFilterObject, (char *) methname) == 1) {
- /* Get a pointer to given method. */
- *methptr = PyObject_GetAttrString(PYFilterObject, (char *) methname);
- } else {
- *methptr = NULL;
- }
-
- if (*methptr == NULL)
- syslog(L_NOTICE, "python method %s not found", methname);
- else if (PyCallable_Check(*methptr) == 0) {
- syslog(L_ERROR, "python object %s found but not a function", methname);
- Py_DECREF(*methptr);
- *methptr = NULL;
- }
-}
-
-
-
-/*
-** Look up the filter methods, so we will know what's available when
-** innd wants to call them.
-*/
-void
-PYdefmethods(void)
-{
- PYdefonemethod(&msgid_method, "filter_messageid");
- PYdefonemethod(&art_method, "filter_art");
- PYdefonemethod(&mode_method, "filter_mode");
- PYdefonemethod(&pre_reload_method, "filter_before_reload");
- PYdefonemethod(&close_method, "filter_close");
-}
-
-
-
-/*
-** Used by "ctlinnd reload filter.python 'reason'".
-*/
-int
-PYreadfilter(void)
-{
- PyObject *newmodule = NULL;
- PyObject *result;
-
- if (!Py_IsInitialized()) {
- syslog(L_ERROR, "python is not initialized");
- return 0;
- }
-
- /* If there is a filter running, let it clean up first. */
- if (pre_reload_method != NULL) {
- result = PyObject_CallFunction(pre_reload_method, NULL);
- Py_XDECREF(result);
- }
-
- /* We need to reimport the module before reloading it because otherwise,
- * it might not be taken into account by Python.
- * See Python API documentation:
- * If a module is syntactically correct but its initialization fails,
- * the first import statement for it does not bind its name locally,
- * but does store a (partially initialized) module object in
- * sys.modules. To reload the module, you must first import it again
- * (this will bind the name to the partially initialized module object)
- * before you can reload() it.
- */
- PYFilterModule = PyImport_ImportModule((char *) _PATH_PYTHON_STARTUP_M);
- if (PYFilterModule == NULL) {
- syslog(L_ERROR, "failed to reimport external python module");
- }
-
- if ((newmodule = PyImport_ReloadModule(PYFilterModule)) == NULL) {
- syslog(L_ERROR, "cant reload python filter module");
- PYfilter(false);
- return 0;
- }
-
- Py_XDECREF(PYFilterModule);
- PYFilterModule = newmodule;
-
- if (PYFilterObject == NULL) {
- syslog(L_ERROR, "python reload error, filter object not defined");
- PYfilter(false);
- return 0;
- }
-
- PYfilter(true);
- PYdefmethods();
-
- return 1;
-}
-
-
-
-/*
-** Called when innd first starts -- this gets the filters hooked in.
-*/
-void
-PYsetup(void)
-{
- const ARTHEADER *hp;
- int hdrindex;
- size_t hdrcount;
-
- setenv("PYTHONPATH", innconf->pathfilter, 1);
- Py_Initialize();
-
- /* It makes Python sad when its stdout and stderr are closed. */
- if ((fileno(stdout) == -1) || (fileno(stderr) == -1))
- PyRun_SimpleString
- ("import sys; sys.stdout=sys.stderr=open('/dev/null', 'a')");
-
- if (!Py_IsInitialized ()) {
- syslog(L_ERROR, "python interpreter NOT initialized");
- return;
- }
- syslog(L_NOTICE, "python interpreter initialized OK");
-
- Py_InitModule("INN", INNPyMethods);
-
- PYFilterModule = PyImport_ImportModule(_PATH_PYTHON_STARTUP_M);
- if (PYFilterModule == NULL)
- syslog(L_ERROR, "failed to import external python module");
-
- if (PYFilterObject == NULL) {
- syslog(L_ERROR, "python filter object is not defined");
- PYfilter(false);
- } else {
- PYfilter(true);
- PYdefmethods();
- syslog(L_NOTICE, "defined python methods");
- }
-
- /* Grab space for these so we aren't forever recreating them. We also
- put the body and the line count into PYheaditem, so it needs to be
- two elements longer than the total number of headers. */
- PYheaders = PyDict_New();
- hdrcount = ARRAY_END(ARTheaders) - ARTheaders;
- PYheaditem = xmalloc((hdrcount + 2) * sizeof(PyObject *));
- PYheadkey = xmalloc(hdrcount * sizeof(PyObject *));
-
- /* Preallocate keys for the article dictionary */
- for (hp = ARTheaders; hp < ARRAY_END(ARTheaders); hp++)
- PYheadkey[hp - ARTheaders] = PyString_InternFromString(hp->Name);
- PYpathkey = PyString_InternFromString("Path");
- PYlineskey = PyString_InternFromString("__LINES__");
- PYbodykey = PyString_InternFromString("__BODY__");
-}
-
-#endif /* defined(DO_PYTHON) */
+++ /dev/null
-/* $Id: rc.c 7751 2008-04-06 14:35:40Z iulius $
-**
-** Routines for the remote connect channel. Create an Internet stream
-** socket that processes connect to. If the incoming site is not one of
-** our feeds, then we optionally pass the connection off to the standard
-** NNTP daemon.
-*/
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <errno.h>
-#include <netdb.h>
-
-#include "inn/innconf.h"
-#include "inn/vector.h"
-#include "innd.h"
-
-#define TEST_CONFIG(a, b) \
- { \
- b = ((peer_params.Keysetbit & (1 << a)) != 0) ? true : false; \
- }
-
-#define SET_CONFIG(a) \
- { \
- peer_params.Keysetbit |= (1 << a); \
- }
-
-/*
-** A remote host has an address and a password.
-*/
-typedef struct _REMOTEHOST {
- char *Label; /* Peer label */
- char *Name; /* Hostname */
- struct sockaddr_storage Address; /* List of ip adresses */
- char *Password; /* Optional password */
- char *Identd; /* Optional identd */
- bool Streaming; /* Streaming allowed ? */
- bool Skip; /* Skip this peer ? */
- bool NoResendId; /* Don't send RESEND responses ? */
- bool Nolist; /* no list command allowed */
- int MaxCnx; /* Max connections (per peer) */
- char **Patterns; /* List of groups allowed */
- char *Pattern; /* List of groups allowed (string) */
- char *Email; /* Email(s) of contact */
- char *Comment; /* Commentary [max size = MAXBUFF] */
- int HoldTime; /* Hold time before disconnect over MaxCnx */
- int Keysetbit; /* Bit to check duplicated key */
-} REMOTEHOST;
-
-typedef struct _REMOTEHOST_DATA {
- int key; /* Key (as defined in the _Keywords enum) */
- int type; /* Type of the value (see _Type enum) */
- char *value; /* Value */
-} REMOTEHOST_DATA;
-
-typedef struct _REMOTETABLE {
- struct sockaddr_storage Address;
- time_t Expires;
-} REMOTETABLE;
-
-static char *RCslaveflag;
-static char *RCnnrpd = NULL;
-static char *RCnntpd = NULL;
-static CHANNEL **RCchan;
-static int chanlimit;
-static REMOTEHOST_DATA *RCpeerlistfile;
-static REMOTEHOST *RCpeerlist;
-static int RCnpeerlist;
-static char RCbuff[BIG_BUFFER];
-
-#define PEER "peer"
-#define GROUP "group"
-#define HOSTNAME "hostname:"
-#define STREAMING "streaming:"
-#define MAX_CONN "max-connections:"
-#define PASSWORD "password:"
-#define IDENTD "identd:"
-#define PATTERNS "patterns:"
-#define EMAIL "email:"
-#define COMMENT "comment:"
-#define SKIP "skip:"
-#define NORESENDID "noresendid:"
-#define HOLD_TIME "hold-time:"
-#define NOLIST "nolist:"
-
-typedef enum {K_END, K_BEGIN_PEER, K_BEGIN_GROUP, K_END_PEER, K_END_GROUP,
- K_STREAM, K_HOSTNAME, K_MAX_CONN, K_PASSWORD, K_IDENTD,
- K_EMAIL, K_PATTERNS, K_COMMENT, K_SKIP, K_NORESENDID,
- K_HOLD_TIME, K_NOLIST
- } _Keywords;
-
-typedef enum {T_STRING, T_BOOLEAN, T_INTEGER} _Types;
-
-#define GROUP_NAME "%s can't get group name in %s line %d"
-#define PEER_IN_PEER "%s peer can't contain peer in %s line %d"
-#define PEER_NAME "%s can't get peer name in %s line %d"
-#define LEFT_BRACE "%s '{' expected in %s line %d"
-#define RIGHT_BRACE "%s '}' unexpected line %d in %s"
-#define INCOMPLETE_PEER "%s incomplete peer (%s) in %s line %d"
-#define INCOMPLETE_GROUP "%s incomplete group (%s) in %s line %d"
-#define MUST_BE_BOOL "%s Must be 'true' or 'false' in %s line %d"
-#define MUST_BE_INT "%s Must be an integer value in %s line %d"
-#define HOST_NEEDED "%s 'hostname' needed in %s line %d"
-#define DUPLICATE_KEY "%s duplicate key in %s line %d"
-
-/*
-** Stuff needed for limiting incoming connects.
-*/
-static char RCterm[] = "\r\n";
-static REMOTETABLE remotetable[REMOTETABLESIZE];
-static int remotecount;
-static int remotefirst;
-
-/*
- * Check that the client has the right identd. Return true if is the
- * case, false, if not.
- */
-static bool
-GoodIdent(int fd, char *identd)
-{
-#define PORT_IDENTD 113
- char IDENTuser[80];
- struct sockaddr_storage ss_local;
- struct sockaddr_storage ss_distant;
- struct sockaddr *s_local = (struct sockaddr *)&ss_local;
- struct sockaddr *s_distant = (struct sockaddr *)&ss_distant;
- int ident_fd;
- socklen_t len;
- int port1,port2;
- ssize_t lu;
- char buf[80], *buf2;
-
- if(identd[0] == '\0') {
- return true;
- }
-
- len = sizeof( ss_local );
- if ((getsockname(fd,s_local,&len)) < 0) {
- syslog(L_ERROR, "can't do getsockname for identd");
- return false;
- }
- len = sizeof( ss_distant );
- if ((getpeername(fd,s_distant,&len)) < 0) {
- syslog(L_ERROR, "can't do getsockname for identd");
- return false;
- }
-#ifdef HAVE_INET6
- if( s_local->sa_family == AF_INET6 )
- {
- struct sockaddr_in6 *s_l6 = (struct sockaddr_in6 *)s_local;
- struct sockaddr_in6 *s_d6 = (struct sockaddr_in6 *)s_distant;
-
- port1=ntohs(s_l6->sin6_port);
- port2=ntohs(s_d6->sin6_port);
- s_l6->sin6_port = 0;
- s_d6->sin6_port = htons( PORT_IDENTD );
- ident_fd=socket(PF_INET6, SOCK_STREAM, 0);
- } else
-#endif
- if( s_local->sa_family == AF_INET )
- {
- struct sockaddr_in *s_l = (struct sockaddr_in *)s_local;
- struct sockaddr_in *s_d = (struct sockaddr_in *)s_distant;
-
- port1=ntohs(s_l->sin_port);
- port2=ntohs(s_d->sin_port);
- s_l->sin_port = 0;
- s_d->sin_port = htons( PORT_IDENTD );
- ident_fd=socket(PF_INET, SOCK_STREAM, 0);
- } else
- {
- syslog(L_ERROR, "Bad address family: %d\n", s_local->sa_family );
- return false;
- }
- if (ident_fd < 0) {
- syslog(L_ERROR, "can't open socket for identd (%m)");
- return false;
- }
- if (bind(ident_fd,s_local,SA_LEN(s_local)) < 0) {
- syslog(L_ERROR, "can't bind socket for identd (%m)");
- close(ident_fd);
- return false;
- }
- if (connect(ident_fd,s_distant,SA_LEN(s_distant)) < 0) {
- syslog(L_ERROR, "can't connect to identd (%m)");
- close(ident_fd);
- return false;
- }
-
- snprintf(buf,sizeof(buf),"%d,%d\r\n",port2, port1);
- write(ident_fd,buf, strlen(buf));
- memset( buf, 0, 80 );
- lu=read(ident_fd, buf, 79); /* pas encore parfait ("not yet perfect"?) */
- if (lu<0)
- {
- syslog(L_ERROR, "error reading from ident server: %m" );
- close( ident_fd );
- return false;
- }
- buf[lu]='\0';
- if ((lu>0) && (strstr(buf,"ERROR")==NULL)
- && ((buf2=strrchr(buf,':'))!=NULL))
- {
- buf2++;
- while(*buf2 == ' ') buf2++;
- strlcpy(IDENTuser, buf2, sizeof(IDENTuser));
- buf2=strchr(IDENTuser,'\r');
- if (!buf2) buf2=strchr(IDENTuser,'\n');
- if (buf2) *buf2='\0';
- } else
- strlcpy(IDENTuser, "UNKNOWN", sizeof(IDENTuser));
- close(ident_fd);
-
- return strcmp(identd, IDENTuser) == 0;
-}
-
-/*
- * Split text into comma-separated fields. Return an allocated
- * NULL-terminated array of the fields within the modified argument that
- * the caller is expected to save or free. We don't use strchr() since
- * the text is expected to be either relatively short or "comma-dense."
- * (This function is different from CommaSplit because spaces are allowed
- * and removed here)
- */
-
-static char **
-RCCommaSplit(char *text)
-{
- int i;
- char *p;
- char *q;
- char *r;
- char **av;
- char **save;
-
- /* How much space do we need? */
- for (i = 2, p = text, q = r = xstrdup(text); *p; p++) {
- if (*p != ' ' && *p != '\t' && *p != '\n')
- *q++ = *p;
- if (*p == ',')
- i++;
- }
- *q = '\0';
- free (text);
- for (text = r, av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
- if (*p == ',') {
- *p++ = '\0';
- *av++ = p;
- }
- else
- p++;
- *av = NULL;
- return save;
-}
-
- /*
- * Routine to disable IP-level socket options. This code was taken from 4.4BSD
- * rlogind source, but all mistakes in it are my fault.
- *
- * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
- *
- * 21-Jan-1997 smd
- * Code copied again, and modified for INN, all new mistakes are mine.
- *
- */
-
-/* fix_options - get rid of IP-level socket options */
-#ifndef IP_OPTIONS
-#define IP_OPTIONS 1
-#endif
-
-static int
-RCfix_options(int fd, struct sockaddr_storage *remote)
-{
-#if IP_OPTIONS
- unsigned char optbuf[BUFSIZ / 3], *cp;
- char lbuf[BUFSIZ], *lp;
- socklen_t optsize = sizeof(optbuf);
- int ipproto;
- struct protoent *ip;
-
- switch (remote->ss_family) {
- case AF_INET:
- if ((ip = getprotobyname("ip")) != 0)
- ipproto = ip->p_proto;
- else
- ipproto = IPPROTO_IP;
- break;
-#ifdef HAVE_INET6
- case AF_INET6:
- if ((ip = getprotobyname("ipv6")) != 0)
- ipproto = ip->p_proto;
- else
- ipproto = IPPROTO_IPV6;
- break;
-#endif
- default:
- syslog(LOG_ERR, "unknown address family: %d", remote->ss_family);
- return -1;
- }
-
- if (getsockopt(fd, ipproto, IP_OPTIONS, (char *) optbuf, &optsize) == 0
- && optsize != 0) {
- lp = lbuf;
- for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
- sprintf(lp, " %2.2x", *cp);
- syslog(LOG_NOTICE,
- "connect from %s with IP options (ignored):%s",
- sprint_sockaddr((struct sockaddr *)remote), lbuf);
- if (setsockopt(fd, ipproto, IP_OPTIONS, (char *) 0, optsize) != 0) {
- syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-static bool
-RCaddressmatch(const struct sockaddr_storage *cp, const struct sockaddr_storage *rp)
-{
-#ifdef HAVE_INET6
- struct sockaddr_in *sin_cp, *sin_rp;
- struct sockaddr_in6 *sin6_cp, *sin6_rp;
-
- if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET) {
- sin6_cp = (struct sockaddr_in6 *)cp;
- sin_rp = (struct sockaddr_in *)rp;
- if (IN6_IS_ADDR_V4MAPPED(&sin6_cp->sin6_addr) &&
- memcmp(&sin6_cp->sin6_addr.s6_addr[12],
- &sin_rp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
- return true;
- } else if (cp->ss_family == AF_INET && rp->ss_family == AF_INET6) {
- sin_cp = (struct sockaddr_in *)cp;
- sin6_rp = (struct sockaddr_in6 *)rp;
- if (IN6_IS_ADDR_V4MAPPED(&sin6_rp->sin6_addr) &&
- memcmp(&sin6_rp->sin6_addr.s6_addr[12],
- &sin_cp->sin_addr.s_addr, sizeof(struct in_addr)) == 0)
- return true;
- } else if (cp->ss_family == AF_INET6 && rp->ss_family == AF_INET6) {
-#ifdef HAVE_BROKEN_IN6_ARE_ADDR_EQUAL
- if (!memcmp(&((struct sockaddr_in6 *)cp)->sin6_addr,
- &((struct sockaddr_in6 *)rp)->sin6_addr,
- sizeof(struct in6_addr)))
-#else
- if (IN6_ARE_ADDR_EQUAL( &((struct sockaddr_in6 *)cp)->sin6_addr,
- &((struct sockaddr_in6 *)rp)->sin6_addr))
-#endif
- return true;
- } else
-#endif /* INET6 */
- if (((struct sockaddr_in *)cp)->sin_addr.s_addr ==
- ((struct sockaddr_in *)rp)->sin_addr.s_addr)
- return true;
-
- return false;
-}
-
-/*
-** See if the site properly entered the password.
-*/
-bool
-RCauthorized(CHANNEL *cp, char *pass)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address)) {
- if (rp->Password[0] == '\0' || strcmp(pass, rp->Password) == 0)
- return true;
- syslog(L_ERROR, "%s (%s) bad_auth", rp->Label,
- sprint_sockaddr((struct sockaddr *)&cp->Address));
- return false;
- }
-
- if (!AnyIncoming)
- /* Not found in our table; this can't happen. */
- syslog(L_ERROR, "%s not_found", sprint_sockaddr((struct sockaddr *)&cp->Address));
-
- /* Anonymous hosts should not authenticate. */
- return false;
-}
-
-/*
-** See if a host is limited or not.
-*/
-bool
-RCnolimit(CHANNEL *cp)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return !rp->MaxCnx;
-
- /* Not found in our table; this can't happen. */
- return false;
-}
-
-/*
-** Return the limit (max number of connections) for a host.
-*/
-int
-RClimit(CHANNEL *cp)
-{
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->MaxCnx;
- /* Not found in our table; this can't happen. */
- return RemoteLimit;
-}
-
-
-/*
-** Called when input is ready to read. Shouldn't happen.
-*/
-static void
-RCrejectreader(CHANNEL *cp)
-{
- syslog(L_ERROR, "%s internal RCrejectreader (%s)", LogName,
- sprint_sockaddr((struct sockaddr *)&cp->Address));
-}
-
-
-/*
-** Write-done function for rejects.
-*/
-static void
-RCrejectwritedone(CHANNEL *cp)
-{
- switch (cp->State) {
- default:
- syslog(L_ERROR, "%s internal RCrejectwritedone state %d",
- CHANname(cp), cp->State);
- break;
- case CSwritegoodbye:
- CHANclose(cp, CHANname(cp));
- break;
- }
-}
-
-
-/*
-** Hand off a descriptor to NNRPD.
-*/
-void
-RChandoff(int fd, HANDOFF h)
-{
- const char **argv;
- char buff[SMBUF];
- int i;
- unsigned int j;
- struct vector *flags;
-
- flags = vector_split_space(innconf->nnrpdflags, NULL);
- argv = xmalloc( (flags->count + 6) * sizeof(char*) );
-
- if (RCnnrpd == NULL)
- RCnnrpd = concatpath(innconf->pathbin, "nnrpd");
- if (RCnntpd == NULL)
- RCnntpd = concatpath(innconf->pathbin, "nnrpd");
-#if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
- /* Set KEEPALIVE to catch broken socket connections. */
- i = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof i) < 0)
- syslog(L_ERROR, "fd %d cant setsockopt(KEEPALIVE) %m", fd);
-#endif /* defined(SOL_SOCKET) && defined(SO_KEEPALIVE) */
-
- if (nonblocking(fd, false) < 0)
- syslog(L_ERROR, "%s cant nonblock %d in RChandoff %m", LogName, fd);
- switch (h) {
- default:
- syslog(L_ERROR, "%s internal RChandoff %d type %d", LogName, fd, h);
- /* FALLTHROUGH */
- case HOnnrpd: argv[0] = RCnnrpd; break;
- case HOnntpd: argv[0] = RCnntpd; break;
- }
- argv[1] = "-s ";
- i = 2;
- if (NNRPReason) {
- snprintf(buff, sizeof(buff), "-r%s", NNRPReason);
- argv[i++] = buff;
- }
- if (NNRPTracing)
- argv[i++] = "-t";
- if (RCslaveflag)
- argv[i++] = RCslaveflag;
-
- for(j = 0; j < flags->count; j++) {
- argv[i++] = flags->strings[j];
- }
- argv[i] = NULL;
-
- /* Call NNRP; don't send back a QUIT message if Spawn fails since
- * that's a major error we want to find out about quickly. */
- (void)Spawn(innconf->nicekids, fd, fd, fd, (char * const *)argv);
- vector_free(flags);
- free(argv);
-}
-
-
-/*
-** Read function. Accept the connection and either create an NNTP channel
-** or spawn an nnrpd to handle it.
-*/
-static void
-RCreader(CHANNEL *cp)
-{
- int fd;
- struct sockaddr_storage remote;
- socklen_t size;
- int i;
- REMOTEHOST *rp;
- CHANNEL *new;
- char *name;
- long reject_val = 0;
- const char *reject_message;
- int count;
- int found;
- time_t now;
- CHANNEL tempchan;
- char buff[SMBUF];
-
- for (i = 0 ; i < chanlimit ; i++) {
- if (RCchan[i] == cp) {
- break;
- }
- }
- if (i == chanlimit) {
- syslog(L_ERROR, "%s internal RCreader wrong channel 0x%p",
- LogName, (void *)cp);
- return;
- }
-
- /* Get the connection. */
- size = sizeof remote;
- if ((fd = accept(cp->fd, (struct sockaddr *)&remote, &size)) < 0) {
- if (errno != EWOULDBLOCK && errno != EAGAIN)
- syslog(L_ERROR, "%s cant accept RCreader %m", LogName);
- return;
- }
-
- /*
- ** Clear any IP_OPTIONS, including source routing, on the socket
- */
- /* FIXME RCfix_options breaks IPv6 sockets, at least on Linux -lutchann */
-#ifndef HAVE_INET6
- if (RCfix_options(fd, &remote) != 0) {
- /* shouldn't happen, but we're bit paranoid at this point */
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- }
-#endif
-
- /* If RemoteTimer is not zero, then check the limits on incoming
- connections on a total and per host basis.
-
- The incoming connection table is fixed at 128 entries to make
- calculating the index easy (i + 1) & 7, and to be pretty sure that you
- won't run out of space. The table is used as a ring with new entries
- being added to the end (wrapping around) and expired entries being
- deleted from the front (again wrapping around). It is doubtful that
- you will ever use even half of the table.
-
- There are three parameters controlling the use of the table not
- counting the starting index and count:
-
- H = per host incoming connects per X seconds allowed
- T = total incoming connects per X seconds allowed
- X = number of seconds to remember a successful connect
-
- First, one pass is made over the live entries deleting any that are
- over X seconds old. If the entry hasn't expired, compare the incoming
- connection's host address with the entry's host address. If equal,
- increment the "found" counter.
-
- Second, if the number of entries now in the table is equal to the T
- parameter, reject the connection with a message indicating that the
- server is overloaded.
-
- Third, if the number of entries now in the table which match the
- incoming connection's host address is equal to the H parameter, reject
- the connection.
-
- Finally, if neither rejection happened, add the entry to the table, and
- continue on as a normal connect. */
- memcpy(&tempchan.Address, &remote, SA_LEN((struct sockaddr *)&remote));
- reject_message = NULL;
- if (RemoteTimer != 0) {
- now = time(NULL);
- i = remotefirst;
- count = remotecount;
- found = 0;
- while (count--) {
- if (remotetable[i].Expires < now) {
- remotecount--;
- remotefirst = (remotefirst + 1) & (REMOTETABLESIZE - 1);
- i = (i + 1) & (REMOTETABLESIZE - 1);
- continue;
- }
- if (RCaddressmatch(&remotetable[i].Address, &remote))
- found++;
- i = (i + 1) & (REMOTETABLESIZE - 1);
- }
- if (remotecount == RemoteTotal) {
- reject_val = NNTP_GOODBYE_VAL;
- reject_message = "400 Server overloaded, try later";
- }
- else if (found >= RemoteLimit && !RCnolimit(&tempchan)) {
- reject_val = NNTP_GOODBYE_VAL;
- reject_message = "400 Connection rejected, you're making too"
- " many connects per minute";
- }
- else {
- i = (remotefirst + remotecount) & (REMOTETABLESIZE - 1);
- memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
- remotetable[i].Expires = now + RemoteTimer;
- remotecount++;
- }
- }
-
- /*
- ** Create a reject channel to reject the connection. This is done
- ** to avoid a call to fork.
- */
- if (reject_message) {
- new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
- RCrejectwritedone);
- memcpy(&remotetable[i].Address, &remote, SA_LEN((struct sockaddr *)&remote));
- new->Rejected = reject_val;
- RCHANremove(new);
- WCHANset(new, reject_message, (int)strlen(reject_message));
- WCHANappend(new, RCterm, strlen(RCterm));
- WCHANadd(new);
- return;
- }
-
- /* See if it's one of our servers. */
- for (name = NULL, rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&rp->Address, &remote)) {
- name = rp->Name;
- break;
- }
-
- /* If not a server, and not allowing anyone, hand him off unless
- not spawning nnrpd in which case we return an error. */
- if ((i >= 0) && !rp->Skip) {
-
- /* We check now the identd if we have to */
- if(! GoodIdent(fd, rp->Identd))
- {
- if (!innconf->noreader) {
- RChandoff(fd, HOnntpd);
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- }
- }
-
- if ((new = NCcreate(fd, rp->Password[0] != '\0', false)) != NULL) {
- new->Streaming = rp->Streaming;
- new->Skip = rp->Skip;
- new->NoResendId = rp->NoResendId;
- new->Nolist = rp->Nolist;
- new->MaxCnx = rp->MaxCnx;
- new->HoldTime = rp->HoldTime;
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- if (new->MaxCnx > 0 && new->HoldTime == 0) {
- CHANsetActiveCnx(new);
- if((new->ActiveCnx > new->MaxCnx) && (new->fd > 0)) {
- snprintf(buff, sizeof(buff),
- "You are limited to %d connection%s",
- new->MaxCnx, (new->MaxCnx != 1) ? "s" : "");
- NCwriteshutdown(new, buff);
- syslog(L_NOTICE, "too many connections from %s", rp->Label);
- } else {
- NCwritereply(new, (char *)NCgreeting);
- }
- } else {
- NCwritereply(new, (char *)NCgreeting);
- }
- }
- } else if (AnyIncoming && !rp->Skip) {
- if ((new = NCcreate(fd, false, false)) != NULL) {
- NCwritereply(new, (char *)NCgreeting);
- }
- } else if (!innconf->noreader) {
- RChandoff(fd, HOnntpd);
- if (close(fd) < 0)
- syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
- return;
- } else {
- reject_val = NNTP_ACCESS_VAL;
- reject_message = NNTP_ACCESS;
- new = CHANcreate(fd, CTreject, CSwritegoodbye, RCrejectreader,
- RCrejectwritedone);
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- new->Rejected = reject_val;
- RCHANremove(new);
- WCHANset(new, reject_message, (int)strlen(reject_message));
- WCHANappend(new, RCterm, strlen(RCterm));
- WCHANadd(new);
- return;
- }
-
- if (new != NULL) {
- memcpy(&new->Address, &remote, SA_LEN((struct sockaddr *)&remote));
- syslog(L_NOTICE, "%s connected %d streaming %s",
- name ? name : sprint_sockaddr((struct sockaddr *)&new->Address),
- new->fd, (!StreamingOff && new->Streaming) ? "allowed" : "not allowed");
- }
-}
-
-
-/*
-** Write-done function. Shouldn't happen.
-*/
-static void
-RCwritedone(CHANNEL *unused)
-{
- unused = unused; /* ARGSUSED */
- syslog(L_ERROR, "%s internal RCwritedone", LogName);
-}
-
-/*
- * New config file style. Old hosts.nntp and hosts.nntp.nolimit are merged
- * into one file called incoming.conf (to avoid confusion).
- * See ../samples/incoming.conf for the new syntax.
- *
- * Fabien Tassin <fta@sofaraway.org>, 21-Dec-1997.
- */
-
-
-/*
- * Read something (a word or a double quoted string) from a file.
- */
-static char *
-RCreaddata(int *num, FILE *F, bool *toolong)
-{
- char *p;
- char *s;
- char *t;
- char *word;
- bool flag;
-
- *toolong = false;
- if (*RCbuff == '\0') {
- if (feof (F)) return (NULL);
- fgets(RCbuff, sizeof RCbuff, F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- }
- p = RCbuff;
- do {
- /* Ignore blank and comment lines. */
- if ((p = strchr(RCbuff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(RCbuff, '#')) != NULL) {
- if (p == RCbuff || (p > RCbuff && *(p - 1) != '\\'))
- *p = '\0';
- }
- for (p = RCbuff; *p == ' ' || *p == '\t' ; p++);
- flag = true;
- if (*p == '\0' && !feof (F)) {
- flag = false;
- fgets(RCbuff, sizeof RCbuff, F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- continue;
- }
- break;
- } while (!feof (F) || !flag);
-
- if (*p == '"') { /* double quoted string ? */
- p++;
- do {
- for (t = p; (*t != '"' || (*t == '"' && *(t - 1) == '\\')) &&
- *t != '\0'; t++);
- if (*t == '\0') {
- *t++ = '\n';
- fgets(t, sizeof RCbuff - strlen (RCbuff), F);
- (*num)++;
- if (strlen (RCbuff) == sizeof RCbuff) {
- *toolong = true;
- return (NULL); /* Line too long */
- }
- if ((s = strchr(t, '\n')) != NULL)
- *s = '\0';
- }
- else
- break;
- } while (!feof (F));
- *t++ = '\0';
- }
- else {
- for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++);
- if (*t != '\0')
- *t++ = '\0';
- }
- if (*p == '\0' && feof (F)) return (NULL);
- word = xstrdup (p);
- for (p = RCbuff; *t != '\0'; t++)
- *p++ = *t;
- *p = '\0';
-
- return (word);
-}
-
-/*
- * Add all data into RCpeerlistfile.
- */
-static void
-RCadddata(REMOTEHOST_DATA **d, int *count, int Key, int Type, char* Value)
-{
- (*d)[*count].key = Key;
- (*d)[*count].type = Type;
- (*d)[*count].value = Value;
- (*count)++;
- *d = xrealloc(*d, (*count + 1) * sizeof(REMOTEHOST_DATA));
-}
-
-/*
-** Read in the file listing the hosts we take news from, and fill in the
-** global list of their Internet addresses. A host can have multiple
-** addresses, so we take care to add all of them to the list.
-*/
-static void
-RCreadfile (REMOTEHOST_DATA **data, REMOTEHOST **list, int *count,
- char *filename)
-{
- static char NOPASS[] = "";
- static char NOIDENTD[] = "";
- static char NOEMAIL[] = "";
- static char NOCOMMENT[] = "";
- FILE *F;
- char *p;
- char **q;
- char **r;
-#if !defined( HAVE_INET6)
- struct hostent *hp;
-#endif
-#if !defined(HAVE_UNIX_DOMAIN_SOCKETS) || !defined(HAVE_INET6)
- struct in_addr addr;
-#endif
- int i;
- int j;
- int linecount;
- int infocount;
- int groupcount;
- int maxgroup;
- REMOTEHOST_DATA *dt;
- REMOTEHOST *rp;
- char *word;
- REMOTEHOST *groups;
- REMOTEHOST *group_params = NULL;
- REMOTEHOST peer_params;
- REMOTEHOST default_params;
- bool flag, bit, toolong;
-
- *RCbuff = '\0';
- if (*list) {
- for (rp = *list, i = *count; --i >= 0; rp++) {
- free(rp->Name);
- free(rp->Label);
- free(rp->Email);
- free(rp->Comment);
- free(rp->Password);
- free(rp->Identd);
- if (rp->Patterns) {
- free(rp->Patterns[0]);
- free(rp->Patterns);
- }
- }
- free(*list);
- *list = NULL;
- *count = 0;
- }
- if (*data) {
- for (i = 0; (*data)[i].key != K_END; i++)
- if ((*data)[i].value != NULL)
- free((*data)[i].value);
- free(*data);
- *data = NULL;
- }
-
- *count = 0;
- maxgroup = 0;
- /* Open the server file. */
- if ((F = Fopen(filename, "r", TEMPORARYOPEN)) == NULL) {
- syslog(L_FATAL, "%s cant read %s: %m", LogName, filename);
- exit(1);
- }
- dt = *data = xmalloc(sizeof(REMOTEHOST_DATA));
- rp = *list = xmalloc(sizeof(REMOTEHOST));
-
-#if !defined(HAVE_UNIX_DOMAIN_SOCKETS)
- addr.s_addr = INADDR_LOOPBACK;
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup("localhost");
- rp->Label = xstrdup("localhost");
- rp->Email = xstrdup(NOEMAIL);
- rp->Comment = xstrdup(NOCOMMENT);
- rp->Password = xstrdup(NOPASS);
- rp->Identd = xstrdup(NOIDENTD);
- rp->Patterns = NULL;
- rp->MaxCnx = 0;
- rp->Streaming = true;
- rp->Skip = false;
- rp->NoResendId = false;
- rp->Nolist = false;
- rp->HoldTime = 0;
- rp++;
- (*count)++;
-#endif /* !defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-
- linecount = 0;
- infocount = 0;
- groupcount = 0; /* no group defined yet */
- groups = 0;
- peer_params.Label = NULL;
- default_params.Streaming = true;
- default_params.Skip = false;
- default_params.NoResendId = false;
- default_params.Nolist = false;
- default_params.MaxCnx = 0;
- default_params.HoldTime = 0;
- default_params.Password = xstrdup(NOPASS);
- default_params.Identd = xstrdup(NOIDENTD);
- default_params.Email = xstrdup(NOEMAIL);
- default_params.Comment = xstrdup(NOCOMMENT);
- default_params.Pattern = NULL;
- peer_params.Keysetbit = 0;
-
- /* Read the file to add all the hosts. */
- while ((word = RCreaddata (&linecount, F, &toolong)) != NULL) {
-
- /* group */
- if (!strncmp (word, GROUP, sizeof GROUP)) {
- free(word);
- /* name of the group */
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- syslog(L_ERROR, GROUP_NAME, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_BEGIN_GROUP, T_STRING, word);
- groupcount++;
- if (groupcount == 1) {
- /* First group block. */
- group_params = groups = xmalloc(sizeof(REMOTEHOST));
- }
- else if (groupcount >= maxgroup) {
- /* Alloc 5 groups for extra nested group blocks. */
- groups = xrealloc(groups, (groupcount + 4) * sizeof(REMOTEHOST));
- maxgroup += 5;
- group_params = groups + groupcount - 1;
- }
- else {
- /* Nested group block (no need to extend groups). */
- group_params++;
- }
- group_params->Label = word;
- group_params->Skip = groupcount > 1 ?
- groups[groupcount - 2].Skip : default_params.Skip;
- group_params->Streaming = groupcount > 1 ?
- groups[groupcount - 2].Streaming : default_params.Streaming;
- group_params->NoResendId = groupcount > 1 ?
- groups[groupcount - 2].NoResendId : default_params.NoResendId;
- group_params->Nolist = groupcount > 1 ?
- groups[groupcount - 2].Nolist : default_params.Nolist;
- group_params->Email = groupcount > 1 ?
- groups[groupcount - 2].Email : default_params.Email;
- group_params->Comment = groupcount > 1 ?
- groups[groupcount - 2].Comment : default_params.Comment;
- group_params->Pattern = groupcount > 1 ?
- groups[groupcount - 2].Pattern : default_params.Pattern;
- group_params->Password = groupcount > 1 ?
- groups[groupcount - 2].Password : default_params.Password;
- group_params->Identd = groupcount > 1 ?
- groups[groupcount - 2].Identd : default_params.Identd;
- group_params->MaxCnx = groupcount > 1 ?
- groups[groupcount - 2].MaxCnx : default_params.MaxCnx;
- group_params->HoldTime = groupcount > 1 ?
- groups[groupcount - 2].HoldTime : default_params.HoldTime;
-
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- /* left brace */
- if (strncmp (word, "{", 1)) {
- free(word);
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- else
- free(word);
- peer_params.Keysetbit = 0;
- continue;
- }
-
- /* peer */
- if (!strncmp (word, PEER, sizeof PEER)) {
- free(word);
- if (peer_params.Label != NULL) {
- /* peer can't contain peer */
- syslog(L_ERROR, PEER_IN_PEER, LogName,
- filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
- {
- syslog(L_ERROR, PEER_NAME, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_BEGIN_PEER, T_STRING, word);
- /* name of the peer */
- peer_params.Label = word;
- peer_params.Name = NULL;
- peer_params.Skip = groupcount > 0 ?
- group_params->Skip : default_params.Skip;
- peer_params.Streaming = groupcount > 0 ?
- group_params->Streaming : default_params.Streaming;
- peer_params.NoResendId = groupcount > 0 ?
- group_params->NoResendId : default_params.NoResendId;
- peer_params.Nolist = groupcount > 0 ?
- group_params->Nolist : default_params.Nolist;
- peer_params.Email = groupcount > 0 ?
- group_params->Email : default_params.Email;
- peer_params.Comment = groupcount > 0 ?
- group_params->Comment : default_params.Comment;
- peer_params.Pattern = groupcount > 0 ?
- group_params->Pattern : default_params.Pattern;
- peer_params.Password = groupcount > 0 ?
- group_params->Password : default_params.Password;
- peer_params.Identd = groupcount > 0 ?
- group_params->Identd : default_params.Identd;
- peer_params.MaxCnx = groupcount > 0 ?
- group_params->MaxCnx : default_params.MaxCnx;
- peer_params.HoldTime = groupcount > 0 ?
- group_params->HoldTime : default_params.HoldTime;
-
- peer_params.Keysetbit = 0;
-
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL)
- {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- break;
- }
- /* left brace */
- if (strncmp (word, "{", 1)) {
- syslog(L_ERROR, LEFT_BRACE, LogName, filename, linecount);
- free(word);
- break;
- }
- else
- free(word);
- continue;
- }
-
- /* right brace */
- if (!strncmp (word, "}", 1)) {
- free(word);
- if (peer_params.Label != NULL) {
- RCadddata(data, &infocount, K_END_PEER, T_STRING, NULL);
-
- /* Hostname defaults to label if not given */
- if (peer_params.Name == NULL)
- peer_params.Name = xstrdup(peer_params.Label);
-
- for(r = q = RCCommaSplit(xstrdup(peer_params.Name)); *q != NULL; q++) {
-#ifdef HAVE_INET6
- struct addrinfo *res, *res0, hints;
- int gai_ret;
-#endif
- (*count)++;
-
- /* Grow the array */
- j = rp - *list;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
-#ifdef HAVE_INET6
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = PF_UNSPEC;
- if ((gai_ret = getaddrinfo(*q, NULL, &hints, &res0)) != 0) {
- syslog(L_ERROR, "%s cant getaddrinfo %s %s", LogName, *q,
- gai_strerror( gai_ret ) );
- /* decrement *count, since we never got to add this record. */
- (*count)--;
- continue;
- }
- /* Count the addresses and see if we have to grow the list */
- i = 0;
- for (res = res0; res != NULL; res = res->ai_next)
- i++;
- /* Grow the array */
- j = rp - *list;
- *count += i - 1;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- /* Add all hosts */
- for (res = res0; res != NULL; res = res->ai_next) {
- (void)memcpy(&rp->Address, res->ai_addr, res->ai_addrlen);
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- }
- freeaddrinfo(res0);
-#else /* HAVE_INET6 */
- /* Was host specified as a dotted quad ? */
- if (inet_aton(*q, &addr)) {
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Skip = peer_params.Skip;
- rp->Streaming = peer_params.Streaming;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- continue;
- }
-
- /* Host specified as a text name ? */
- if ((hp = gethostbyname(*q)) == NULL) {
- syslog(L_ERROR, "%s cant gethostbyname %s %m", LogName, *q);
- /* decrement *count, since we never got to add this record. */
- (*count)--;
- continue;
- }
-
- /* Count the adresses and see if we have to grow the list */
- for (i = 0; hp->h_addr_list[i]; i++)
- continue;
- if (i == 0) {
- syslog(L_ERROR, "%s no_address %s %m", LogName, *q);
- continue;
- }
- if (i == 1) {
- char **rr;
- int t = 0;
- /* Strange DNS ? try this.. */
- for (rr = hp->h_aliases; *rr != 0; rr++) {
- if (!inet_aton(*rr, &addr))
- continue;
- (*count)++;
- /* Grow the array */
- j = rp - *list;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- make_sin( (struct sockaddr_in *)&rp->Address, &addr );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- t++;
- }
- if (t == 0) {
- /* Just one, no need to grow. */
- make_sin( (struct sockaddr_in *)&rp->Address,
- (struct in_addr *)hp->h_addr_list[0] );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- continue;
- }
- }
- /* Grow the array */
- j = rp - *list;
- *count += i - 1;
- *list = xrealloc(*list, *count * sizeof(REMOTEHOST));
- rp = *list + j;
-
- /* Add all the hosts. */
- for (i = 0; hp->h_addr_list[i]; i++) {
- make_sin( (struct sockaddr_in *)&rp->Address,
- (struct in_addr *)hp->h_addr_list[i] );
- rp->Name = xstrdup (*q);
- rp->Label = xstrdup (peer_params.Label);
- rp->Email = xstrdup(peer_params.Email);
- rp->Comment = xstrdup(peer_params.Comment);
- rp->Streaming = peer_params.Streaming;
- rp->Skip = peer_params.Skip;
- rp->NoResendId = peer_params.NoResendId;
- rp->Nolist = peer_params.Nolist;
- rp->Password = xstrdup(peer_params.Password);
- rp->Identd = xstrdup(peer_params.Identd);
- rp->Patterns = peer_params.Pattern != NULL ?
- RCCommaSplit(xstrdup(peer_params.Pattern)) : NULL;
- rp->MaxCnx = peer_params.MaxCnx;
- rp->HoldTime = peer_params.HoldTime;
- rp++;
- }
-#endif /* HAVE_INET6 */
- }
- free(r[0]);
- free(r);
- peer_params.Label = NULL;
- }
- else if (groupcount > 0 && group_params->Label != NULL) {
- RCadddata(data, &infocount, K_END_GROUP, T_STRING, NULL);
- group_params->Label = NULL;
- groupcount--;
- if (groupcount == 0) {
- /* We are now outside a group block. */
- free(groups);
- maxgroup = 0;
- } else {
- group_params--;
- }
- }
- else {
- syslog(L_ERROR, RIGHT_BRACE, LogName, linecount, filename);
- }
- continue;
- }
-
- /* streaming */
- if (!strncmp (word, STREAMING, sizeof STREAMING)) {
- free(word);
- TEST_CONFIG(K_STREAM, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_STREAM, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Streaming = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Streaming = flag;
- else
- default_params.Streaming = flag;
- SET_CONFIG(K_STREAM);
- continue;
- }
-
- /* skip */
- if (!strncmp (word, SKIP, sizeof SKIP)) {
- free(word);
- TEST_CONFIG(K_SKIP, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_SKIP, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Skip = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Skip = flag;
- else
- default_params.Skip = flag;
- SET_CONFIG(K_SKIP);
- continue;
- }
-
- /* noresendid */
- if (!strncmp (word, NORESENDID, sizeof NORESENDID)) {
- free(word);
- TEST_CONFIG(K_NORESENDID, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_NORESENDID, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.NoResendId = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->NoResendId = flag;
- else
- default_params.NoResendId = flag;
- SET_CONFIG(K_NORESENDID);
- continue;
- }
-
- /* nolist */
- if (!strncmp (word, NOLIST, sizeof NOLIST)) {
- free(word);
- TEST_CONFIG(K_NOLIST, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- if (!strcmp (word, "true"))
- flag = true;
- else
- if (!strcmp (word, "false"))
- flag = false;
- else {
- syslog(L_ERROR, MUST_BE_BOOL, LogName, filename, linecount);
- break;
- }
- RCadddata(data, &infocount, K_NOLIST, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Nolist = flag;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Nolist = flag;
- else
- default_params.Nolist = flag;
- SET_CONFIG(K_NOLIST);
- continue;
- }
-
- /* max-connections */
- if (!strncmp (word, MAX_CONN, sizeof MAX_CONN)) {
- int max;
- free(word);
- TEST_CONFIG(K_MAX_CONN, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_MAX_CONN, T_STRING, word);
- for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
- if (!strcmp (word, "none") || !strcmp (word, "unlimited")) {
- max = 0;
- } else {
- if (*p != '\0') {
- syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
- break;
- }
- max = atoi(word);
- }
- if (peer_params.Label != NULL)
- peer_params.MaxCnx = max;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->MaxCnx = max;
- else
- default_params.MaxCnx = max;
- SET_CONFIG(K_MAX_CONN);
- continue;
- }
-
- /* hold-time */
- if (!strncmp (word, HOLD_TIME, sizeof HOLD_TIME)) {
- free(word);
- TEST_CONFIG(K_HOLD_TIME, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_HOLD_TIME, T_STRING, word);
- for (p = word; CTYPE(isdigit, *p) && *p != '\0'; p++);
- if (*p != '\0') {
- syslog(L_ERROR, MUST_BE_INT, LogName, filename, linecount);
- break;
- }
- if (peer_params.Label != NULL)
- peer_params.HoldTime = atoi(word);
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->HoldTime = atoi(word);
- else
- default_params.HoldTime = atoi(word);
- SET_CONFIG(K_HOLD_TIME);
- continue;
- }
-
- /* hostname */
- if (!strncmp (word, HOSTNAME, sizeof HOSTNAME)) {
- free(word);
- TEST_CONFIG(K_HOSTNAME, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_HOSTNAME, T_STRING, word);
- peer_params.Name = word;
- SET_CONFIG(K_HOSTNAME);
- continue;
- }
-
- /* password */
- if (!strncmp (word, PASSWORD, sizeof PASSWORD)) {
- free(word);
- TEST_CONFIG(K_PASSWORD, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_PASSWORD, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Password = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Password = word;
- else
- default_params.Password = word;
- SET_CONFIG(K_PASSWORD);
- continue;
- }
-
- /* identd */
- if (!strncmp (word, IDENTD, sizeof IDENTD)) {
- free(word);
- TEST_CONFIG(K_IDENTD, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_IDENTD, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Identd = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Identd = word;
- else
- default_params.Identd = word;
- SET_CONFIG(K_IDENTD);
- continue;
- }
-
- /* patterns */
- if (!strncmp (word, PATTERNS, sizeof PATTERNS)) {
- TEST_CONFIG(K_PATTERNS, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- free(word);
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_PATTERNS, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Pattern = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Pattern = word;
- else
- default_params.Pattern = word;
- SET_CONFIG(K_PATTERNS);
- continue;
- }
-
- /* email */
- if (!strncmp (word, EMAIL, sizeof EMAIL)) {
- free(word);
- TEST_CONFIG(K_EMAIL, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_EMAIL, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Email = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Email = word;
- else
- default_params.Email = word;
- SET_CONFIG(K_EMAIL);
- continue;
- }
-
- /* comment */
- if (!strncmp (word, COMMENT, sizeof COMMENT)) {
- free(word);
- TEST_CONFIG(K_COMMENT, bit);
- if (bit) {
- syslog(L_ERROR, DUPLICATE_KEY, LogName, filename, linecount);
- break;
- }
- if ((word = RCreaddata (&linecount, F, &toolong)) == NULL) {
- break;
- }
- RCadddata(data, &infocount, K_COMMENT, T_STRING, word);
- if (peer_params.Label != NULL)
- peer_params.Comment = word;
- else
- if (groupcount > 0 && group_params->Label != NULL)
- group_params->Comment = word;
- else
- default_params.Comment = word;
- SET_CONFIG(K_COMMENT);
- continue;
- }
-
- if (toolong)
- syslog(L_ERROR, "%s line too long at %d: %s",
- LogName, --linecount, filename);
- else
- syslog(L_ERROR, "%s Unknown value line %d: %s",
- LogName, linecount, filename);
- free(word);
- break;
- }
- free(default_params.Email);
- free(default_params.Comment);
- RCadddata(data, &infocount, K_END, T_STRING, NULL);
-
- if (feof (F)) {
- if (peer_params.Label != NULL)
- syslog(L_ERROR, INCOMPLETE_PEER, LogName, peer_params.Label,
- filename, linecount);
- if (groupcount > 0 && group_params->Label != NULL)
- syslog(L_ERROR, INCOMPLETE_GROUP, LogName, group_params->Label,
- filename, linecount);
- }
- else
- syslog(L_ERROR, "%s Syntax error in %s at or before line %d", LogName,
- filename, linecount);
-
- if (Fclose(F) == EOF)
- syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
-
- free(default_params.Password);
- free(default_params.Identd);
-}
-
-
-/*
-** Indent a line with 3 * c blanks.
-** Used by RCwritelist().
-*/
-static void
-RCwritelistindent(FILE *F, int c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- fprintf(F, " ");
-}
-
-/*
-** Add double quotes around a string, if needed.
-** Used by RCwritelist().
-*/
-static void
-RCwritelistvalue(FILE *F, char *value)
-{
- if (*value == '\0' || strchr (value, '\n') ||
- strchr (value, ' ') || strchr (value, '\t'))
- fprintf(F, "\"%s\"", value);
- else
- fprintf(F, "%s", value);
-}
-
-/*
-** Write the incoming configuration (memory->disk)
-*/
-static void UNUSED
-RCwritelist(char *filename)
-{
- FILE *F;
- int i;
- int inc;
- char *p;
- char *q;
- char *r;
-
- if ((F = Fopen(filename, "w", TEMPORARYOPEN)) == NULL) {
- syslog(L_FATAL, "%s cant write %s: %m", LogName, filename);
- return;
- }
-
- /* Write a standard header.. */
-
- /* Find the filename */
- p = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
- for (r = q = p; *p; p++)
- if (*p == '/')
- q = p + 1;
-
- fprintf (F, "## $Revision: 7751 $\n");
- fprintf (F, "## %s - names and addresses that feed us news\n", q);
- free(r);
- fprintf (F, "##\n\n");
-
- /* ... */
-
- inc = 0;
- for (i = 0; RCpeerlistfile[i].key != K_END; i++) {
- switch (RCpeerlistfile[i].key) {
- case K_BEGIN_PEER:
- fputc ('\n', F);
- RCwritelistindent (F, inc);
- fprintf(F, "%s %s {\n", PEER, RCpeerlistfile[i].value);
- inc++;
- break;
- case K_BEGIN_GROUP:
- fputc ('\n', F);
- RCwritelistindent (F, inc);
- fprintf(F, "%s %s {\n", GROUP, RCpeerlistfile[i].value);
- inc++;
- break;
- case K_END_PEER:
- case K_END_GROUP:
- inc--;
- RCwritelistindent (F, inc);
- fprintf(F, "}\n");
- break;
- case K_STREAM:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", STREAMING);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_SKIP:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", SKIP);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_NORESENDID:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", NORESENDID);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_NOLIST:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", NOLIST);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_HOSTNAME:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", HOSTNAME);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_MAX_CONN:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", MAX_CONN);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_HOLD_TIME:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", HOLD_TIME);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_PASSWORD:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", PASSWORD);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_IDENTD:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", IDENTD);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_EMAIL:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", EMAIL);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_PATTERNS:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", PATTERNS);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- case K_COMMENT:
- RCwritelistindent (F, inc);
- fprintf(F, "%s\t", COMMENT);
- RCwritelistvalue (F, RCpeerlistfile[i].value);
- fputc ('\n', F);
- break;
- default:
- fprintf(F, "# ***ERROR***\n");
- }
- }
- if (Fclose(F) == EOF)
- syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
-
-}
-
-void
-RCreadlist(void)
-{
- static char *INNDHOSTS = NULL;
-
- if (INNDHOSTS == NULL)
- INNDHOSTS = concatpath(innconf->pathetc, _PATH_INNDHOSTS);
- StreamingOff = false;
- RCreadfile(&RCpeerlistfile, &RCpeerlist, &RCnpeerlist, INNDHOSTS);
- /* RCwritelist("/tmp/incoming.conf.new"); */
-}
-
-/*
-** Find the name of a remote host we've connected to.
-*/
-char *
-RChostname(const CHANNEL *cp)
-{
- static char buff[SMBUF];
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->Name;
- strlcpy(buff, sprint_sockaddr((struct sockaddr *)&cp->Address),
- sizeof(buff));
- return buff;
-}
-
-/*
-** Find the label name of a remote host we've connected to.
-*/
-char *
-RClabelname(CHANNEL *cp) {
- REMOTEHOST *rp;
- int i;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- if (RCaddressmatch(&cp->Address, &rp->Address))
- return rp->Label;
- }
- return NULL;
-}
-
-/*
-** Is the remote site allowed to post to this group?
-*/
-int
-RCcanpost(CHANNEL *cp, char *group)
-{
- REMOTEHOST *rp;
- char match;
- char subvalue;
- char **argv;
- char *pat;
- int i;
-
- /* Connections from lc.c are from local nnrpd and should always work */
- if (cp->Address.ss_family == 0)
- return 1;
-
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- if (!RCaddressmatch(&cp->Address, &rp->Address))
- continue;
- if (rp->Patterns == NULL)
- break;
- for (match = 0, argv = rp->Patterns; (pat = *argv++) != NULL; ) {
- subvalue = (*pat != SUB_NEGATE) && (*pat != SUB_POISON) ?
- 0 : *pat;
- if (subvalue)
- pat++;
- if ((match != subvalue) && uwildmat(group, pat)) {
- if (subvalue == SUB_POISON)
- return -1;
- match = subvalue;
- }
- }
- return !match;
- }
- return 1;
-}
-
-
-/*
-** Create the channel.
-*/
-void
-RCsetup(int i)
-{
-#if defined(SO_REUSEADDR)
- int on;
-#endif /* defined(SO_REUSEADDR) */
- int j;
- CHANNEL *rcchan;
-
- /* This code is called only when inndstart is not being used */
- if (i < 0) {
-#ifdef HAVE_INET6
- syslog(L_FATAL, "%s innd MUST be started with inndstart", LogName);
- exit(1);
-#else
- /* Create a socket and name it. */
- struct sockaddr_in server;
-
- if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
- exit(1);
- }
-#if defined(SO_REUSEADDR)
- on = 1;
- if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on) < 0)
- syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName);
-#endif /* defined(SO_REUSEADDR) */
- memset(&server, 0, sizeof server);
- server.sin_port = htons(innconf->port);
- server.sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_LEN
- server.sin_len = sizeof( struct sockaddr_in );
-#endif
- server.sin_addr.s_addr = htonl(INADDR_ANY);
- if (innconf->bindaddress) {
- if (!inet_aton(innconf->bindaddress, &server.sin_addr)) {
- syslog(L_FATAL, "unable to determine bind ip (%s) %m",
- innconf->bindaddress);
- exit(1);
- }
- }
- if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) {
- syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
- exit(1);
- }
-#endif /* HAVE_INET6 */
- }
-
- /* Set it up to wait for connections. */
- if (listen(i, MAXLISTEN) < 0) {
- j = errno;
- syslog(L_FATAL, "%s cant listen RCreader %m", LogName);
- /* some IPv6 systems already listening on any address will
- return EADDRINUSE when trying to listen on the IPv4 socket */
- if (j == EADDRINUSE)
- return;
- exit(1);
- }
-
- rcchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
- syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(rcchan));
- RCHANadd(rcchan);
-
- for (j = 0 ; j < chanlimit ; j++ ) {
- if (RCchan[j] == NULL) {
- break;
- }
- }
- if (j < chanlimit) {
- RCchan[j] = rcchan;
- } else if (chanlimit == 0) {
- /* assuming two file descriptors(AF_INET and AF_INET6) */
- chanlimit = 2;
- RCchan = xmalloc(chanlimit * sizeof(CHANNEL **));
- for (j = 0 ; j < chanlimit ; j++ ) {
- RCchan[j] = NULL;
- }
- RCchan[0] = rcchan;
- } else {
- /* extend to double size */
- RCchan = xrealloc(RCchan, chanlimit * 2 * sizeof(CHANNEL **));
- for (j = chanlimit ; j < chanlimit * 2 ; j++ ) {
- RCchan[j] = NULL;
- }
- RCchan[chanlimit] = rcchan;
- chanlimit *= 2;
- }
-
- /* Get the list of hosts we handle. */
- RCreadlist();
-}
-
-
-/*
-** Cleanly shut down the channel.
-*/
-void
-RCclose(void)
-{
- REMOTEHOST *rp;
- int i;
-
- for (i = 0 ; i < chanlimit ; i++) {
- if (RCchan[i] != NULL) {
- CHANclose(RCchan[i], CHANname(RCchan[i]));
- } else {
- break;
- }
- }
- if (chanlimit != 0)
- free(RCchan);
- RCchan = NULL;
- chanlimit = 0;
- if (RCpeerlist) {
- for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
- free(rp->Name);
- free(rp->Label);
- free(rp->Email);
- free(rp->Password);
- free(rp->Identd);
- free(rp->Comment);
- if (rp->Patterns) {
- free(rp->Patterns[0]);
- free(rp->Patterns);
- }
- }
- free(RCpeerlist);
- RCpeerlist = NULL;
- RCnpeerlist = 0;
- }
-
- if (RCpeerlistfile) {
- for (i = 0; RCpeerlistfile[i].key != K_END; i++)
- if (RCpeerlistfile[i].value != NULL)
- free(RCpeerlistfile[i].value);
- free(RCpeerlistfile);
- RCpeerlistfile = NULL;
- }
-}
+++ /dev/null
-/* $Id: site.c 7748 2008-04-06 13:49:56Z iulius $
-**
-** Routines to implement site-feeding. Mainly working with channels to
-** do buffering and determine what to send.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-
-static int SITEcount;
-static int SITEhead = NOSITE;
-static int SITEtail = NOSITE;
-static char SITEshell[] = _PATH_SH;
-
-
-/*
-** Called when input is ready to read. Shouldn't happen.
-*/
-static void
-SITEreader(CHANNEL *cp)
-{
- syslog(L_ERROR, "%s internal SITEreader: %s", LogName, CHANname(cp));
-}
-
-
-/*
-** Called when write is done. No-op.
-*/
-static void
-SITEwritedone(CHANNEL *cp UNUSED)
-{
-}
-
-
-/*
-** Make a site start spooling.
-*/
-static bool
-SITEspool(SITE *sp, CHANNEL *cp)
-{
- int i;
- char buff[SPOOLNAMEBUFF];
- char *name;
-
- name = sp->SpoolName;
- i = open(name, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
- if (i < 0 && errno == EISDIR) {
- FileGlue(buff, sp->SpoolName, '/', "togo");
- name = buff;
- i = open(buff, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
- }
- if (i < 0) {
- i = errno;
- syslog(L_ERROR, "%s cant open %s %m", sp->Name, name);
- IOError("site batch file", i);
- sp->Channel = NULL;
- return false;
- }
- if (cp) {
- if (cp->fd >= 0)
- /* syslog(L_ERROR, "DEBUG ERROR SITEspool trashed:%d %s:%d", cp->fd, sp->Name, i);
- CPU-eating bug, killed by kre. */
- WCHANremove(cp);
- RCHANremove(cp);
- SCHANremove(cp);
- close(cp->fd);
- cp->fd = i;
- return true;
- }
- sp->Channel = CHANcreate(i, CTfile, CSwriting, SITEreader, SITEwritedone);
- if (sp->Channel == NULL) {
- syslog(L_ERROR, "%s cant channel %m", sp->Name);
- close(i);
- return false;
- }
- WCHANset(sp->Channel, "", 0);
- sp->Spooling = true;
- return true;
-}
-
-
-/*
-** Delete a site from the file writing list. Can be called even if
-** site is not on the list.
-*/
-static void
-SITEunlink(SITE *sp)
-{
- if (sp->Next != NOSITE || sp->Prev != NOSITE
- || (SITEhead != NOSITE && sp == &Sites[SITEhead]))
- SITEcount--;
-
- if (sp->Next != NOSITE)
- Sites[sp->Next].Prev = sp->Prev;
- else if (SITEtail != NOSITE && sp == &Sites[SITEtail])
- SITEtail = sp->Prev;
-
- if (sp->Prev != NOSITE)
- Sites[sp->Prev].Next = sp->Next;
- else if (SITEhead != NOSITE && sp == &Sites[SITEhead])
- SITEhead = sp->Next;
-
- sp->Next = sp->Prev = NOSITE;
-}
-
-
-/*
-** Find the oldest "file feed" site and buffer it.
-*/
-static void
-SITEbufferoldest(void)
-{
- SITE *sp;
- struct buffer *bp;
- struct buffer *out;
-
- /* Get the oldest user of a file. */
- if (SITEtail == NOSITE) {
- syslog(L_ERROR, "%s internal no oldest site found", LogName);
- SITEcount = 0;
- return;
- }
-
- sp = &Sites[SITEtail];
- SITEunlink(sp);
-
- if (sp->Buffered) {
- syslog(L_ERROR, "%s internal oldest (%s) was buffered", LogName,
- sp->Name);
- return;
- }
-
- if (sp->Type != FTfile) {
- syslog(L_ERROR, "%s internal oldest (%s) not FTfile", LogName,
- sp->Name);
- return;
- }
-
- /* Write out what we can. */
- WCHANflush(sp->Channel);
-
- /* Get a buffer for the site. */
- sp->Buffered = true;
- bp = &sp->Buffer;
- bp->used = 0;
- bp->left = 0;
- if (bp->size == 0) {
- bp->size = sp->Flushpoint;
- bp->data = xmalloc(bp->size);
- }
- else {
- bp->size = sp->Flushpoint;
- bp->data = xrealloc(bp->data, bp->size);
- }
-
- /* If there's any unwritten data, copy it. */
- out = &sp->Channel->Out;
- if (out->left) {
- buffer_set(bp, &out->data[out->used], out->left);
- out->left = 0;
- }
-
- /* Now close the original channel. */
- CHANclose(sp->Channel, sp->Name);
- sp->Channel = NULL;
-}
-
-/*
- * * Bilge Site's Channel out buffer.
- */
-static bool
-SITECHANbilge(SITE *sp)
-{
- int fd;
- int i;
- char buff[SPOOLNAMEBUFF];
- char *name;
-
- name = sp->SpoolName;
- fd = open(name, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
- if (fd < 0 && errno == EISDIR) {
- FileGlue(buff, sp->SpoolName, '/', "togo");
- name = buff;
- fd = open(buff, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
- }
- if (fd < 0) {
- int oerrno = errno ;
- syslog(L_ERROR, "%s cant open %s %m", sp->Name, name);
- IOError("site batch file",oerrno);
- sp->Channel = NULL;
- return false;
- }
- while (sp->Channel->Out.left > 0) {
- i = write(fd, &sp->Channel->Out.data[sp->Channel->Out.used],
- sp->Channel->Out.left);
- if(i <= 0) {
- syslog(L_ERROR,"%s cant spool count %lu", CHANname(sp->Channel),
- (unsigned long) sp->Channel->Out.left);
- close(fd);
- return false;
- }
- sp->Channel->Out.left -= i;
- sp->Channel->Out.used += i;
- }
- close(fd);
- free(sp->Channel->Out.data);
- sp->Channel->Out.data = xmalloc(SMBUF);
- sp->Channel->Out.size = SMBUF;
- sp->Channel->Out.left = 0;
- sp->Channel->Out.used = 0;
- return true;
-}
-
-/*
-** Check if we need to write out the site's buffer. If we're buffered
-** or the feed is backed up, this gets a bit complicated.
-*/
-static void
-SITEflushcheck(SITE *sp, struct buffer *bp)
-{
- int i;
- CHANNEL *cp;
-
- /* If we're buffered, and we hit the flushpoint, do an LRU. */
- if (sp->Buffered) {
- if (bp->left < sp->Flushpoint)
- return;
- while (SITEcount >= MaxOutgoing)
- SITEbufferoldest();
- if (!SITEsetup(sp) || sp->Buffered) {
- syslog(L_ERROR, "%s cant unbuffer %m", sp->Name);
- return;
- }
- WCHANsetfrombuffer(sp->Channel, bp);
- WCHANadd(sp->Channel);
- /* Reset buffer; data has been moved. */
- buffer_set(bp, "", 0);
- }
-
- if (PROCneedscan)
- PROCscan();
-
- /* Handle buffering. */
- cp = sp->Channel;
- i = cp->Out.left;
- if (i < sp->StopWriting)
- WCHANremove(cp);
- if ((sp->StartWriting == 0 || i > sp->StartWriting)
- && !CHANsleeping(cp)) {
- if (sp->Type == FTchannel) { /* channel feed, try the write */
- int j;
- if (bp->left == 0)
- return;
- j = write(cp->fd, &bp->data[bp->used], bp->left);
- if (j > 0) {
- bp->left -= j;
- bp->used += j;
- i = cp->Out.left;
- /* Since we just had a successful write, we need to clear the
- * channel's error counts. - dave@jetcafe.org */
- cp->BadWrites = 0;
- cp->BlockedWrites = 0;
- }
- if (bp->left <= 0) {
- /* reset Used, Left on bp, keep channel buffer size from
- exploding. */
- bp->used = bp->left = 0;
- WCHANremove(cp);
- } else
- WCHANadd(cp);
- }
- else
- WCHANadd(cp);
- }
-
- cp->LastActive = Now.time;
-
- /* If we're a channel that's getting big, see if we need to spool. */
- if (sp->Type == FTfile || sp->StartSpooling == 0 || i < sp->StartSpooling)
- return;
-
- syslog(L_ERROR, "%s spooling %d bytes", sp->Name, i);
- if(!SITECHANbilge(sp)) {
- syslog(L_ERROR, "%s overflow %d bytes", sp->Name, i);
- return;
- }
-}
-
-
-/*
-** Send a control line to an exploder.
-*/
-void
-SITEwrite(SITE *sp, const char *text)
-{
- static char PREFIX[] = { EXP_CONTROL, '\0' };
- struct buffer *bp;
-
- if (sp->Buffered)
- bp = &sp->Buffer;
- else {
- if (sp->Channel == NULL)
- return;
- sp->Channel->LastActive = Now.time;
- bp = &sp->Channel->Out;
- }
- buffer_append(bp, PREFIX, strlen(PREFIX));
- buffer_append(bp, text, strlen(text));
- buffer_append(bp, "\n", 1);
- if (sp->Channel != NULL)
- WCHANadd(sp->Channel);
-}
-
-
-/*
-** Send the desired data about an article down a channel.
-*/
-static void
-SITEwritefromflags(SITE *sp, ARTDATA *Data)
-{
- HDRCONTENT *hc = Data->HdrContent;
- static char ITEMSEP[] = " ";
- static char NL[] = "\n";
- char pbuff[12];
- char *p;
- bool Dirty;
- struct buffer *bp;
- SITE *spx;
- int i;
-
- if (sp->Buffered)
- bp = &sp->Buffer;
- else {
- /* This should not happen, but if we tried to spool and failed,
- * e.g., because of a bad F param for this site, we can get
- * into this state. We already logged a message so give up. */
- if (sp->Channel == NULL)
- return;
- bp = &sp->Channel->Out;
- }
- for (Dirty = false, p = sp->FileFlags; *p; p++) {
- switch (*p) {
- default:
- syslog(L_ERROR, "%s internal SITEwritefromflags %c", sp->Name, *p);
- continue;
- case FEED_BYTESIZE:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->Bytes + sizeof("Bytes: ") - 1,
- Data->BytesLength);
- break;
- case FEED_FULLNAME:
- case FEED_NAME:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->TokenText, sizeof(TOKEN) * 2 + 2);
- break;
- case FEED_HASH:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, "[", 1);
- buffer_append(bp, HashToText(*(Data->Hash)), sizeof(HASH)*2);
- buffer_append(bp, "]", 1);
- break;
- case FEED_HDR_DISTRIB:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, HDR(HDR__DISTRIBUTION),
- HDR_LEN(HDR__DISTRIBUTION));
- break;
- case FEED_HDR_NEWSGROUP:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, HDR(HDR__NEWSGROUPS), HDR_LEN(HDR__NEWSGROUPS));
- break;
- case FEED_HEADERS:
- if (Dirty)
- buffer_append(bp, NL, strlen(NL));
- buffer_append(bp, Data->Headers.data, Data->Headers.left);
- break;
- case FEED_OVERVIEW:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->Overview.data, Data->Overview.left);
- break;
- case FEED_PATH:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- if (!Data->Hassamepath || Data->AddAlias || Pathcluster.used) {
- if (Pathcluster.used)
- buffer_append(bp, Pathcluster.data, Pathcluster.used);
- buffer_append(bp, Path.data, Path.used);
- if (Data->AddAlias)
- buffer_append(bp, Pathalias.data, Pathalias.used);
- }
- if (Data->Hassamecluster)
- buffer_append(bp, HDR(HDR__PATH) + Pathcluster.used,
- HDR_LEN(HDR__PATH) - Pathcluster.used);
- else
- buffer_append(bp, HDR(HDR__PATH), HDR_LEN(HDR__PATH));
- break;
- case FEED_REPLIC:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->Replic, Data->ReplicLength);
- break;
- case FEED_STOREDGROUP:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->Newsgroups.List[0],
- Data->StoredGroupLength);
- break;
- case FEED_TIMERECEIVED:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- snprintf(pbuff, sizeof(pbuff), "%ld", (long) Data->Arrived);
- buffer_append(bp, pbuff, strlen(pbuff));
- break;
- case FEED_TIMEPOSTED:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- snprintf(pbuff, sizeof(pbuff), "%ld", (long) Data->Posted);
- buffer_append(bp, pbuff, strlen(pbuff));
- break;
- case FEED_TIMEEXPIRED:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- snprintf(pbuff, sizeof(pbuff), "%ld", (long) Data->Expires);
- buffer_append(bp, pbuff, strlen(pbuff));
- break;
- case FEED_MESSAGEID:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, HDR(HDR__MESSAGE_ID), HDR_LEN(HDR__MESSAGE_ID));
- break;
- case FEED_FNLNAMES:
- if (sp->FNLnames.data) {
- /* Funnel; write names of our sites that got it. */
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, sp->FNLnames.data, sp->FNLnames.used);
- }
- else {
- /* Not funnel; write names of all sites that got it. */
- for (spx = Sites, i = nSites; --i >= 0; spx++)
- if (spx->Sendit) {
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, spx->Name, spx->NameLength);
- Dirty = true;
- }
- }
- break;
- case FEED_NEWSGROUP:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- if (sp->ng)
- buffer_append(bp, sp->ng->Name, sp->ng->NameLength);
- else
- buffer_append(bp, "?", 1);
- break;
- case FEED_SITE:
- if (Dirty)
- buffer_append(bp, ITEMSEP, strlen(ITEMSEP));
- buffer_append(bp, Data->Feedsite, Data->FeedsiteLength);
- break;
- }
- Dirty = true;
- }
- if (Dirty) {
- buffer_append(bp, "\n", 1);
- SITEflushcheck(sp, bp);
- }
-}
-
-
-/*
-** Send one article to a site.
-*/
-void
-SITEsend(SITE *sp, ARTDATA *Data)
-{
- int i;
- char *p;
- char *temp;
- char buff[BUFSIZ];
- char * argv[MAX_BUILTIN_ARGV];
-
- switch (sp->Type) {
- default:
- syslog(L_ERROR, "%s internal SITEsend type %d", sp->Name, sp->Type);
- break;
- case FTlogonly:
- break;
- case FTfunnel:
- syslog(L_ERROR, "%s funnel_send", sp->Name);
- break;
- case FTfile:
- case FTchannel:
- case FTexploder:
- SITEwritefromflags(sp, Data);
- break;
- case FTprogram:
- /* Set up the argument vector. */
- if (sp->FNLwantsnames) {
- i = strlen(sp->Param) + sp->FNLnames.used;
- if (i + (sizeof(TOKEN) * 2) + 3 >= sizeof buff) {
- syslog(L_ERROR, "%s toolong need %lu for %s",
- sp->Name, (unsigned long) (i + (sizeof(TOKEN) * 2) + 3),
- sp->Name);
- break;
- }
- temp = xmalloc(i + 1);
- p = strchr(sp->Param, '*');
- *p = '\0';
- strlcpy(temp, sp->Param, i + 1);
- strlcat(temp, sp->FNLnames.data, i + 1);
- strlcat(temp, &p[1], i + 1);
- *p = '*';
- snprintf(buff, sizeof(buff), temp, Data->TokenText);
- free(temp);
- }
- else
- snprintf(buff, sizeof(buff), sp->Param, Data->TokenText);
-
- if (NeedShell(buff, (const char **)argv, (const char **)ARRAY_END(argv))) {
- argv[0] = SITEshell;
- argv[1] = (char *) "-c";
- argv[2] = buff;
- argv[3] = NULL;
- }
-
- /* Start the process. */
- i = Spawn(sp->Nice, 0, (int)fileno(Errlog), (int)fileno(Errlog), argv);
- if (i >= 0)
- PROCwatch(i, -1);
- break;
- }
-}
-
-
-/*
-** The channel was sleeping because we had to spool our output to
-** a file. Flush and restart.
-*/
-static void
-SITEspoolwake(CHANNEL *cp)
-{
- SITE *sp;
- int *ip;
-
- ip = (int *) cp->Argument;
- sp = &Sites[*ip];
- free(cp->Argument);
- cp->Argument = NULL;
- if (sp->Channel != cp) {
- syslog(L_ERROR, "%s internal SITEspoolwake %s got %d, not %d",
- LogName, sp->Name, cp->fd, sp->Channel->fd);
- return;
- }
- syslog(L_NOTICE, "%s spoolwake", sp->Name);
- SITEflush(sp, true);
-}
-
-
-/*
-** Start up a process for a channel, or a spool to a file if we can't.
-** Create a channel for the site to talk to.
-*/
-static bool
-SITEstartprocess(SITE *sp)
-{
- pid_t i;
- char *argv[MAX_BUILTIN_ARGV];
- char *process;
- int *ip;
- int pan[2];
-
-#if HAVE_SOCKETPAIR
- /* Create a socketpair. */
- if (socketpair(PF_UNIX, SOCK_STREAM, 0, pan) < 0) {
- syslog(L_ERROR, "%s cant socketpair %m", sp->Name);
- return false;
- }
-#else
- /* Create a pipe. */
- if (pipe(pan) < 0) {
- syslog(L_ERROR, "%s cant pipe %m", sp->Name);
- return false;
- }
-#endif
- close_on_exec(pan[PIPE_WRITE], true);
-
- /* Set up the argument vector. */
- process = xstrdup(sp->Param);
- if (NeedShell(process, (const char **)argv, (const char **)ARRAY_END(argv))) {
- argv[0] = SITEshell;
- argv[1] = (char *) "-c";
- argv[2] = process;
- argv[3] = NULL;
- }
-
- /* Fork a child. */
- i = Spawn(sp->Nice, pan[PIPE_READ], (int)fileno(Errlog),
- (int)fileno(Errlog), argv);
- if (i > 0) {
- sp->pid = i;
- sp->Spooling = false;
- sp->Process = PROCwatch(i, sp - Sites);
- close(pan[PIPE_READ]);
- sp->Channel = CHANcreate(pan[PIPE_WRITE],
- sp->Type == FTchannel ? CTprocess : CTexploder,
- CSwriting, SITEreader, SITEwritedone);
- free(process);
- return true;
- }
-
- /* Error. Switch to spooling. */
- syslog(L_ERROR, "%s cant spawn spooling %m", sp->Name);
- close(pan[PIPE_WRITE]);
- close(pan[PIPE_READ]);
- free(process);
- if (!SITEspool(sp, (CHANNEL *)NULL))
- return false;
-
- /* We'll try to restart the channel later. */
- syslog(L_ERROR, "%s cant spawn spooling %m", sp->Name);
- ip = xmalloc(sizeof(int));
- *ip = sp - Sites;
- SCHANadd(sp->Channel, Now.time + innconf->chanretrytime, NULL,
- SITEspoolwake, ip);
- return true;
-}
-
-
-/*
-** Set up a site for internal buffering.
-*/
-static void
-SITEbuffer(SITE *sp)
-{
- struct buffer *bp;
-
- SITEunlink(sp);
- sp->Buffered = true;
- sp->Channel = NULL;
- bp = &sp->Buffer;
- buffer_resize(bp, sp->Flushpoint);
- buffer_set(bp, "", 0);
- syslog(L_NOTICE, "%s buffered", sp->Name);
-}
-
-
-/*
-** Link a site at the head of the "currently writing to a file" list
-*/
-static void
-SITEmovetohead(SITE *sp)
-{
- if ((SITEhead == NOSITE) && ((sp->Next != NOSITE) || (sp->Prev != NOSITE)))
- SITEunlink(sp);
-
- if ((sp->Next = SITEhead) != NOSITE)
- Sites[SITEhead].Prev = sp - Sites;
- sp->Prev = NOSITE;
-
- SITEhead = sp - Sites;
- if (SITEtail == NOSITE)
- SITEtail = sp - Sites;
-
- SITEcount++;
-}
-
-
-/*
-** Set up a site's feed. This means opening a file or channel if needed.
-*/
-bool
-SITEsetup(SITE *sp)
-{
- int fd;
- int oerrno;
-
- switch (sp->Type) {
- default:
- syslog(L_ERROR, "%s internal SITEsetup %d",
- sp->Name, sp->Type);
- return false;
- case FTfunnel:
- case FTlogonly:
- case FTprogram:
- /* Nothing to do here. */
- break;
- case FTfile:
- if (SITEcount >= MaxOutgoing)
- SITEbuffer(sp);
- else {
- sp->Buffered = false;
- fd = open(sp->Param, O_APPEND | O_CREAT | O_WRONLY, BATCHFILE_MODE);
- if (fd < 0) {
- if (errno == EMFILE) {
- syslog(L_ERROR, "%s cant open %s %m", sp->Name, sp->Param);
- SITEbuffer(sp);
- break;
- }
- oerrno = errno;
- syslog(L_NOTICE, "%s cant open %s %m", sp->Name, sp->Param);
- IOError("site file", oerrno);
- return false;
- }
- SITEmovetohead(sp);
- sp->Channel = CHANcreate(fd, CTfile, CSwriting,
- SITEreader, SITEwritedone);
- syslog(L_NOTICE, "%s opened %s", sp->Name, CHANname(sp->Channel));
- WCHANset(sp->Channel, "", 0);
- }
- break;
- case FTchannel:
- case FTexploder:
- if (!SITEstartprocess(sp))
- return false;
- syslog(L_NOTICE, "%s spawned %s", sp->Name, CHANname(sp->Channel));
- WCHANset(sp->Channel, "", 0);
- WCHANadd(sp->Channel);
- break;
- }
- return true;
-}
-
-
-/*
-** A site's channel process died; restart it.
-*/
-void
-SITEprocdied(SITE *sp, int process, PROCESS *pp)
-{
- syslog(pp->Status ? L_ERROR : L_NOTICE, "%s exit %d elapsed %ld pid %ld",
- sp->Name ? sp->Name : "?", pp->Status,
- (long) (pp->Collected - pp->Started), (long) pp->Pid);
- if (sp->Process != process || sp->Name == NULL)
- /* We already started a new process for this channel
- * or this site has been dropped. */
- return;
- if (sp->Channel != NULL)
- CHANclose(sp->Channel, CHANname(sp->Channel));
- sp->Working = SITEsetup(sp);
- if (!sp->Working) {
- syslog(L_ERROR, "%s cant restart %m", sp->Name);
- return;
- }
- syslog(L_NOTICE, "%s restarted", sp->Name);
-}
-
-/*
-** A channel is about to be closed; see if any site cares.
-*/
-void
-SITEchanclose(CHANNEL *cp)
-{
- int i;
- SITE *sp;
- int *ip;
-
- for (i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Channel == cp) {
- /* Found the site that has this channel. Start that
- * site spooling, copy any data that might be pending,
- * and arrange to retry later. */
- if (!SITEspool(sp, (CHANNEL *)NULL)) {
- syslog(L_ERROR, "%s loss %lu bytes", sp->Name,
- (unsigned long) cp->Out.left);
- return;
- }
- WCHANsetfrombuffer(sp->Channel, &cp->Out);
- WCHANadd(sp->Channel);
- ip = xmalloc(sizeof(int));
- *ip = sp - Sites;
- SCHANadd(sp->Channel, Now.time + innconf->chanretrytime, NULL,
- SITEspoolwake, ip);
- break;
- }
-}
-
-
-/*
-** Flush any pending data waiting to be sent.
-*/
-void
-SITEflush(SITE *sp, const bool Restart)
-{
- CHANNEL *cp;
- struct buffer *out;
- int count;
-
- if (sp->Name == NULL)
- return;
-
- if (Restart)
- SITEforward(sp, "flush");
-
- switch (sp->Type) {
- default:
- syslog(L_ERROR, "%s internal SITEflush %d", sp->Name, sp->Type);
- return;
-
- case FTlogonly:
- case FTprogram:
- case FTfunnel:
- /* Nothing to do here. */
- return;
-
- case FTchannel:
- case FTexploder:
- /* If spooling, close the file right now -- documented behavior. */
- if (sp->Spooling && (cp = sp->Channel) != NULL) {
- WCHANflush(cp);
- CHANclose(cp, CHANname(cp));
- sp->Channel = NULL;
- }
- break;
-
- case FTfile:
- /* We must ensure we have a file open for this site, so if
- * we're buffered we HACK and pretend we have no sites
- * for a moment. */
- if (sp->Buffered) {
- count = SITEcount;
- SITEcount = 0;
- if (!SITEsetup(sp) || sp->Buffered)
- syslog(L_ERROR, "%s cant unbuffer to flush", sp->Name);
- else
- buffer_swap(&sp->Buffer, &sp->Channel->Out);
- SITEcount += count;
- }
- break;
- }
-
- /* We're only dealing with files and channels now. */
- if ((cp = sp->Channel) != NULL)
- WCHANflush(cp);
-
- /* Restart the site, copy any pending data. */
- if (Restart) {
- if (!SITEsetup(sp))
- syslog(L_ERROR, "%s cant restart %m", sp->Name);
- else if (cp != NULL) {
- if (sp->Buffered) {
- /* SITEsetup had to buffer us; save any residue. */
- out = &cp->Out;
- if (out->left)
- buffer_set(&sp->Buffer, &out->data[out->used], out->left);
- }
- else
- WCHANsetfrombuffer(sp->Channel, &cp->Out);
- }
- }
- else if (cp != NULL && cp->Out.left) {
- if (sp->Type == FTfile || sp->Spooling) {
- /* Can't flush a file? Hopeless. */
- syslog(L_ERROR, "%s dataloss %lu", sp->Name,
- (unsigned long) cp->Out.left);
- return;
- }
- /* Must be a working channel; spool and retry. */
- syslog(L_ERROR, "%s spooling %lu bytes", sp->Name,
- (unsigned long) cp->Out.left);
- if (SITEspool(sp, cp))
- SITEflush(sp, false);
- return;
- }
-
- /* Close the old channel if it was open. */
- if (cp != NULL) {
- /* Make sure we have no dangling pointers to it. */
- if (!Restart)
- sp->Channel = NULL;
- CHANclose(cp, sp->Name);
- if (sp->Type == FTfile)
- SITEunlink(sp);
- }
-}
-
-
-/*
-** Flush all sites.
-*/
-void
-SITEflushall(const bool Restart)
-{
- int i;
- SITE *sp;
-
- for (i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Name)
- SITEflush(sp, Restart);
-}
-
-
-/*
-** Run down the site's pattern list and see if it wants the specified
-** newsgroup.
-*/
-bool
-SITEwantsgroup(SITE *sp, char *name)
-{
- bool match;
- bool subvalue;
- char *pat;
- char **argv;
-
- match = SUB_DEFAULT;
- if (ME.Patterns) {
- for (argv = ME.Patterns; (pat = *argv++) != NULL; ) {
- subvalue = *pat != SUB_NEGATE && *pat != SUB_POISON;
- if (!subvalue)
- pat++;
- if ((match != subvalue) && uwildmat(name, pat))
- match = subvalue;
- }
- }
- for (argv = sp->Patterns; (pat = *argv++) != NULL; ) {
- subvalue = *pat != SUB_NEGATE && *pat != SUB_POISON;
- if (!subvalue)
- pat++;
- if ((match != subvalue) && uwildmat(name, pat))
- match = subvalue;
- }
- return match;
-}
-
-
-/*
-** Run down the site's pattern list and see if specified newsgroup is
-** considered poison.
-*/
-bool
-SITEpoisongroup(SITE *sp, char *name)
-{
- bool match;
- bool poisonvalue;
- char *pat;
- char **argv;
-
- match = SUB_DEFAULT;
- if (ME.Patterns) {
- for (argv = ME.Patterns; (pat = *argv++) != NULL; ) {
- poisonvalue = *pat == SUB_POISON;
- if (*pat == SUB_NEGATE || *pat == SUB_POISON)
- pat++;
- if (uwildmat(name, pat))
- match = poisonvalue;
- }
- }
- for (argv = sp->Patterns; (pat = *argv++) != NULL; ) {
- poisonvalue = *pat == SUB_POISON;
- if (*pat == SUB_NEGATE || *pat == SUB_POISON)
- pat++;
- if (uwildmat(name, pat))
- match = poisonvalue;
- }
- return match;
-}
-
-
-/*
-** Find a site.
-*/
-SITE *
-SITEfind(const char *p)
-{
- int i;
- SITE *sp;
-
- for (i = nSites, sp = Sites; --i >= 0; sp++)
- if (sp->Name && strcasecmp(p, sp->Name) == 0)
- return sp;
- return NULL;
-}
-
-
-/*
-** Find the next site that matches this site.
-*/
-SITE *
-SITEfindnext(const char *p, SITE *sp)
-{
- SITE *end;
-
- for (sp++, end = &Sites[nSites]; sp < end; sp++)
- if (sp->Name && strcasecmp(p, sp->Name) == 0)
- return sp;
- return NULL;
-}
-
-
-/*
-** Close a site down.
-*/
-void
-SITEfree(SITE *sp)
-{
- SITE *s;
- HASHFEEDLIST *hf, *hn;
- int new;
- int i;
-
- if (sp->Channel) {
- CHANclose(sp->Channel, CHANname(sp->Channel));
- sp->Channel = NULL;
- }
-
- SITEunlink(sp);
-
- sp->Name = NULL;
- if (sp->Process > 0) {
- /* Kill the backpointer so PROCdied won't call us. */
- PROCunwatch(sp->Process);
- sp->Process = -1;
- }
- if (sp->Entry) {
- free(sp->Entry);
- sp->Entry = NULL;
- }
- if (sp->Originator) {
- free(sp->Originator);
- sp->Originator = NULL;
- }
- if (sp->Param) {
- free(sp->Param);
- sp->Param = NULL;
- }
- if (sp->SpoolName) {
- free(sp->SpoolName);
- sp->SpoolName = NULL;
- }
- if (sp->Patterns) {
- free(sp->Patterns);
- sp->Patterns = NULL;
- }
- if (sp->Exclusions) {
- free(sp->Exclusions);
- sp->Exclusions = NULL;
- }
- if (sp->Distributions) {
- free(sp->Distributions);
- sp->Distributions = NULL;
- }
- if (sp->Buffer.data) {
- free(sp->Buffer.data);
- sp->Buffer.data = NULL;
- sp->Buffer.size = 0;
- }
- if (sp->FNLnames.data) {
- free(sp->FNLnames.data);
- sp->FNLnames.data = NULL;
- sp->FNLnames.size = 0;
- }
- if (sp->HashFeedList) {
- for (hf = sp->HashFeedList; hf; hf = hn) {
- hn = hf->next;
- free(hf);
- }
- sp->HashFeedList = NULL;
- }
-
- /* If this site was a master, find a new one. */
- if (sp->IsMaster) {
- for (new = NOSITE, s = Sites, i = nSites; --i >= 0; s++)
- if (&Sites[s->Master] == sp) {
- if (new == NOSITE) {
- s->Master = NOSITE;
- s->IsMaster = true;
- new = s - Sites;
- }
- else
- s->Master = new;
- }
- sp->IsMaster = false;
- }
-}
-
-
-/*
-** If a site is an exploder or funnels into one, forward a command
-** to it.
-*/
-void
-SITEforward(SITE *sp, const char *text)
-{
- SITE *fsp;
- char buff[SMBUF];
-
- fsp = sp;
- if (fsp->Funnel != NOSITE)
- fsp = &Sites[fsp->Funnel];
- if (sp->Name == NULL || fsp->Name == NULL)
- return;
- if (fsp->Type == FTexploder) {
- strlcpy(buff, text, sizeof(buff));
- if (fsp != sp && fsp->FNLwantsnames) {
- strlcat(buff, " ", sizeof(buff));
- strlcat(buff, sp->Name, sizeof(buff));
- }
- SITEwrite(fsp, buff);
- }
-}
-
-
-/*
-** Drop a site.
-*/
-void
-SITEdrop(SITE *sp)
-{
- SITEforward(sp, "drop");
- SITEflush(sp, false);
- SITEfree(sp);
-}
-
-
-/*
-** Append info about the current state of the site to the buffer
-*/
-void
-SITEinfo(struct buffer *bp, SITE *sp, const bool Verbose)
-{
- static char FREESITE[] = "<<No name>>\n\n";
- char *p;
- CHANNEL *cp;
- const char *sep;
- char buff[BUFSIZ];
-
- if (sp->Name == NULL) {
- buffer_append(bp, FREESITE, strlen(FREESITE));
- return;
- }
-
- p = buff;
- snprintf(buff, sizeof(buff), "%s%s:\t", sp->Name,
- sp->IsMaster ? "(*)" : "");
- p += strlen(p);
-
- if (sp->Type == FTfunnel) {
- sp = &Sites[sp->Funnel];
- sprintf(p, "funnel -> %s: ", sp->Name);
- p += strlen(p);
- }
-
- switch (sp->Type) {
- default:
- sprintf(p, "unknown feed type %d", sp->Type);
- p += strlen(p);
- break;
- case FTerror:
- case FTfile:
- p += strlen(strcpy(p, "file"));
- if (sp->Buffered) {
- sprintf(p, " buffered(%lu)", (unsigned long) sp->Buffer.left);
- p += strlen(p);
- }
- else if ((cp = sp->Channel) == NULL)
- p += strlen(strcpy(p, " no channel?"));
- else {
- sprintf(p, " open fd=%d, in mem %lu", cp->fd,
- (unsigned long) cp->Out.left);
- p += strlen(p);
- }
- break;
- case FTchannel:
- p += strlen(strcpy(p, "channel"));
- goto Common;
- case FTexploder:
- p += strlen(strcpy(p, "exploder"));
-Common:
- if (sp->Process >= 0) {
- sprintf(p, " pid=%ld", (long) sp->pid);
- p += strlen(p);
- }
- if (sp->Spooling)
- p += strlen(strcpy(p, " spooling"));
- if ((cp = sp->Channel) == NULL)
- p += strlen(strcpy(p, " no channel?"));
- else {
- sprintf(p, " fd=%d, in mem %lu", cp->fd,
- (unsigned long) cp->Out.left);
- p += strlen(p);
- }
- break;
- case FTfunnel:
- p += strlen(strcpy(p, "recursive funnel"));
- break;
- case FTlogonly:
- p += strlen(strcpy(p, "log only"));
- break;
- case FTprogram:
- p += strlen(strcpy(p, "program"));
- if (sp->FNLwantsnames)
- p += strlen(strcpy(p, " with names"));
- break;
- }
- *p++ = '\n';
- if (Verbose) {
- sep = "\t";
- if (sp->Buffered && sp->Flushpoint) {
- sprintf(p, "%sFlush @ %ld", sep, sp->Flushpoint);
- p += strlen(p);
- sep = "; ";
- }
- if (sp->StartWriting || sp->StopWriting) {
- sprintf(p, "%sWrite [%ld..%ld]", sep,
- sp->StopWriting, sp->StartWriting);
- p += strlen(p);
- sep = "; ";
- }
- if (sp->StartSpooling) {
- sprintf(p, "%sSpool @ %ld", sep, sp->StartSpooling);
- p += strlen(p);
- sep = "; ";
- }
- if (sep[0] != '\t')
- *p++ = '\n';
- if (sp->Spooling && sp->SpoolName) {
- sprintf(p, "\tSpooling to \"%s\"\n", sp->SpoolName);
- p += strlen(p);
- }
- if ((cp = sp->Channel) != NULL) {
- sprintf(p, "\tChannel created %.12s",
- ctime(&cp->Started) + 4);
- p += strlen(p);
- sprintf(p, ", last active %.12s\n",
- ctime(&cp->LastActive) + 4);
- p += strlen(p);
- if (cp->Waketime > Now.time) {
- sprintf(p, "\tSleeping until %.12s\n",
- ctime(&cp->Waketime) + 4);
- p += strlen(p);
- }
- }
-
- }
- buffer_append(bp, buff, p - buff);
-}
+++ /dev/null
-/* $Id: status.c 7547 2006-08-26 06:18:14Z eagle $
-**
-** Periodic status reporting.
-*/
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-#include "innperl.h"
-
-#define MIN_REFRESH 60 /* 1 min */
-#define HTML_STATUS
-#if defined(HTML_STATUS)
-#define STATUS_FILE "inn_status.html" /* will be in pathhttp */
-#else
-#define STATUS_FILE "inn.status" /* will be in pathlog */
-#endif
-
-typedef struct _STATUS {
- char name[SMBUF];
- char ip_addr[64];
- bool can_stream;
- unsigned short activeCxn;
- unsigned short sleepingCxns;
- time_t seconds;
- unsigned long accepted;
- unsigned long refused;
- unsigned long rejected;
- unsigned long Duplicate;
- unsigned long Unwanted_u;
- unsigned long Unwanted_d;
- unsigned long Unwanted_g;
- unsigned long Unwanted_s;
- unsigned long Unwanted_f;
- float Size;
- float DuplicateSize;
- unsigned long Check;
- unsigned long Check_send;
- unsigned long Check_deferred;
- unsigned long Check_got;
- unsigned long Check_cybercan;
- unsigned long Takethis;
- unsigned long Takethis_Ok;
- unsigned long Takethis_Err;
- unsigned long Ihave;
- unsigned long Ihave_Duplicate;
- unsigned long Ihave_Deferred;
- unsigned long Ihave_SendIt;
- unsigned long Ihave_Cybercan;
- struct _STATUS *next;
-} STATUS;
-
-static unsigned STATUSlast_time;
-char start_time[50];
-
-static unsigned
-STATUSgettime(void)
-{
- static int init = 0;
- static struct timeval start_tv;
- struct timeval tv;
-
- if (!init) {
- gettimeofday(&start_tv, NULL);
- init++;
- }
- gettimeofday(&tv, NULL);
- return((tv.tv_sec - start_tv.tv_sec) * 1000 +
- (tv.tv_usec - start_tv.tv_usec) / 1000);
-}
-
-void
-STATUSinit(void)
-{
- time_t now;
-
- STATUSlast_time = STATUSgettime(); /* First invocation */
- now = time (NULL) ;
- strlcpy(start_time, ctime(&now), sizeof(start_time));
-}
-
-static char *
-PrettySize(float size, char *str)
-{
- if (size > 1073741824) /* 1024*1024*1024 */
- sprintf (str, "%.1fGb", size / 1073741824.);
- else
- if (size > 1048576) /* 1024*1024 */
- sprintf (str, "%.1fMb", size / 1048576.);
- else
- sprintf (str, "%.1fkb", size / 1024.);
- return (str);
-}
-
-static void
-STATUSsummary(void)
-{
- FILE *F;
- int i, j;
- CHANNEL *cp;
- int activeCxn = 0;
- int sleepingCxns = 0;
- time_t seconds = 0;
- unsigned long duplicate = 0;
- unsigned long offered;
- unsigned long accepted = 0;
- unsigned long refused = 0;
- unsigned long rejected = 0;
- float size = 0;
- float DuplicateSize = 0;
- int peers = 0;
- char TempString[SMBUF];
- char *path;
- STATUS *head, *status, *tmp;
- char str[9];
- time_t now;
-
-#if defined(HTML_STATUS)
- path = concatpath(innconf->pathhttp, STATUS_FILE);
-#else
- path = concatpath(innconf->pathlog, STATUS_FILE);
-#endif
- if ((F = Fopen(path, "w", TEMPORARYOPEN)) == NULL) {
- syslog(L_ERROR, "%s cannot open %s: %m", LogName, path);
- return;
- }
-
-#if defined(HTML_STATUS)
- /* HTML Header */
-
- fprintf (F,"<HTML>\n<HEAD>\n<META HTTP-EQUIV=\"Refresh\" CONTENT=\"%ld;\">\n",
- innconf->status < MIN_REFRESH ? MIN_REFRESH : innconf->status);
- fprintf (F, "<TITLE>%s: incoming feeds</TITLE>\n", innconf->pathhost);
- fprintf (F, "</HEAD>\n<BODY>\n<PRE>\n") ;
-#endif /* defined(HTML_STATUS) */
-
- fprintf (F, "%s\n", inn_version_string);
- fprintf (F, "pid %d started %s\n", (int) getpid(), start_time);
-
- tmp = head = NULL;
- for (i = 0; (cp = CHANiter(&i, CTnntp)) != NULL; ) {
- j = 0;
- strlcpy(TempString,
- cp->Address.ss_family == 0 ? "localhost" : RChostname(cp),
- sizeof(TempString));
- for (status = head ; status != NULL ; status = status->next) {
- if (strcmp(TempString, status->name) == 0)
- break;
- }
- if (status == NULL) {
- status = xmalloc(sizeof(STATUS));
- peers++; /* a new peer */
- strlcpy(status->name, TempString, sizeof(status->name));
- if (cp->Address.ss_family == 0) {
- /* Connections from lc.c do not have an IP address. */
- memset(&status->ip_addr, 0, sizeof(status->ip_addr));
- } else {
- strlcpy(status->ip_addr,
- sprint_sockaddr((struct sockaddr *)&cp->Address),
- sizeof(status->ip_addr));
- }
- status->can_stream = cp->Streaming;
- status->seconds = status->Size = status->DuplicateSize = 0;
- status->Ihave = status->Ihave_Duplicate =
- status->Ihave_Deferred = status->Ihave_SendIt =
- status->Ihave_Cybercan = 0;
- status->Check = status->Check_send =
- status->Check_deferred = status->Check_got =
- status->Check_cybercan = 0;
- status->Takethis = status->Takethis_Ok = status->Takethis_Err = 0;
- status->activeCxn = status->sleepingCxns = 0;
- status->accepted = 0;
- status->refused = status->rejected = 0;
- status->Duplicate = status->Unwanted_u = 0;
- status->Unwanted_d = status->Unwanted_g = 0;
- status->Unwanted_s = status->Unwanted_f = 0;
- status->next = NULL;
- if (head == NULL)
- head = status;
- else
- tmp->next = status;
- tmp = status;
- }
- if (Now.time - cp->Started > status->seconds)
- status->seconds = Now.time - cp->Started;
- if (Now.time - cp->Started > seconds)
- seconds = Now.time - cp->Started;
- status->accepted += cp->Received;
- accepted += cp->Received;
- status->refused += cp->Refused;
- refused += cp->Refused;
- status->rejected += cp->Rejected;
- rejected += cp->Rejected;
- status->Duplicate += cp->Duplicate;
- duplicate += cp->Duplicate;
- status->Unwanted_u += cp->Unwanted_u;
- status->Unwanted_d += cp->Unwanted_d;
- status->Unwanted_g += cp->Unwanted_g;
- status->Unwanted_s += cp->Unwanted_s;
- status->Unwanted_f += cp->Unwanted_f;
- status->Ihave += cp->Ihave;
- status->Ihave_Duplicate += cp->Ihave_Duplicate;
- status->Ihave_Deferred += cp->Ihave_Deferred;
- status->Ihave_SendIt += cp->Ihave_SendIt;
- status->Ihave_Cybercan += cp->Ihave_Cybercan;
- status->Check += cp->Check;
- status->Check_send += cp->Check_send;
- status->Check_deferred += cp->Check_deferred;
- status->Check_got += cp->Check_got;
- status->Check_cybercan += cp->Check_cybercan;
- status->Takethis += cp->Takethis;
- status->Takethis_Ok += cp->Takethis_Ok;
- status->Takethis_Err += cp->Takethis_Err;
- status->Size += cp->Size;
- status->DuplicateSize += cp->DuplicateSize;
- size += cp->Size;
- DuplicateSize += cp->DuplicateSize;
- if (CHANsleeping(cp)) {
- sleepingCxns++;
- status->sleepingCxns++;
- } else {
- activeCxn++;
- status->activeCxn++;
- }
- }
-
- /* Header */
- now = time (NULL);
- strlcpy (TempString, ctime (&now), sizeof(TempString));
- fprintf (F, "Updated: %s", TempString);
- fprintf (F, "(peers: %d, active-cxns: %d, sleeping-cxns: %d)\n\n",
- peers, activeCxn, sleepingCxns);
-
- fprintf (F, "Mode: %s", Mode == OMrunning ? "running" :
- Mode == OMpaused ? "paused" :
- Mode == OMthrottled ? "throttled" : "Unknown");
- if ((Mode == OMpaused) || (Mode == OMthrottled))
- fprintf (F, " (%s)", ModeReason);
-
- /* Global configuration */
- fprintf (F, "\n\nConfiguration file: %s\n\n", _PATH_CONFIG);
-
- fprintf (F, "Global configuration parameters:\n");
- fprintf (F, " Largest Article: %ld bytes\n", innconf->maxartsize);
- fprintf (F, " Max Incoming connections: ");
- if (innconf->maxconnections)
- fprintf (F, "%ld\n", innconf->maxconnections);
- else
- fprintf (F, "unlimited\n");
- fprintf (F, " Max Outgoing file feeds: %d\n", MaxOutgoing);
- fprintf (F, " Cutoff: ");
- if (innconf->artcutoff)
- fprintf (F, "%ld days\n", innconf->artcutoff);
- else
- fprintf (F, "none\n");
- fprintf (F, " Timeout period: %ld seconds\n",
- (long)TimeOut.tv_sec);
- if (innconf->remembertrash) {
- fprintf (F, " Remember Trash: Yes\n");
- } else {
- fprintf (F, " Remember Trash: No\n");
- }
-#if defined(DO_TCL)
- fprintf (F, " Tcl filtering: %s\n",
- TCLFilterActive ? "enabled" : "disabled");
-#endif /* defined(DO_TCL) */
-#if defined(DO_PERL)
- fprintf (F, " Perl filtering: %s\n",
- PerlFilterActive ? "enabled" : "disabled");
-#endif /* defined(DO_PERL) */
-
- fputc ('\n', F) ;
-
- /* Global values */
- fprintf (F, "global (process)\n");
- fprintf (F, " seconds: %ld\n", (long) seconds);
- offered = accepted + refused + rejected;
- fprintf (F, " offered: %-9ld\n", offered);
- if (!offered) offered = 1; /* to avoid division by zero */
- if (!size) size = 1; /* avoid divide by zero here too */
- fprintf (F, " accepted: %-9ld %%accepted: %.1f%%\n",
- accepted, (float) accepted / offered * 100);
- fprintf (F, " refused: %-9ld %%refused: %.1f%%\n",
- refused, (float) refused / offered * 100);
- fprintf (F, " rejected: %-9ld %%rejected: %.1f%%\n",
- rejected, (float) rejected / offered * 100);
- fprintf (F, " duplicated: %-9ld %%duplicated: %.1f%%\n",
- duplicate, (float) duplicate / offered * 100);
- fprintf (F, " bytes: %-7s\n", PrettySize (size + DuplicateSize, str));
- fprintf (F, " duplicated size: %-7s %%duplicated size: %.1f%%\n",
- PrettySize(DuplicateSize, str), (float) DuplicateSize / size * 100);
- fputc ('\n', F) ;
-
- /* Incoming Feeds */
- for (status = head ; status != NULL ;) {
- fprintf (F, "%s\n", status->name);
- fprintf (F, " seconds: %-7ld ", (long) status->seconds);
- fprintf (F, " duplicates: %-7ld ", status->Duplicate);
- fprintf (F, " ip address: %s\n", status->ip_addr);
- fprintf (F, " offered: %-7ld ",
- status->accepted + status->refused + status->rejected);
- fprintf (F, " uw newsgroups: %-7ld ", status->Unwanted_g);
- fprintf (F, " active cxns: %d\n", status->activeCxn);
- fprintf (F, " accepted: %-7ld ", status->accepted);
- fprintf (F, "uw distributions: %-7ld ", status->Unwanted_d);
- fprintf (F, " sleeping cxns: %d\n", status->sleepingCxns);
- fprintf (F, " refused: %-7ld ", status->refused);
- fprintf (F, " unapproved: %-7ld ", status->Unwanted_u);
- fprintf (F, "want streaming: %s\n",
- status->can_stream ? "Yes" : "No");
- fprintf (F, " rejected: %-7ld ", status->rejected);
- fprintf (F, " filtered: %-7ld ", status->Unwanted_f);
- fprintf (F, " is streaming: %s\n",
- (status->Check || status->Takethis) ? "Yes" : "No");
- fprintf (F, " size: %-8s ", PrettySize(status->Size, str));
- fprintf (F, " bad sites: %-7ld ", status->Unwanted_s);
- fprintf (F, "duplicate size: %s\n", PrettySize(status->DuplicateSize, str));
- fprintf (F, " Protocol:\n");
- fprintf (F, " Ihave: %-6ld SendIt[%d]: %-6ld Got[%d]: %-6ld Deferred[%d]: %ld\n",
- status->Ihave, NNTP_SENDIT_VAL, status->Ihave_SendIt,
- NNTP_HAVEIT_VAL, status->Ihave_Duplicate, NNTP_RESENDIT_VAL,
- status->Ihave_Deferred);
- fprintf (F, " Check: %-6ld SendIt[%d]: %-6ld Got[%d]: %-6ld Deferred[%d]: %ld\n",
- status->Check, NNTP_OK_SENDID_VAL, status->Check_send,
- NNTP_ERR_GOTID_VAL, status->Check_got, NNTP_RESENDID_VAL,
- status->Check_deferred);
- fprintf (F, " Takethis: %-6ld Ok[%d]: %-6ld Error[%d]: %-6ld\n",
- status->Takethis, NNTP_OK_RECID_VAL, status->Takethis_Ok,
- NNTP_ERR_FAILID_VAL, status->Takethis_Err);
- if (innconf->refusecybercancels) {
- fprintf (F, " Cancelrejects: Ihave[%d]: %-6ld Check[%d]: %-6ld\n",
- NNTP_HAVEIT_VAL, status->Ihave_Cybercan,
- NNTP_ERR_GOTID_VAL, status->Check_cybercan);
- }
- fputc ('\n', F) ;
- tmp = status->next;
- free(status);
- status = tmp;
- }
-
-#if defined(HTML_STATUS)
- /* HTML Footer */
- fprintf (F,"</PRE>\n</BODY>\n</HTML>\n");
-#endif /* defined(HTML_STATUS) */
-
- Fclose(F);
-}
-
-void
-STATUSmainloophook(void)
-{
- unsigned now;
-
- if (!innconf->status)
- return;
- now = STATUSgettime();
-
- if (now - STATUSlast_time > (unsigned)(innconf->status * 1000)) {
- STATUSsummary();
- STATUSlast_time = now;
- }
-}
+++ /dev/null
-/* $Id: tcl.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Support for TCL things
-**
-** By Bob Heiney, Network Systems Laboratory, Digital Equipment Corporation
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-#if defined(DO_TCL)
-
-Tcl_Interp *TCLInterpreter;
-bool TCLFilterActive;
-struct buffer *TCLCurrArticle;
-ARTDATA *TCLCurrData;
-
-static char *TCLSTARTUP = NULL;
-static char *TCLFILTER = NULL;
-
-
-void
-TCLfilter(value)
- bool value;
-{
- TCLFilterActive=value;
-
- syslog(L_NOTICE, "%s tcl filtering %s", LogName,
- TCLFilterActive ? "enabled" : "disabled");
-}
-
-
-void
-TCLreadfilter(void)
-{
- int code;
-
- /* do before reload callback */
- code = Tcl_Eval(TCLInterpreter, "filter_before_reload");
- if (code != TCL_OK) {
- if (strcmp(TCLInterpreter->result,
- "invalid command name: \"filter_before_reload\"")!=0)
- syslog(L_ERROR, "%s Tcl filter_before_reload failed: %s",
- LogName, TCLInterpreter->result);
- }
-
- /* read the filter file */
- if (TCLFILTER == NULL)
- TCLFILTER = concatpath(innconf->pathfilter, _PATH_TCL_FILTER);
- code = Tcl_EvalFile(TCLInterpreter, TCLFILTER);
- if (code != TCL_OK) {
- syslog(L_ERROR, "%s cant evaluate Tcl filter file: %s", LogName,
- TCLInterpreter->result);
- TCLfilter(false);
- }
-
- /* do the after callback, discarding any errors */
- code = Tcl_Eval(TCLInterpreter, "filter_after_reload");
- if (code != TCL_OK) {
- if (strcmp(TCLInterpreter->result,
- "invalid command name: \"filter_after_reload\"")!=0)
- syslog(L_ERROR, "%s Tcl filter_after_reload failed: %s",
- LogName, TCLInterpreter->result);
- }
-}
-
-
-/* makeCheckSum
- *
- * Compute a checksum. This function does a one's-complement addition
- * of a series of 32-bit words. "buflen" is in bytes, not words. This is
- * hard because the number of bits with which our machine can do arithmetic
- * is the same as the size of the checksum being created, but our hardware
- * is 2's-complement and C has no way to check for integer overflow.
- *
- * Note that the checksum is returned in network byte order and not host
- * byte order; this makes it suitable for putting into packets and for
- * comparing with what is found in packets.
- */
-
-static uint32_t
-makechecksum(u_char *sumbuf, int buflen)
-{
- u_char *buf = (u_char *)sumbuf;
- int32_t len = buflen;
- int32_t sum;
- uint32_t bwordl,bwordr,bword,suml,sumr;
- int rmdr;
- u_char tbuf[4];
- u_char *ptbuf;
-
- suml = 0; sumr = 0;
-
- len = len/4;
- rmdr = buflen - 4*len;
-
- while (len-- > 0) {
- bwordr = (buf[3] & 0xFF)
- + ((buf[2] & 0xFF) << 8);
- bwordl = (buf[1] & 0xFF)
- + ((buf[0] & 0xFF) << 8);
- bword = ( bwordl << 16) | bwordr;
- bword = ntohl(bword);
- bwordl = (bword >> 16) & 0xFFFF;
- bwordr = bword & 0xFFFF;
- sumr += bwordr;
- if (sumr & ~0xFFFF) {
- sumr &= 0xFFFF;
- suml++;
- }
- suml += bwordl;
- if (suml & ~0xFFFF) {
- suml &= 0xFFFF;
- sumr++;
- }
- buf += 4;
- }
- /* if buffer size was not an even multiple of 4 bytes,
- we have work to do */
- if (rmdr > 0) {
- tbuf[3] = 0; tbuf[2] = 0; tbuf[1] = 0;
- /* tbuf[0] will always be copied into, and tbuf[3] will
- * always be zero (else this would not be a remainder)
- */
- ptbuf = tbuf;
- while (rmdr--) *ptbuf++ = *buf++;
- bwordr = (tbuf[3] & 0xFF)
- + ((tbuf[2] & 0xFF) << 8);
- bwordl = (tbuf[1] & 0xFF)
- + ((tbuf[0] & 0xFF) << 8);
- bword = ( bwordl << 16) | bwordr;
- bword = ntohl(bword);
- bwordl = (bword >> 16) & 0xFFFF;
- bwordr = bword & 0xFFFF;
- sumr += bwordr;
- if (sumr & ~0xFFFF) {
- sumr &= 0xFFFF;
- suml++;
- }
- suml += bwordl;
- if (suml & ~0xFFFF) {
- suml &= 0xFFFF;
- sumr++;
- }
- }
- sum = htonl( (suml << 16) | sumr);
- return (~sum);
-}
-
-
-int
-TCLCksumArt(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[])
-{
- char buf[100];
-
- snprintf(buf, sizeof(buf), "%08x",
- makechecksum(TCLCurrArticle->data + TCLCurrData->Body,
- TCLCurrData->Body));
- Tcl_SetResult(interp, buf, TCL_VOLATILE);
- return TCL_OK;
-}
-
-
-void
-TCLsetup(void)
-{
- int code;
-
- TCLInterpreter = Tcl_CreateInterp();
- if (TCLSTARTUP == NULL)
- TCLSTARTUP = concatpath(innconf->pathfilter, _PATH_TCL_STARTUP);
- code = Tcl_EvalFile(TCLInterpreter, TCLSTARTUP);
- if (code != TCL_OK) {
- syslog(L_FATAL, "%s cant read Tcl startup file: %s", LogName,
- TCLInterpreter->result);
- exit(1);
- }
-
- Tcl_CreateCommand(TCLInterpreter, "checksum_article", TCLCksumArt,
- NULL, NULL);
-
- TCLfilter(true);
- TCLreadfilter();
-}
-
-
-void
-TCLclose(void)
-{
-}
-
-
-#endif /* defined(DO_TCL) */
+++ /dev/null
-/* $Id: util.c 6138 2003-01-19 04:13:51Z rra $
-**
-** Various miscellaneous utility functions for innd internal use.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "libinn.h"
-
-#include "innd.h"
-
-/*
-** Sprintf a long into a buffer with enough leading zero's so that it
-** takes up width characters. Don't add trailing NUL. Return true
-** if it fit. Used for updating high-water marks in the active file
-** in-place.
-*/
-bool
-FormatLong(char *p, unsigned long value, int width)
-{
- for (p += width - 1; width-- > 0; ) {
- *p-- = (int)(value % 10) + '0';
- value /= 10;
- }
- return value == 0;
-}
-
-
-/*
-** Glue a string, a char, and a string together. Useful for making
-** filenames.
-*/
-void
-FileGlue(char *p, const char *n1, char c,
- const char *n2)
-{
- p += strlen(strcpy(p, n1));
- *p++ = c;
- strcpy(p, n2);
-}
-
-
-/*
-** Turn any \r or \n in text into spaces. Used to splice back multi-line
-** headers into a single line.
-*/
-static char *
-Join(char *text)
-{
- char *p;
-
- for (p = text; *p; p++)
- if (*p == '\n' || *p == '\r')
- *p = ' ';
- return text;
-}
-
-
-/*
-** Return a short name that won't overrun our bufer or syslog's buffer.
-** q should either be p, or point into p where the "interesting" part is.
-*/
-char *
-MaxLength(const char *p, const char *q)
-{
- static char buff[80];
- unsigned int i;
-
- /* Already short enough? */
- i = strlen(p);
- if (i < sizeof buff - 1) {
- strlcpy(buff, p, sizeof(buff));
- return Join(buff);
- }
-
- /* Simple case of just want the begining? */
- if ((unsigned)(q - p) < sizeof buff - 4) {
- strlcpy(buff, p, sizeof(buff) - 3);
- strlcat(buff, "...", sizeof(buff));
- }
- /* Is getting last 10 characters good enough? */
- else if ((p + i) - q < 10) {
- strlcpy(buff, p, sizeof(buff) - 13);
- strlcat(buff, "...", sizeof(buff) - 10);
- strlcat(buff, &p[i - 10], sizeof(buff));
- }
- else {
- /* Not in last 10 bytes, so use double elipses. */
- strlcpy(buff, p, sizeof(buff) - 16);
- strlcat(buff, "...", sizeof(buff) - 13);
- strlcat(buff, &q[-5], sizeof(buff) - 3);
- strlcat(buff, "...", sizeof(buff));
- }
- return Join(buff);
-}
-
-
-/*
-** Split text into comma-separated fields. Return an allocated
-** NULL-terminated array of the fields within the modified argument that
-** the caller is expected to save or free. We don't use strchr() since
-** the text is expected to be either relatively short or "comma-dense."
-*/
-char **
-CommaSplit(char *text)
-{
- int i;
- char *p;
- char **av;
- char **save;
-
- /* How much space do we need? */
- for (i = 2, p = text; *p; p++)
- if (*p == ',')
- i++;
-
- for (av = save = xmalloc(i * sizeof(char *)), *av++ = p = text; *p; )
- if (*p == ',') {
- *p++ = '\0';
- *av++ = p;
- }
- else
- p++;
- *av = NULL;
- return save;
-}
-
-
-/*
-** Set up LISTBUFFER so that data will be put into array
-** it allocates buffer and array for data if needed, otherwise use already
-** allocated one
-*/
-void
-SetupListBuffer(int size, LISTBUFFER *list)
-{
- /* get space for data to be splitted */
- if (list->Data == NULL) {
- list->DataLength = size;
- list->Data = xmalloc(list->DataLength + 1);
- } else if (list->DataLength < size) {
- list->DataLength = size;
- list->Data = xrealloc(list->Data, list->DataLength + 1);
- }
- /* get an array of character pointers. */
- if (list->List == NULL) {
- list->ListLength = DEFAULTNGBOXSIZE;
- list->List = xmalloc(list->ListLength * sizeof(char *));
- }
-}
-
-
-/*
-** Do we need a shell for the command? If not, av is filled in with
-** the individual words of the command and the command is modified to
-** have NUL's inserted.
-*/
-bool
-NeedShell(char *p, const char **av, const char **end)
-{
- static const char Metachars[] = ";<>|*?[]{}()#$&=`'\"\\~\n";
- const char *q;
-
- /* We don't use execvp(); works for users, fails out of /etc/rc. */
- if (*p != '/')
- return true;
- for (q = p; *q; q++)
- if (strchr(Metachars, *q) != NULL)
- return true;
-
- for (end--; av < end; ) {
- /* Mark this word, check for shell meta-characters. */
- for (*av++ = p; *p && !ISWHITE(*p); p++)
- continue;
-
- /* If end of list, we're done. */
- if (*p == '\0') {
- *av = NULL;
- return false;
- }
-
- /* Skip whitespace, find next word. */
- for (*p++ = '\0'; ISWHITE(*p); p++)
- continue;
- if (*p == '\0') {
- *av = NULL;
- return false;
- }
- }
-
- /* Didn't fit. */
- return true;
-}
-
-
-/*
-** Spawn a process, with I/O redirected as needed. Return the PID or -1
-** (and a syslog'd message) on error.
-*/
-pid_t
-Spawn(int niceval, int fd0, int fd1, int fd2, char * const av[])
-{
- static char NOCLOSE[] = "%s cant close %d in %s %m";
- static char NODUP2[] = "%s cant dup2 %d to %d in %s %m";
- pid_t i;
-
- /* Fork; on error, give up. If not using the patched dbz, make
- * this call fork! */
- i = fork();
- if (i == -1) {
- syslog(L_ERROR, "%s cant fork %s %m", LogName, av[0]);
- return -1;
- }
-
- /* If parent, do nothing. */
- if (i > 0)
- return i;
-
- /* Child -- do any I/O redirection. */
- if (fd0 != 0) {
- if (dup2(fd0, 0) < 0) {
- syslog(L_FATAL, NODUP2, LogName, fd0, 0, av[0]);
- _exit(1);
- }
- if (fd0 != fd1 && fd0 != fd2 && close(fd0) < 0)
- syslog(L_ERROR, NOCLOSE, LogName, fd0, av[0]);
- }
- if (fd1 != 1) {
- if (dup2(fd1, 1) < 0) {
- syslog(L_FATAL, NODUP2, LogName, fd1, 1, av[0]);
- _exit(1);
- }
- if (fd1 != fd2 && close(fd1) < 0)
- syslog(L_ERROR, NOCLOSE, LogName, fd1, av[0]);
- }
- if (fd2 != 2) {
- if (dup2(fd2, 2) < 0) {
- syslog(L_FATAL, NODUP2, LogName, fd2, 2, av[0]);
- _exit(1);
- }
- if (close(fd2) < 0)
- syslog(L_ERROR, NOCLOSE, LogName, fd2, av[0]);
- }
- close_on_exec(0, false);
- close_on_exec(1, false);
- close_on_exec(2, false);
-
- /* Nice our child if we're supposed to. */
- if (niceval != 0 && nice(niceval) == -1)
- syslog(L_ERROR, "SERVER cant nice child to %d: %m", niceval);
-
- /* Start the desired process (finally!). */
- execv(av[0], av);
- syslog(L_FATAL, "%s cant exec in %s %m", LogName, av[0]);
- _exit(1);
-
- /* Not reached. */
- return -1;
-}
-
-/*
-** We ran out of space or other I/O error, throttle ourselves.
-*/
-void
-ThrottleIOError(const char *when)
-{
- char buff[SMBUF];
- const char * p;
- int oerrno;
-
- if (Mode == OMrunning) {
- oerrno = errno;
- if (Reservation) {
- free(Reservation);
- Reservation = NULL;
- }
- snprintf(buff, sizeof(buff), "%s writing %s file -- throttling",
- strerror(oerrno), when);
- if ((p = CCblock(OMthrottled, buff)) != NULL)
- syslog(L_ERROR, "%s cant throttle %s", LogName, p);
- syslog(L_FATAL, "%s throttle %s", LogName, buff);
- errno = oerrno;
- ThrottledbyIOError = true;
- }
-}
-
-/*
-** No matching storage.conf, throttle ourselves.
-*/
-void
-ThrottleNoMatchError(void)
-{
- char buff[SMBUF];
- const char *p;
-
- if (Mode == OMrunning) {
- if (Reservation) {
- free(Reservation);
- Reservation = NULL;
- }
- snprintf(buff, sizeof(buff), "%s storing article -- throttling",
- SMerrorstr);
- if ((p = CCblock(OMthrottled, buff)) != NULL)
- syslog(L_ERROR, "%s cant throttle %s", LogName, p);
- syslog(L_FATAL, "%s throttle %s", LogName, buff);
- ThrottledbyIOError = true;
- }
-}
-
-void
-InndHisOpen(void)
-{
- char *histpath;
- int flags;
- size_t synccount;
-
- histpath = concatpath(innconf->pathdb, _PATH_HISTORY);
- if (innconf->hismethod == NULL) {
- sysdie("hismethod is not defined");
- /*NOTREACHED*/
- }
-
- flags = HIS_RDWR | (INND_DBZINCORE ? HIS_MMAP : HIS_ONDISK);
- History = HISopen(histpath, innconf->hismethod, flags);
- if (!History) {
- sysdie("SERVER can't open history %s", histpath);
- /*NOTREACHED*/
- }
- free(histpath);
- HISsetcache(History, 1024 * innconf->hiscachesize);
- synccount = innconf->icdsynccount;
- HISctl(History, HISCTLS_SYNCCOUNT, &synccount);
-}
-
-void
-InndHisClose(void)
-{
- if (History == NULL)
- return;
- if (!HISclose(History)) {
- char *histpath;
-
- histpath = concatpath(innconf->pathdb, _PATH_HISTORY);
- sysdie("SERVER can't close history %s", histpath);
- free(histpath);
- }
- History = NULL;
-}
-
-bool
-InndHisWrite(const char *key, time_t arrived, time_t posted, time_t expires,
- TOKEN *token)
-{
- bool r = HISwrite(History, key, arrived, posted, expires, token);
-
- if (r != true)
- IOError("history write", errno);
- return r;
-}
-
-bool
-InndHisRemember(const char *key)
-{
- bool r = HISremember(History, key, Now.time);
-
- if (r != true)
- IOError("history remember", errno);
- return r;
-}
-
-void
-InndHisLogStats(void)
-{
- struct histstats stats = HISstats(History);
-
- syslog(L_NOTICE, "ME HISstats %d hitpos %d hitneg %d missed %d dne",
- stats.hitpos, stats.hitneg, stats.misses, stats.dne);
-}
-
-
+++ /dev/null
-/* $Id: wip.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Routines for keeping track of incoming articles, articles that haven't
-** acked from a duplex channel feed, and history caching.
-**
-** WIP stands for work-in-progress
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "innd.h"
-
-#define WIPTABLESIZE 1024
-#define WIP_ARTMAX 300 /* innfeed default max send time */
-
-static WIP *WIPtable[WIPTABLESIZE]; /* Top level of the WIP hash table */
-
-void
-WIPsetup(void)
-{
- memset(WIPtable, '\0', sizeof(WIPtable));
-}
-
-/* Add a new entry into the table. It is the appilications responsiblity to
- to call WIPinprogress or WIPbyid first. */
-WIP *
-WIPnew(const char *messageid, CHANNEL *cp)
-{
- HASH hash;
- unsigned long bucket;
- WIP *new;
-
- hash = Hash(messageid, strlen(messageid));
- memcpy(&bucket, &hash,
- sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
- bucket = bucket % WIPTABLESIZE;
-
- new = xmalloc(sizeof(WIP));
- new->MessageID = hash;
- new->Timestamp = Now.time;
- new->Chan = cp;
- /* Link the new entry into the list */
- new->Next = WIPtable[bucket];
- WIPtable[bucket] = new;
- return new;
-}
-
-void
-WIPprecomfree(CHANNEL *cp)
-{
- WIP *cur;
- int i;
- if (cp == NULL)
- return;
-
- for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
- cur = cp->PrecommitWIP[i];
- if (cur != (WIP *)NULL) {
- WIPfree(cur);
- }
- }
-}
-
-void
-WIPfree(WIP *wp)
-{
- unsigned long bucket;
- WIP *cur;
- WIP *prev = NULL;
- int i;
- /* This is good error checking, but also allows us to
- WIPfree(WIPbymessageid(id))
- without having to check if id exists first */
- if (wp == NULL)
- return;
-
- memcpy(&bucket, &wp->MessageID,
- sizeof(bucket) < sizeof(HASH) ? sizeof(bucket) : sizeof(HASH));
- bucket = bucket % WIPTABLESIZE;
-
- for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
- if (wp->Chan->PrecommitWIP[i] == wp) {
- wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
- break;
- }
- }
- for (cur = WIPtable[bucket]; (cur != NULL) && (cur != wp); prev = cur, cur = cur->Next);
-
- if (cur == NULL)
- return;
-
- if (prev == NULL)
- WIPtable[bucket] = cur->Next;
- else
- prev->Next = cur->Next;
-
- /* unlink the entry and free the memory */
- free(wp);
-}
-
-/* Check if the given messageid is being transfered on another channel. If
- Add is true then add the given message-id to the current channel */
-bool
-WIPinprogress(const char *msgid, CHANNEL *cp, bool Precommit)
-{
- WIP *wp;
- int i;
-
- if ((wp = WIPbyid(msgid)) != NULL) {
- if(wp->Chan->ArtBeg == 0)
- i = 0;
- else {
- i = wp->Chan->ArtMax;
- if(i > WIP_ARTMAX)
- i = WIP_ARTMAX;
- }
-
- if ((Now.time - wp->Timestamp) < (i + innconf->wipcheck))
- return true;
- if ((Now.time - wp->Timestamp) > (i + innconf->wipexpire)) {
- for (i = 0 ; i < PRECOMMITCACHESIZE ; i++) {
- if (wp->Chan->PrecommitWIP[i] == wp) {
- wp->Chan->PrecommitWIP[i] = (WIP *)NULL;
- break;
- }
- }
- WIPfree(wp);
- WIPinprogress(msgid, cp, Precommit);
- return false;
- }
- if (wp->Chan == cp)
- return true;
- return false;
- }
- wp = WIPnew(msgid, cp);
- if (Precommit) {
- if (cp->PrecommitiCachenext == PRECOMMITCACHESIZE)
- cp->PrecommitiCachenext = 0;
- if (cp->PrecommitWIP[cp->PrecommitiCachenext])
- WIPfree(cp->PrecommitWIP[cp->PrecommitiCachenext]);
- cp->PrecommitWIP[cp->PrecommitiCachenext++] = wp;
- } else {
- WIPfree(WIPbyhash(cp->CurrentMessageIDHash));
- cp->CurrentMessageIDHash = wp->MessageID;
- }
- return false;
-}
-
-WIP *
-WIPbyid(const char *messageid)
-{
- HASH hash;
- unsigned long bucket;
- WIP *wp;
-
- hash = Hash(messageid, strlen(messageid));
- memcpy(&bucket, &hash,
- sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
- bucket = bucket % WIPTABLESIZE;
-
- /* Traverse the list until we find a match or find the head again */
- for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next)
- if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
- return wp;
-
- return NULL;
-}
-
-WIP *
-WIPbyhash(const HASH hash)
-{
- unsigned long bucket;
- WIP *wp;
-
- memcpy(&bucket, &hash,
- sizeof(bucket) < sizeof(hash) ? sizeof(bucket) : sizeof(hash));
- bucket = bucket % WIPTABLESIZE;
-
- /* Traverse the list until we find a match or find the head again */
- for (wp = WIPtable[bucket]; wp != NULL; wp = wp->Next)
- if (!memcmp(&hash, &wp->MessageID, sizeof(HASH)))
- return wp;
-
- return NULL;
-}
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) $(SASLINC)
-
-ALL = innfeed procbatch startinnfeed imapfeed
-
-SOURCES = article.c buffer.c config_l.c config_y.c \
- endpoint.c host.c innlistener.c main.c misc.c \
- startinnfeed.c tape.c version.c
-
-INCLUDES = article.h buffer.h configfile.h config_y.h connection.h \
- endpoint.h host.h innfeed.h innlistener.h misc.h tape.h
-
-# The objects linked into innfeed. All SOURCES except startinnfeed.
-OBJECTS = article.o buffer.o config_l.o config_y.o \
- endpoint.o host.o innlistener.o main.o misc.o tape.o \
- version.o
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPRI) innfeed $D$(PATHBIN)/innfeed
- $(LI_XPRI) imapfeed $D$(PATHBIN)/imapfeed
- $(CP_XPRI) procbatch $D$(PATHBIN)/procbatch
- @ME=`$(WHOAMI)` ; \
- if [ x"$$ME" = xroot ] ; then \
- echo $(LI_SPRI) startinnfeed $D$(PATHBIN)/startinnfeed ; \
- $(LI_SPRI) startinnfeed $D$(PATHBIN)/startinnfeed ; \
- else \
- echo $(LI_XPRI) startinnfeed $D$(PATHBIN)/startinnfeed ; \
- $(LI_XPRI) startinnfeed $D$(PATHBIN)/startinnfeed ; \
- echo '' ; \
- echo '========================' ; \
- echo 'NOTE NOTE NOTE NOTE NOTE' ; \
- ls -l $D$(PATHBIN)/startinnfeed ; \
- echo '$D$(PATHBIN)/startinnfeed needs to be installed setuid root' ; \
- echo '' ; echo ; \
- fi
-
-
-clean:
- rm -f *.o $(ALL) version.c innfeed-convcfg
- rm -f profiled innfeedp
- rm -rf .libs
-
-clobber distclean: clean
- rm -f tags y.tab.c y.tab.h lex.yy.c config_y.c config_y.h
-
-tags: $(SOURCES) $(INCLUDES)
- $(CTAGS) $(SOURCES) $(INCLUDES)
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Compilation rules.
-
-INNFEEDLIBS = $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) \
- $(SASLLIB) $(LIBS)
-
-config_y.c config_y.h: configfile.y
- $(YACC) -d $?
- mv y.tab.h config_y.h
- mv y.tab.c config_y.c
-
-config_l.c: configfile.l
- $(LEX) $?
- mv lex.yy.c config_l.c
-
-version.c: Makefile ../Makefile.global
- version=`echo '$(VERSION) ($(VERSION_EXTRA))' | sed 's/ ()//'` ; \
- echo 'const char *versionInfo = "innfeed' "$$version\" ;" > $@
-
-innfeed: $(OBJECTS) connection.o $(LIBSTORAGE) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(OBJECTS) connection.o $(INNFEEDLIBS)
-
-imapfeed: $(OBJECTS) imap_connection.o $(LIBSTORAGE) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(OBJECTS) imap_connection.o $(INNFEEDLIBS)
-
-procbatch: procbatch.in $(FIXSCRIPT)
- $(FIXSCRIPT) procbatch.in
-
-startinnfeed: startinnfeed.o $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ startinnfeed.o $(LIBINN) $(LIBS)
-
-# Not normally built.
-innfeed-convcfg: innfeed-convcfg.in $(FIXSCRIPT)
- $(FIXSCRIPT) -i innfeed-convcfg.in
-
-tst: config_y.c config_l.c
- gcc -DWANT_MAIN -o tst -g -Wall config_y.c config_l.c -ly -ll
-
-
-## Profiling. These rules have not been checked for a while and may need
-## some work.
-
-profiled: innfeedp
- date >$@
-
-innfeedp: $(SOURCES)
- rm -f $(OBJECTS)
- $(MAKEPROFILING) innfeed
- mv innfeed innfeedp
- rm -f $(OBJECTS)
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-article.o: article.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/config.h \
- ../include/inn/defines.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h \
- ../include/inn/messages.h ../include/libinn.h ../include/storage.h \
- article.h misc.h buffer.h endpoint.h
-buffer.o: buffer.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/config.h \
- ../include/inn/defines.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/libinn.h buffer.h misc.h
-config_l.o: config_l.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/libinn.h \
- ../include/inn/defines.h ../include/config.h configfile.h config_y.h \
- misc.h ../include/config.h
-config_y.o: config_y.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/config.h \
- ../include/inn/defines.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/libinn.h configfile.h misc.h
-endpoint.o: endpoint.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/config.h \
- ../include/inn/defines.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/innconf.h \
- ../include/inn/messages.h ../include/libinn.h buffer.h misc.h \
- configfile.h endpoint.h host.h
-host.o: host.c innfeed.h ../include/inn/timer.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/config.h ../include/inn/defines.h \
- ../include/clibrary.h ../include/config.h ../include/portable/socket.h \
- ../include/config.h ../include/inn/innconf.h ../include/inn/messages.h \
- ../include/libinn.h article.h misc.h buffer.h configfile.h connection.h \
- endpoint.h host.h innlistener.h tape.h
-innlistener.o: innlistener.c innfeed.h ../include/inn/timer.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/config.h \
- ../include/inn/defines.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/libinn.h article.h misc.h buffer.h \
- configfile.h endpoint.h host.h innlistener.h ../include/nntp.h tape.h
-main.o: main.c innfeed.h ../include/inn/timer.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/config.h ../include/inn/defines.h \
- ../include/clibrary.h ../include/config.h ../include/portable/socket.h \
- ../include/config.h ../include/portable/time.h ../include/inn/innconf.h \
- ../include/inn/messages.h ../include/libinn.h ../include/storage.h \
- article.h misc.h buffer.h configfile.h connection.h endpoint.h host.h \
- innlistener.h tape.h
-misc.o: misc.c innfeed.h ../include/inn/timer.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/config.h ../include/inn/defines.h \
- ../include/clibrary.h ../include/config.h ../include/inn/messages.h \
- ../include/libinn.h endpoint.h misc.h tape.h
-startinnfeed.o: startinnfeed.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h
-tape.o: tape.c innfeed.h ../include/inn/timer.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/config.h ../include/inn/defines.h \
- ../include/clibrary.h ../include/config.h ../include/inn/innconf.h \
- ../include/inn/messages.h ../include/libinn.h article.h misc.h \
- configfile.h endpoint.h tape.h
-version.o: version.c
+++ /dev/null
-This is version 1.0 of the INN feeder program `innfeed.'
-It is written in ANSI C and tries to be POSIX.1 compliant. This software
-was originally written and maintained by James Brister <brister@vix.com>
-and is now part of INN. The features of it are:
-
- 1. Handles the STREAM extenstion to NNTP.
- 2. Will open multiple connections to the remote host to parallel
- feed.
- 3. Will handle multiple remote hosts.
- 4. Will tear down idle connections.
- 5. Runs as a channel/funnel feed from INN, or by reading a funnel
- file.
- 6. Will stop issuing CHECK commands and go straight to TAKETHIS if
- the remote responds affermatively to enough CHECKs.
- 7. It will go back to issuing CHECKs if enough TAKETHIS commands fail.
-
-
-Changes for 0.10.1
-
- 1. Config file inclusion now works via the syntax:
-
- $INCLUDE pathname
-
- Config files can be included up to a nesting depth of 10. Line
- numbers and file names are not properly reported yet on errors
- when includes are used, though.
-
- 2. Signal handling is tidied up a bit. If your compiler doesn't
- support the ``volatile'' keyword, then see the comment in
- sysconfig.h.
-
- 3. If you have a stdio library that hash limit on open files lower
- then the process limit for open plain files (all flavours of
- SunOS), then a new config file variable ``stdio-fdmax'' can be
- used to give that upper bound. When set, all new network
- connections will be limited to file descriptors over this value,
- leaving the lower file descriptors free for stdio. See
- innfeed.conf(5) for more details. Remember that the config file
- value overrides any compiled in value.
-
-Changes for 0.10
-
- 1. A major change has been made to the config file. The new format
- is quite extensible and will let new data items be added in the
- future without changing the basic format. There's a new option
- ``-C'' (for ``check'') that will make innfeed read the config
- file and report on any errors and then exit. This will let you
- verify things before locking them into a newsfeeds file entry. A
- program has been added ``innfeed-convcfg'' that will read your
- old config off the command line (or stdin), and will write a new
- version to stdout.
-
- The new config file structure permits non-peer-specific items to
- be declared (like the location of the status file, or whether to
- wrap the generated status file in HTML). This is part of the
- included sample:
-
- use-mmap: true
- news-spool: /var/news/spool/articles
- backlog-directory: /var/news/spool/innfeed
- pid-file: innfeed.pid
- status-file: innfeed.status
- gen-html: false
- log-file: innfeed.log
- backlog-factor: 1.10
- connection-stats: false
- max-reconnect-time: 3600
-
- so only option you'll probably need now is the ``-c'' option to
- locate the config file, and as this is also compiled in, you may
- not even need that.
-
- See the innfeed.conf(5) man page for more details on config file
- structure.
-
- 2. The backlog file handling is changed slightly:
-
- - The .output file is always kept open (until rotation time).
- - The .output file is allowed to grow for at least 30
- seconds (or the value defined by the key
- backlog-rotate-period in the config file). This prevents
- thrashing of backlog files.
- - The hand-prepared file is checked for only every 600
- seconds maximum (or the value defined by the key
- backlog-new), not every time the files are rotated.
- - The stating of the three backlog files is reduced
- dramatically.
-
- 3. Signal handling is changed so that they are more synchronous
- with other activity. This should stop the frequent core-dumps
- that occured when running in funnel file mode and sending
- SIGTERM or SIGALRM.
-
- 4. A bug related to zero-length articles was fixed. They will now be
- logged.
-
- 5. More information is in the innfeed.status file, including the
- reasons return by the remote when it is throttled.
-
- 6. SIGEMT is now a trigger for closing and reopening all the
- backlog files. If you have scripts that need to fool with the
- backlogs, then have the scripts move the backlogs out of the way
- and then send the SIGEMT.
-
-Changes for 0.9.3
-
- 1. If your system supports mmap() *and* if you have your articles
- stored on disk in NNTP-ready format (rare), then you can have
- innfeed mmap article data to save on memory (thanks to Dave
- Lawrence). There is an important issue with this:
-
- if you try to have innfeed handle too many articles (by
- running many connections and/or high max-check values in
- innfeed.conf) at once, then your system (not your process)
- may run out of free vnodes (global file descriptors), as a
- vnode is used as long as the file is mmaped. So be careful.
-
- If your articles are not in NNTP format then this will be
- noticed and the article will be pulled into memory for fixing up
- (and then immediately munmap'd). You can disable use of MMAP if
- you've built it in by using the '-M' flag. I tried mixing
- mmap'ing and articles not in NNTP format and it was a real
- performance loss. I'll be trying it differently later.
-
- 2. If innfeed is asked to send an article to a host it knows
- nothing about, or which it cannot acquire the required lock for
- (which causes the "ME locked cannot setup peer ..." and "ME
- unconfigured peer" syslog messages), then innfeed will deposit
- the article information into a file matching the pattern
- innfeed-dropped.* in the backlog directory (TAPE_DIRECTORY in
- config.h). This file will not be processed in any manner -- it's
- up to you to decide what to do with it (wait for innfeed to exit
- before doing anything with it, or send innfeed a SIGHUP to get
- it to reread its config file, which will roll this file).
-
- 4. The output backlog files will now be kept below a certain byte
- limit. This happens via the ``-e'' option. If, after writing to
- an output file, the new length is bigger than the given limit
- (multiplied by a fudge factor defined in config.h -- default of
- 1.10) then the file will be shrunk down to this size (or slightly
- smaller to find the end of line boundary). The front of the file
- will be removed to do this. This means lost articles for the
- entries removed.
-
- 3. A SIGHUP will make the config be reloaded.
-
- 4. The .checkpoint files have been dropped in favour of scribbling
- the offset into the input file itself.
-
- 5. When the process exits normally a final syslog entry covering
- all of the peers over the life of the process is written. It
- looks like:
-
- Jan 12 15:51:53 data innfeed.tester[24189]: ME global
- seconds 2472 offered 43820 accepted 10506
- refused 31168 rejected 1773 missing 39
-
- 6. SIGALARM now rolls the input file, rather than the log
- file. This is useful in funnel file mode when you move the input
- file and tell innd to flush it, then send innfeed the signal.
-
- 7. The location of the pid file, config file and status file, can
- now be relative, in which case they're relative to the backlog
- directory.
-
- 8. stdin stdout and stderr are initialized properly when innfeed is
- started by a process that has closed them.
-
- 9. Various values in config.h have changed (paths to look more like
- values used in inn 1.5 and others to support point #7 above
- more easily.)
-
- 10. procbatch.pl can now 'require' innshellvars.pl that comes with
- 1.5. The default is not to. You nead to do a one line tweak if
- you want it to. The defaults in procbatch.pl match the new
- defaults of innfeed.
-
- 11. Core files that get generated on purpose will be done so in
- CORE_DIRECTORY (as defined in config.h), if that is defined to a
- pathname. If CORE_DIRECTORY is defined to be NULL (the default
- now), then the core will be generated in the backlog directory (as
- possibly modified by the '-b' option).
-
-
-Changes for 0.9.2
-
- 1. Now includes David Lawrence's patches to handle funnel files.
-
- 2. EAGAIN errors on read and writes are caught and dealt with (of
- interest to Solaris `victims').
-
- 3. It is now much faster at servicing the file descriptor attached
- to innd. This means it is faster at recognising it has been
- flushed and at dropping connections. This means fewer
- conflicts with new innfeeds starting before the old one has
- finished up. It is still a good net-citizen and it finishes the
- commands already started, so the fast response is only as fast
- as your slowest peer, but it no longer tries to send
- everything it had queued internally, and locks get released much
- quicker.
-
- 4. Includes Michael Hucka's patch to make the innfeed.status output
- neater.
-
- 5. Includes Andy Vasilyev's HTML-in-innfeed.status patch (but you
- have to enable it in config.h).
-
- 6. Added a '-a' (top of news spool) and a '-p' (pid file path)
- option.
-
-Changes for 0.9
-
- 1. Format of innfeed.conf file changed slightly (for per-peer
- streaming specs).
- 2. Including Greg Patten's innlog.pl (taken from
- ftp://loose.apana.org.au/pub/local/innlog/innlog.pl)
- 3. Added Christophe Wolfhugel's patch to permit a per-peer
- restriction on using streaming.
- 4. More robust handling of peers that return bad responses (no long
- just calling abort).
-
-Changes for 0.8.5
-
- 1. Massive syslog messages cleanup courtesy of kre.
- 2. The innlog.awk-patch hash been dropped from the distribution
- until the new syslog messages are dealt with.
- 3. State machine more robust in the face of unexpected responses
- from remote. Connection gets torn down and bad response's
- logged.
- 4. The fixed timers (article reception timeout, read timeout,
- and flush timeout) are all adjusted by up to +/-10% so that
- things aren't quite so synchronised.
- 5. The innfeed.status file has been expanded and reformatted to
- include more information.
-
-Changes for 0.8.4
-
- 1. A change in the handing off of articles to connections in order to
- encourage connections that were opened due to activity spikes,
- to close down sooner.
- 2. The backlog files are no longer concatenated together at process
- startup, but the .input is simply used if it exists, and if not
- then the hand-dropped file is used first and the .output file
- second.
- 3. The innfeed.status is no longer updated by a innfeed that is in
- its death-throws.
- 4. Specifically catch the 480 response code from NNRPD when we try
- to give it an IHAVE.
- 5. The connection reestablishment time gets properly increased when
- the connection fails to go through (up to and including the
- reading of the banner message).
- 6. Bug fix that occasionally had articles sit in a connection and
- never get processed.
- 7. Bug fix in the counter of number of sleeping connections.
- 8. Bug fix in config file parsing.
- 9. Procbatch.pl included.
-
-Changes for version 0.8.1
-
- 1. various bug fixes.
- 2. core files generated by ASSERT are (possibly) put in a seperate
- directory to ease debugging are
-
-Changes for version 0.8
-
- 1. The implicit state machine in the Connection objects has been
- made explicit.
- 2. Various bug fixes.
-
-Changes for version 0.7.1
-
- 1. Pulled the source to inet_addr.c from the bind distribution.
- (Solaris and some others don't have it).
-
-Changes for version 0.7
-
- 1. The backlog file mechanism has been completely reworked. There are
- now only two backlog files: one for output and on for input. The
- output file becomes the input file when the input file is
- exhausted.
- 2. Much less strenuous use of writev. Solaris and other sv4r
- machines have an amazingly low value for the maximum number of
- iovecs that can be passed into writev.
- 3. Proper connection cleanup (QUIT issued) at shutdown.
- 4. A lock is taken out in the backlog directory for each peer. To feed
- the same peer from two different instances of innfeed (with a
- batch file for example), then you must use another directory.
- 5. Creating a file in the backlog directory with the same name as the
- peer, the that file will be used next time backlog files are
- processed. Its format must be:
-
- pathname msgid
-
- where pathname is absolute, or relative to the top of the news
- spool.
- 6. More command line options.
- 7. Dynamic peer creation. If the proper command line option is
- used (-y) and innfeed is to told to feed a peer that it doesn't
- have in its config file, then it will create a new binding to
- the new peer. The ip name must be the same as the peername,
- i.e. if innd tells innfeed about a peer fooBarBat, then
- gethostbyname("fooBarBat") better work.
- 8. Connections will be periodically torn down (1 hour is the
- default), even if they're active, so that non-innd peers don't
- have problems with their history files being kept open for too
- long.
- 9. The input backlog files are checkpointed every 30 seconds
- so that a crash while processing a large backlog doesn't require
- starting over from the beginning.
-
-Changes for version 0.6
-
- 1. Logging of spooling of backlog only happens once per
- stats-logging period.
-
-Bugs/Problems/Notes etc:
-
- 1. There is no graceful handling of file descriptor exhaustion.
-
- 2. If the following situation occurs:
-
- - articles on disk are NOT in NNTP-ready format.
- - innfeed was built with HAVE_MMAP defined.
- - memory usage is higher than expected
-
- try running innfeed with the '-M' flag (or recompiling with
- HAVE_MMAP undefined). Solaris, and possibly other SVR4 machines,
- waste a lot of swap space.
-
- 3. On the stats logging the 'offered' may not equal the sum of the
- other fields. This is because the stats at that moment were
- generated while waiting for a response to a command to come
- back. Innfeed considers an article ``offered'' when it sends the
- command, not when it gets a response back. Perhaps this should
- change.
-
- 4. If all the Connections for a peer are idle and a new backlog file
- is dropped in by hand, then it will not be picked up until the
- next time it gets an article from innd for that peer. This will
- be fixed in a later version, but for now, if the peer is likely
- to be idle for a long time, then flush the process.
-
- 5. Adding a backlog file by hand does not cause extra Connections to
- be automatically created, only the existing Connections will use
- the file. If the extra load requires new Connections to be built
- when innd delivers new articles for tranmission, then they too
- will use the file, but this a side effect and not a direct
- consequence. This means if you want to run in '-x' mode, then
- make sure your config file entry states the correct number of
- initial connections, as they're all the Connections that will be
- created.
-
- 6. If '-x' is used and the config file has an entry for a peer that
- has no batch file to process, then innfeed will not exit after
- all batch files have been finished--it will just site there idle.
-
- 7. If the remote is running inn and only has you in the nnrp.access
- file, then innfeed will end up talking to nnrpd. Innfeed will
- try every 30 seconds to reconnect to a server that will accept
- IHAVE commands. i.e. there is no exponential back of retry
- attempt. This is because the connection is considered good once
- the MODE STREAM command has been accepted or rejected (and nnrpd
- rejects it).
-
-Futures:
-
- 1. Innfeed will eventually take exploder commands.
-
- 2. The config file will be revamped to allow for more global
- options etc and run-time configuration. Too much is compile-time
- dependant at the moment.
-
- 3. The connection retry time will get more sophisticated to catch
- problems like the nnrpd issue mentioned above.
-
- 4. Include the number of takesthis/check/ihave commands issued in
- the log entries.
-
- 5. Heaps more stuff requested that's buried in my mail folders.
-
-
-Any compliments, complaints, requests, porting issues etc. should go to
-inn-bugs@isc.org.
-
-Many thanks to the following people for extra help (above and beyond the
-call of duty) with pateches, beta testing and/or suggestions:
-
- Christophe Wolfhugel <wolf@pasteur.fr>
- Robert Elz <kre@munnari.oz.au>
- Russell Vincent <vincent@ucthpx.uct.ac.za>
- Paul Vixie <paul@vix.com>
- Stephen Stuart <stuart@pa.dec.com>
- John T. Stapleton <stapes@mro.dec.com>
- Alan Barrett <apb@iafrica.com>
- Lee McLoughlin <lmjm@doc.ic.ac.uk>
- Dan Ellis <ellis@mail.microserve.net>
- Katsuhiro Kondou <kondou@uxd.fc.nec.co.jp>
- Marc G. Fournier <scrappy@ki.net>
- Steven Bauer <sbauer@msmailgw.sdsmt.edu>
- Richard Perini <rpp@ci.com.au>
- Per Hedeland <per@erix.ericsson.se>
- Clayton O'Neill <coneill@premier.net>
- Dave Pascoe <dave@mathworks.com>
- Michael Handler <handler@netaxs.com>
- Petr Lampa <lampa@fee.vutbr.cz>
- David Lawrence <tale@uu.net>
- Don Lewis <Don.Lewis@tsc.tdk.com>
- Landon Curt Noll <noll@sgi.com>
-
-If I've forgotten anybody, please let me know.
-
-Thanks also to the ISC for sponsoring this work.
+++ /dev/null
-/* $Id: article.c 7285 2005-06-07 06:38:24Z eagle $
-**
-** The Article class for innfeed.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The implementation of the Article class. Articles are the abstraction for
-** the actual news articles. They are a reference counted object because they
-** need to be shared by multiple Host and Connection objects. When an Article
-** is created it verifies that the actual file exists. When a Connection
-** wants the article's contents for transmission the Article reads the data
-** off disk and returns a set of Buffer objects. The Article holds onto these
-** Buffers so that the next Connection that wants to transmit it won't have
-** to wait for a disk read to be done again.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <sys/stat.h>
-#include <syslog.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "storage.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "endpoint.h"
-
-#if defined (NDEBUG)
-#define VALIDATE_HASH_TABLE() (void (0))
-#else
-#define VALIDATE_HASH_TABLE() hashValidateTable ()
-#endif
-
-extern bool useMMap ;
-
-struct map_info_s {
- ARTHANDLE *arthandle;
- const void *mMapping;
- size_t size;
- int refCount;
- struct map_info_s *next;
-};
-
-typedef struct map_info_s *MapInfo;
-
-struct article_s
-{
- int refCount ; /* the reference count on this article */
- char *fname ; /* the file name of the article */
- char *msgid ; /* the msgid of the article (INN tells us) */
- Buffer contents ; /* the buffer of the actual on disk stuff */
- Buffer *nntpBuffers ; /* list of buffers for transmisson */
- MapInfo mapInfo; /* arthandle and mMapping */
- bool loggedMissing ; /* true if article is missing and we logged */
- bool articleOk ; /* true until we know otherwise. */
- bool inWireFormat ; /* true if ->contents is \r\n/dot-escaped */
-} ;
-
-struct hash_entry_s {
- struct hash_entry_s *next ;
- struct hash_entry_s *prev ;
- struct hash_entry_s *nextTime ;
- struct hash_entry_s *prevTime ;
- unsigned int hash ;
- Article article ;
-};
-
-typedef struct hash_entry_s *HashEntry ;
-
- /*
- * Private functions
- */
-
-static Buffer artGetContents (Article article) ; /* Return the buffer that
- fillContents() filled
- up. */
-
- /* Log statistics on article memory usage. */
-static void logArticleStats (TimeoutId id, void *data) ;
-
-static bool fillContents (Article article) ; /* Read the article's bits
- off the disk. */
-
- /* Append buffer B to the buffer array BUFFS. */
-static void appendBuffer (Buffer b, Buffer **buffs, int *newSpot, int *curLen);
-
-static bool prepareArticleForNNTP (Article article) ; /* Do the necessary
- CR-LF stuff */
-
-static bool artFreeContents (Article art) ; /* Tell the Article to release
- its contents buffer if
- possible. */
-
-static void artUnmap (Article art) ; /* munmap an mmap()ed
- article */
-
-
- /*
- * Hash table routine declarations.
- */
-
- /* Returns a has value for the given string */
-static unsigned int hashString (const char *string) ;
-
- /* Locates the article with the given message ID, in the has table. */
-static Article hashFindArticle (const char *msgid) ;
-
- /* Puts the given article in the hash table. */
-static void hashAddArticle (Article article) ;
-
- /* Removes the given article from the has table */
-static bool hashRemoveArticle (Article article) ;
-
- /* Does some simple-minded hash table validation */
-static void hashValidateTable (void) ;
-
-
-
- /*
- * Private data
- */
-
-
-static unsigned int missingArticleCount ; /* Number of articles that were missing */
-
-static bool logMissingArticles ; /* if true then we log the details on a
- missing article. */
-
-static unsigned int preparedBytes ; /* The number of areticle bytes read in so
- far of disk (will wrap around) */
-
-static unsigned int preparedNewlines ; /* The number of newlines found in all the
- preparedBytes */
-
-static unsigned int avgCharsPerLine ; /* The average number of characters per
- line over all articles. */
-
-static bool rolledOver ; /* true if preparedBytes wrapped around */
-
-static unsigned int bytesInUse ; /* count of article contents bytes in use--just
- the amount read from the article files, not
- all memory involved in. */
-
-static unsigned int maxBytesInUse ; /* the limit we want to stay under for total
- bytes resident in memory dedicated to
- article contents. */
-
-static unsigned int articlesInUse ; /* number of articles currently allocated. */
-
-static unsigned int byteTotal ; /* number of bytes for article contents
- allocated totally since last log. */
-
-static unsigned int articleTotal ; /* number of articles alloced since last log. */
-
-static TimeoutId articleStatsId ; /* The timer callback id. */
-
-static MapInfo mapInfo;
-
- /*
- * Hash Table data
- */
-
-static HashEntry *hashTable ; /* the has table itself */
-static HashEntry chronList ; /* chronologically ordered. Points at newest */
-
-#define TABLE_SIZE 2048 /* MUST be a power of 2 */
-#define HASH_MASK (TABLE_SIZE - 1)
-#define TABLE_ENTRY(hash) ((hash) & HASH_MASK)
-
-
-
- /*******************************************************************/
- /** PUBLIC FUNCTIONS **/
- /*******************************************************************/
-
- /* Create a new article object. First looks to see if one with the given
- message id already exists in the hash table and if so returns that
- (after incrementing the reference count). */
-Article newArticle (const char *filename, const char *msgid)
-{
- Article newArt = NULL ;
-
- TMRstart(TMR_NEWARTICLE);
- if (hashTable == NULL)
- { /* first-time through initialization. */
- int i ;
-
- ASSERT ((TABLE_SIZE & HASH_MASK) == 0) ;
- hashTable = xmalloc (sizeof(HashEntry) * TABLE_SIZE) ;
-
- addPointerFreedOnExit ((char *)hashTable) ;
-
- for (i = 0 ; i < TABLE_SIZE ; i++)
- hashTable [i] = NULL ;
-
- if (ARTICLE_STATS_PERIOD > 0)
- articleStatsId = prepareSleep (logArticleStats,ARTICLE_STATS_PERIOD,0);
- }
-
- /* now look for it in the hash table. We presume the disk file is still
- ok */
- if ((newArt = hashFindArticle (msgid)) == NULL)
- {
- newArt = xcalloc (1, sizeof(struct article_s)) ;
-
- newArt->fname = xstrdup (filename) ;
- newArt->msgid = xstrdup (msgid) ;
-
- newArt->contents = NULL ;
- newArt->mapInfo = NULL ;
- newArt->refCount = 1 ;
- newArt->loggedMissing = false ;
- newArt->articleOk = true ;
- newArt->inWireFormat = false ;
-
- d_printf (3,"Adding a new article(%p): %s\n", (void *)newArt, msgid) ;
-
- articlesInUse++ ;
- articleTotal++ ;
-
- hashAddArticle (newArt) ;
- }
- else
- {
- if (strcmp (filename,newArt->fname) != 0)
- warn ("ME two filenames for same article: %s, %s", filename,
- newArt->fname) ;
-
- newArt->refCount++ ;
- d_printf (2,"Reusing existing article for %s\nx",msgid) ;
- }
- TMRstop(TMR_NEWARTICLE);
- return newArt ;
-}
-
-
- /* Decrement the reference count on the article and free up its memory if
- the ref count gets to 0. */
-void delArticle (Article article)
-{
- if (article == NULL)
- return ;
-
- ASSERT (article->refCount > 0) ;
-
- if (--(article->refCount) == 0)
- {
- bool removed = hashRemoveArticle (article) ;
-
- ASSERT (removed == true) ;
-
- d_printf (2,"Cleaning up article (%p): %s\n",
- (void *)article, article->msgid) ;
-
- if (article->contents != NULL)
- {
- if (article->mapInfo)
- artUnmap(article);
- else
- bytesInUse -= bufferDataSize (article->contents) ;
-
- if (article->nntpBuffers != NULL)
- freeBufferArray (article->nntpBuffers) ;
-
- delBuffer (article->contents) ;
- }
-
- articlesInUse-- ;
-
- free (article->fname) ;
- free (article->msgid) ;
- free (article) ;
- }
-
- VALIDATE_HASH_TABLE () ;
-}
-
-
-void gPrintArticleInfo (FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Article information : (count %d) {\n",
- indent, articlesInUse) ;
-
- fprintf (fp,"%s missingArticleCount : %d\n",indent,missingArticleCount) ;
- fprintf (fp,"%s logMissingArticles : %d\n",indent,logMissingArticles) ;
- fprintf (fp,"%s preparedBytes : %d\n",indent,preparedBytes) ;
- fprintf (fp,"%s preparedNewlines : %d\n",indent,preparedNewlines) ;
- fprintf (fp,"%s avgCharsPerLine : %d\n",indent,avgCharsPerLine) ;
- fprintf (fp,"%s rolledOver : %s\n",indent,boolToString (rolledOver)) ;
- fprintf (fp,"%s bytesInUse : %d\n",indent,bytesInUse) ;
- fprintf (fp,"%s maxBytesInUse : %d\n",indent,maxBytesInUse) ;
- fprintf (fp,"%s articlesInUse : %d\n",indent,articlesInUse) ;
- fprintf (fp,"%s byteTotal : %d\n",indent,byteTotal) ;
- fprintf (fp,"%s articleTotal : %d\n",indent,articleTotal) ;
- fprintf (fp,"%s articleStatsId : %d\n",indent,articleStatsId) ;
-
- {
- HashEntry he ;
-
- for (he = chronList ; he != NULL ; he = he->nextTime)
- printArticleInfo (he->article,fp,indentAmt + INDENT_INCR) ;
- }
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void printArticleInfo (Article art, FILE *fp, unsigned int indentAmt)
-{
- Buffer *b ;
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sArticle : %p {\n",indent,(void *) art) ;
- fprintf (fp,"%s article ok : %s\n",indent,boolToString (art->articleOk)) ;
- fprintf (fp,"%s refcount : %d\n",indent,art->refCount) ;
- fprintf (fp,"%s filename : %s\n",indent,art->fname) ;
- fprintf (fp,"%s msgid : %s\n",indent,art->msgid) ;
-
- fprintf (fp,"%s contents buffer : {\n",indent) ;
-#if 0
- printBufferInfo (art->contents,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) art->contents) ;
-#endif
-
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s nntp buffers : {\n",indent) ;
- for (b = art->nntpBuffers ; b != NULL && *b != NULL ; b++)
-#if 0
- printBufferInfo (*b,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) *b) ;
-#endif
-
- fprintf (fp,"%s }\n", indent) ;
-
- fprintf (fp,"%s logged missing : %s\n",
- indent,boolToString (art->loggedMissing));
- fprintf (fp,"%s}\n", indent) ;
-
-}
-
- /* return true if we have or are able to get the contents off the disk */
-bool artContentsOk (Article article)
-{
- bool rval = false ;
-
- if ( prepareArticleForNNTP (article) )
- rval = true ;
-
- return rval ;
-}
-
-
- /* bump reference count on the article. */
-Article artTakeRef (Article article)
-{
- if (article != NULL)
- article->refCount++ ;
-
- return article ;
-}
-
-
- /* return the filename of the article */
-const char *artFileName (Article article)
-{
- if (article == NULL)
- return NULL ;
- else
- return article->fname ;
-}
-
-
- /* Get a NULL terminated array of Buffers that is ready for sending via NNTP */
-
-Buffer *artGetNntpBuffers (Article article)
-{
- if ( !prepareArticleForNNTP (article) )
- return NULL ;
-
- return dupBufferArray (article->nntpBuffers) ;
-}
-
-
- /* return the message id of the article */
-const char *artMsgId (Article article)
-{
- return article->msgid ;
-}
-
- /* return size of the article */
-int artSize (Article article)
-{
- if (article == NULL || article->contents == NULL)
- return (int)0 ;
- return (int)bufferDataSize(article->contents);
-}
-
-
- /* return how many NNTP-ready buffers the article contains */
-unsigned int artNntpBufferCount (Article article)
-{
- if ( !prepareArticleForNNTP (article) )
- return 0 ;
-
- return bufferArrayLen (article->nntpBuffers) ;
-}
-
-
- /* if VAL is true then all missing articles will be logged. */
-void artLogMissingArticles (bool val)
-{
- logMissingArticles = val ;
-}
-
-
- /* set the limit we want to stay under. */
-void artSetMaxBytesInUse (unsigned int val)
-{
- ASSERT (maxBytesInUse > 0) ; /* can only set one time. */
- ASSERT (val > 0) ;
-
- maxBytesInUse = val ;
-}
-
-
- /**********************************************************************/
- /** STATIC FUNCTIONS **/
- /**********************************************************************/
-
-
- /* return a single buffer that contains the disk image of the article (i.e.
- not fixed up for NNTP). */
-static Buffer artGetContents (Article article)
-{
- Buffer rval = NULL ;
-
- if (article->articleOk)
- {
- if (article->contents == NULL)
- fillContents (article) ;
-
- if (article->contents != NULL)
- rval = bufferTakeRef (article->contents) ;
- }
-
- return rval ;
-}
-
- /* arthandle/mMapping needs to be refcounted since a buffer
- may exist referencing it after delArticle if the remote
- host sends the return status too soon (diablo, 439). */
-
-static MapInfo getMapInfo(ARTHANDLE *arthandle,
- const void *mMapping, size_t size)
-{
- MapInfo m;
-
- for (m = mapInfo; m; m = m->next) {
- if (m->arthandle == arthandle &&
- m->mMapping == mMapping) {
- m->refCount++;
- return m;
- }
- }
-
- m = xmalloc(sizeof(struct map_info_s));
- m->refCount = 1;
- m->arthandle = arthandle;
- m->mMapping = mMapping;
- m->size = size;
- m->next = mapInfo;
- mapInfo = m;
-
- return m;
-}
-
-static void delMapInfo(void *vm)
-{
- MapInfo i, prev;
- MapInfo m = (MapInfo)vm;
-
- if (m == NULL)
- return;
-
- if (--(m->refCount) > 0)
- return;
-
- if (m->arthandle)
- SMfreearticle(m->arthandle);
- else
- if (munmap(m->mMapping, m->size) < 0)
- syslog (LOG_NOTICE, "munmap article: %m");
-
- prev = NULL;
- for (i = mapInfo; i != m; i = i->next)
- prev = i;
-
- if (prev)
- prev->next = m->next;
- else
- mapInfo = m->next;
-
- free(m);
-}
-
-static void artUnmap (Article article) {
-
- delMapInfo(article->mapInfo);
- article->mapInfo = NULL;
-}
-
-
-
-static void logArticleStats (TimeoutId id, void *data UNUSED)
-{
- ASSERT (id == articleStatsId) ;
-
- notice ("ME articles active %d bytes %d", articlesInUse, bytesInUse) ;
- notice ("ME articles total %d bytes %d", articleTotal, byteTotal) ;
-
- byteTotal = 0 ;
- articleTotal = 0 ;
-
- articleStatsId = prepareSleep (logArticleStats,ARTICLE_STATS_PERIOD,0) ;
-}
-
-
- /* do the actual read of the article off disk into a Buffer that is stored
- in the Article object. The Article will end up with its contents field
- having a buffer with the article data in it. This buffer may be
- holding a mmapped pointer, or it may be simply a regular buffer with
- the data read off disk into it. In the regular buffer case the
- contents may be copied around after reading to insert a carriage
- return before each newline. */
-
-static bool fillContents (Article article)
-{
- int fd = -1;
- char *p;
- static bool maxLimitNotified ;
- bool opened;
- size_t articlesize = 0;
- char *buffer = NULL ;
- int amt = 0 ;
- size_t idx = 0, amtToRead ;
- size_t newBufferSize ;
- HashEntry h ;
- ARTHANDLE *arthandle = NULL;
- const void *mMapping = NULL;
-
- ASSERT (article->contents == NULL) ;
-
- TMRstart(TMR_READART);
- if (maxBytesInUse == 0)
- maxBytesInUse = SOFT_ARTICLE_BYTE_LIMIT ;
-
- if (avgCharsPerLine == 0)
- avgCharsPerLine = 75 ; /* roughly number of characters per line */
-
- if (IsToken(article->fname)) {
- opened = ((arthandle = SMretrieve(TextToToken(article->fname), RETR_ALL)) != NULL) ? true : false;
- if (opened)
- articlesize = arthandle->len;
- else {
- if (SMerrno != SMERR_NOENT && SMerrno != SMERR_UNINIT) {
- syslog(LOG_ERR, "Could not retrieve %s: %s",
- article->fname, SMerrorstr);
- article->articleOk = false;
- TMRstop(TMR_READART);
- return false;
- }
- }
- } else {
- struct stat sb ;
-
- opened = ((fd = open (article->fname,O_RDONLY,0)) >= 0) ? true : false;
- arthandle = NULL;
- if (opened) {
- if (fstat (fd, &sb) < 0) {
- article->articleOk = false ;
- syswarn ("ME oserr fstat %s", article->fname) ;
- TMRstop(TMR_READART);
- return false;
- }
- if (!S_ISREG (sb.st_mode)) {
- article->articleOk = false ;
- warn ("ME article file-type: %s", article->fname) ;
- TMRstop(TMR_READART);
- return false;
- }
- if (sb.st_size == 0) {
- article->articleOk = false ;
- warn ("ME article 0 bytes: %s", article->fname) ;
- TMRstop(TMR_READART);
- return false;
- }
- articlesize = sb.st_size;
- }
- }
-
- if (!opened) {
- article->articleOk = false ;
- missingArticleCount++ ;
-
- if (logMissingArticles && !article->loggedMissing)
- {
- notice ("ME article missing: %s, %s", article->msgid,
- article->fname) ;
- article->loggedMissing = true ;
- }
- TMRstop(TMR_READART);
- return false;
- }
- amtToRead = articlesize ;
- newBufferSize = articlesize ;
-
- if (arthandle || useMMap) {
- if (arthandle)
- mMapping = arthandle->data;
- else
- mMapping = mmap(NULL, articlesize, PROT_READ,
- MAP_SHARED, fd, 0);
-
- if (mMapping == MAP_FAILED) {
- /* dunno, but revert to plain reading */
- mMapping = NULL ;
- syswarn ("ME mmap failure %s (%s)",
- article->fname,
- strerror(errno)) ;
- } else {
- article->contents = newBufferByCharP(mMapping,
- articlesize,
- articlesize);
- article->mapInfo = getMapInfo(arthandle, mMapping, articlesize);
- article->mapInfo->refCount++; /* one more for the buffer */
- bufferSetDeletedCbk(article->contents, delMapInfo, article->mapInfo);
-
- buffer = bufferBase (article->contents) ;
- if ((p = strchr(buffer, '\n')) == NULL) {
- article->articleOk = false;
- delBuffer (article->contents) ;
- article->contents = NULL ;
- warn ("ME munged article %s", article->fname) ;
- } else {
- if (p[-1] == '\r') {
- article->inWireFormat = true ;
- } else {
- /* we need to copy the contents into a buffer below */
- delBuffer (article->contents) ;
- article->contents = NULL ;
- }
- }
- }
- }
-
- if (article->contents == NULL && article->articleOk) {
- /* an estimate to give some room for nntpPrepareBuffer to use. */
- newBufferSize *= (1.0 + (1.0 / avgCharsPerLine)) ;
- newBufferSize ++ ;
-
- /* if we're going over the limit try to free up some older article's
- contents. */
- if (amtToRead + bytesInUse > maxBytesInUse)
- {
- for (h = chronList ; h != NULL ; h = h->nextTime)
- {
- if (artFreeContents (h->article))
- if (amtToRead + bytesInUse <= maxBytesInUse)
- break ;
- }
- }
-
- /* we we couldn't get below, then log it (one time only) */
- if ((amtToRead + bytesInUse) > maxBytesInUse && maxLimitNotified == false) {
- maxLimitNotified = true ;
- notice ("ME exceeding maximum article byte limit: %d (max),"
- " %lu (cur)", maxBytesInUse,
- (unsigned long) (amtToRead + bytesInUse)) ;
- }
-
- if ((article->contents = newBuffer (newBufferSize)) == NULL)
- amtToRead = 0 ;
- else {
- buffer = bufferBase (article->contents) ;
- bytesInUse += articlesize ;
- byteTotal += articlesize ;
- }
-
- if (mMapping && buffer != NULL) {
- memcpy(buffer, mMapping, articlesize);
- artUnmap(article) ;
- amtToRead = 0;
- }
-
- while (amtToRead > 0) {
- if ((amt = read (fd, buffer + idx,amtToRead)) <= 0) {
- syswarn ("ME article read error: %s", article->fname) ;
- bytesInUse -= articlesize ;
- byteTotal -= articlesize ;
- amtToRead = 0 ;
-
- delBuffer (article->contents) ;
- article->contents = NULL ;
- }
- else {
- idx += amt ;
- amtToRead -= amt ;
- }
- }
-
- if (article->contents != NULL) {
- bufferSetDataSize (article->contents, articlesize) ;
-
- if ((p = strchr(buffer, '\n')) == NULL) {
- article->articleOk = false;
- warn ("ME munged article %s", article->fname) ;
- }
- else if (p[-1] == '\r') {
- article->inWireFormat = true ;
- }
- else {
- if ( nntpPrepareBuffer (article->contents) ) {
- size_t diff =
- (bufferDataSize (article->contents) - articlesize) ;
-
- if (((unsigned int) UINT_MAX) - diff <= preparedBytes) {
- d_printf (2,"Newline ratio so far: %02.2f\n",
- ((double) preparedBytes / preparedNewlines)) ;
- notice ("ME newline to file size ratio: %0.2f (%d/%d)",
- ((double) preparedBytes)/preparedNewlines,
- preparedBytes,preparedNewlines) ;
- preparedBytes = 0 ;
- preparedNewlines = 0 ;
- rolledOver = true ;
- }
-
- preparedBytes += articlesize ;
- preparedNewlines += diff ;
- bytesInUse += diff ;
- byteTotal += diff ;
-
- if (preparedBytes > (1024 * 1024)) {
- avgCharsPerLine =
- ((double) preparedBytes) / preparedNewlines ;
- avgCharsPerLine++ ;
- }
- article->inWireFormat = true ;
- } else {
- warn ("ME internal failed to prepare buffer for NNTP") ;
- bytesInUse -= articlesize ;
- byteTotal -= articlesize ;
-
- delBuffer (article->contents) ;
- article->contents = NULL ;
- }
- }
- }
- }
-
-
- /* If we're not useing storage api, we should close a valid file descriptor */
- if (!arthandle && (fd >= 0))
- close (fd) ;
-
- TMRstop(TMR_READART);
- return (article->contents != NULL ? true : false) ;
-}
-
-
-
- /* stick the buffer B into the Buffer array pointed at by BUFFS *BUFFS is
- reallocated if necessary. NEWSPOT points at the index where B should be
- put (presumably the end). CURLEN points at the length of the BUFFS and
- it will get updated if BUFFS is reallocated. */
-static void appendBuffer (Buffer b, Buffer **buffs, int *newSpot, int *curLen)
-{
- if (*newSpot == *curLen)
- {
- *curLen += 10 ;
- *buffs = xrealloc (*buffs, sizeof(Buffer) * *curLen) ;
- }
- (*buffs) [(*newSpot)++] = b ;
-}
-
-
-
- /* Takes the articles contents buffer and overlays a set of new buffers on
- top of it. These buffers insert the required carriage return and dot
- characters as needed */
-static bool prepareArticleForNNTP (Article article)
-{
- static Buffer dotFirstBuffer ;
- static Buffer dotBuffer ;
- static Buffer crlfBuffer ;
- Buffer *nntpBuffs = NULL ;
- int buffLen = 0 ;
- int buffIdx = 0 ;
- char *start, *end ;
- Buffer contents ;
-
- contents = artGetContents (article) ; /* returns a reference */
-
- TMRstart(TMR_PREPART);
- if (contents == NULL) {
- TMRstop(TMR_PREPART);
- return false ;
- }
- else if (article->nntpBuffers != NULL)
- {
- delBuffer (contents) ;
- TMRstop(TMR_PREPART);
- return true ; /* already done */
- }
-
- if (dotBuffer == NULL)
- {
- dotBuffer = newBufferByCharP (".\r\n",3,3) ;
- dotFirstBuffer = newBufferByCharP ("\r\n.",3,3) ;
- crlfBuffer = newBufferByCharP ("\r\n",2,2) ;
- }
-
- /* overlay a set of buffers on top of the articles contents buffer. This
- is a real speed loss at the moment, so by default it's disabled (by
- calling artBitFiddleContents(true) in main(). */
- if (article->inWireFormat == false)
- {
- end = bufferBase (contents) ;
- do
- {
- start = end ;
-
- while (*end && *end != '\n')
- end++ ;
-
- appendBuffer (newBufferByCharP (start, (size_t) (end - start),
- (size_t) (end - start)),
- &nntpBuffs,&buffIdx,&buffLen) ;
-
- if (*end != '\0')
- end++ ;
-
- }
- while (*end != '\0') ;
-
- appendBuffer (bufferTakeRef (dotBuffer), &nntpBuffs,&buffIdx,&buffLen) ;
- appendBuffer (NULL,&nntpBuffs,&buffIdx,&buffLen) ;
- }
- else
- {
- /* we already fixed the contents up when we read in the article */
- nntpBuffs = xmalloc (sizeof(Buffer) * 3) ;
- nntpBuffs [0] = newBufferByCharP (bufferBase (contents),
- bufferDataSize (contents),
- bufferDataSize (contents)) ;
- if (article->mapInfo) {
- article->mapInfo->refCount++;
- bufferSetDeletedCbk(nntpBuffs[0], delMapInfo, article->mapInfo);
- }
- nntpBuffs [1] = NULL ;
- }
-
-
- delBuffer (contents) ; /* the article is still holding a reference */
- article->nntpBuffers = nntpBuffs ;
- TMRstop(TMR_PREPART);
- return true ;
-}
-
-
- /* free the contents of the buffers if article is the only thing holding a
- reference. Returns true if it could, false if it couldn't */
-static bool artFreeContents (Article art)
-{
- if (art->contents == NULL)
- return false ;
-
- if (art->nntpBuffers != NULL)
- {
- if (bufferRefCount (art->nntpBuffers[0]) > 1)
- return false ;
- else
- {
- freeBufferArray (art->nntpBuffers) ;
- art->nntpBuffers = NULL ;
- }
- }
-
- ASSERT (bufferRefCount (art->contents) == 1) ;
-
- if (art->mapInfo)
- artUnmap(art);
- else
- bytesInUse -= bufferDataSize (art->contents) ;
-
- delBuffer (art->contents) ;
-
- art->contents = NULL ;
-
- return true ;
-}
-
-
-
-
-
-
-
-
- /**********************************************************************/
- /* Private hash table and routines for storing articles */
- /**********************************************************************/
-
-
-
-
- /* Hash function lifted from perl 5 */
-static unsigned int hashString (const char *string)
-{
- unsigned int i ;
-
- for (i = 0 ; string && *string ; string++)
- i = 33 * i + (u_char) *string ;
-
- return i ;
-}
-
-
- /* find the article in the has table and return it. */
-static Article hashFindArticle (const char *msgid)
-{
- unsigned int hash = hashString (msgid) ;
- HashEntry h ;
-
- for (h = hashTable [TABLE_ENTRY(hash)] ; h != NULL ; h = h->next)
- if (hash == h->hash && strcmp (msgid,h->article->msgid) == 0)
- break ;
-
- return (h == NULL ? NULL : h->article) ;
-}
-
-
- /* add the article to the hash table. */
-static void hashAddArticle (Article article)
-{
- unsigned int hash = hashString (article->msgid) ;
- HashEntry h ;
- HashEntry ne ;
-
- h = hashTable [TABLE_ENTRY(hash)] ;
-
- ne = xmalloc (sizeof(struct hash_entry_s));
-
- ne->article = article ;
- ne->hash = hash ;
- ne->next = hashTable [TABLE_ENTRY(hash)] ;
- ne->prev = NULL ;
-
- if (h != NULL)
- h->prev = ne ;
-
- hashTable [TABLE_ENTRY(hash)] = ne ;
-
- ne->nextTime = chronList ;
- ne->prevTime = NULL ;
-
- if (chronList != NULL)
- chronList->prevTime = ne ;
-
- chronList = ne ;
-}
-
-
- /* remove the article from the hash table and chronological list.
- Does not delete the article itself. */
-static bool hashRemoveArticle (Article article)
-{
- unsigned int hash = hashString (article->msgid) ;
- HashEntry h ;
-
- for (h = hashTable [TABLE_ENTRY(hash)] ; h != NULL ; h = h->next)
- if (hash == h->hash && strcmp (article->msgid,h->article->msgid) == 0)
- break ;
-
- if (h == NULL)
- return false ;
-
- if (h == hashTable [TABLE_ENTRY(hash)])
- {
- hashTable [TABLE_ENTRY(hash)] = h->next ;
- if (h->next != NULL)
- h->next->prev = NULL ;
- }
- else
- {
- h->prev->next = h->next ;
- if (h->next != NULL)
- h->next->prev = h->prev ;
- }
-
- if (chronList == h)
- {
- chronList = h->nextTime ;
- if (chronList != NULL)
- chronList->prevTime = NULL ;
- }
- else
- {
- h->prevTime->nextTime = h->nextTime ;
- if (h->nextTime != NULL)
- h->nextTime->prevTime = h->prevTime ;
- }
-
- free (h) ;
-
- return true ;
-}
-
-#define HASH_VALIDATE_BUCKET_COUNT 1 /* hash buckets to check per call */
-
-static void hashValidateTable (void)
-{
- static int hbn = 0 ;
- int i ;
- HashEntry he ;
-
-#if ! defined (NDEBUG)
- for (i = 0 ; i < HASH_VALIDATE_BUCKET_COUNT ; i++)
- {
- for (he = hashTable [hbn] ; he != NULL ; he = he->next)
- ASSERT (he->article->refCount > 0) ;
- if (++hbn >= TABLE_SIZE)
- hbn = 0 ;
- }
-#endif
-}
+++ /dev/null
-/* $Id: article.h 6648 2004-01-25 20:07:11Z rra $
-**
-** The public interface to articles.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The public interface to articles. The articles are implemented via
-** reference counting. This interface provides the methods for getting the
-** contents of the article.
-**
-** When an Article is created there's a chance that another copy of it
-** already exists. For example if the Article is pulled out of a Tape for a
-** particular host it may already be in existance in some other host. This
-** class will manage this situation to prevent multiple copies of the article
-** being in core.
-*/
-
-#if ! defined ( article_h__ )
-#define article_h__
-
-#include <stdio.h>
-
-#include "misc.h"
-
-
- /* Create a new Article object. FILENAME is the path of the file the */
- /* article is in. MSGID is the news message id of the article */
-Article newArticle (const char *filename, const char *msgid) ;
-
- /* delete the given article. Just decrements refcount and then FREEs if the
- refcount is 0. */
-void delArticle (Article article) ;
-
-void gPrintArticleInfo (FILE *fp, unsigned int indentAmt) ;
-
- /* print some debugging info about the article. */
-void printArticleInfo (Article art, FILE *fp, unsigned int indentAmt) ;
-
- /* return true if this article's file still exists. */
-bool artFileIsValid (Article article) ;
-
- /* return true if we have the article's contents (calling this may trigger
- the reading off the disk). */
-bool artContentsOk (Article article) ;
-
- /* increments reference count and returns a copy of article that can be
- kept (or passed off to someone else) */
-Article artTakeRef (Article article) ;
-
- /* return the pathname of the file the article is in. */
-const char *artFileName (Article article) ;
-
- /* return a list of buffers suitable for giving to an endpoint. The return
- value can (must) be given to freeBufferArray */
-Buffer *artGetNntpBuffers (Article article) ;
-
- /* return the message id stoed in the article object */
-const char *artMsgId (Article article) ;
-
- /* return size of the article */
-int artSize (Article article) ;
-
- /* return the number of buffers that artGetNntpBuffers() would return. */
-unsigned int artNntpBufferCount (Article article) ;
-
- /* tell the Article class to log (or not) missing articles as they occur. */
-void artLogMissingArticles (bool val) ;
-
- /* if VAL is true, then when an article is read off disk the necesary
- carriage returns are inserted instead of setting up iovec-style buffers
- for writev. Useful for systems like solaris that have very small max
- number of iovecs that writev can take. Must be called only once before
- the first article is created. */
-void artBitFiddleContents (bool val) ;
-
- /* set the limit on the number of bytes in all articles (this is not a hard
- limit). Can only be called one time before any articles are created. */
-void artSetMaxBytesInUse (unsigned int val) ;
-
-#endif /* article_h__ */
+++ /dev/null
-/* $Id: buffer.c 7285 2005-06-07 06:38:24Z eagle $
-**
-** The Buffer class for innfeed.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The implementation of the Buffer class. Buffers are reference counted
-** objects that abstract memory regions in a way similar to struct iovec.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include <assert.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "buffer.h"
-
-
-static Buffer gBufferList = NULL ;
-static Buffer bufferPool = NULL ;
-static unsigned int bufferCount = 0 ;
-static unsigned int bufferByteCount = 0 ;
-
-
-struct buffer_s
-{
- int refCount ;
- char *mem ;
- size_t memSize ; /* the length of mem */
- size_t dataSize ; /* amount that has actual data in it. */
- bool deletable ;
- void (*bufferDeletedCbk)(void *);
- void *bufferDeletedCbkData;
- struct buffer_s *next ;
- struct buffer_s *prev ;
-};
-
-#define BUFFER_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (struct buffer_s)))
-
-static void fillBufferPool (void)
-{
- unsigned int i ;
-
- bufferPool = xmalloc (sizeof(struct buffer_s) * BUFFER_POOL_SIZE) ;
-
- for (i = 0; i < BUFFER_POOL_SIZE - 1; i++)
- bufferPool[i] . next = &(bufferPool [i + 1]) ;
- bufferPool [BUFFER_POOL_SIZE-1] . next = NULL ;
-}
-
-
-Buffer newBuffer (size_t size)
-{
- Buffer nb ;
-
- if (bufferPool == NULL)
- fillBufferPool() ;
-
- nb = bufferPool;
- ASSERT (nb != NULL) ;
- bufferPool = bufferPool->next ;
-
- nb->refCount = 1 ;
-
- nb->mem = xmalloc (size + 1) ;
-
- nb->mem [size] = '\0' ;
- nb->memSize = size ;
- nb->dataSize = 0 ;
- nb->deletable = true ;
- nb->bufferDeletedCbk = NULL;
- nb->bufferDeletedCbkData = NULL;
-
- bufferByteCount += size + 1 ;
- bufferCount++ ;
-
- nb->next = gBufferList ;
- nb->prev = NULL;
- if (gBufferList != NULL)
- gBufferList->prev = nb ;
- gBufferList = nb ;
-
-#if 0
- d_printf (1,"Creating a DELETABLE buffer %p\n",nb) ;
-#endif
-
- return nb ;
-}
-
-
-Buffer newBufferByCharP (const char *ptr, size_t size, size_t dataSize)
-{
- Buffer nb ;
-
- if (bufferPool == NULL)
- fillBufferPool() ;
-
- nb = bufferPool;
- ASSERT (nb != NULL) ;
- bufferPool = bufferPool->next ;
-
- nb->refCount = 1 ;
- nb->mem = (char *) ptr ; /* cast away const */
- nb->memSize = size ;
- nb->dataSize = dataSize ;
- nb->deletable = false ;
- nb->bufferDeletedCbk = NULL;
- nb->bufferDeletedCbkData = NULL;
-
- nb->next = gBufferList ;
- nb->prev = NULL;
- if (gBufferList != NULL)
- gBufferList->prev = nb ;
- gBufferList = nb ;
-
- bufferCount++ ;
-#if 0
- d_printf (1,"Creating a NON-DELETABLE buffer %p\n",nb) ;
-#endif
-
- return nb ;
-}
-
-
-void delBuffer (Buffer buff)
-{
- if (buff != NULL && --(buff->refCount) == 0)
- {
-#if 0
- d_printf (1,"Freeing a %s buffer (%p)\n",
- (buff->deletable ? "DELETABLE" : "NON-DELETABLE"), buff) ;
-#endif
-
- bufferCount-- ;
- if (buff->deletable)
- {
- bufferByteCount -= (buff->memSize + 1) ;
- free (buff->mem) ;
- buff->mem = NULL ;
- }
-
- if (buff->bufferDeletedCbk) {
- (buff->bufferDeletedCbk)(buff->bufferDeletedCbkData);
- buff->bufferDeletedCbk = NULL;
- buff->bufferDeletedCbkData = NULL;
- }
-
- if (buff->next != NULL)
- buff->next->prev = buff->prev ;
- if (buff->prev != NULL)
- buff->prev->next = buff->next ;
- else
- {
- ASSERT(gBufferList == buff) ;
- gBufferList = buff->next ;
- }
-
- buff->next = bufferPool ;
- bufferPool = buff ;
- }
-}
-
-Buffer bufferTakeRef (Buffer buff)
-{
- ASSERT (buff != NULL) ;
-
- if (buff != NULL)
- buff->refCount++ ;
-
- return buff ;
-}
-
-
-void gPrintBufferInfo (FILE *fp, unsigned int indentAmt)
-{
- Buffer b ;
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Buffer List : (count %d) {\n",indent,bufferCount) ;
-
- for (b = gBufferList ; b != NULL ; b = b->next)
- printBufferInfo (b,fp,indentAmt + INDENT_INCR) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-void printBufferInfo (Buffer buffer, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- char bufferStart [256] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sBuffer : %p {\n",indent,(void *) buffer) ;
-
- if (buffer == NULL)
- {
- fprintf (fp,"%s}\n",indent) ;
- return ;
- }
-
- i = MIN(sizeof (bufferStart) - 1,buffer->dataSize) ;
- memcpy (bufferStart,buffer->mem,i) ;
- bufferStart[i] = '\0';
-
- fprintf (fp,"%s refcount : %d\n",indent,buffer->refCount) ;
- fprintf (fp,"%s data-size : %ld\n",indent,(long) buffer->dataSize) ;
- fprintf (fp,"%s mem-size : %ld\n",indent,(long) buffer->memSize) ;
- fprintf (fp,"%s base : %p\n", indent,(void *) buffer->mem) ;
- fprintf (fp,"%s deletable : %s\n",indent,boolToString(buffer->deletable));
- fprintf (fp,"%s buffer [0:%ld] : \"%s\"\n",
- indent, (long) i, bufferStart) ;
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void *bufferBase (Buffer buff)
-{
- return buff->mem ;
-}
-
-size_t bufferSize (Buffer buff)
-{
- return buff->memSize ;
-}
-
-size_t bufferDataSize (Buffer buff)
-{
- return buff->dataSize ;
-}
-
-void bufferIncrDataSize (Buffer buff, size_t size)
-{
- if (buff->dataSize + size > buff->memSize)
- die ("Trying to make a buffer data size bigger than its memory alloc");
- else
- buff->dataSize += size ;
-}
-
-void bufferDecrDataSize (Buffer buff, size_t size)
-{
- ASSERT (size > buff->dataSize) ;
-
- buff->dataSize -= size ;
-}
-
-void bufferSetDataSize (Buffer buff, size_t size)
-{
- buff->dataSize = size ;
-
- ASSERT (buff->dataSize <= buff->memSize) ;
-}
-
-void bufferSetDeletedCbk (Buffer buff, void (*cbk)(void *), void *data)
-{
- ASSERT(buff->bufferDeletedCbk == NULL &&
- buff->bufferDeletedCbk != cbk);
- ASSERT(buff->bufferDeletedCbkData == NULL &&
- buff->bufferDeletedCbkData != data);
- buff->bufferDeletedCbk = cbk;
- buff->bufferDeletedCbkData = data;
-}
-
-void freeBufferArray (Buffer *buffs)
-{
- Buffer *b = buffs ;
-
- while (b && *b)
- {
- delBuffer (*b) ;
- b++ ;
- }
-
- if (buffs)
- free (buffs) ;
-}
-
-
- /* Allocate an array and put all the arguments (the last of which must be
- NULL) into it. The terminating NULL is put in the returned array. */
-Buffer *makeBufferArray (Buffer buff, ...)
-{
- va_list ap ;
- size_t cLen = 10, idx = 0 ;
- Buffer *ptr, p ;
-
- ptr = xcalloc (cLen, sizeof(Buffer)) ;
-
- ptr [idx++] = buff ;
-
- va_start (ap, buff) ;
- do
- {
- p = va_arg (ap, Buffer) ;
- if (idx == cLen)
- {
- cLen += 10 ;
- ptr = xrealloc (ptr, sizeof(Buffer) * cLen) ;
- }
- ptr [idx++] = p ;
- }
- while (p != NULL) ;
- va_end (ap) ;
-
- return ptr ;
-}
-
-
-bool isDeletable (Buffer buff)
-{
- return buff->deletable ;
-}
-
-
-
- /* Dups the array including taking out references on the Buffers inside */
-Buffer *dupBufferArray (Buffer *array)
-{
- Buffer *newArr ;
- int count = 0 ;
-
- while (array && array [count] != NULL)
- count++ ;
-
- newArr = xmalloc (sizeof(Buffer) * (count + 1)) ;
-
- for (count = 0 ; array [count] != NULL ; count++)
- newArr [count] = bufferTakeRef (array [count]) ;
-
- newArr [count] = NULL ;
-
- return newArr ;
-}
-
-
-unsigned int bufferArrayLen (Buffer *array)
-{
- unsigned int count = 0 ;
-
- if (array != NULL)
- while (*array != NULL)
- {
- count++ ;
- array++ ;
- }
-
- return count ;
-}
-
-
-bool copyBuffer (Buffer dest, Buffer src)
-{
- char *baseDest = bufferBase (dest) ;
- char *baseSrc = bufferBase (src) ;
- unsigned int amt = bufferDataSize (src) ;
-
- if (amt > bufferSize (dest))
- return false ;
-
- memcpy (baseDest, baseSrc, amt) ;
-
- bufferSetDataSize (dest,amt) ;
-
- return true ;
-}
-
-
-unsigned int bufferRefCount (Buffer buf)
-{
- return buf->refCount ;
-}
-
-
-void bufferAddNullByte (Buffer buff)
-{
- char *p = bufferBase (buff) ;
-
- p [buff->dataSize] = '\0' ;
-}
-
-
- /* append the src buffer to the dest buffer growing the dest as needed.
- Can only be done to deletable buffers. */
-bool concatBuffer (Buffer dest, Buffer src)
-{
- ASSERT (dest->deletable) ;
-
- if ( !dest->deletable )
- return false ; /* yeah, i know this is taken care of above */
-
- if ((dest->dataSize + src->dataSize) > dest->memSize)
- {
- char *newMem = xcalloc (dest->dataSize + src->dataSize + 1, 1) ;
-
- bufferByteCount += ((dest->dataSize + src->dataSize) - dest->memSize) ;
-
- memcpy (newMem, dest->mem, dest->dataSize) ;
-
- ASSERT (dest->mem != NULL) ;
- free (dest->mem) ;
-
- dest->mem = newMem ;
- dest->memSize = dest->dataSize + src->dataSize ; /* yep. 1 less */
- }
-
- memcpy (&dest->mem[dest->dataSize], src->mem, dest->dataSize) ;
-
- dest->dataSize += src->dataSize ;
-
- return true ;
-}
-
-
- /* realloc the buffer's memory to increase the size by AMT */
-bool expandBuffer (Buffer buff, size_t amt)
-{
- d_printf (2,"Expanding buffer....\n") ;
-
- if (!buff->deletable)
- return false ;
-
- bufferByteCount += amt ;
- buff->memSize += amt ;
-
- buff->mem = xrealloc (buff->mem, buff->memSize + 1) ;
-
- return true ;
-}
-
-
- /* Take a buffer and shift the contents around to add the necessary CR
- before every line feed and a '.' before every '.' at the start of a
- line. */
-bool nntpPrepareBuffer (Buffer buffer)
-{
- int msize, newDsize, dsize, extra ;
- char *base, p, *src, *dst ;
- bool needfinal = false ;
-
- ASSERT (buffer != NULL) ;
-
- dsize = buffer->dataSize ;
- msize = buffer->memSize - 1 ;
- base = buffer->mem ;
-
- extra = 3 ;
- p = '\0' ;
- for (src = base + dsize - 1 ; src > base ; )
- {
- if (*src == '\n')
- {
- extra++ ;
- if (p == '.')
- extra++ ;
- }
- p = *src-- ;
- }
- if (*src == '\n')
- {
- extra++ ;
- if (p == '.')
- extra++ ;
- }
-
- if (dsize > 0 && base [dsize - 1] != '\n')
- {
- needfinal = true ;
- extra += 2 ;
- }
-
- newDsize = dsize + extra ;
-
- if (msize - dsize < extra)
- {
- d_printf (2,"Expanding buffer in nntpPrepareBuffer (from %d to %d)\n",
- msize, msize + (extra - (msize - dsize))) ;
-
- if ( !expandBuffer (buffer, extra - (msize - dsize)) )
- {
- d_printf (1,"Expand failed...\n") ;
- return false ;
- }
-
- ASSERT (dsize == (int) buffer->dataSize) ;
-
- base = buffer->mem ;
- }
-
- base [newDsize] = '\0' ;
- base [newDsize - 1] = '\n' ;
- base [newDsize - 2] = '\r' ;
- base [newDsize - 3] = '.' ;
- newDsize -= 3 ;
- extra -= 3 ;
-
- if (needfinal)
- {
- base [newDsize - 1] = '\n' ;
- base [newDsize - 2] = '\r' ;
- newDsize -= 2 ;
- extra -= 2 ;
- }
-
- if (extra)
- {
- p = '\0';
- src = base + dsize - 1 ;
- dst = base + newDsize - 1 ;
- while (1)
- {
- if (*src == '\n')
- {
- if (p == '.')
- {
- *dst-- = '.' ;
- extra-- ;
- }
- *dst-- = '\n' ;
- *dst = '\r' ;
- if (--extra <= 0)
- break ;
- p = '\0' ;
- dst-- ;
- src-- ;
- }
- else
- p = *dst-- = *src-- ;
- }
- ASSERT(dst >= base && src >= base) ;
- }
-
- newDsize += 3;
- if (needfinal)
- newDsize += 2 ;
-
- bufferSetDataSize (buffer,newDsize) ;
-
- return true ;
-}
+++ /dev/null
-/* $Id: buffer.h 7285 2005-06-07 06:38:24Z eagle $
-**
-** The public interface to the Buffer class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The Buffer class encapsulates a region of memory. It provides reference
-** counting so that redundant memory allocation and copying is minimized. A
-** good example of this is the need to write the same data (e.g. an article
-** body) out more than one socket. The data is stored in a Buffer and the
-** Buffer is given to each EndPoint that is to write it. With the Refcount
-** appropriately set the EndPoints can release their references at will and
-** the Buffer will be cleaned up when necessary.
-*/
-
-#if ! defined ( buffer_h__ )
-#define buffer_h__
-
-
-#include <sys/types.h>
-#include <stdio.h>
-
-#include "misc.h"
-
-
-/*
- * Create a new Buffer object and initialize it.
- */
-Buffer newBuffer (size_t size) ;
-
-/* Create a new Buffer object around the preallocted PTR, which is SIZE
- bytes long. The data size of the Buffer is set to DATASIZE. When then
- buffer is released it will not delete the ptr (this is useful to have
- Buffers around contant strings, or Buffers around other Buffers) */
-Buffer newBufferByCharP (const char *ptr, size_t size, size_t dataSize) ;
-
-/*
- * give up interest in the Buffer. Decrement refcount and delete if no
- * more referants
- */
-void delBuffer (Buffer buff) ;
-
- /* print some debugging information about the buffer. */
-void printBufferInfo (Buffer buffer, FILE *fp, unsigned int indentAmt) ;
-
- /* print debugging information about all outstanding buffers. */
-void gPrintBufferInfo (FILE *fp, unsigned int indentAmt) ;
-
-/* increment reference counts so that the buffer object can be */
-/* handed off to another function without it being deleted when that */
-/* function calls bufferDelete(). Returns buff, so the call can be */
-/* used in function arg list. */
-Buffer bufferTakeRef (Buffer buff) ;
-
-/* returns the address of the base of the memory owned by the Buffer */
-void *bufferBase (Buffer buff) ;
-
-/* returns the size of the memory buffer has available. This always returns
- 1 less than the real size so that there's space left for a null byte
- when needed. The extra byte is accounted for when the newBuffer function
- is called. */
-size_t bufferSize (Buffer) ;
-
-/* return the amount of data actually in the buffer */
-size_t bufferDataSize (Buffer buff) ;
-
-/* increment the size of the buffer's data region */
-void bufferIncrDataSize (Buffer buff, size_t size) ;
-
-/* decrement the size of the buffer's data region */
-void bufferDecrDataSize (Buffer buff, size_t size) ;
-
-/* set the size of the data actually in the buffer */
-void bufferSetDataSize (Buffer buff, size_t size) ;
-
-/* callback to be called when buffer gets deleted */
-void bufferSetDeletedCbk (Buffer buff, void (*cbk)(void *), void *data);
-
-/* walk down the BUFFS releasing each buffer and then freeing BUFFS itself */
-void freeBufferArray (Buffer *buffs) ;
-
-/* All arguments are non-NULL Buffers, except for the last which must be
- NULL. Creates a free'able array and puts all the buffers into it (does
- not call bufferTakeRef on them). */
-Buffer *makeBufferArray (Buffer buff, ...) ;
-
-/* returns true if the buffer was created via
- newBuffer (vs. newBufferByCharP) */
-bool isDeletable (Buffer buff) ;
-
-/* Dups the array including taking out references on the Buffers
- inside. Return value must be freed (or given to freeBufferArray) */
-Buffer *dupBufferArray (Buffer *array) ;
-
-/* return the number of non-NULL elements in the array. */
-unsigned int bufferArrayLen (Buffer *array) ;
-
-/* copies the contents of the SRC buffer into the DEST buffer and sets the
- data size appropriately. Returns false if src is bigger than dest. */
-bool copyBuffer (Buffer dest, Buffer src) ;
-
-/* return the ref count on the buffer */
-unsigned int bufferRefCount (Buffer buff) ;
-
-/* insert a null byte at the end of the data region */
-void bufferAddNullByte (Buffer buff) ;
-
-/* append the data of src to the data of dest, if dest is big enough */
-bool concatBuffer (Buffer dest, Buffer src) ;
-
-/* expand the buffer's memory by the given AMT */
-bool expandBuffer (Buffer buff, size_t amt) ;
-
-/* Expand the buffer (if necessary) and insert carriage returns before very
- line feed. Adjusts the data size. The base address may change
- afterwards. */
-bool nntpPrepareBuffer (Buffer buffer) ;
-
-#endif /* buffer_h__ */
+++ /dev/null
-/* A lexical scanner generated by flex */
-
-/* Scanner skeleton version:
- * $Header$
- */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-
-#include <stdio.h>
-#include <errno.h>
-
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
-#ifdef c_plusplus
-#ifndef __cplusplus
-#define __cplusplus
-#endif
-#endif
-
-
-#ifdef __cplusplus
-
-#include <stdlib.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-/* Use prototypes in function declarations. */
-#define YY_USE_PROTOS
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-#if __STDC__
-
-#define YY_USE_PROTOS
-#define YY_USE_CONST
-
-#endif /* __STDC__ */
-#endif /* ! __cplusplus */
-
-#ifdef __TURBOC__
- #pragma warn -rch
- #pragma warn -use
-#include <io.h>
-#include <stdlib.h>
-#define YY_USE_CONST
-#define YY_USE_PROTOS
-#endif
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-
-#ifdef YY_USE_PROTOS
-#define YY_PROTO(proto) proto
-#else
-#define YY_PROTO(proto) ()
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN yy_start = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START ((yy_start - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart( yyin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#define YY_BUF_SIZE 16384
-
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-
-extern int yyleng;
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-/* The funky do-while in the following #define is used to turn the definition
- * int a single C statement (which needs a semi-colon terminator). This
- * avoids problems with code like:
- *
- * if ( condition_holds )
- * yyless( 5 );
- * else
- * do_something_else();
- *
- * Prior to using the do-while the compiler would get upset at the
- * "else" because it interpreted the "if" statement as being all
- * done when it reached the ';' after the yyless() call.
- */
-
-/* Return all but the first 'n' matched characters back to the input stream. */
-
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- *yy_cp = yy_hold_char; \
- YY_RESTORE_YY_MORE_OFFSET \
- yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up yytext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, yytext_ptr )
-
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-typedef unsigned int yy_size_t;
-
-
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via yyrestart()), so that the user can continue scanning by
- * just pointing yyin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
- };
-
-static YY_BUFFER_STATE yy_current_buffer = 0;
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- */
-#define YY_CURRENT_BUFFER yy_current_buffer
-
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-
-
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart YY_PROTO(( FILE *input_file ));
-
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
-void yy_load_buffer_state YY_PROTO(( void ));
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
-
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
-
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
-static void yy_flex_free YY_PROTO(( void * ));
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! yy_current_buffer ) \
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
- yy_current_buffer->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! yy_current_buffer ) \
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
- yy_current_buffer->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
-
-typedef unsigned char YY_CHAR;
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-typedef int yy_state_type;
-extern char *yytext;
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
-static int yy_get_next_buffer YY_PROTO(( void ));
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
- yytext_ptr = yy_bp; \
- yyleng = (int) (yy_cp - yy_bp); \
- yy_hold_char = *yy_cp; \
- *yy_cp = '\0'; \
- yy_c_buf_p = yy_cp;
-
-#define YY_NUM_RULES 19
-#define YY_END_OF_BUFFER 20
-static yyconst short int yy_accept[55] =
- { 0,
- 0, 0, 7, 7, 20, 18, 11, 1, 15, 10,
- 19, 16, 2, 18, 18, 3, 4, 18, 8, 7,
- 19, 18, 11, 15, 10, 0, 0, 17, 16, 18,
- 18, 18, 8, 7, 13, 0, 0, 17, 18, 18,
- 18, 0, 12, 18, 5, 18, 0, 9, 18, 14,
- 18, 18, 6, 0
- } ;
-
-static yyconst int yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 2, 1, 4, 5, 6, 1, 1, 7, 1,
- 1, 1, 1, 1, 8, 9, 1, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 11, 1, 1,
- 1, 1, 1, 1, 1, 1, 12, 13, 14, 1,
- 15, 1, 16, 1, 1, 17, 1, 18, 19, 20,
- 1, 21, 1, 1, 22, 1, 1, 1, 1, 1,
- 1, 23, 1, 1, 1, 1, 24, 24, 1, 1,
-
- 25, 24, 15, 1, 1, 1, 1, 1, 1, 24,
- 19, 20, 1, 26, 1, 24, 27, 24, 1, 1,
- 1, 1, 28, 1, 29, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-static yyconst int yy_meta[30] =
- { 0,
- 1, 2, 3, 4, 5, 1, 6, 1, 1, 7,
- 5, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 7, 7, 1, 7, 1, 1, 1
- } ;
-
-static yyconst short int yy_base[62] =
- { 0,
- 0, 100, 28, 30, 105, 0, 102, 107, 0, 0,
- 80, 25, 107, 15, 23, 0, 0, 86, 0, 99,
- 107, 0, 98, 0, 0, 92, 32, 88, 34, 78,
- 24, 78, 0, 87, 107, 78, 75, 65, 18, 25,
- 57, 54, 107, 43, 0, 45, 54, 0, 38, 107,
- 37, 33, 0, 107, 51, 58, 65, 72, 79, 86,
- 88
- } ;
-
-static yyconst short int yy_def[62] =
- { 0,
- 54, 1, 55, 55, 54, 56, 54, 54, 57, 58,
- 59, 56, 54, 56, 56, 56, 56, 56, 60, 54,
- 54, 56, 54, 57, 58, 54, 61, 56, 56, 56,
- 56, 56, 60, 54, 54, 54, 54, 56, 56, 56,
- 56, 54, 54, 56, 56, 56, 54, 56, 56, 54,
- 56, 56, 56, 0, 54, 54, 54, 54, 54, 54,
- 54
- } ;
-
-static yyconst short int yy_nxt[137] =
- { 0,
- 6, 7, 8, 9, 10, 6, 11, 12, 6, 12,
- 13, 6, 6, 6, 14, 6, 6, 6, 6, 15,
- 6, 6, 6, 6, 6, 6, 6, 16, 17, 20,
- 21, 20, 21, 28, 29, 30, 31, 40, 35, 44,
- 30, 36, 28, 29, 44, 45, 53, 31, 40, 52,
- 45, 19, 19, 19, 19, 19, 19, 19, 22, 51,
- 50, 49, 48, 47, 22, 24, 24, 24, 46, 24,
- 24, 24, 25, 25, 38, 25, 25, 25, 25, 26,
- 26, 43, 26, 26, 26, 26, 33, 42, 34, 33,
- 33, 33, 33, 37, 37, 41, 39, 38, 35, 23,
-
- 34, 32, 27, 23, 54, 18, 5, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54
- } ;
-
-static yyconst short int yy_chk[137] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
- 3, 4, 4, 12, 12, 14, 15, 31, 27, 39,
- 14, 27, 29, 29, 39, 40, 52, 15, 31, 51,
- 40, 55, 55, 55, 55, 55, 55, 55, 56, 49,
- 47, 46, 44, 42, 56, 57, 57, 57, 41, 57,
- 57, 57, 58, 58, 38, 58, 58, 58, 58, 59,
- 59, 37, 59, 59, 59, 59, 60, 36, 34, 60,
- 60, 60, 60, 61, 61, 32, 30, 28, 26, 23,
-
- 20, 18, 11, 7, 5, 2, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54
- } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "configfile.l"
-#define INITIAL 0
-#line 2 "configfile.l"
-/* $Id: config_l.c 6145 2003-01-19 19:42:22Z rra $
-**
-** A flex input file for the innfeed config file.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-
-#include "libinn.h"
-
-#include "configfile.h"
-#include "config_y.h"
-#include "misc.h"
-
-#if ! defined (FLEX_SCANNER)
-#error "You must use FLEX to process the lex input file."
-#endif
-
-#if defined (FLEX_DEBUG)
-#define YY_USER_INIT yy_flex_debug = (getenv ("YYDEBUG") == NULL ? 0 : 1)
-#endif
-
-/* We never use this function but flex always defines it, so silence the
- warnings about it. */
-static void yyunput(int, char *) UNUSED;
-
-char *strPtr = 0 ;
-int strPtrLen = 0 ;
-int strIdx = 0 ;
-int sawBsl ;
-int lineCount = 0 ;
-int current ;
-
-static void strAppend (int ch);
-static void strAppend (int ch)
-{
- if (strIdx == strPtrLen)
- {
- if (strPtr == 0)
- strPtr = xmalloc (strPtrLen = 50) ;
- else
- strPtr = xrealloc (strPtr,strPtrLen += 10) ;
- }
- strPtr [strIdx++] = ch ;
-}
-
-#define MAX_INCLUDE_DEPTH 11
-struct includeFile {
- YY_BUFFER_STATE state;
- char *name ;
-} include_stack[MAX_INCLUDE_DEPTH];
-int include_stack_ptr = 0;
-
-#define incl 1
-
-#line 474 "lex.yy.c"
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap YY_PROTO(( void ));
-#else
-extern int yywrap YY_PROTO(( void ));
-#endif
-#endif
-
-#ifndef YY_NO_UNPUT
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));
-#endif
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-static int yyinput YY_PROTO(( void ));
-#else
-static int input YY_PROTO(( void ));
-#endif
-#endif
-
-#if YY_STACK_USED
-static int yy_start_stack_ptr = 0;
-static int yy_start_stack_depth = 0;
-static int *yy_start_stack = 0;
-#ifndef YY_NO_PUSH_STATE
-static void yy_push_state YY_PROTO(( int new_state ));
-#endif
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state YY_PROTO(( void ));
-#endif
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state YY_PROTO(( void ));
-#endif
-
-#else
-#define YY_NO_PUSH_STATE 1
-#define YY_NO_POP_STATE 1
-#define YY_NO_TOP_STATE 1
-#endif
-
-#ifdef YY_MALLOC_DECL
-YY_MALLOC_DECL
-#else
-#if __STDC__
-#ifndef __cplusplus
-#include <stdlib.h>
-#endif
-#else
-/* Just try to get by without declaring the routines. This will fail
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
- * or sizeof(void*) != sizeof(int).
- */
-#endif
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- if ( yy_current_buffer->yy_is_interactive ) \
- { \
- int c = '*', n; \
- for ( n = 0; n < max_size && \
- (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } \
- else \
- { \
- errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(yyin); \
- } \
- }
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL int yylex YY_PROTO(( void ))
-#endif
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- if ( yyleng > 0 ) \
- yy_current_buffer->yy_at_bol = \
- (yytext[yyleng - 1] == '\n'); \
- YY_USER_ACTION
-
-YY_DECL
- {
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
-#line 67 "configfile.l"
-
-
-#line 642 "lex.yy.c"
-
- if ( yy_init )
- {
- yy_init = 0;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! yy_start )
- yy_start = 1; /* first start state */
-
- if ( ! yyin )
- yyin = stdin;
-
- if ( ! yyout )
- yyout = stdout;
-
- if ( ! yy_current_buffer )
- yy_current_buffer =
- yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_load_buffer_state();
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = yy_c_buf_p;
-
- /* Support of yytext. */
- *yy_cp = yy_hold_char;
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = yy_start;
- yy_current_state += YY_AT_BOL();
-yy_match:
- do
- {
- register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 55 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- ++yy_cp;
- }
- while ( yy_base[yy_current_state] != 107 );
-
-yy_find_action:
- yy_act = yy_accept[yy_current_state];
- if ( yy_act == 0 )
- { /* have to back up */
- yy_cp = yy_last_accepting_cpos;
- yy_current_state = yy_last_accepting_state;
- yy_act = yy_accept[yy_current_state];
- }
-
- YY_DO_BEFORE_ACTION;
-
-
-do_action: /* This label is used only to access EOF actions. */
-
-
- switch ( yy_act )
- { /* beginning of action switch */
- case 0: /* must back up */
- /* undo the effects of YY_DO_BEFORE_ACTION */
- *yy_cp = yy_hold_char;
- yy_cp = yy_last_accepting_cpos;
- yy_current_state = yy_last_accepting_state;
- goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 69 "configfile.l"
-lineCount++ ;
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 71 "configfile.l"
-{ return (COLON) ; }
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 73 "configfile.l"
-{ return (LBRACE) ; }
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 75 "configfile.l"
-{ return (RBRACE) ; }
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 77 "configfile.l"
-{ return (PEER) ; }
- YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 79 "configfile.l"
-BEGIN(incl);
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-#line 81 "configfile.l"
-/* eat the whitespace before include filename */
- YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 83 "configfile.l"
-{
- if (include_stack_ptr == MAX_INCLUDE_DEPTH - 1)
- {
- int i ;
- fprintf( stderr, "Includes nested too deeply:\n" );
- for (i = 1 ; i <= include_stack_ptr ; i++)
- fprintf (stderr,"\t%s\n",include_stack[i].name) ;
-
- syslog (LOG_ERR, "includes nested to deeply") ;
- exit( 1 );
- }
-
- if ((yyin = fopen(yytext,"r")) == NULL)
- {
- syslog (LOG_CRIT,"include file fopen failed: %s %s",
- yytext,strerror(errno));
- fprintf (stderr,"include file fopen failed: %s %s\n",
- yytext,strerror(errno));
- exit (1) ;
- }
- else
- {
- d_printf (1,"Including (%d) from %s\n",
- include_stack_ptr + 1,yytext) ;
- include_stack[include_stack_ptr].state = YY_CURRENT_BUFFER;
- include_stack[++include_stack_ptr].name = xstrdup (yytext) ;
- yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- }
-
- BEGIN(INITIAL);
-}
- YY_BREAK
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(incl):
-#line 115 "configfile.l"
-{
- if ( include_stack_ptr <= 0 )
- yyterminate();
- else
- {
- free (include_stack[include_stack_ptr].name) ;
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(include_stack[--include_stack_ptr].state);
- }
-}
- YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 126 "configfile.l"
-{ return (GROUP) ; }
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-#line 128 "configfile.l"
-{ (void) 0 ; }
- YY_BREAK
-case 11:
-YY_RULE_SETUP
-#line 130 "configfile.l"
-{ (void) 1 ; }
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-#line 132 "configfile.l"
-{
- switch (yytext[2]) {
- case '\\': yylval.chr = '\\' ; break ;
- case 'a': yylval.chr = 007 ; break ;
- case 'b': yylval.chr = 010 ; break ;
- case 'f': yylval.chr = 014 ; break ;
- case 'n': yylval.chr = 012 ; break ;
- case 'r': yylval.chr = 015 ; break ;
- case 't': yylval.chr = 011 ; break ;
- case 'v': yylval.chr = 013 ; break ;
- }
- return (CHAR) ; }
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-#line 145 "configfile.l"
-{ yylval.chr = yytext[1] ; return (CHAR) ; }
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-#line 147 "configfile.l"
-{ yylval.chr = (char)strtol(&yytext[2], (char **)NULL, 8);
- return (CHAR) ;}
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-#line 150 "configfile.l"
-{{
- int i ;
-
- for (i = 1, strIdx = 0, sawBsl = 0 ; ; i++)
- {
- if (i < yyleng)
- current = yytext [i] ;
- else
- current = input() ;
-
- if (current != EOF)
- {
- switch (current)
- {
- case '\\':
- if (sawBsl)
- {
- strAppend (current) ;
- sawBsl = 0 ;
- }
- else
- sawBsl = 1 ;
- break ;
-
- case '\n':
- if (!sawBsl)
- strAppend(current) ;
- sawBsl = 0 ;
- lineCount++ ;
- break ;
-
- case '\"':
- if (sawBsl)
- {
- strAppend (current) ;
- sawBsl = 0 ;
- }
- else
- {
- strAppend ('\0') ;
- yylval.string = strPtr ;
- strPtr = 0 ;
- strPtrLen = strIdx = 0 ;
- return (XSTRING) ;
- }
- break ;
-
- case 'a':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- case 'v':
- if (sawBsl)
- {
- switch (current)
- {
- case 'a': strAppend (007) ; break ;
- case 'b': strAppend (010) ; break ;
- case 'f': strAppend (014) ; break ;
- case 'n': strAppend (012) ; break ;
- case 'r': strAppend (015) ; break ;
- case 't': strAppend (011) ; break ;
- case 'v': strAppend (013) ; break ;
- }
- sawBsl = 0 ;
- }
- else
- strAppend (current) ;
- break ;
-
- default:
- strAppend (current) ;
- sawBsl = 0 ;
- break ;
- }
- }
- else
- {
- return (XSTRING) ;
- }
- }
-}}
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-#line 235 "configfile.l"
-{ yylval.integer = atoi (yytext) ; return (IVAL) ; }
- YY_BREAK
-case 17:
-YY_RULE_SETUP
-#line 237 "configfile.l"
-{ yylval.real = atof (yytext) ; return (RVAL) ; }
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-#line 239 "configfile.l"
-{
- yylval.name = xstrdup (yytext) ;
- if (strcasecmp (yylval.name,"false") == 0)
- return (FALSEBVAL) ;
- else if (strcasecmp (yylval.name,"true") == 0)
- return (TRUEBVAL) ;
- else
- return (WORD) ;
-}
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-#line 249 "configfile.l"
-ECHO;
- YY_BREAK
-#line 968 "lex.yy.c"
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = yy_hold_char;
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed yyin at a new source and called
- * yylex(). If so, then we have to assure
- * consistency between yy_current_buffer and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yy_current_buffer->yy_input_file = yyin;
- yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = yytext_ptr + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++yy_c_buf_p;
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = yy_c_buf_p;
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_END_OF_FILE:
- {
- yy_did_buffer_switch_on_eof = 0;
-
- if ( yywrap() )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * yytext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p =
- yytext_ptr + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- yy_c_buf_p =
- &yy_current_buffer->yy_ch_buf[yy_n_chars];
-
- yy_current_state = yy_get_previous_state();
-
- yy_cp = yy_c_buf_p;
- yy_bp = yytext_ptr + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
- } /* end of yylex */
-
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-
-static int yy_get_next_buffer()
- {
- register char *dest = yy_current_buffer->yy_ch_buf;
- register char *source = yytext_ptr;
- register int number_to_move, i;
- int ret_val;
-
- if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( yy_current_buffer->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- yy_current_buffer->yy_n_chars = yy_n_chars = 0;
-
- else
- {
- int num_to_read =
- yy_current_buffer->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-#ifdef YY_USES_REJECT
- YY_FATAL_ERROR(
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
-#else
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = yy_current_buffer;
-
- int yy_c_buf_p_offset =
- (int) (yy_c_buf_p - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
- int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
- else
- b->yy_buf_size *= 2;
-
- b->yy_ch_buf = (char *)
- /* Include room in for 2 EOB chars. */
- yy_flex_realloc( (void *) b->yy_ch_buf,
- b->yy_buf_size + 2 );
- }
- else
- /* Can't grow it, we don't own it. */
- b->yy_ch_buf = 0;
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = yy_current_buffer->yy_buf_size -
- number_to_move - 1;
-#endif
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
- yy_n_chars, num_to_read );
-
- yy_current_buffer->yy_n_chars = yy_n_chars;
- }
-
- if ( yy_n_chars == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- yyrestart( yyin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- yy_current_buffer->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- yy_n_chars += number_to_move;
- yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
- yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
-
- yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
-
- return ret_val;
- }
-
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-static yy_state_type yy_get_previous_state()
- {
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = yy_start;
- yy_current_state += YY_AT_BOL();
-
- for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
- {
- register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 55 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- }
-
- return yy_current_state;
- }
-
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
-
-#ifdef YY_USE_PROTOS
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
-#else
-static yy_state_type yy_try_NUL_trans( yy_current_state )
-yy_state_type yy_current_state;
-#endif
- {
- register int yy_is_jam;
- register char *yy_cp = yy_c_buf_p;
-
- register YY_CHAR yy_c = 1;
- if ( yy_accept[yy_current_state] )
- {
- yy_last_accepting_state = yy_current_state;
- yy_last_accepting_cpos = yy_cp;
- }
- while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
- {
- yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 55 )
- yy_c = yy_meta[(unsigned int) yy_c];
- }
- yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 54);
-
- return yy_is_jam ? 0 : yy_current_state;
- }
-
-
-#ifndef YY_NO_UNPUT
-#ifdef YY_USE_PROTOS
-static void yyunput( int c, register char *yy_bp )
-#else
-static void yyunput( c, yy_bp )
-int c;
-register char *yy_bp;
-#endif
- {
- register char *yy_cp = yy_c_buf_p;
-
- /* undo effects of setting up yytext */
- *yy_cp = yy_hold_char;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = yy_n_chars + 2;
- register char *dest = &yy_current_buffer->yy_ch_buf[
- yy_current_buffer->yy_buf_size + 2];
- register char *source =
- &yy_current_buffer->yy_ch_buf[number_to_move];
-
- while ( source > yy_current_buffer->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- yy_current_buffer->yy_n_chars =
- yy_n_chars = yy_current_buffer->yy_buf_size;
-
- if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
-
- yytext_ptr = yy_bp;
- yy_hold_char = *yy_cp;
- yy_c_buf_p = yy_cp;
- }
-#endif /* ifndef YY_NO_UNPUT */
-
-
-#ifdef __cplusplus
-static int yyinput()
-#else
-static int input()
-#endif
- {
- int c;
-
- *yy_c_buf_p = yy_hold_char;
-
- if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
- /* This was really a NUL. */
- *yy_c_buf_p = '\0';
-
- else
- { /* need more input */
- int offset = yy_c_buf_p - yytext_ptr;
- ++yy_c_buf_p;
-
- switch ( yy_get_next_buffer() )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- yyrestart( yyin );
-
- /* fall through */
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( yywrap() )
- return EOF;
-
- if ( ! yy_did_buffer_switch_on_eof )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- yy_c_buf_p = yytext_ptr + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
- *yy_c_buf_p = '\0'; /* preserve yytext */
- yy_hold_char = *++yy_c_buf_p;
-
- yy_current_buffer->yy_at_bol = (c == '\n');
-
- return c;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yyrestart( FILE *input_file )
-#else
-void yyrestart( input_file )
-FILE *input_file;
-#endif
- {
- if ( ! yy_current_buffer )
- yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
-
- yy_init_buffer( yy_current_buffer, input_file );
- yy_load_buffer_state();
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
-#else
-void yy_switch_to_buffer( new_buffer )
-YY_BUFFER_STATE new_buffer;
-#endif
- {
- if ( yy_current_buffer == new_buffer )
- return;
-
- if ( yy_current_buffer )
- {
- /* Flush out information for old buffer. */
- *yy_c_buf_p = yy_hold_char;
- yy_current_buffer->yy_buf_pos = yy_c_buf_p;
- yy_current_buffer->yy_n_chars = yy_n_chars;
- }
-
- yy_current_buffer = new_buffer;
- yy_load_buffer_state();
-
- /* We don't actually know whether we did this switch during
- * EOF (yywrap()) processing, but the only time this flag
- * is looked at is after yywrap() is called, so it's safe
- * to go ahead and always set it.
- */
- yy_did_buffer_switch_on_eof = 1;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_load_buffer_state( void )
-#else
-void yy_load_buffer_state()
-#endif
- {
- yy_n_chars = yy_current_buffer->yy_n_chars;
- yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
- yyin = yy_current_buffer->yy_input_file;
- yy_hold_char = *yy_c_buf_p;
- }
-
-
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
-#else
-YY_BUFFER_STATE yy_create_buffer( file, size )
-FILE *file;
-int size;
-#endif
- {
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- yy_init_buffer( b, file );
-
- return b;
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_delete_buffer( YY_BUFFER_STATE b )
-#else
-void yy_delete_buffer( b )
-YY_BUFFER_STATE b;
-#endif
- {
- if ( ! b )
- return;
-
- if ( b == yy_current_buffer )
- yy_current_buffer = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- yy_flex_free( (void *) b->yy_ch_buf );
-
- yy_flex_free( (void *) b );
- }
-
-
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#ifndef YY_ALWAYS_INTERACTIVE
-#ifndef YY_NEVER_INTERACTIVE
-extern int isatty YY_PROTO(( int ));
-#endif
-#endif
-#endif
-
-#ifdef YY_USE_PROTOS
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
-#else
-void yy_init_buffer( b, file )
-YY_BUFFER_STATE b;
-FILE *file;
-#endif
-
-
- {
- yy_flush_buffer( b );
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
-#if YY_ALWAYS_INTERACTIVE
- b->yy_is_interactive = 1;
-#else
-#if YY_NEVER_INTERACTIVE
- b->yy_is_interactive = 0;
-#else
- b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-#endif
-#endif
- }
-
-
-#ifdef YY_USE_PROTOS
-void yy_flush_buffer( YY_BUFFER_STATE b )
-#else
-void yy_flush_buffer( b )
-YY_BUFFER_STATE b;
-#endif
-
- {
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == yy_current_buffer )
- yy_load_buffer_state();
- }
-
-
-#ifndef YY_NO_SCAN_BUFFER
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
-#else
-YY_BUFFER_STATE yy_scan_buffer( base, size )
-char *base;
-yy_size_t size;
-#endif
- {
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- yy_switch_to_buffer( b );
-
- return b;
- }
-#endif
-
-
-#ifndef YY_NO_SCAN_STRING
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
-#else
-YY_BUFFER_STATE yy_scan_string( yy_str )
-yyconst char *yy_str;
-#endif
- {
- int len;
- for ( len = 0; yy_str[len]; ++len )
- ;
-
- return yy_scan_bytes( yy_str, len );
- }
-#endif
-
-
-#ifndef YY_NO_SCAN_BYTES
-#ifdef YY_USE_PROTOS
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
-#else
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )
-yyconst char *bytes;
-int len;
-#endif
- {
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = len + 2;
- buf = (char *) yy_flex_alloc( n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
- for ( i = 0; i < len; ++i )
- buf[i] = bytes[i];
-
- buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = yy_scan_buffer( buf, n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
- }
-#endif
-
-
-#ifndef YY_NO_PUSH_STATE
-#ifdef YY_USE_PROTOS
-static void yy_push_state( int new_state )
-#else
-static void yy_push_state( new_state )
-int new_state;
-#endif
- {
- if ( yy_start_stack_ptr >= yy_start_stack_depth )
- {
- yy_size_t new_size;
-
- yy_start_stack_depth += YY_START_STACK_INCR;
- new_size = yy_start_stack_depth * sizeof( int );
-
- if ( ! yy_start_stack )
- yy_start_stack = (int *) yy_flex_alloc( new_size );
-
- else
- yy_start_stack = (int *) yy_flex_realloc(
- (void *) yy_start_stack, new_size );
-
- if ( ! yy_start_stack )
- YY_FATAL_ERROR(
- "out of memory expanding start-condition stack" );
- }
-
- yy_start_stack[yy_start_stack_ptr++] = YY_START;
-
- BEGIN(new_state);
- }
-#endif
-
-
-#ifndef YY_NO_POP_STATE
-static void yy_pop_state()
- {
- if ( --yy_start_stack_ptr < 0 )
- YY_FATAL_ERROR( "start-condition stack underflow" );
-
- BEGIN(yy_start_stack[yy_start_stack_ptr]);
- }
-#endif
-
-
-#ifndef YY_NO_TOP_STATE
-static int yy_top_state()
- {
- return yy_start_stack[yy_start_stack_ptr - 1];
- }
-#endif
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-#ifdef YY_USE_PROTOS
-static void yy_fatal_error( yyconst char msg[] )
-#else
-static void yy_fatal_error( msg )
-char msg[];
-#endif
- {
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
- }
-
-
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up yytext. */ \
- yytext[yyleng] = yy_hold_char; \
- yy_c_buf_p = yytext + n; \
- yy_hold_char = *yy_c_buf_p; \
- *yy_c_buf_p = '\0'; \
- yyleng = n; \
- } \
- while ( 0 )
-
-
-/* Internal utility routines. */
-
-#ifndef yytext_ptr
-#ifdef YY_USE_PROTOS
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
-#else
-static void yy_flex_strncpy( s1, s2, n )
-char *s1;
-yyconst char *s2;
-int n;
-#endif
- {
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
- }
-#endif
-
-#ifdef YY_NEED_STRLEN
-#ifdef YY_USE_PROTOS
-static int yy_flex_strlen( yyconst char *s )
-#else
-static int yy_flex_strlen( s )
-yyconst char *s;
-#endif
- {
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
- }
-#endif
-
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_alloc( yy_size_t size )
-#else
-static void *yy_flex_alloc( size )
-yy_size_t size;
-#endif
- {
- return (void *) malloc( size );
- }
-
-#ifdef YY_USE_PROTOS
-static void *yy_flex_realloc( void *ptr, yy_size_t size )
-#else
-static void *yy_flex_realloc( ptr, size )
-void *ptr;
-yy_size_t size;
-#endif
- {
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
- }
-
-#ifdef YY_USE_PROTOS
-static void yy_flex_free( void *ptr )
-#else
-static void yy_flex_free( ptr )
-void *ptr;
-#endif
- {
- free( ptr );
- }
-
-#if YY_MAIN
-int main()
- {
- yylex();
- return 0;
- }
-#endif
-#line 249 "configfile.l"
-
-
-
-
+++ /dev/null
-/* $Id: configfile.h 5801 2002-10-07 07:36:12Z rra $
-**
-** Interface to innfeed's configuration file parser.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#if ! defined ( configfile_h__ )
-#define configfile_h__
-
-/* Avoid conflicts with parsedate.y's generated yacc code. */
-#define yy_yyv innfeed_yy_yyv
-#define yyact innfeed_yyact
-#define yychk innfeed_yychk
-#define yydef innfeed_yydef
-#define yyexca innfeed_yyexca
-#define yylval innfeed_yylval
-#define yypact innfeed_yypact
-#define yypgo innfeed_yypgo
-#define yyr1 innfeed_yyr1
-#define yyr2 innfeed_yyr2
-#define yys innfeed_yys
-#define yyv innfeed_yyv
-#define yyval innfeed_yyval
-
-/* pointer to function taking void-star param and returning int. */
-typedef int (*PFIVP)(void *) ;
-
-typedef enum { intval, charval, boolval, realval, stringval, scopeval } tag ;
-
-typedef struct _scope {
- struct _value *me ;
- char *scope_type ;
- int value_count ;
- int value_idx ;
- struct _value **values ;
- struct _scope *parent ;
-} scope ;
-
-typedef struct _value {
- char *name ;
- struct _scope *myscope ;
- tag type ;
- union {
- char *charp_val ;
- char char_val ;
- double real_val ;
- int bool_val ;
- long int_val ;
- struct _scope *scope_val ;
- } v ;
-} value ;
-
-extern scope *topScope ;
-extern char *errbuff ;
-
-int isWord (scope *s, const char *name, int inherit) ;
-int isName (scope *s, const char *name, int inherit) ;
-
-int getReal (scope *s, const char *name, double *rval, int inherit) ;
-int getInteger (scope *s, const char *name, long *rval, int inherit) ;
-int getBool (scope *s, const char *name, int *rval, int inherit) ;
-int getString (scope *s, const char *name, char **rval, int inherit) ;
-int getWord (scope *s, const char *name, char **rval, int inherit) ;
-
-void freeScopeTree (scope *s) ;
-char *addInteger (scope *s, const char *name, long val) ;
-char *addChar (scope *s, const char *name, char val) ;
-char *addBoolean (scope *s, const char *name, int val) ;
-char *addName (scope *s, const char *name, char *val) ;
-char *addWord (scope *s, const char *name, char *val) ;
-char *addReal (scope *s, const char *name, double val) ;
-char *addString (scope *s, const char *name, const char *val) ;
-scope *findScope (scope *s, const char *name, int mustExist) ;
-value *findValue (scope *s, const char *name, int inherit) ;
-value *findPeer (const char *name) ;
-value *getNextPeer (int *cookie) ;
-void configAddLoadCallback (PFIVP func,void *arg) ;
-void configRemoveLoadCallback (PFIVP func) ;
-int readConfig (const char *file, FILE *errorDest, int justCheck, int dump) ;
-int buildPeerTable (FILE *fp, scope *currScope);
-void configCleanup (void) ;
-
-#define ARTICLE_TIMEOUT "article-timeout"
-#define BACKLOG_LIMIT "backlog-limit"
-#define INITIAL_CONNECTIONS "initial-connections"
-#define IP_NAME "ip-name"
-#define MAX_CONNECTIONS "max-connections"
-#define MAX_QUEUE_SIZE "max-queue-size"
-#define NO_CHECK_HIGH "no-check-high"
-#define NO_CHECK_LOW "no-check-low"
-#define PORT_NUMBER "port-number"
-#define RESP_TIMEOUT "response-timeout"
-#define STREAMING "streaming"
-#define DROP_DEFERRED "drop-deferred"
-
-#define ISPEER(V) (ISSCOPE(V) && strcmp ((V)->v.scope_val->scope_type,"peer") == 0)
-#define ISSCOPE(V) (V->type == scopeval)
-
-#define INHERIT 1
-#define NO_INHERIT 0
-
-/* Interface between lexer and parser. */
-int yylex (void) ;
-
-#endif /* configfile_h__ */
+++ /dev/null
-%{
-/* $Id: configfile.l 6145 2003-01-19 19:42:22Z rra $
-**
-** A flex input file for the innfeed config file.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-
-#include "libinn.h"
-
-#include "configfile.h"
-#include "config_y.h"
-#include "misc.h"
-
-#if ! defined (FLEX_SCANNER)
-#error "You must use FLEX to process the lex input file."
-#endif
-
-#if defined (FLEX_DEBUG)
-#define YY_USER_INIT yy_flex_debug = (getenv ("YYDEBUG") == NULL ? 0 : 1)
-#endif
-
-/* We never use this function but flex always defines it, so silence the
- warnings about it. */
-static void yyunput(int, char *) UNUSED;
-
-char *strPtr = 0 ;
-int strPtrLen = 0 ;
-int strIdx = 0 ;
-int sawBsl ;
-int lineCount = 0 ;
-int current ;
-
-static void strAppend (int ch);
-static void strAppend (int ch)
-{
- if (strIdx == strPtrLen)
- {
- if (strPtr == 0)
- strPtr = xmalloc (strPtrLen = 50) ;
- else
- strPtr = xrealloc (strPtr,strPtrLen += 10) ;
- }
- strPtr [strIdx++] = ch ;
-}
-
-#define MAX_INCLUDE_DEPTH 11
-struct includeFile {
- YY_BUFFER_STATE state;
- char *name ;
-} include_stack[MAX_INCLUDE_DEPTH];
-int include_stack_ptr = 0;
-
-%}
-
-%x incl
-
-ID [a-zA-Z][-a-zA-Z0-9._/]+
-
-%%
-
-\n lineCount++ ;
-
-":" { return (COLON) ; }
-
-"{" { return (LBRACE) ; }
-
-"}" { return (RBRACE) ; }
-
-[pP][eE][eE][rR] { return (PEER) ; }
-
-^"$INCLUDE" BEGIN(incl);
-
-<incl>[ \t]* /* eat the whitespace before include filename */
-
-<incl>[^ \t\n]+ {
- if (include_stack_ptr == MAX_INCLUDE_DEPTH - 1)
- {
- int i ;
- fprintf( stderr, "Includes nested too deeply:\n" );
- for (i = 1 ; i <= include_stack_ptr ; i++)
- fprintf (stderr,"\t%s\n",include_stack[i].name) ;
-
- syslog (LOG_ERR, "includes nested to deeply") ;
- exit( 1 );
- }
-
- if ((yyin = fopen(yytext,"r")) == NULL)
- {
- syslog (LOG_CRIT,"include file fopen failed: %s %s",
- yytext,strerror(errno));
- fprintf (stderr,"include file fopen failed: %s %s\n",
- yytext,strerror(errno));
- exit (1) ;
- }
- else
- {
- d_printf (1,"Including (%d) from %s\n",
- include_stack_ptr + 1,yytext) ;
- include_stack[include_stack_ptr].state = YY_CURRENT_BUFFER;
- include_stack[++include_stack_ptr].name = xstrdup (yytext) ;
- yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
- }
-
- BEGIN(INITIAL);
-}
-
-<<EOF>> {
- if ( include_stack_ptr <= 0 )
- yyterminate();
- else
- {
- free (include_stack[include_stack_ptr].name) ;
- yy_delete_buffer(YY_CURRENT_BUFFER);
- yy_switch_to_buffer(include_stack[--include_stack_ptr].state);
- }
-}
-
-[gG][rR][oO][uU][pP] { return (GROUP) ; }
-
-#[^\n]* { (void) 0 ; }
-
-[ \t]+ { (void) 1 ; }
-
-'\\[\\abfnrtv]' {
- switch (yytext[2]) {
- case '\\': yylval.chr = '\\' ; break ;
- case 'a': yylval.chr = 007 ; break ;
- case 'b': yylval.chr = 010 ; break ;
- case 'f': yylval.chr = 014 ; break ;
- case 'n': yylval.chr = 012 ; break ;
- case 'r': yylval.chr = 015 ; break ;
- case 't': yylval.chr = 011 ; break ;
- case 'v': yylval.chr = 013 ; break ;
- }
- return (CHAR) ; }
-
-'.' { yylval.chr = yytext[1] ; return (CHAR) ; }
-
-'\\[0-9][0-9][0-9]' { yylval.chr = (char)strtol(&yytext[2], (char **)NULL, 8);
- return (CHAR) ;}
-
-\"[^\"]* {{
- int i ;
-
- for (i = 1, strIdx = 0, sawBsl = 0 ; ; i++)
- {
- if (i < yyleng)
- current = yytext [i] ;
- else
- current = input() ;
-
- if (current != EOF)
- {
- switch (current)
- {
- case '\\':
- if (sawBsl)
- {
- strAppend (current) ;
- sawBsl = 0 ;
- }
- else
- sawBsl = 1 ;
- break ;
-
- case '\n':
- if (!sawBsl)
- strAppend(current) ;
- sawBsl = 0 ;
- lineCount++ ;
- break ;
-
- case '\"':
- if (sawBsl)
- {
- strAppend (current) ;
- sawBsl = 0 ;
- }
- else
- {
- strAppend ('\0') ;
- yylval.string = strPtr ;
- strPtr = 0 ;
- strPtrLen = strIdx = 0 ;
- return (XSTRING) ;
- }
- break ;
-
- case 'a':
- case 'b':
- case 'f':
- case 'n':
- case 'r':
- case 't':
- case 'v':
- if (sawBsl)
- {
- switch (current)
- {
- case 'a': strAppend (007) ; break ;
- case 'b': strAppend (010) ; break ;
- case 'f': strAppend (014) ; break ;
- case 'n': strAppend (012) ; break ;
- case 'r': strAppend (015) ; break ;
- case 't': strAppend (011) ; break ;
- case 'v': strAppend (013) ; break ;
- }
- sawBsl = 0 ;
- }
- else
- strAppend (current) ;
- break ;
-
- default:
- strAppend (current) ;
- sawBsl = 0 ;
- break ;
- }
- }
- else
- {
- return (XSTRING) ;
- }
- }
-}}
-
-[-0-9][0-9]* { yylval.integer = atoi (yytext) ; return (IVAL) ; }
-
-[-0-9][0-9]*\.[0-9]* { yylval.real = atof (yytext) ; return (RVAL) ; }
-
-[^#:\'\" \t\n]+ {
- yylval.name = xstrdup (yytext) ;
- if (strcasecmp (yylval.name,"false") == 0)
- return (FALSEBVAL) ;
- else if (strcasecmp (yylval.name,"true") == 0)
- return (TRUEBVAL) ;
- else
- return (WORD) ;
-}
-
-%%
-
-
-
+++ /dev/null
-%{
-/* $Id: configfile.y 6372 2003-05-31 19:48:28Z rra $
-**
-** A yacc input file for the innfeed config file.
-**
-** Written by James Brister <brister@vix.com>
-**
-** This file contains the heart of the innfeed configuration parser, written
-** in yacc. It uses an external lexer generated by flex.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <ctype.h>
-#include <syslog.h>
-
-#if defined(_HPUX_SOURCE)
-# include <alloca.h>
-#endif
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "configfile.h"
-#include "misc.h"
-
-#define UNKNOWN_SCOPE_TYPE "line %d: unknown scope type: %s"
-#define SYNTAX_ERROR "line %d: syntax error"
-
-extern int lineCount ;
-scope *topScope = NULL ;
-static scope *currScope = NULL ;
-char *errbuff = NULL ;
-
-static void appendName (scope *s, char *p, size_t len) ;
-static char *valueScopedName (value *v) ;
-static void freeValue (value *v) ;
-static char *checkName (scope *s, const char *name) ;
-static void addValue (scope *s, value *v) ;
-static char *addScope (scope *s, const char *name, scope *val) ;
-static void printScope (FILE *fp, scope *s, int indent) ;
-static void printValue (FILE *fp, value *v, int indent) ;
-static scope *newScope (const char *type) ;
-#if 0
-static int strNCaseCmp (const char *a, const char *b, size_t len) ;
-#endif
-
-int yyerror (const char *s) ;
-int yywrap (void) ;
-int yyparse (void) ;
-
-
-#if 0
-int isString (scope *s, const char *name, int inherit)
-{
- value *v = findValue (s,name,inherit) ;
-
- return (v != NULL && v->type == stringval) ;
-}
-#endif
-
-int getBool (scope *s, const char *name, int *rval, int inherit)
-{
- value *v = findValue (s,name,inherit) ;
-
- if (v == NULL)
- return 0 ;
- else if (v->type != boolval)
- return 0 ;
-
- *rval = v->v.bool_val ;
- return 1 ;
-}
-
-
-int getString (scope *s, const char *name, char **rval, int inherit)
-{
- value *v = findValue (s,name,inherit) ;
-
- if (v == NULL)
- return 0 ;
- else if (v->type != stringval)
- return 0 ;
-
- *rval = xstrdup (v->v.charp_val) ;
- return 1 ;
-}
-
-
-int getReal (scope *s, const char *name, double *rval, int inherit)
-{
- value *v = findValue (s,name,inherit) ;
-
- if (v == NULL)
- return 0 ;
- else if (v->type != realval)
- return 0 ;
-
- *rval = v->v.real_val ;
- return 1 ;
-}
-
-int getInteger (scope *s, const char *name, long *rval, int inherit)
-{
- value *v = findValue (s,name,inherit) ;
-
- if (v == NULL)
- return 0 ;
- else if (v->type != intval)
- return 0 ;
-
- *rval = v->v.int_val ;
- return 1 ;
-}
-
-void freeScopeTree (scope *s)
-{
- int i ;
-
- if (s == NULL)
- return ;
-
- if (s->parent == NULL && s->me != NULL)
- { /* top level scope */
- free (s->me->name) ;
- free (s->me) ;
- }
-
-
- for (i = 0 ; i < s->value_idx ; i++)
- if (s->values[i] != NULL)
- freeValue (s->values [i]) ;
-
- free (s->values) ;
- free (s->scope_type) ;
-
- s->parent = NULL ;
- s->values = NULL ;
-
- free (s) ;
-}
-
-
-char *addInteger (scope *s, const char *name, long val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (currScope,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = intval ;
- v->v.int_val = val ;
-
- addValue (s,v) ;
-
- return NULL ;
-}
-
-char *addChar (scope *s, const char *name, char val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (currScope,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = charval ;
- v->v.char_val = val ;
-
- addValue (s,v) ;
-
- return NULL ;
-}
-
-char *addBoolean (scope *s, const char *name, int val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (currScope,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = boolval ;
- v->v.bool_val = val ;
-
- addValue (s,v) ;
-
- return NULL ;
-}
-
-char *addReal (scope *s, const char *name, double val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (currScope,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = realval ;
- v->v.real_val = val ;
-
- addValue (s,v) ;
-
- return NULL ;
-}
-
-char *addString (scope *s, const char *name, const char *val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (currScope,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = stringval ;
- v->v.charp_val = xstrdup (val) ;
-
- addValue (s,v) ;
-
- return NULL ;
-}
-
-value *findValue (scope *s, const char *name, int inherit)
-{
- const char *p ;
-
- if (name == NULL || *name == '\0')
- return NULL ;
-
- if (*name == ':')
- return findValue (topScope,name + 1,0) ;
- else if (s == NULL)
- return findValue (topScope,name,0) ;
- else
- {
- int i ;
-
- if ((p = strchr (name,':')) == NULL)
- p = name + strlen (name) ;
-
- for (i = 0 ; i < s->value_idx ; i++)
- {
- if (strlen (s->values[i]->name) == (size_t) (p - name) &&
- strncmp (s->values[i]->name,name,p - name) == 0)
- {
- if (*p == '\0') /* last segment of name */
- return s->values[i] ;
- else if (s->values[i]->type != scopeval)
- errbuff = xstrdup ("Component not a scope") ;
- else
- return findValue (s->values[i]->v.scope_val,p + 1,0) ;
- }
- }
-
- /* not in this scope. Go up if inheriting values and only if no ':'
- in name */
- if (inherit && *p == '\0')
- return findValue (s->parent,name,inherit) ;
- }
-
- return NULL ;
-}
-
-/* find the scope that name belongs to. If mustExist is true then the name
- must be a fully scoped name of a value. relative scopes start at s. */
-scope *findScope (scope *s, const char *name, int mustExist)
-{
- scope *p = NULL ;
- char *q ;
- int i ;
-
-
- if ((q = strchr (name,':')) == NULL)
- {
- if (!mustExist)
- p = s ;
- else
- for (i = 0 ; p == NULL && i < s->value_idx ; i++)
- if (strcmp (s->values[i]->name,name) == 0)
- p = s ;
-
- return p ;
- }
- else if (*name == ':')
- {
- while (s->parent != NULL)
- s = s->parent ;
-
- return findScope (s,name + 1,mustExist) ;
- }
- else
- {
- for (i = 0 ; i < s->value_idx ; i++)
- if (strncmp (s->values[i]->name,name,q - name) == 0)
- if (s->values[i]->type == scopeval)
- return findScope (s->values[i]->v.scope_val,q + 1,mustExist) ;
- }
-
- return NULL ;
-}
-
-/****************************************************************************/
-/* */
-/****************************************************************************/
-
-
-static void appendName (scope *s, char *p, size_t len)
-{
- if (s == NULL)
- return ;
- else
- {
- appendName (s->parent,p,len) ;
- strlcat (p,s->me->name,len) ;
- strlcat (p,":",len) ;
- }
-}
-
-static char *valueScopedName (value *v)
-{
- scope *p = v->myscope ;
- int len = strlen (v->name) ;
- char *q ;
-
- while (p != NULL)
- {
- len += strlen (p->me->name) + 1 ;
- p = p->parent ;
- }
- len++;
-
- q = xmalloc (len) ;
- q [0] = '\0' ;
- appendName (v->myscope,q,len) ;
- strlcat (q,v->name,len) ;
-
- return q ;
-}
-
-static void freeValue (value *v)
-{
- free (v->name) ;
- switch (v->type)
- {
- case scopeval:
- freeScopeTree (v->v.scope_val) ;
- break ;
-
- case stringval:
- free (v->v.charp_val) ;
- break ;
-
- default:
- break ;
- }
- free (v) ;
-}
-
-static char *checkName (scope *s, const char *name)
-{
- int i ;
- char *error = NULL ;
-
- if (s == NULL)
- return NULL ;
-
- for (i = 0 ; i < s->value_idx ; i++)
- {
- char *n = NULL ;
-
- if (strcmp (name,s->values [i]->name) == 0) {
- n = valueScopedName (s->values[i]) ;
- error = concat ("Two definitions of ", n, (char *) 0) ;
- free (n) ;
- return error ;
- }
- }
-
- return error ;
-}
-
-
-static void addValue (scope *s, value *v)
-{
- v->myscope = s ;
-
- if (s == NULL)
- return ;
-
- if (s->value_count == s->value_idx)
- {
- if (s->values == 0)
- {
- s->values = (value **) calloc (10,sizeof (value *)) ;
- s->value_count = 10 ;
- }
- else
- {
- s->value_count += 10 ;
- s->values = (value **) realloc (s->values,
- sizeof (value *) * s->value_count);
- }
- }
-
- s->values [s->value_idx++] = v ;
-}
-
-
-
-static char *addScope (scope *s, const char *name, scope *val)
-{
- value *v ;
- char *error ;
-
- if ((error = checkName (s,name)) != NULL)
- return error ;
-
- v = (value *) calloc (1,sizeof (value)) ;
- v->name = xstrdup (name) ;
- v->type = scopeval ;
- v->v.scope_val = val ;
- val->me = v ;
- val->parent = s ;
-
- addValue (s,v) ;
-
- currScope = val ;
-
- return NULL ;
-}
-
-
-static void printScope (FILE *fp, scope *s, int indent)
-{
- int i ;
- for (i = 0 ; i < s->value_idx ; i++)
- printValue (fp,s->values [i],indent + 5) ;
-}
-
-static void printValue (FILE *fp, value *v, int indent)
-{
- int i ;
-
- for (i = 0 ; i < indent ; i++)
- fputc (' ',fp) ;
-
- switch (v->type)
- {
- case intval:
- fprintf (fp,"%s : %ld # INTEGER\n",v->name,v->v.int_val) ;
- break ;
-
- case stringval:
- fprintf (fp,"%s : \"",v->name) ;
- {
- char *p = v->v.charp_val ;
- while (*p)
- {
- if (*p == '"' || *p == '\\')
- fputc ('\\',fp) ;
- fputc (*p,fp) ;
- p++ ;
- }
- }
- fprintf (fp,"\" # STRING\n") ;
- break ;
-
- case charval:
- fprintf (fp,"%s : %c",v->name,047) ;
- switch (v->v.char_val)
- {
- case '\\':
- fprintf (fp,"\\\\") ;
- break ;
-
- default:
- if (CTYPE (isprint, v->v.char_val))
- fprintf (fp,"%c",v->v.char_val) ;
- else
- fprintf (fp,"\\%03o",v->v.char_val) ;
- }
- fprintf (fp,"%c # CHARACTER\n",047) ;
- break ;
-
- case realval:
- fprintf (fp,"%s : %f # REAL\n",v->name,v->v.real_val) ;
- break ;
-
- case boolval:
- fprintf (fp,"%s : %s # BOOLEAN\n",
- v->name,(v->v.bool_val ? "true" : "false")) ;
- break ;
-
- case scopeval:
- fprintf (fp,"%s %s { # SCOPE\n",v->v.scope_val->scope_type,v->name) ;
- printScope (fp,v->v.scope_val,indent + 5) ;
- for (i = 0 ; i < indent ; i++)
- fputc (' ',fp) ;
- fprintf (fp,"}\n") ;
- break ;
-
- default:
- fprintf (fp,"UNKNOWN value type: %d\n",v->type) ;
- exit (1) ;
- }
-}
-
-
-
-static scope *newScope (const char *type)
-{
- scope *t ;
- int i ;
-
- t = (scope *) calloc (1,sizeof (scope)) ;
- t->parent = NULL ;
- t->scope_type = xstrdup (type) ;
-
- for (i = 0 ; t->scope_type[i] != '\0' ; i++)
- t->scope_type[i] = tolower (t->scope_type[i]) ;
-
- return t ;
-}
-
-
-
-#if 0
-static int strNCaseCmp (const char *a, const char *b, size_t len)
-{
- while (a && b && *a && *b && (tolower (*a) == tolower (*b)) && len > 0)
- a++, b++, len-- ;
-
- if (a == NULL && b == NULL)
- return 0 ;
- else if (a == NULL)
- return 1 ;
- else if (b == NULL)
- return -1 ;
- else if (*a == '\0' && *b == '\0')
- return 0 ;
- else if (*a == '\0')
- return 1 ;
- else if (*b == '\0')
- return -1 ;
- else if (*a < *b)
- return 1 ;
- else if (*a > *b)
- return -1 ;
- else
- return 0 ;
-
- abort () ;
-}
-#endif
-
-#define BAD_KEY "line %d: illegal key name: %s"
-#define NON_ALPHA "line %d: keys must start with a letter: %s"
-
-static char *keyOk (const char *key)
-{
- const char *p = key ;
- char *rval ;
-
- if (key == NULL)
- {
- rval = xmalloc (strlen ("line : NULL key") + 15) ;
- sprintf (rval,"line %d: NULL key", lineCount) ;
- return rval ;
- }
- else if (*key == '\0')
- {
- rval = xmalloc (strlen ("line : EMPTY KEY") + 15) ;
- sprintf (rval,"line %d: EMPTY KEY", lineCount) ;
- return rval ;
- }
-
- if (!CTYPE(isalpha, *p))
- {
- rval = xmalloc (strlen (NON_ALPHA) + strlen (key) + 15) ;
- sprintf (rval,NON_ALPHA,lineCount, key) ;
- return rval ;
- }
-
- p++ ;
- while (*p)
- {
- if (!(CTYPE (isalnum, *p) || *p == '_' || *p == '-'))
- {
- rval = xmalloc (strlen (BAD_KEY) + strlen (key) + 15) ;
- sprintf (rval,BAD_KEY,lineCount,key) ;
- return rval ;
- }
- p++ ;
- }
-
- return NULL ;
-}
-
-static PFIVP *funcs = NULL ;
-static void **args = NULL ;
-static int funcCount ;
-static int funcIdx ;
-
-void configAddLoadCallback (PFIVP func,void *arg)
-{
- if (func == NULL)
- return ;
-
- if (funcIdx == funcCount)
- {
- funcCount += 10 ;
- if (funcs == NULL)
- {
- funcs = xmalloc (sizeof (PFIVP) * funcCount);
- args = xmalloc (sizeof (void *) * funcCount) ;
- }
- else
- {
- funcs = xrealloc (funcs,sizeof (PFIVP) * funcCount);
- args = xrealloc (args,sizeof (void *) * funcCount) ;
- }
- }
-
- args [funcIdx] = arg ;
- funcs [funcIdx++] = func ;
-
-}
-
-
-void configRemoveLoadCallback (PFIVP func)
-{
- int i, j ;
-
- for (i = 0 ; i < funcIdx ; i++)
- if (funcs [i] == func)
- break ;
-
- for (j = i ; j < funcIdx - 1 ; j++)
- {
- funcs [j] = funcs [j + 1] ;
- args [j] = args [j + 1] ;
- }
-
- if (funcIdx > 1 && i < funcIdx)
- {
- funcs [i - 2] = funcs [i - 1] ;
- args [i - 2] = args [i - 1] ;
- }
-
- if (funcIdx > 0 && i < funcIdx)
- funcIdx-- ;
-}
-
-
-static int doCallbacks (void)
-{
- int i ;
- int rval = 1 ;
-
- for (i = 0 ; i < funcIdx ; i++)
- if (funcs [i] != NULL)
- rval = (funcs[i](args [i]) && rval) ;
-
- return rval ;
-}
-
-
-
-
-
-static char *key ;
-%}
-
-%union{
- scope *scp ;
- value *val ;
- char *name ;
- int integer ;
- double real ;
- char *string ;
- char chr ;
-}
-
-%token PEER
-%token GROUP
-%token IVAL
-%token RVAL
-%token NAME
-%token XSTRING
-%token SCOPE
-%token COLON
-%token LBRACE
-%token RBRACE
-%token TRUEBVAL
-%token FALSEBVAL
-%token CHAR
-%token WORD
-%token IP_ADDRESS
-
-%type <integer> IVAL
-%type <real> RVAL
-%type <string> XSTRING
-%type <chr> CHAR
-%type <name> TRUEBVAL FALSEBVAL WORD
-
-%%
-input: {
- lineCount = 1 ;
- addScope (NULL,"",newScope ("")) ;
- topScope = currScope ;
- } entries { if (!doCallbacks()) YYABORT ; } ;
-
-scope: entries ;
-
-entries:
- | entries entry
- | entries error {
- errbuff = xmalloc (strlen(SYNTAX_ERROR) + 12) ;
- sprintf (errbuff,SYNTAX_ERROR,lineCount) ;
- YYABORT ;
- }
- ;
-
-entry: PEER WORD LBRACE {
- errbuff = addScope (currScope,$2,newScope ("peer")) ;
- free ($2) ;
- if (errbuff != NULL) YYABORT ;
- } scope RBRACE {
- currScope = currScope->parent ;
- }
- | GROUP WORD LBRACE {
- errbuff = addScope (currScope,$2,newScope ("group")) ;
- free ($2) ;
- if (errbuff != NULL) YYABORT ;
- } scope RBRACE {
- currScope = currScope->parent ;
- }
- | WORD WORD LBRACE {
- errbuff = xmalloc (strlen(UNKNOWN_SCOPE_TYPE) + 15 +
- strlen ($1)) ;
- sprintf (errbuff,UNKNOWN_SCOPE_TYPE,lineCount,$1) ;
- free ($1) ;
- free ($2) ;
- YYABORT ;
- }
- | WORD {
- if ((errbuff = keyOk($1)) != NULL) {
- YYABORT ;
- } else
- key = $1 ;
- } COLON value ;
-
-value: WORD {
- if ((errbuff = addString (currScope, key, $1)) != NULL)
- YYABORT ;
- free (key) ;
- free ($1) ;
- }
- | IVAL {
- if ((errbuff = addInteger(currScope, key, $1)) != NULL)
- YYABORT;
- free (key) ;
- }
- | TRUEBVAL {
- if ((errbuff = addBoolean (currScope, key, 1)) != NULL)
- YYABORT ;
- free (key) ;
- free ($1) ;
- }
- | FALSEBVAL {
- if ((errbuff = addBoolean (currScope, key, 0)) != NULL)
- YYABORT ;
- free (key) ;
- free ($1) ;
- }
- | RVAL {
- if ((errbuff = addReal (currScope, key, $1)) != NULL)
- YYABORT ;
- free (key) ;
- }
- | XSTRING {
- if ((errbuff = addString (currScope, key, $1)) != NULL)
- YYABORT;
- free (key) ;
- }
- | CHAR {
- if ((errbuff = addChar (currScope, key, $1)) != NULL)
- YYABORT ;
- free (key) ;
- }
-;
-
-%%
-
-int yyerror (const char *s)
-{
-#undef FMT
-#define FMT "line %d: %s"
-
- errbuff = xmalloc (strlen (s) + strlen (FMT) + 20) ;
- sprintf (errbuff,FMT,lineCount,s) ;
-
- return 0 ;
-}
-
-int yywrap (void)
-{
- return 1 ;
-}
-
-extern FILE *yyin ;
-int yydebug ;
-
-#define NO_INHERIT 0
-
-
-#if ! defined (WANT_MAIN)
-
-struct peer_table_s
-{
- char *peerName ;
- value *peerValue ;
-} ;
-
-static struct peer_table_s *peerTable ;
-static int peerTableCount ;
-static int peerTableIdx ;
-
-void configCleanup (void)
-{
- int i ;
-
- for (i = 0 ; i < peerTableIdx ; i++)
- free (peerTable[i].peerName) ;
- free (peerTable) ;
-
- freeScopeTree (topScope);
- free (funcs) ;
- free (args) ;
-}
-
-
-int buildPeerTable (FILE *fp, scope *s)
-{
- int rval = 1 ;
- int i, j ;
-
- for (i = 0 ; i < s->value_idx ; i++)
- {
- if (ISSCOPE (s->values[i]) && ISPEER (s->values[i]))
- {
- for (j = 0 ; j < peerTableIdx ; j++)
- {
- if (strcmp (peerTable[j].peerName,s->values[i]->name) == 0)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: two peers with the same name: %s",
- peerTable[j].peerName) ;
- rval = 0 ;
- break ;
- }
- }
-
- if (j == peerTableIdx)
- {
- if (peerTableCount == peerTableIdx)
- {
- peerTableCount += 10 ;
- if (peerTable == NULL)
- peerTable = xmalloc (sizeof(struct peer_table_s)
- * peerTableCount) ;
- else
- peerTable = xrealloc (peerTable,
- sizeof(struct peer_table_s)
- * peerTableCount) ;
- }
-
- peerTable[peerTableIdx].peerName = xstrdup (s->values[i]->name);
- peerTable[peerTableIdx].peerValue = s->values[i] ;
- peerTableIdx++ ;
- }
- }
- else if (ISSCOPE (s->values[i]))
- rval = (buildPeerTable (fp,s->values[i]->v.scope_val) && rval) ;
- }
-
- return rval ;
-}
-
-
-/* read the config file. Any errors go to errorDest if it is non-NULL,
- otherwise they are syslogged. If justCheck is true then return after
- parsing */
-static int inited = 0 ;
-int readConfig (const char *file, FILE *errorDest, int justCheck, int dump)
-{
- scope *oldTop = topScope ;
- FILE *fp ;
- int rval ;
-
- if (!inited)
- {
- inited = 1 ;
- yydebug = (getenv ("YYDEBUG") == NULL ? 0 : 1) ;
- if (yydebug)
- atexit (configCleanup) ;
- }
-
- if (file == NULL || strlen (file) == 0 || !fileExistsP (file))
- {
- logOrPrint (LOG_ERR,errorDest,
- "ME config aborting, no such config file: %s",
- file ? file : "(null)") ;
- d_printf (1,"No such config file: %s\n", file ? file : "(null)") ;
- exit (1) ;
- }
-
- if ((fp = fopen (file,"r")) == NULL)
- {
- logOrPrint (LOG_ERR,errorDest, "ME config aborting fopen %s: %s",
- file, strerror (errno)) ;
- exit (1) ;
- }
-
- logOrPrint (LOG_NOTICE,errorDest,"loading %s", file) ;
-
- yyin = fp ;
-
- topScope = NULL ;
-
- rval = yyparse () ;
-
- fclose (fp) ;
-
- if (rval != 0) /* failure */
- {
- freeScopeTree (topScope) ;
- if (justCheck)
- freeScopeTree (oldTop) ;
- else
- topScope = oldTop ;
- topScope = NULL ;
-
- if (errbuff != NULL)
- {
- if (errorDest != NULL)
- fprintf (errorDest,"config file error: %s\n",errbuff) ;
- else
- warn ("ME config file error: %s", errbuff) ;
-
- free (errbuff) ;
- }
-
- return 0 ;
- }
-
- if (dump)
- {
- fprintf (errorDest ? errorDest : stderr,"Parsed config file:\n") ;
- printScope (errorDest ? errorDest : stderr,topScope,-5) ;
- fprintf (errorDest ? errorDest : stderr,"\n") ;
- }
-
- if (justCheck)
- {
- freeScopeTree (topScope) ;
- freeScopeTree (oldTop) ;
-
- topScope = NULL ;
- }
- else
- {
- for (peerTableIdx-- ; peerTableIdx >= 0 ; peerTableIdx--)
- {
- free (peerTable [peerTableIdx].peerName) ;
- peerTable [peerTableIdx].peerName = NULL ;
- peerTable [peerTableIdx].peerValue = NULL ;
- }
- peerTableIdx = 0 ;
-
- if (!buildPeerTable (errorDest,topScope))
- logAndExit (1,"Failed to build list of peers") ;
- }
-
- return 1 ;
-}
-
-
-value *getNextPeer (int *cookie)
-{
- value *rval ;
-
- if (*cookie < 0 || *cookie >= peerTableIdx)
- return NULL ;
-
- rval = peerTable[*cookie].peerValue ;
-
- (*cookie)++ ;
-
- return rval ;
-}
-
-
-value *findPeer (const char *name)
-{
- value *v = NULL ;
- int i ;
-
- for (i = 0 ; i < peerTableIdx ; i++)
- if (strcmp (peerTable[i].peerName,name) == 0)
- {
- v = peerTable[i].peerValue ;
- break ;
- }
-
- return v ;
-}
-
-#endif
-
-#if defined (WANT_MAIN)
-int main (int argc, char **argv) {
- if ( yyparse() )
- printf ("parsing failed: %s\n",errbuff ? errbuff : "NONE") ;
- else
- {
- printScope (stdout,topScope,-5) ;
-
- if (argc == 3)
- {
-#if 0
- printf ("Looking for %s of type %s: ",argv[2],argv[1]) ;
- if (strncmp (argv[1],"int",3) == 0)
- {
- int i = 0 ;
-
- if (!getInteger (topScope,argv[2],&i))
- printf ("wasn't found.\n") ;
- else
- printf (" %d\n",i) ;
- }
- else if (strncmp (argv[1],"real",4) == 0)
- {
- double d = 0.0 ;
-
- if (!getReal (topScope,argv[2],&d))
- printf ("wasn't found.\n") ;
- else
- printf (" %0.5f\n",d) ;
- }
-#else
- value *v = findValue (topScope,argv[1],1) ;
-
- if (v == NULL)
- printf ("Can't find %s\n",argv[1]) ;
- else
- {
- long ival = 987654 ;
-
- if (getInteger (v->v.scope_val,argv[2],&ival,1))
- printf ("Getting %s : %ld",argv[2],ival) ;
- else
- printf ("Name is not legal: %s\n",argv[2]) ;
- }
-#endif
- }
- else if (argc == 2)
- {
-#if 1
- value *v = findValue (topScope,argv[1],1) ;
-
- if (v == NULL)
- printf ("Can't find %s\n",argv[1]) ;
- else
- {
- printf ("Getting %s : ",argv[1]) ;
- printValue (stdout,v,0) ;
- }
-#else
- if (findScope (topScope,argv[1],1) == NULL)
- printf ("Can't find the scope of %s\n",argv[1]) ;
-#endif
- }
- }
-
- freeScopeTree (topScope) ;
-
- return 0 ;
-}
-#endif /* defined (WANT_MAIN) */
+++ /dev/null
-/* $Id: connection.c 7793 2008-04-26 08:15:40Z iulius $
-**
-** The implementation of the innfeed Connection class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The Connection object is what manages the NNTP protocol. If the remote
-** doesn't do streaming, then the standard IHAVE lock-step protcol is
-** performed. In the streaming situation we have two cases. One where we must
-** send CHECK commands, and the other where we can directly send TAKETHIS
-** commands without a prior CHECK.
-**
-** The Connection object maintains four article queues. The first one is
-** where new articles are put if they need to have an IHAVE or CHECK command
-** sent for them. The second queue is where the articles move from the first
-** after their IHAVE/CHECK command is sent, but the reply has not yet been
-** seen. The third queue is where articles go after the IHAVE/CHECK reply has
-** been seen (and the reply says to send the article). It is articles in the
-** third queue that have the TAKETHIS command sent, or the body of an IHAVE.
-** The third queue is also where new articles go if the connection is running
-** in no-CHECK mode. The fourth queue is where the articles move to from the
-** third queue after their IHAVE-body or TAKETHIS command has been sent. When
-** the response to the IHAVE-body or TAKETHIS is received the articles are
-** removed from the fourth queue and the Host object controlling this
-** Connection is notified of the success or failure of the transfer.
-**
-** The whole system is event-driven by the EndPoint class and the Host via
-** calls to prepareRead() and prepareWrite() and prepareSleep().
-**
-**
-** We should probably store the results of gethostbyname in the connection so
-** we can rotate through the address when one fails for connecting. Perhaps
-** the gethostbyname should be done in the Host and the connection should
-** just be given the address to use.
-**
-** Should we worry about articles being stuck on a queue for ever if the
-** remote forgets to send a response to a CHECK?
-**
-** Perhaps instead of killing the connection on some of the more simple
-** errors, we should perhaps try to flush the input and keep going.
-**
-** Worry about counter overflow.
-**
-** Worry about stats gathering when switch to no-check mode.
-**
-** XXX if issueQUIT() has a problem and the state goes to cxnDeadS this is
-** not handled properly everywhere yet.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <signal.h>
-#include <syslog.h>
-
-#if defined (__FreeBSD__)
-# include <sys/ioctl.h>
-#endif
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "configfile.h"
-#include "connection.h"
-#include "endpoint.h"
-#include "host.h"
-
-#if defined (NDEBUG)
-#define VALIDATE_CONNECTION(x) ((void) 0)
-#else
-#define VALIDATE_CONNECTION(x) validateConnection (x)
-#endif
-
-extern char **PointersFreedOnExit ;
-extern const char *pidFile ;
-
-/*
- * Private types.
- */
-
-/* We keep a linked list of articles the connection is trying to transmit */
-typedef struct art_holder_s
-{
- Article article ;
- struct art_holder_s *next ;
-} *ArtHolder ;
-
-
-typedef enum {
- cxnStartingS, /* the connection's start state. */
- cxnWaitingS, /* not connected. Waiting for an article. */
- cxnConnectingS, /* in the middle of connecting */
- cxnIdleS, /* open and ready to feed, has empty queues */
- cxnIdleTimeoutS, /* timed out in the idle state */
- cxnFeedingS, /* in the processes of feeding articles */
- cxnSleepingS, /* blocked on reestablishment timer */
- cxnFlushingS, /* am waiting for queues to drain to bounce connection. */
- cxnClosingS, /* have been told to close down permanently when queues drained */
- cxnDeadS /* connection is dead. */
-} CxnState ;
-
-/* The Connection class */
-struct connection_s
-{
- Host myHost ; /* the host who owns the connection */
- EndPoint myEp ; /* the endpoint the connection talks through */
- unsigned int ident ; /* an identifier for syslogging. */
- CxnState state ; /* the state the connection is in */
-
-
- /*
- * The Connection maintains 4 queue of articles.
- */
- ArtHolder checkHead ; /* head of article list to do CHECK/IHAVE */
- ArtHolder checkRespHead ; /* head of list waiting on CHECK/IHAVE
- response */
- ArtHolder takeHead ; /* head of list of articles to send
- TAKETHIS/IHAVE-body */
- ArtHolder takeRespHead ; /* list of articles waiting on
- TAKETHIS/IHAVE-body response */
- unsigned int articleQTotal ; /* number of articles in all four queues */
- ArtHolder missing ; /* head of missing list */
-
-
- Buffer respBuffer ; /* buffer all responses are read into */
-
- char *ipName ; /* the ip name (possibly quad) of the remote */
-
- unsigned int maxCheck ; /* the max number of CHECKs to send */
- unsigned short port ; /* the port number to use */
-
- /*
- * Timeout values and their callback IDs
- */
-
- /* Timer for max amount of time between receiving articles from the
- Host */
- unsigned int articleReceiptTimeout ;
- TimeoutId artReceiptTimerId ;
-
- /* Timer for the max amount of time to wait for a response from the
- remote */
- unsigned int readTimeout ;
- TimeoutId readBlockedTimerId ;
-
- /* Timer for the max amount of time to wait for a any amount of data
- to be written to the remote */
- unsigned int writeTimeout ;
- TimeoutId writeBlockedTimerId ;
-
- /* Timer for the max number of seconds to keep the network connection
- up (long lasting connections give older nntp servers problems). */
- unsigned int flushTimeout ;
- TimeoutId flushTimerId ;
-
- /* Timer for the number of seconds to sleep before attempting a
- reconnect. */
- unsigned int sleepTimeout ;
- TimeoutId sleepTimerId ;
-
-
- bool loggedNoCr ; /* true if we logged the NOCR_MSG */
- bool immedRecon ; /* true if we recon immediately after flushing. */
- bool doesStreaming ; /* true if remote will handle streaming */
- bool authenticated ; /* true if remote authenticated */
- bool quitWasIssued ; /* true if QUIT command was sent. */
- bool needsChecks ; /* true if we issue CHECK commands in
- streaming mode (rather than just sending
- TAKETHIS commands) */
-
- time_t timeCon ; /* the time the connect happened (including
- the MODE STREAM command). */
-
- /*
- * STATISTICS
- */
- unsigned int artsTaken ; /* the number of articles INN gave this cxn */
- unsigned int checksIssued ; /* the number of CHECKS/IHAVES we
- sent. Note that if we're running in
- no-CHECK mode, then we add in the
- TAKETHIS commands too */
- unsigned int checksRefused ; /* the number of response 435/438 */
- unsigned int takesRejected ; /* the number of response 437/439 recevied */
- unsigned int takesOkayed ; /* the number of response 235/239 received */
-
- double takesSizeRejected ;
- double takesSizeOkayed ;
-
- double onThreshold ; /* for no-CHECK mode */
- double offThreshold ; /* for no-CHECK mode */
- double filterValue ; /* current value of IIR filter */
- double lowPassFilter ; /* time constant for IIR filter */
-
- Connection next ; /* for global list. */
-};
-
-static Connection gCxnList = NULL ;
-static unsigned int gCxnCount = 0 ;
-static unsigned int max_reconnect_period = MAX_RECON_PER ;
-static unsigned int init_reconnect_period = INIT_RECON_PER ;
-#if 0
-static bool inited = false ;
-#endif
-static Buffer dotFirstBuffer ;
-static Buffer dotBuffer ;
-static Buffer crlfBuffer ;
-
-
-/***************************************************
- *
- * Private function declarations.
- *
- ***************************************************/
-
-
-/* I/O Callbacks */
-static void connectionDone (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void getBanner (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void getAuthUserResponse (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void getAuthPassResponse (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void getModeResponse (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void responseIsRead (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void quitWritten (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void ihaveBodyDone (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void commandWriteDone (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void modeCmdIssued (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void authUserIssued (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void authPassIssued (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-static void writeProgress (EndPoint e, IoStatus i, Buffer *b, void *d) ;
-
-
-/* Timer callbacks */
-static void responseTimeoutCbk (TimeoutId id, void *data) ;
-static void writeTimeoutCbk (TimeoutId id, void *data) ;
-static void reopenTimeoutCbk (TimeoutId id, void *data) ;
-static void flushCxnCbk (TimeoutId, void *data) ;
-static void articleTimeoutCbk (TimeoutId id, void *data) ;
-
-/* Work callbacks */
-static void cxnWorkProc (EndPoint ep, void *data) ;
-
-
-static void cxnSleepOrDie (Connection cxn) ;
-
-/* Response processing. */
-static void processResponse205 (Connection cxn, char *response) ;
-static void processResponse238 (Connection cxn, char *response) ;
-static void processResponse431 (Connection cxn, char *response) ;
-static void processResponse438 (Connection cxn, char *response) ;
-static void processResponse239 (Connection cxn, char *response) ;
-static void processResponse439 (Connection cxn, char *response) ;
-static void processResponse235 (Connection cxn, char *response) ;
-static void processResponse335 (Connection cxn, char *response) ;
-static void processResponse400 (Connection cxn, char *response) ;
-static void processResponse435 (Connection cxn, char *response) ;
-static void processResponse436 (Connection cxn, char *response) ;
-static void processResponse437 (Connection cxn, char *response) ;
-static void processResponse480 (Connection cxn, char *response) ;
-static void processResponse503 (Connection cxn, char *response) ;
-
-
-/* Misc functions */
-static void cxnSleep (Connection cxn) ;
-static void cxnDead (Connection cxn) ;
-static void cxnIdle (Connection cxn) ;
-static void noSuchMessageId (Connection cxn, unsigned int responseCode,
- const char *msgid, const char *response) ;
-static void abortConnection (Connection cxn) ;
-static void resetConnection (Connection cxn) ;
-static void deferAllArticles (Connection cxn) ;
-static void deferQueuedArticles (Connection cxn) ;
-static void doSomeWrites (Connection cxn) ;
-static bool issueIHAVE (Connection cxn) ;
-static void issueIHAVEBody (Connection cxn) ;
-static bool issueStreamingCommands (Connection cxn) ;
-static Buffer buildCheckBuffer (Connection cxn) ;
-static Buffer *buildTakethisBuffers (Connection cxn, Buffer checkBuffer) ;
-static void issueQUIT (Connection cxn) ;
-static void initReadBlockedTimeout (Connection cxn) ;
-static int prepareWriteWithTimeout (EndPoint endp, Buffer *buffers,
- EndpRWCB done, Connection cxn) ;
-static void delConnection (Connection cxn) ;
-static void incrFilter (Connection cxn) ;
-static void decrFilter (Connection cxn) ;
-static bool writesNeeded (Connection cxn) ;
-static void validateConnection (Connection cxn) ;
-static const char *stateToString (CxnState state) ;
-
-static void issueModeStream (EndPoint e, Connection cxn) ;
-static void issueAuthUser (EndPoint e, Connection cxn) ;
-static void issueAuthPass (EndPoint e, Connection cxn) ;
-
-static void prepareReopenCbk (Connection cxn) ;
-
-
-/* Article queue management routines. */
-static ArtHolder newArtHolder (Article art) ;
-static void delArtHolder (ArtHolder artH) ;
-static bool remArtHolder (ArtHolder art, ArtHolder *head, unsigned int *count) ;
-static void appendArtHolder (ArtHolder artH, ArtHolder *head, unsigned int *count) ;
-static ArtHolder artHolderByMsgId (const char *msgid, ArtHolder head) ;
-
-static int fudgeFactor (int initVal) ;
-
-
-
-
-/***************************************************
- *
- * Public functions implementation.
- *
- ***************************************************/
-
-
-int cxnConfigLoadCbk (void *data UNUSED)
-{
- long iv ;
- int rval = 1 ;
- FILE *fp = (FILE *) data ;
-
- if (getInteger (topScope,"max-reconnect-time",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld", "max-reconnect-time",
- iv,"global scope",(long) MAX_RECON_PER);
- iv = MAX_RECON_PER ;
- }
- }
- else
- iv = MAX_RECON_PER ;
- max_reconnect_period = (unsigned int) iv ;
-
- if (getInteger (topScope,"initial-reconnect-time",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld", "initial-reconnect-time",
- iv,"global scope",(long)INIT_RECON_PER);
- iv = INIT_RECON_PER ;
- }
- }
- else
- iv = INIT_RECON_PER ;
- init_reconnect_period = (unsigned int) iv ;
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * Create a new Connection object and return it. All fields are
- * initialized to reasonable values.
- */
-Connection newConnection (Host host,
- unsigned int id,
- const char *ipname,
- unsigned int articleReceiptTimeout,
- unsigned int portNum,
- unsigned int respTimeout,
- unsigned int flushTimeout,
- double lowPassLow,
- double lowPassHigh,
- double lowPassFilter)
-{
- Connection cxn ;
- bool croak = false ;
-
- if (ipname == NULL)
- {
- d_printf (1,"NULL ipname in newConnection\n") ;
- croak = true ;
- }
-
- if (ipname && strlen (ipname) == 0)
- {
- d_printf (1,"Empty ipname in newConnection\n") ;
- croak = true ;
- }
-
- if (croak)
- return NULL ;
-
- cxn = xcalloc (1, sizeof(struct connection_s));
-
- cxn->myHost = host ;
- cxn->myEp = NULL ;
- cxn->ident = id ;
-
- cxn->checkHead = NULL ;
- cxn->checkRespHead = NULL ;
- cxn->takeHead = NULL ;
- cxn->takeRespHead = NULL ;
-
- cxn->articleQTotal = 0 ;
- cxn->missing = NULL ;
-
- cxn->respBuffer = newBuffer (BUFFER_SIZE) ;
- ASSERT (cxn->respBuffer != NULL) ;
-
- cxn->ipName = xstrdup (ipname) ;
- cxn->port = portNum ;
-
- /* Time out the higher numbered connections faster */
- cxn->articleReceiptTimeout = articleReceiptTimeout * 10.0 / (10.0 + id) ;
- cxn->artReceiptTimerId = 0 ;
-
- cxn->readTimeout = respTimeout ;
- cxn->readBlockedTimerId = 0 ;
-
- cxn->writeTimeout = respTimeout ; /* XXX should be a separate value */
- cxn->writeBlockedTimerId = 0 ;
-
- cxn->flushTimeout = fudgeFactor (flushTimeout) ;
- cxn->flushTimerId = 0 ;
-
- cxn->onThreshold = lowPassHigh * lowPassFilter / 100.0 ;
- cxn->offThreshold = lowPassLow * lowPassFilter / 100.0 ;
- cxn->lowPassFilter = lowPassFilter;
-
- cxn->sleepTimerId = 0 ;
- cxn->sleepTimeout = init_reconnect_period ;
-
- resetConnection (cxn) ;
-
- cxn->next = gCxnList ;
- gCxnList = cxn ;
- gCxnCount++ ;
-
- cxn->state = cxnStartingS ;
-
- return cxn ;
-}
-
-
-
-
-\f
-/* Create a new endpoint hooked to a non-blocking socket that is trying to
- * connect to the host info stored in the Connection. On fast machines
- * connecting locally the connect() may have already succeeded when this
- * returns, but typically the connect will still be running and when it
- * completes. The Connection will be notified via a write callback setup by
- * prepareWrite below. If nothing goes wrong then this will return true
- * (even if the connect() has not yet completed). If something fails
- * (hostname lookup etc.) then it returns false (and the Connection is left
- * in the sleeping state)..
- *
- * Pre-state Reason cxnConnect called
- * --------- ------------------------
- * cxnStartingS Connection owner issued call.
- * cxnWaitingS side effect of cxnTakeArticle() call
- * cxnConnecting side effect of cxnFlush() call
- * cxnSleepingS side effect of reopenTimeoutCbk() call.
- */
-bool cxnConnect (Connection cxn)
-{
- const struct sockaddr_storage cxnAddr, cxnSelf ;
- const struct sockaddr *retAddr;
- int fd, rval ;
- const char *peerName = hostPeerName (cxn->myHost) ;
- char msgbuf[100];
- const struct sockaddr_in *bind_addr = hostBindAddr (cxn->myHost) ;
- int family = 0;
-#ifdef HAVE_INET6
- char paddr[INET6_ADDRSTRLEN];
- const struct sockaddr_in6 *bind_addr6 = hostBindAddr6 (cxn->myHost) ;
-#endif
-
- ASSERT (cxn->myEp == NULL) ;
-
- if (!(cxn->state == cxnStartingS ||
- cxn->state == cxnWaitingS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnSleepingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return false;
- }
-
- if (cxn->state == cxnWaitingS)
- ASSERT (cxn->articleQTotal == 1) ;
- else
- ASSERT (cxn->articleQTotal == 0) ;
-
- cxn->state = cxnConnectingS ;
-
-#ifdef HAVE_INET6
- family = hostAddrFamily (cxn->myHost);
-#endif
- retAddr = hostIpAddr (cxn->myHost, family) ;
-
- if (retAddr == NULL)
- {
- cxnSleepOrDie (cxn) ;
- return false ;
- }
-
- memcpy( (void *)&cxnAddr, retAddr, SA_LEN(retAddr) );
-
-#ifdef HAVE_INET6
- if( cxnAddr.ss_family == AF_INET6 )
- {
- ((struct sockaddr_in6 *)&cxnAddr)->sin6_port = htons(cxn->port) ;
- fd = socket (PF_INET6, SOCK_STREAM, 0);
- }
- else
-#endif
- {
- ((struct sockaddr_in *)&cxnAddr)->sin_port = htons(cxn->port) ;
- fd = socket (PF_INET, SOCK_STREAM, 0);
- }
- if (fd < 0)
- {
- syswarn ("%s:%d cxnsleep can't create socket", peerName, cxn->ident) ;
- d_printf (1,"Can't get a socket: %s\n", strerror (errno)) ;
-
- cxnSleepOrDie (cxn) ;
-
- return false ;
- }
-
-#ifdef HAVE_INET6
- /* bind to a specified IPv6 address */
- if( (cxnAddr.ss_family == AF_INET6) && bind_addr6 )
- {
- memcpy( (void *)&cxnSelf, bind_addr6, sizeof(struct sockaddr_in6) );
- if (bind (fd, (struct sockaddr *) &cxnSelf,
- sizeof(struct sockaddr_in6)) < 0)
- {
- snprintf(msgbuf, sizeof(msgbuf), "bind (%s): %%m",
- inet_ntop(AF_INET6, bind_addr6->sin6_addr.s6_addr,
- paddr, sizeof(paddr)) );
-
- syslog (LOG_ERR, msgbuf) ;
-
- cxnSleepOrDie (cxn) ;
-
- return false ;
- }
- }
- else
-#endif
- /* bind to a specified IPv4 address */
-#ifdef HAVE_INET6
- if ( (cxnAddr.ss_family == AF_INET) && bind_addr )
-#else
- if (bind_addr)
-#endif
- {
- memcpy( (void *)&cxnSelf, bind_addr, sizeof(struct sockaddr_in) );
- if (bind (fd, (struct sockaddr *) &cxnSelf,
- sizeof(struct sockaddr_in) ) < 0)
- {
- snprintf(msgbuf, sizeof(msgbuf), "bind (%s): %%m",
- inet_ntoa(bind_addr->sin_addr));
- syslog (LOG_ERR, msgbuf) ;
-
- cxnSleepOrDie (cxn) ;
-
- return false ;
- }
- }
-
- /* set our file descriptor to non-blocking */
-#if defined (O_NONBLOCK)
- rval = fcntl (fd, F_GETFL, 0) ;
- if (rval >= 0)
- rval = fcntl (fd, F_SETFL, rval | O_NONBLOCK) ;
-#else
- {
- int state = 1 ;
- rval = ioctl (fd, FIONBIO, (char *) &state) ;
- }
-#endif
-
- if (rval < 0)
- {
- syswarn ("%s:%d cxnsleep can't set socket non-blocking", peerName,
- cxn->ident) ;
- close (fd) ;
-
- cxnSleepOrDie (cxn) ;
-
- return false ;
- }
-
- rval = connect (fd, (struct sockaddr *) &cxnAddr,
- SA_LEN((struct sockaddr *)&cxnAddr)) ;
- if (rval < 0 && errno != EINPROGRESS)
- {
- syswarn ("%s:%d connect", peerName, cxn->ident) ;
- hostIpFailed (cxn->myHost) ;
- close (fd) ;
-
- cxnSleepOrDie (cxn) ;
-
- return false ;
- }
-
- if ((cxn->myEp = newEndPoint (fd)) == NULL)
- {
- /* If this happens, then fd was bigger than what select could handle,
- so endpoint.c refused to create the new object. */
- close (fd) ;
- cxnSleepOrDie (cxn) ;
- return false ;
- }
-
-
- if (rval < 0)
- /* when the write callback gets done the connection went through */
- prepareWrite (cxn->myEp, NULL, NULL, connectionDone, cxn) ;
- else
- connectionDone (cxn->myEp, IoDone, NULL, cxn) ;
-
- /* connectionDone() could set state to sleeping */
- return (cxn->state == cxnConnectingS ? true : false) ;
-}
-
-
-
-
-\f
-/* Put the Connection into the wait state.
- *
- * Pre-state Reason cxnWait called
- * --------- ------------------------
- * cxnStartingS - Connection owner called cxnWait()
- * cxnSleepingS - side effect of cxnFlush() call.
- * cxnConnectingS - side effect of cxnFlush() call.
- * cxnFlushingS - side effect of receiving response 205
- * and Connection had no articles when
- * cxnFlush() was issued.
- * - prepareRead failed.
- * - I/O failed.
- *
- */
-void cxnWait (Connection cxn)
-{
- ASSERT (cxn->state == cxnStartingS ||
- cxn->state == cxnSleepingS ||
- cxn->state == cxnConnectingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnFlushingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- abortConnection (cxn) ;
-
- cxn->state = cxnWaitingS ;
-
- hostCxnWaiting (cxn->myHost,cxn) ; /* tell our Host we're waiting */
-}
-
-
-
-
-\f
-/* Tells the Connection to flush itself (i.e. push out all articles,
- * issue a QUIT and drop the network connection. If necessary a
- * reconnect will be done immediately after. Called by the Host, or
- * by the timer callback.
- *
- * Pre-state Reason cxnFlush called
- * --------- ------------------------
- * ALL (except cxnDeadS - Connection owner called cxnFlush()
- * and cxnStartingS)
- * cxnFeedingS - side effect of flushCxnCbk() call.
- */
-void cxnFlush (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state != cxnStartingS) ;
- ASSERT (cxn->state != cxnDeadS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- switch (cxn->state)
- {
- case cxnSleepingS:
- cxnWait (cxn) ;
- break ;
-
- case cxnConnectingS:
- cxnWait (cxn) ;
- cxnConnect (cxn) ;
- break ;
-
- case cxnIdleTimeoutS:
- case cxnIdleS:
- ASSERT (cxn->articleQTotal == 0) ;
- if (cxn->state != cxnIdleTimeoutS)
- clearTimer (cxn->artReceiptTimerId) ;
- clearTimer (cxn->flushTimerId) ;
- cxn->state = cxnFlushingS ;
- issueQUIT (cxn) ;
- break ;
-
- case cxnClosingS:
- case cxnFlushingS:
- case cxnWaitingS:
- if (cxn->articleQTotal == 0 && !writeIsPending (cxn->myEp))
- issueQUIT (cxn) ;
- break ;
-
- case cxnFeedingS:
- /* we only reconnect immediately if we're not idle when cxnFlush()
- is called. */
- if (!cxn->immedRecon)
- {
- cxn->immedRecon = (cxn->articleQTotal > 0 ? true : false) ;
- d_printf (1,"%s:%d immediate reconnect for a cxnFlush()\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- clearTimer (cxn->flushTimerId) ;
-
- cxn->state = cxnFlushingS ;
-
- if (cxn->articleQTotal == 0 && !writeIsPending (cxn->myEp))
- issueQUIT (cxn) ;
- break ;
-
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-}
-
-
-\f
-/*
- * Tells the Connection to dump all articles that are queued and to issue a
- * QUIT as quickly as possible. Much like cxnClose, except queued articles
- * are not sent, but are given back to the Host.
- */
-void cxnTerminate (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state != cxnDeadS) ;
- ASSERT (cxn->state != cxnStartingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- switch (cxn->state)
- {
- case cxnFeedingS:
- d_printf (1,"%s:%d Issuing terminate\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- clearTimer (cxn->flushTimerId) ;
-
- cxn->state = cxnClosingS ;
-
- deferQueuedArticles (cxn) ;
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ; /* send out the QUIT if we can */
- break ;
-
- case cxnIdleTimeoutS:
- case cxnIdleS:
- ASSERT (cxn->articleQTotal == 0) ;
- if (cxn->state != cxnIdleTimeoutS)
- clearTimer (cxn->artReceiptTimerId) ;
- clearTimer (cxn->flushTimerId) ;
- cxn->state = cxnClosingS ;
- issueQUIT (cxn) ;
- break ;
-
- case cxnFlushingS: /* we are in the middle of a periodic close. */
- d_printf (1,"%s:%d Connection already being flushed\n",
- hostPeerName (cxn->myHost),cxn->ident);
- cxn->state = cxnClosingS ;
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ; /* send out the QUIT if we can */
- break ;
-
- case cxnClosingS:
- d_printf (1,"%s:%d Connection already closing\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- break ;
-
- case cxnWaitingS:
- case cxnConnectingS:
- case cxnSleepingS:
- cxnDead (cxn) ;
- break ;
-
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- if (cxn->state == cxnDeadS)
- {
- d_printf (1,"%s:%d Deleting connection\n",hostPeerName (cxn->myHost),
- cxn->ident) ;
-
- delConnection (cxn) ;
- }
-}
-
-
-\f
-/* Tells the Connection to do a disconnect and then when it is
- * disconnected to delete itself.
- *
- * Pre-state Reason cxnClose called
- * --------- ------------------------
- * ALL (except cxnDeadS - Connecton owner called directly.
- * and cxnStartingS).
- */
-void cxnClose (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state != cxnDeadS) ;
- ASSERT (cxn->state != cxnStartingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- switch (cxn->state)
- {
- case cxnFeedingS:
- d_printf (1,"%s:%d Issuing disconnect\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- clearTimer (cxn->flushTimerId) ;
-
- cxn->state = cxnClosingS ;
-
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ; /* send out the QUIT if we can */
- break ;
-
- case cxnIdleS:
- case cxnIdleTimeoutS:
- ASSERT (cxn->articleQTotal == 0) ;
- if (cxn->state != cxnIdleTimeoutS)
- clearTimer (cxn->artReceiptTimerId) ;
- clearTimer (cxn->flushTimerId) ;
- cxn->state = cxnClosingS ;
- issueQUIT (cxn) ;
- break ;
-
- case cxnFlushingS: /* we are in the middle of a periodic close. */
- d_printf (1,"%s:%d Connection already being flushed\n",
- hostPeerName (cxn->myHost),cxn->ident);
- cxn->state = cxnClosingS ;
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ; /* send out the QUIT if we can */
- break ;
-
- case cxnClosingS:
- d_printf (1,"%s:%d Connection already closing\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- break ;
-
- case cxnWaitingS:
- case cxnConnectingS:
- case cxnSleepingS:
- cxnDead (cxn) ;
- break ;
-
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- if (cxn->state == cxnDeadS)
- {
- d_printf (1,"%s:%d Deleting connection\n",hostPeerName (cxn->myHost),
- cxn->ident) ;
-
- delConnection (cxn) ;
- }
-}
-
-
-
-
-\f
-/* This is what the Host calls to get us to tranfer an article. If
- * we're running the IHAVE sequence, then we can't take it if we've
- * got an article already. If we're running the CHECK/TAKETHIS
- * sequence, then we'll take as many as we can (up to our MAXCHECK
- * limit).
- */
-bool cxnTakeArticle (Connection cxn, Article art)
-{
- bool rval = true ;
-
- ASSERT (cxn != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- if ( !cxnQueueArticle (cxn,art) ) /* might change cxnIdleS to cxnFeedingS */
- return false ;
-
- if (!(cxn->state == cxnConnectingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnWaitingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return false ;
- }
-
- if (cxn->state != cxnWaitingS) /* because articleQTotal == 1 */
- VALIDATE_CONNECTION (cxn) ;
- else
- ASSERT (cxn->articleQTotal == 1) ;
-
- switch (cxn->state)
- {
- case cxnWaitingS:
- cxnConnect (cxn) ;
- break ;
-
- case cxnFeedingS:
- doSomeWrites (cxn) ;
- break ;
-
- case cxnConnectingS:
- break ;
-
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-
- return rval ;
-}
-
-
-
-
-\f
-/* if there's room in the Connection then stick the article on the
- * queue, otherwise return false.
- */
-bool cxnQueueArticle (Connection cxn, Article art)
-{
- ArtHolder newArt ;
- bool rval = false ;
-
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state != cxnStartingS) ;
- ASSERT (cxn->state != cxnDeadS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- switch (cxn->state)
- {
- case cxnClosingS:
- d_printf (5,"%s:%d Refusing article due to closing\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- break ;
-
- case cxnFlushingS:
- d_printf (5,"%s:%d Refusing article due to flushing\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- break ;
-
- case cxnSleepingS:
- d_printf (5,"%s:%d Refusing article due to sleeping\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- break ;
-
- case cxnWaitingS:
- rval = true ;
- newArt = newArtHolder (art) ;
- appendArtHolder (newArt, &cxn->checkHead, &cxn->articleQTotal) ;
- break ;
-
- case cxnConnectingS:
- if (cxn->articleQTotal != 0)
- break ;
- rval = true ;
- newArt = newArtHolder (art) ;
- appendArtHolder (newArt, &cxn->checkHead, &cxn->articleQTotal) ;
- break ;
-
- case cxnIdleS:
- case cxnFeedingS:
- if (cxn->articleQTotal >= cxn->maxCheck)
- d_printf (5, "%s:%d Refusing article due to articleQTotal >= maxCheck (%d > %d)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->articleQTotal, cxn->maxCheck) ;
- else
- {
- rval = true ;
- newArt = newArtHolder (art) ;
- if (cxn->needsChecks)
- appendArtHolder (newArt, &cxn->checkHead, &cxn->articleQTotal) ;
- else
- appendArtHolder (newArt, &cxn->takeHead, &cxn->articleQTotal) ;
- if (cxn->state == cxnIdleS)
- {
- cxn->state = cxnFeedingS ;
- clearTimer (cxn->artReceiptTimerId) ;
- }
- }
- break ;
-
- default:
- die ("Invalid state: %s\n", stateToString (cxn->state)) ;
- }
-
- if (rval)
- {
- d_printf (5,"%s:%d accepting article %s\n",hostPeerName (cxn->myHost),
- cxn->ident,artMsgId (art)) ;
-
- cxn->artsTaken++ ;
- }
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * generate a log message for activity. Usually called by the Connection's
- * owner
- */
-void cxnLogStats (Connection cxn, bool final)
-{
- const char *peerName ;
- time_t now = theTime() ;
-
- ASSERT (cxn != NULL) ;
-
- /* only log stats when in one of these three states. */
- switch (cxn->state)
- {
- case cxnFeedingS:
- case cxnFlushingS:
- case cxnClosingS:
- break ;
-
- default:
- return ;
- }
-
- peerName = hostPeerName (cxn->myHost) ;
-
- notice ("%s:%d %s seconds %ld offered %d accepted %d refused %d"
- " rejected %d accsize %.0f rejsize %.0f", peerName, cxn->ident,
- (final ? "final" : "checkpoint"), (long) (now - cxn->timeCon),
- cxn->checksIssued, cxn->takesOkayed, cxn->checksRefused,
- cxn->takesRejected, cxn->takesSizeOkayed, cxn->takesSizeRejected) ;
-
- if (final)
- {
- cxn->artsTaken = 0 ;
- cxn->checksIssued = 0 ;
- cxn->checksRefused = 0 ;
- cxn->takesRejected = 0 ;
- cxn->takesOkayed = 0 ;
- cxn->takesSizeRejected = 0 ;
- cxn->takesSizeOkayed = 0 ;
-
- if (cxn->timeCon > 0)
- cxn->timeCon = theTime() ;
- }
-}
-
-
-
-
-\f
-/*
- * return the number of articles the connection will accept.
- */
-size_t cxnQueueSpace (Connection cxn)
-{
- int rval = 0 ;
-
- ASSERT (cxn != NULL) ;
-
- if (cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnConnectingS ||
- cxn->state == cxnWaitingS)
- rval = cxn->maxCheck - cxn->articleQTotal ;
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * Print info on all the connections that currently exist.
- */
-void gPrintCxnInfo (FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
- Connection cxn ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Connection list : (count %d) {\n",
- indent,gCxnCount) ;
- for (cxn = gCxnList ; cxn != NULL ; cxn = cxn->next)
- printCxnInfo (cxn,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-\f
-/*
- * Print the info about the given connection.
- */
-void printCxnInfo (Connection cxn, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
- ArtHolder artH ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sConnection : %p {\n",indent, (void *) cxn) ;
- fprintf (fp,"%s host : %p\n",indent, (void *) cxn->myHost) ;
- fprintf (fp,"%s endpoint : %p\n",indent, (void *) cxn->myEp) ;
- fprintf (fp,"%s state : %s\n",indent, stateToString (cxn->state)) ;
- fprintf (fp,"%s ident : %d\n",indent,cxn->ident) ;
- fprintf (fp,"%s ip-name : %s\n", indent, cxn->ipName) ;
- fprintf (fp,"%s port-number : %d\n",indent,cxn->port) ;
- fprintf (fp,"%s max-checks : %d\n",indent,cxn->maxCheck) ;
- fprintf (fp,"%s does-streaming : %s\n",indent,
- boolToString (cxn->doesStreaming)) ;
- fprintf (fp,"%s authenticated : %s\n",indent,
- boolToString (cxn->authenticated)) ;
- fprintf (fp,"%s quitWasIssued : %s\n",indent,
- boolToString (cxn->quitWasIssued)) ;
- fprintf (fp,"%s needs-checks : %s\n",indent,
- boolToString (cxn->needsChecks)) ;
-
- fprintf (fp,"%s time-connected : %ld\n",indent,(long) cxn->timeCon) ;
- fprintf (fp,"%s articles from INN : %d\n",indent,cxn->artsTaken) ;
- fprintf (fp,"%s articles offered : %d\n",indent,
- cxn->checksIssued) ;
- fprintf (fp,"%s articles refused : %d\n",indent,
- cxn->checksRefused) ;
- fprintf (fp,"%s articles rejected : %d\n",indent,
- cxn->takesRejected) ;
- fprintf (fp,"%s articles accepted : %d\n",indent,
- cxn->takesOkayed) ;
- fprintf (fp,"%s low-pass upper limit : %0.6f\n", indent,
- cxn->onThreshold) ;
- fprintf (fp,"%s low-pass lower limit : %0.6f\n", indent,
- cxn->offThreshold) ;
- fprintf (fp,"%s low-pass filter tc : %0.6f\n", indent,
- cxn->lowPassFilter) ;
- fprintf (fp,"%s low-pass filter : %0.6f\n", indent,
- cxn->filterValue) ;
-
- fprintf (fp,"%s article-timeout : %d\n",indent,cxn->articleReceiptTimeout) ;
- fprintf (fp,"%s article-callback : %d\n",indent,cxn->artReceiptTimerId) ;
-
- fprintf (fp,"%s response-timeout : %d\n",indent,cxn->readTimeout) ;
- fprintf (fp,"%s response-callback : %d\n",indent,cxn->readBlockedTimerId) ;
-
- fprintf (fp,"%s write-timeout : %d\n",indent,cxn->writeTimeout) ;
- fprintf (fp,"%s write-callback : %d\n",indent,cxn->writeBlockedTimerId) ;
-
- fprintf (fp,"%s flushTimeout : %d\n",indent,cxn->flushTimeout) ;
- fprintf (fp,"%s flushTimerId : %d\n",indent,cxn->flushTimerId) ;
-
- fprintf (fp,"%s reopen wait : %d\n",indent,cxn->sleepTimeout) ;
- fprintf (fp,"%s reopen id : %d\n",indent,cxn->sleepTimerId) ;
-
- fprintf (fp,"%s CHECK queue {\n",indent) ;
- for (artH = cxn->checkHead ; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s CHECK Response queue {\n",indent) ;
- for (artH = cxn->checkRespHead ; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s TAKE queue {\n",indent) ;
- for (artH = cxn->takeHead ; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s TAKE response queue {\n",indent) ;
- for (artH = cxn->takeRespHead ; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s response buffer {\n",indent) ;
- printBufferInfo (cxn->respBuffer,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-\f
-/*
- * return the number of articles the connection will accept.
- */
-bool cxnCheckstate (Connection cxn)
-{
- bool rval = false ;
-
- ASSERT (cxn != NULL) ;
-
- if (cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnConnectingS)
- rval = true ;
-
- return rval ;
-}
-
-
-
-
-\f
-/**********************************************************************/
-/** STATIC PRIVATE FUNCTIONS **/
-/**********************************************************************/
-
-
-/*
- * ENDPOINT CALLBACK AREA.
- *
- * All the functions in this next section are callbacks fired by the
- * EndPoint objects/class (either timers or i/o completion callbacks)..
- */
-
-\f
-/*
- * this is the first stage of the NNTP FSM. This function is called
- * when the tcp/ip network connection is setup and we should get
- * ready to read the banner message. When this function returns the
- * state of the Connection will still be cxnConnectingS unless
- * something broken, in which case it probably went into the
- * cxnSleepingS state.
- */
-static void connectionDone (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Buffer *readBuffers ;
- Connection cxn = (Connection) d ;
- const char *peerName ;
- int optval;
- socklen_t size ;
-
- ASSERT (b == NULL) ;
- ASSERT (cxn->state == cxnConnectingS) ;
- ASSERT (!writeIsPending (cxn->myEp)) ;
-
- size = sizeof (optval) ;
- peerName = hostPeerName (cxn->myHost) ;
-
- if (i != IoDone)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep i/o failed", peerName, cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (getsockopt (endPointFd (e), SOL_SOCKET, SO_ERROR,
- (char *) &optval, &size) != 0)
- {
- /* This is bad. Can't even get the SO_ERROR value out of the socket */
- syswarn ("%s:%d cxnsleep internal getsockopt", peerName, cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (optval != 0)
- {
- /* if the connect failed then the only way to know is by getting
- the SO_ERROR value out of the socket. */
- errno = optval ;
- syswarn ("%s:%d cxnsleep connect", peerName, cxn->ident) ;
- hostIpFailed (cxn->myHost) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- readBuffers = makeBufferArray (bufferTakeRef (cxn->respBuffer), NULL) ;
-
- if ( !prepareRead (e, readBuffers, getBanner, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- initReadBlockedTimeout (cxn) ;
-
- /* set up the callback for closing down the connection at regular
- intervals (due to problems with long running nntpd). */
- if (cxn->flushTimeout > 0)
- cxn->flushTimerId = prepareSleep (flushCxnCbk,
- cxn->flushTimeout,cxn) ;
-
- /* The state doesn't change yet until we've read the banner and
- tried the MODE STREAM command. */
- }
- }
- VALIDATE_CONNECTION (cxn) ;
-}
-
-
-
-
-\f
-/*
- * This is called when we are so far in the connection setup that
- * we're confident it'll work. If the connection is IPv6, remove
- * the IPv4 addresses from the address list.
- */
-static void connectionIfIpv6DeleteIpv4Addr (Connection cxn)
-{
-#ifdef HAVE_INET6
- struct sockaddr_storage ss;
- socklen_t len = sizeof(ss);
-
- if (getpeername (endPointFd (cxn->myEp), (struct sockaddr *)&ss, &len) < 0)
- return;
- if (ss.ss_family != AF_INET6)
- return;
-
- hostDeleteIpv4Addr (cxn->myHost);
-#endif
-}
-
-
-
-
-
-/*
- * Called when the banner message has been read off the wire and is
- * in the buffer(s). When this function returns the state of the
- * Connection will still be cxnConnectingS unless something broken,
- * in which case it probably went into the cxnSleepiongS state.
- */
-static void getBanner (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Buffer *readBuffers ;
- Connection cxn = (Connection) d ;
- char *p = bufferBase (b[0]) ;
- int code ;
- bool isOk = false ;
- const char *peerName ;
- char *rest ;
-
- ASSERT (e == cxn->myEp) ;
- ASSERT (b[0] == cxn->respBuffer) ;
- ASSERT (b[1] == NULL) ;
- ASSERT (cxn->state == cxnConnectingS) ;
- ASSERT (!writeIsPending (cxn->myEp));
-
-
- peerName = hostPeerName (cxn->myHost) ;
-
- bufferAddNullByte (b[0]) ;
-
- if (i != IoDone)
- {
- errno = endPointErrno (cxn->myEp) ;
- syswarn ("%s:%d cxnsleep can't read banner", peerName, cxn->ident) ;
- hostIpFailed (cxn->myHost) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (strchr (p, '\n') == NULL)
- { /* partial read. expand buffer and retry */
- expandBuffer (b[0], BUFFER_EXPAND_AMOUNT) ;
- readBuffers = makeBufferArray (bufferTakeRef (b[0]), NULL) ;
-
- if ( !prepareRead (e, readBuffers, getBanner, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- }
- else if ( !getNntpResponse (p, &code, &rest) )
- {
- trim_ws (p) ;
-
- warn ("%s:%d cxnsleep response format: %s", peerName, cxn->ident, p) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- trim_ws (p) ;
-
- switch (code)
- {
- case 200: /* normal */
- case 201: /* can transfer but not post -- old nntpd */
- isOk = true ;
- break ;
-
- case 400:
- cxnSleepOrDie (cxn) ;
- hostIpFailed (cxn->myHost) ;
- hostCxnBlocked (cxn->myHost, cxn, rest) ;
- break ;
-
- case 502:
- warn ("%s:%d cxnsleep no permission to talk: %s", peerName,
- cxn->ident, p) ;
- cxnSleepOrDie (cxn) ;
- hostIpFailed (cxn->myHost) ;
- hostCxnBlocked (cxn->myHost, cxn, rest) ;
- break ;
-
- default:
- warn ("%s:%d cxnsleep response unknown banner: %d %s", peerName,
- cxn->ident, code, p) ;
- d_printf (1,"%s:%d Unknown response code: %d: %s\n",
- hostPeerName (cxn->myHost),cxn->ident, code, p) ;
- cxnSleepOrDie (cxn) ;
- hostIpFailed (cxn->myHost) ;
- hostCxnBlocked (cxn->myHost, cxn, rest) ;
- break ;
- }
-
- if ( isOk )
- {
- /* If we got this far and the connection is IPv6, remove
- the IPv4 addresses from the address list. */
- connectionIfIpv6DeleteIpv4Addr (cxn);
-
- if (hostUsername (cxn->myHost) != NULL
- && hostPassword (cxn->myHost) != NULL)
- issueAuthUser (e,cxn);
- else
- issueModeStream (e,cxn);
- }
- }
- freeBufferArray (b) ;
-}
-
-
-
-
-\f
-static void issueAuthUser (EndPoint e, Connection cxn)
-{
- Buffer authUserBuffer;
- Buffer *authUserCmdBuffers,*readBuffers;
- size_t lenBuff = 0 ;
- char *t ;
-
- /* 17 == strlen("AUTHINFO USER \r\n\0") */
- lenBuff = (17 + strlen (hostUsername (cxn->myHost))) ;
- authUserBuffer = newBuffer (lenBuff) ;
- t = bufferBase (authUserBuffer) ;
-
- sprintf (t, "AUTHINFO USER %s\r\n", hostUsername (cxn->myHost)) ;
- bufferSetDataSize (authUserBuffer, strlen (t)) ;
-
- authUserCmdBuffers = makeBufferArray (authUserBuffer, NULL) ;
-
- if ( !prepareWriteWithTimeout (e, authUserCmdBuffers, authUserIssued,
- cxn) )
- {
- die ("%s:%d fatal prepare write for authinfo user failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- bufferSetDataSize (cxn->respBuffer, 0) ;
-
- readBuffers = makeBufferArray (bufferTakeRef(cxn->respBuffer),NULL);
-
- if ( !prepareRead (e, readBuffers, getAuthUserResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", hostPeerName (cxn->myHost),
- cxn->ident) ;
- freeBufferArray (readBuffers) ;
- cxnSleepOrDie (cxn) ;
- }
-
-}
-
-
-
-
-
-\f
-static void issueAuthPass (EndPoint e, Connection cxn)
-{
- Buffer authPassBuffer;
- Buffer *authPassCmdBuffers,*readBuffers;
- size_t lenBuff = 0 ;
- char *t ;
-
- /* 17 == strlen("AUTHINFO PASS \r\n\0") */
- lenBuff = (17 + strlen (hostPassword (cxn->myHost))) ;
- authPassBuffer = newBuffer (lenBuff) ;
- t = bufferBase (authPassBuffer) ;
-
- sprintf (t, "AUTHINFO PASS %s\r\n", hostPassword (cxn->myHost)) ;
- bufferSetDataSize (authPassBuffer, strlen (t)) ;
-
- authPassCmdBuffers = makeBufferArray (authPassBuffer, NULL) ;
-
- if ( !prepareWriteWithTimeout (e, authPassCmdBuffers, authPassIssued,
- cxn) )
- {
- die ("%s:%d fatal prepare write for authinfo pass failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- bufferSetDataSize (cxn->respBuffer, 0) ;
-
- readBuffers = makeBufferArray (bufferTakeRef(cxn->respBuffer),NULL);
-
- if ( !prepareRead (e, readBuffers, getAuthPassResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", hostPeerName (cxn->myHost),
- cxn->ident) ;
- freeBufferArray (readBuffers) ;
- cxnSleepOrDie (cxn) ;
- }
-
-}
-
-
-
-
-
-\f
-static void issueModeStream (EndPoint e, Connection cxn)
-{
- Buffer *modeCmdBuffers,*readBuffers ;
- Buffer modeBuffer ;
- char *p;
-
-#define MODE_CMD "MODE STREAM\r\n"
-
- modeBuffer = newBuffer (strlen (MODE_CMD) + 1) ;
- p = bufferBase (modeBuffer) ;
-
- /* now issue the MODE STREAM command */
- d_printf (1,"%s:%d Issuing the streaming command: %s\n",
- hostPeerName (cxn->myHost),cxn->ident,MODE_CMD) ;
-
- strcpy (p, MODE_CMD) ;
-
- bufferSetDataSize (modeBuffer, strlen (p)) ;
-
- modeCmdBuffers = makeBufferArray (modeBuffer, NULL) ;
-
- if ( !prepareWriteWithTimeout (e, modeCmdBuffers, modeCmdIssued,
- cxn) )
- {
- die ("%s:%d fatal prepare write for mode stream failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- bufferSetDataSize (cxn->respBuffer, 0) ;
-
- readBuffers = makeBufferArray (bufferTakeRef(cxn->respBuffer),NULL);
-
- if ( !prepareRead (e, readBuffers, getModeResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", hostPeerName (cxn->myHost),
- cxn->ident) ;
- freeBufferArray (readBuffers) ;
- cxnSleepOrDie (cxn) ;
- }
-}
-
-
-
-
-\f
-/*
- *
- */
-static void getAuthUserResponse (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- int code ;
- char *p = bufferBase (b[0]) ;
- Buffer *buffers ;
- const char *peerName ;
-
- ASSERT (e == cxn->myEp) ;
- ASSERT (b [0] == cxn->respBuffer) ;
- ASSERT (b [1] == NULL) ; /* only ever one buffer on this read */
- ASSERT (cxn->state == cxnConnectingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- bufferAddNullByte (b[0]) ;
-
- d_printf (1,"%s:%d Processing authinfo user response: %s", /* no NL */
- hostPeerName (cxn->myHost), cxn->ident, p) ;
-
- if (i == IoDone && writeIsPending (cxn->myEp))
- {
- /* badness. should never happen */
- warn ("%s:%d cxnsleep authinfo command still pending", peerName,
- cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (i != IoDone)
- {
- if (i != IoEOF)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't read response", peerName, cxn->ident);
- }
- cxnSleepOrDie (cxn) ;
- }
- else if (strchr (p, '\n') == NULL)
- {
- /* partial read */
- expandBuffer (b [0], BUFFER_EXPAND_AMOUNT) ;
-
- buffers = makeBufferArray (bufferTakeRef (b [0]), NULL) ;
- if ( !prepareRead (e, buffers, getAuthUserResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
- freeBufferArray (buffers) ;
- cxnSleepOrDie (cxn) ;
- }
- }
- else
- {
- clearTimer (cxn->readBlockedTimerId) ;
-
- if ( !getNntpResponse (p, &code, NULL) )
- {
- warn ("%s:%d cxnsleep response to AUTHINFO USER: %s", peerName,
- cxn->ident, p) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- notice ("%s:%d connected", peerName, cxn->ident) ;
-
- switch (code)
- {
- case 381:
- issueAuthPass (e,cxn);
- break ;
-
- default:
- warn ("%s:%d cxnsleep response to AUTHINFO USER: %s", peerName,
- cxn->ident, p) ;
- cxn->authenticated = true;
- issueModeStream (e,cxn);
- break ;
- }
-
- }
- }
-}
-
-
-
-
-\f
-/*
- *
- */
-static void getAuthPassResponse (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- int code ;
- char *p = bufferBase (b[0]) ;
- Buffer *buffers ;
- const char *peerName ;
-
- ASSERT (e == cxn->myEp) ;
- ASSERT (b [0] == cxn->respBuffer) ;
- ASSERT (b [1] == NULL) ; /* only ever one buffer on this read */
- ASSERT (cxn->state == cxnConnectingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- bufferAddNullByte (b[0]) ;
-
- d_printf (1,"%s:%d Processing authinfo pass response: %s", /* no NL */
- hostPeerName (cxn->myHost), cxn->ident, p) ;
-
- if (i == IoDone && writeIsPending (cxn->myEp))
- {
- /* badness. should never happen */
- warn ("%s:%d cxnsleep authinfo command still pending", peerName,
- cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (i != IoDone)
- {
- if (i != IoEOF)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't read response", peerName, cxn->ident);
- }
- cxnSleepOrDie (cxn) ;
- }
- else if (strchr (p, '\n') == NULL)
- {
- /* partial read */
- expandBuffer (b [0], BUFFER_EXPAND_AMOUNT) ;
-
- buffers = makeBufferArray (bufferTakeRef (b [0]), NULL) ;
- if ( !prepareRead (e, buffers, getAuthPassResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
- freeBufferArray (buffers) ;
- cxnSleepOrDie (cxn) ;
- }
- }
- else
- {
- clearTimer (cxn->readBlockedTimerId) ;
-
- if ( !getNntpResponse (p, &code, NULL) )
- {
- warn ("%s:%d cxnsleep response to AUTHINFO PASS: %s", peerName,
- cxn->ident, p) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- switch (code)
- {
- case 281:
- notice ("%s:%d authenticated", peerName, cxn->ident) ;
- cxn->authenticated = true ;
- issueModeStream (e,cxn);
- break ;
-
- default:
- warn ("%s:%d cxnsleep response to AUTHINFO PASS: %s", peerName,
- cxn->ident, p) ;
- cxnSleepOrDie (cxn) ;
- break ;
- }
-
- }
- }
-}
-
-
-
-
-\f
-/*
- * Process the remote's response to our MODE STREAM command. This is where
- * the Connection moves into the cxnFeedingS state. If the remote has given
- * us a good welcome banner, but then immediately dropped the connection,
- * we'll arrive here with the MODE STREAM command still queued up.
- */
-static void getModeResponse (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- int code ;
- char *p = bufferBase (b[0]) ;
- Buffer *buffers ;
- const char *peerName ;
-
- ASSERT (e == cxn->myEp) ;
- ASSERT (b [0] == cxn->respBuffer) ;
- ASSERT (b [1] == NULL) ; /* only ever one buffer on this read */
- ASSERT (cxn->state == cxnConnectingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- bufferAddNullByte (b[0]) ;
-
- d_printf (1,"%s:%d Processing mode response: %s", /* no NL */
- hostPeerName (cxn->myHost), cxn->ident, p) ;
-
- if (i == IoDone && writeIsPending (cxn->myEp))
- { /* badness. should never happen */
- warn ("%s:%d cxnsleep mode stream command still pending", peerName,
- cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if (i != IoDone)
- {
- if (i != IoEOF)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't read response", peerName, cxn->ident);
- }
- cxnSleepOrDie (cxn) ;
- }
- else if (strchr (p, '\n') == NULL)
- { /* partial read */
- expandBuffer (b [0], BUFFER_EXPAND_AMOUNT) ;
-
- buffers = makeBufferArray (bufferTakeRef (b [0]), NULL) ;
- if ( !prepareRead (e, buffers, getModeResponse, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
- freeBufferArray (buffers) ;
- cxnSleepOrDie (cxn) ;
- }
- }
- else
- {
- clearTimer (cxn->readBlockedTimerId) ;
-
- if ( !getNntpResponse (p, &code, NULL) )
- {
- warn ("%s:%d cxnsleep response to MODE STREAM: %s", peerName,
- cxn->ident, p) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- if (!cxn->authenticated)
- notice ("%s:%d connected", peerName, cxn->ident) ;
-
- switch (code)
- {
- case 203: /* will do streaming */
- hostRemoteStreams (cxn->myHost, cxn, true) ;
-
- if (hostWantsStreaming (cxn->myHost))
- {
- cxn->doesStreaming = true ;
- cxn->maxCheck = hostMaxChecks (cxn->myHost) ;
- }
- else
- cxn->maxCheck = 1 ;
-
- break ;
-
- default: /* won't do it */
- hostRemoteStreams (cxn->myHost, cxn, false) ;
- cxn->maxCheck = 1 ;
- break ;
- }
-
- /* now we consider ourselves completly connected. */
- cxn->timeCon = theTime () ;
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- else
- cxn->state = cxnFeedingS ;
-
- /* one for the connection and one for the buffer array */
- ASSERT (cxn->authenticated || bufferRefCount (cxn->respBuffer) == 2) ;
-
- /* there was only one line in there, right? */
- bufferSetDataSize (cxn->respBuffer, 0) ;
- buffers = makeBufferArray (bufferTakeRef (cxn->respBuffer), NULL) ;
-
- /* sleepTimeout get changed at each failed attempt, so reset. */
- cxn->sleepTimeout = init_reconnect_period ;
-
- if ( !prepareRead (cxn->myEp, buffers, responseIsRead, cxn, 1) )
- {
- freeBufferArray (buffers) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- /* now we wait for articles from our Host, or we have some
- articles already. On infrequently used connections, the
- network link is torn down and rebuilt as needed. So we may
- be rebuilding the connection here in which case we have an
- article to send. */
- if (writesNeeded (cxn) || hostGimmeArticle (cxn->myHost,cxn))
- doSomeWrites (cxn) ;
- }
- }
- }
-
- freeBufferArray (b) ;
-}
-
-
-
-
-\f
-/*
- * called when a response has been read from the socket. This is
- * where the bulk of the processing starts.
- */
-static void responseIsRead (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- char *response ;
- char *endr ;
- char *bufBase ;
- unsigned int respSize ;
- int code ;
- char *rest = NULL ;
- Buffer buf ;
- Buffer *bArr ;
- const char *peerName ;
-
- ASSERT (e == cxn->myEp) ;
- ASSERT (b != NULL) ;
- ASSERT (b [1] == NULL) ;
- ASSERT (b [0] == cxn->respBuffer) ;
- ASSERT (cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnClosingS ||
- cxn->state == cxnFlushingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- bufferAddNullByte (b [0]) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- if (i != IoDone)
- { /* uh oh. */
- if (i != IoEOF)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't read response", peerName, cxn->ident);
- }
- freeBufferArray (b) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state == cxnClosingS)
- {
- cxnDead (cxn) ;
- delConnection (cxn) ;
- }
- else
- cxnSleep (cxn) ;
-
- return ;
- }
-
- buf = b [0] ;
- bufBase = bufferBase (buf) ;
-
- /* check that we have (at least) a full line response. If not expand
- the buffer and resubmit the read. */
- if (strchr (bufBase, '\n') == 0)
- {
- if (!expandBuffer (buf, BUFFER_EXPAND_AMOUNT))
- {
- warn ("%s:%d cxnsleep can't expand input buffer", peerName,
- cxn->ident) ;
- freeBufferArray (b) ;
-
- cxnSleepOrDie (cxn) ;
- }
- else if ( !prepareRead (cxn->myEp, b, responseIsRead, cxn, 1))
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
- freeBufferArray (b) ;
-
- cxnSleepOrDie (cxn) ;
- }
-
- return ;
- }
-
-
- freeBufferArray (b) ; /* connection still has reference to buffer */
-
-
- /*
- * Now process all the full responses that we have.
- */
- response = bufBase ;
- respSize = bufferDataSize (cxn->respBuffer) ;
-
- while ((endr = strchr (response, '\n')) != NULL)
- {
- char *next = endr + 1 ;
-
- if (*next == '\r')
- next++ ;
-
- endr-- ;
- if (*endr != '\r')
- endr++ ;
-
- if (next - endr != 2 && !cxn->loggedNoCr)
- {
- /* only a newline there. we'll live with it */
- warn ("%s:%d remote not giving out CR characters", peerName,
- cxn->ident) ;
- cxn->loggedNoCr = true ;
- }
-
- *endr = '\0' ;
-
- if ( !getNntpResponse (response, &code, &rest) )
- {
- warn ("%s:%d cxnsleep response format: %s", peerName, cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
-
- return ;
- }
-
- d_printf (5,"%s:%d Response %d: %s\n", peerName, cxn->ident, code, response) ;
-
- /* now handle the response code. I'm not using symbolic names on
- purpose--the numbers are all you see in the RFC's. */
- switch (code)
- {
- case 205: /* OK response to QUIT. */
- processResponse205 (cxn, response) ;
- break ;
-
-
-
- /* These three are from the CHECK command */
- case 238: /* no such article found */
- /* Do not incrFilter (cxn) now, wait till after
- subsequent TAKETHIS */
- processResponse238 (cxn, response) ;
- break ;
-
- case 431: /* try again later (also for TAKETHIS) */
- decrFilter (cxn) ;
- if (hostDropDeferred (cxn->myHost))
- processResponse438 (cxn, response) ;
- else
- processResponse431 (cxn, response) ;
- break ;
-
- case 438: /* already have it */
- decrFilter (cxn) ;
- processResponse438 (cxn, response) ;
- break ;
-
-
-
- /* These are from the TAKETHIS command */
- case 239: /* article transferred OK */
- incrFilter (cxn) ;
- processResponse239 (cxn, response) ;
- break ;
-
- case 439: /* article rejected */
- decrFilter (cxn) ;
- processResponse439 (cxn, response) ;
- break ;
-
-
-
- /* These are from the IHAVE command */
- case 335: /* send article */
- processResponse335 (cxn, response) ;
- break ;
-
- case 435: /* article not wanted */
- processResponse435 (cxn, response) ;
- break ;
-
- case 436: /* transfer failed try again later */
- if (cxn->takeRespHead == NULL && hostDropDeferred (cxn->myHost))
- processResponse435 (cxn, response) ;
- else
- processResponse436 (cxn, response) ;
- break ;
-
- case 437: /* article rejected */
- processResponse437 (cxn, response) ;
- break ;
-
- case 400: /* has stopped accepting articles */
- processResponse400 (cxn, response) ;
- break ;
-
-
-
- case 235: /* article transfered OK (IHAVE-body) */
- processResponse235 (cxn, response) ;
- break ;
-
-
- case 480: /* Transfer permission denied. */
- processResponse480 (cxn,response) ;
- break ;
-
- case 503: /* remote timeout. */
- processResponse503 (cxn,response) ;
- break ;
-
- default:
- warn ("%s:%d cxnsleep response unknown: %d %s", peerName,
- cxn->ident, code, response) ;
- cxnSleepOrDie (cxn) ;
- break ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- if (cxn->state != cxnFeedingS && cxn->state != cxnClosingS &&
- cxn->state != cxnFlushingS && cxn->state != cxnIdleS /* XXX */)
- break ; /* connection is terminated */
-
- response = next ;
- }
-
- d_printf (5,"%s:%d done with responses\n",hostPeerName (cxn->myHost),
- cxn->ident) ;
-
- switch (cxn->state)
- {
- case cxnIdleS:
- case cxnFeedingS:
- case cxnClosingS:
- case cxnFlushingS:
- /* see if we need to drop in to or out of no-CHECK mode */
- if (cxn->state == cxnFeedingS && cxn->doesStreaming)
- {
- if ((cxn->filterValue > cxn->onThreshold) && cxn->needsChecks) {
- cxn->needsChecks = false;
- hostLogNoCheckMode (cxn->myHost, true,
- cxn->offThreshold/cxn->lowPassFilter,
- cxn->filterValue/cxn->lowPassFilter,
- cxn->onThreshold/cxn->lowPassFilter) ;
- /* on and log */
- } else if ((cxn->filterValue < cxn->offThreshold) &&
- !cxn->needsChecks) {
- cxn->needsChecks = true;
- hostLogNoCheckMode (cxn->myHost, false,
- cxn->offThreshold/cxn->lowPassFilter,
- cxn->filterValue/cxn->lowPassFilter,
- cxn->onThreshold/cxn->lowPassFilter) ;
- /* off and log */
- }
- }
-
- /* Now handle possible remaining partial reponse and set up for
- next read. */
- if (*response != '\0')
- { /* partial response */
- unsigned int leftAmt = respSize - (response - bufBase) ;
-
- d_printf (2,"%s:%d handling a partial response\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- /* first we shift what's left in the buffer down to the
- bottom, if needed, or just expand the buffer */
- if (response != bufBase)
- {
- /* so next read appends */
- memmove (bufBase, response, leftAmt) ;
- bufferSetDataSize (cxn->respBuffer, leftAmt) ;
- }
- else if (!expandBuffer (cxn->respBuffer, BUFFER_EXPAND_AMOUNT))
- die ("%s:%d cxnsleep can't expand input buffer", peerName,
- cxn->ident) ;
- }
- else
- bufferSetDataSize (cxn->respBuffer, 0) ;
-
- bArr = makeBufferArray (bufferTakeRef (cxn->respBuffer), NULL) ;
-
- if ( !prepareRead (e, bArr, responseIsRead, cxn, 1) )
- {
- warn ("%s:%d cxnsleep prepare read failed", peerName, cxn->ident) ;
- freeBufferArray (bArr) ;
- cxnWait (cxn) ;
- return ;
- }
- else
- {
- /* only setup the timer if we're still waiting for a response
- to something. There's not necessarily a 1-to-1 mapping
- between reads and writes in streaming mode. May have been
- set already above (that would be unlikely I think). */
- VALIDATE_CONNECTION (cxn) ;
-
- d_printf (5,"%s:%d about to do some writes\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- doSomeWrites (cxn) ;
-
- /* If the read timer is (still) running, update it to give
- those terminally slow hosts that take forever to drain
- the network buffers and just dribble out responses the
- benefit of the doubt. XXX - maybe should just increase
- timeout for these! */
- if (cxn->readBlockedTimerId)
- cxn->readBlockedTimerId = updateSleep (cxn->readBlockedTimerId,
- responseTimeoutCbk,
- cxn->readTimeout,
- cxn) ;
- }
- VALIDATE_CONNECTION (cxn) ;
- break ;
-
- case cxnWaitingS: /* presumably after a code 205 or 400 */
- case cxnConnectingS: /* presumably after a code 205 or 400 */
- case cxnSleepingS: /* probably after a 480 */
- break ;
-
- case cxnDeadS:
- delConnection (cxn) ;
- break ;
-
- case cxnStartingS:
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-}
-
-
-
-
-\f
-/*
- * called when the write of the QUIT command has completed.
- */
-static void quitWritten (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- const char *peerName ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- ASSERT (cxn->myEp == e) ;
- VALIDATE_CONNECTION (cxn) ;
-
- if (i != IoDone)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't write QUIT", peerName, cxn->ident) ;
- if (cxn->state == cxnClosingS)
- {
- cxnDead (cxn) ;
- delConnection (cxn) ;
- }
- else
- cxnWait (cxn) ;
- }
- else
- /* The QUIT command has been sent, so start the response timer. */
- initReadBlockedTimeout (cxn) ;
-
- freeBufferArray (b) ;
-}
-
-
-
-
-\f
-/*
- * called when the write of the IHAVE-body data is finished
- */
-static void ihaveBodyDone (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
-
- ASSERT (e == cxn->myEp) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- if (i != IoDone)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't write IHAVE body",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state == cxnClosingS)
- {
- cxnDead (cxn) ;
- delConnection (cxn) ;
- }
- else
- cxnSleep (cxn) ;
- }
- else
- /* The article has been sent, so start the response timer. */
- initReadBlockedTimeout (cxn) ;
-
-
- freeBufferArray (b) ;
-
- return ;
-}
-
-
-
-
-\f
-/*
- * Called when a command set (IHAVE, CHECK, TAKETHIS) has been
- * written to the remote.
- */
-static void commandWriteDone (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
- const char *peerName ;
-
- ASSERT (e == cxn->myEp) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- freeBufferArray (b) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- if (i != IoDone)
- {
- errno = endPointErrno (e) ;
- syswarn ("%s:%d cxnsleep can't write command", peerName, cxn->ident) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state == cxnClosingS)
- {
- cxnDead (cxn) ;
- delConnection (cxn) ;
- }
- else
- {
- /* XXX - so cxnSleep() doesn't die in VALIDATE_CONNECTION () */
- deferAllArticles (cxn) ;
- cxnIdle (cxn) ;
-
- cxnSleep (cxn) ;
- }
- }
- else
- {
- /* Some(?) hosts return the 439 response even before we're done
- sending, so don't go idle until here */
- if (cxn->state == cxnFeedingS && cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- else
- /* The command set has been sent, so start the response timer.
- XXX - we'd like finer grained control */
- initReadBlockedTimeout (cxn) ;
-
- if ( cxn->doesStreaming )
- doSomeWrites (cxn) ; /* pump data as fast as possible */
- /* XXX - will clear the read timeout */
- }
-}
-
-
-
-
-\f
-/*
- * Called when the MODE STREAM command has been written down the pipe.
- */
-static void modeCmdIssued (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
-
- ASSERT (e == cxn->myEp) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- /* The mode command has been sent, so start the response timer */
- initReadBlockedTimeout (cxn) ;
-
- if (i != IoDone)
- {
- d_printf (1,"%s:%d MODE STREAM command failed to write\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- syswarn ("%s:%d cxnsleep can't write MODE STREAM",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
-
- freeBufferArray (b) ;
-}
-
-
-
-
-\f
-/*
- * Called when the AUTHINFO USER command has been written down the pipe.
- */
-static void authUserIssued (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
-
- ASSERT (e == cxn->myEp) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- /* The authinfo user command has been sent, so start the response timer */
- initReadBlockedTimeout (cxn) ;
-
- if (i != IoDone)
- {
- d_printf (1,"%s:%d AUTHINFO USER command failed to write\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- syswarn ("%s:%d cxnsleep can't write AUTHINFO USER",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
-
- freeBufferArray (b) ;
-}
-
-
-
-
-
-\f
-/*
- * Called when the AUTHINFO USER command has been written down the pipe.
- */
-static void authPassIssued (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- Connection cxn = (Connection) d ;
-
- ASSERT (e == cxn->myEp) ;
-
- clearTimer (cxn->writeBlockedTimerId) ;
-
- /* The authinfo pass command has been sent, so start the response timer */
- initReadBlockedTimeout (cxn) ;
-
- if (i != IoDone)
- {
- d_printf (1,"%s:%d AUTHINFO PASS command failed to write\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- syswarn ("%s:%d cxnsleep can't write AUTHINFO PASS",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnSleepOrDie (cxn) ;
- }
-
- freeBufferArray (b) ;
-}
-
-
-
-
-
-\f
-/*
- * Called whenever some amount of data has been written to the pipe but
- * more data remains to be written
- */
-static void writeProgress (EndPoint e UNUSED, IoStatus i, Buffer *b UNUSED,
- void *d)
-{
- Connection cxn = (Connection) d ;
-
- ASSERT (i == IoProgress) ;
-
- if (cxn->writeTimeout > 0)
- cxn->writeBlockedTimerId = updateSleep (cxn->writeBlockedTimerId,
- writeTimeoutCbk, cxn->writeTimeout,
- cxn) ;
-}
-
-
-
-
-\f
-/*
- * Timers.
- */
-
-/*
- * This is called when the timeout for the reponse from the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void responseTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
- const char *peerName ;
-
- ASSERT (id == cxn->readBlockedTimerId) ;
- ASSERT (cxn->state == cxnConnectingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnClosingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- /* XXX - let abortConnection clear readBlockedTimerId, otherwise
- VALIDATE_CONNECTION() will croak */
-
- peerName = hostPeerName (cxn->myHost) ;
-
- warn ("%s:%d cxnsleep non-responsive connection", peerName, cxn->ident) ;
- d_printf (1,"%s:%d shutting down non-repsonsive connection\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state == cxnClosingS)
- {
- abortConnection (cxn) ;
- delConnection (cxn) ;
- }
- else
- cxnSleep (cxn) ; /* will notify the Host */
-}
-
-
-
-
-\f
-/*
- * This is called when the data write timeout for the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void writeTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
- const char *peerName ;
-
- ASSERT (id == cxn->writeBlockedTimerId) ;
- ASSERT (cxn->state == cxnConnectingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnClosingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- /* XXX - let abortConnection clear writeBlockedTimerId, otherwise
- VALIDATE_CONNECTION() will croak */
-
- peerName = hostPeerName (cxn->myHost) ;
-
- warn ("%s:%d cxnsleep write timeout", peerName, cxn->ident) ;
- d_printf (1,"%s:%d shutting down non-responsive connection\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state == cxnClosingS)
- {
- abortConnection (cxn) ;
- delConnection (cxn) ;
- }
- else
- cxnSleep (cxn) ; /* will notify the Host */
-}
-
-
-
-
-\f
-/*
- * Called by the EndPoint class when the timer goes off
- */
-void reopenTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
-
- ASSERT (id == cxn->sleepTimerId) ;
-
- cxn->sleepTimerId = 0 ;
-
- if (cxn->state != cxnSleepingS)
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- }
- else
- cxnConnect (cxn) ;
-}
-
-
-
-
-\f
-/*
- * timeout callback to close down long running connection.
- */
-static void flushCxnCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
-
- ASSERT (id == cxn->flushTimerId) ;
- VALIDATE_CONNECTION (cxn) ;
-
- cxn->flushTimerId = 0 ;
-
- if (!(cxn->state == cxnFeedingS || cxn->state == cxnConnectingS ||
- cxn->state == cxnIdleS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- d_printf (1,"%s:%d Handling periodic connection close.\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- notice ("%s:%d periodic close", hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxnFlush (cxn) ;
- }
-}
-
-
-
-
-\f
-/*
- * Timer callback for when the connection has not received an
- * article from INN. When that happens we tear down the network
- * connection to help recycle fds
- */
-static void articleTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
- const char *peerName = hostPeerName (cxn->myHost) ;
-
- ASSERT (cxn->artReceiptTimerId == id) ;
- VALIDATE_CONNECTION (cxn) ;
-
- cxn->artReceiptTimerId = 0 ;
-
- if (cxn->state != cxnIdleS)
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
-
- return ;
- }
-
- /* it's doubtful (right?) that this timer could go off and there'd
- still be articles in the queue. */
- if (cxn->articleQTotal > 0)
- {
- warn ("%s:%d idle connection still has articles", peerName, cxn->ident) ;
- }
- else
- {
- notice ("%s:%d idle tearing down connection", peerName, cxn->ident) ;
- cxn->state = cxnIdleTimeoutS ;
- cxnFlush (cxn) ;
- }
-}
-
-
-
-
-\f
-/*
- * function to be called when the fd is not ready for reading, but there is
- * an article on tape or in the queue to be done. Things are done this way
- * so that a Connection doesn't hog time trying to find the next good
- * article for writing. With a large backlog of expired articles that would
- * take a long time. Instead the Connection just tries its next article on
- * tape or queue, and if that's no good then it registers this callback so
- * that other Connections have a chance of being serviced.
- */
-static void cxnWorkProc (EndPoint ep UNUSED, void *data)
-{
- Connection cxn = (Connection) data ;
-
- d_printf (2,"%s:%d calling work proc\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- if (writesNeeded (cxn))
- doSomeWrites (cxn) ; /* may re-register the work proc... */
- else if (cxn->state == cxnFlushingS || cxn->state == cxnClosingS)
- {
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ;
- }
- else
- d_printf (2,"%s:%d no writes were needed....\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-}
-
-
-
-/****************************************************************************
- *
- * END EndPoint callback area.
- *
- ****************************************************************************/
-
-
-
-
-\f
-/****************************************************************************
- *
- * REPONSE CODE PROCESSING.
- *
- ***************************************************************************/
-
-
-/*
- * A connection needs to sleep, but if it's closing it needs to die instead.
- */
-static void cxnSleepOrDie (Connection cxn)
-{
- if (cxn->state == cxnClosingS)
- cxnDead (cxn) ;
- else
- cxnSleep (cxn) ;
-}
-
-
-/*
- * Handle the response 205 to our QUIT command, which means the
- * remote is going away and we can happily cleanup
- */
-static void processResponse205 (Connection cxn, char *response UNUSED)
-{
- bool immedRecon ;
-
- VALIDATE_CONNECTION (cxn) ;
-
- if (!(cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- switch (cxn->state)
- {
- case cxnFlushingS:
- case cxnClosingS:
- ASSERT (cxn->articleQTotal == 0) ;
-
- cxnLogStats (cxn,true) ;
-
- immedRecon = cxn->immedRecon ;
-
- hostCxnDead (cxn->myHost,cxn) ;
-
- if (cxn->state == cxnFlushingS && immedRecon)
- {
- abortConnection (cxn) ;
- if (!cxnConnect (cxn))
- notice ("%s:%d flush re-connect failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
- else if (cxn->state == cxnFlushingS)
- cxnWait (cxn) ;
- else
- cxnDead (cxn) ;
- break ;
-
- case cxnIdleS:
- case cxnFeedingS:
- /* this shouldn't ever happen... */
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost), cxn->ident, 205) ;
- cxnSleepOrDie (cxn) ;
- break ;
-
- default:
- die ("Bad connection state: %s\n",stateToString (cxn->state)) ;
- }
-}
-
-
-
-
-\f
-/*
- * Handle a response code of 238 which is the "no such article"
- * reply to the CHECK command (i.e. remote wants it).
- */
-static void processResponse238 (Connection cxn, char *response)
-{
- char *msgid ;
- ArtHolder artHolder ;
-
- if (!cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected streaming response for non-streaming"
- " connection: %s", hostPeerName (cxn->myHost), cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- msgid = getMsgId (response) ;
-
- if (cxn->checkRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,238) ;
- cxnSleepOrDie (cxn) ;
- }
- else if (msgid == NULL || strlen (msgid) == 0 ||
- (artHolder = artHolderByMsgId (msgid, cxn->checkRespHead)) == NULL)
- noSuchMessageId (cxn,238,msgid,response) ;
- else
- {
- /* now remove the article from the check queue and move it onto the
- transmit queue. Another function wil take care of transmitting */
- remArtHolder (artHolder, &cxn->checkRespHead, &cxn->articleQTotal) ;
- if (cxn->state != cxnClosingS)
- appendArtHolder (artHolder, &cxn->takeHead, &cxn->articleQTotal) ;
- else
- {
- hostTakeBackArticle (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
- }
- }
-
- if (msgid != NULL)
- free (msgid) ;
-}
-
-
-
-
-\f
-/*
- * process the response "try again later" to the CHECK command If this
- * returns true then the connection is still usable.
- */
-static void processResponse431 (Connection cxn, char *response)
-{
- char *msgid ;
- ArtHolder artHolder ;
-
- if (!cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected streaming response for non-streaming"
- " connection: %s", hostPeerName (cxn->myHost), cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- msgid = getMsgId (response) ;
-
- if (cxn->checkRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,431) ;
- cxnSleepOrDie (cxn) ;
- }
- else if (msgid == NULL || strlen (msgid) == 0 ||
- (artHolder = artHolderByMsgId (msgid, cxn->checkRespHead)) == NULL)
- noSuchMessageId (cxn,431,msgid,response) ;
- else
- {
- remArtHolder (artHolder, &cxn->checkRespHead, &cxn->articleQTotal) ;
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- hostArticleDeferred (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
- }
-
- if (msgid != NULL)
- free (msgid) ;
-}
-
-
-
-
-\f
-/*
- * process the "already have it" response to the CHECK command. If this
- * returns true then the connection is still usable.
- */
-static void processResponse438 (Connection cxn, char *response)
-{
- char *msgid ;
- ArtHolder artHolder ;
-
- if (!cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected streaming response for non-streaming"
- " connection: %s", hostPeerName (cxn->myHost), cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- msgid = getMsgId (response) ;
-
- if (cxn->checkRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,438) ;
- cxnSleepOrDie (cxn) ;
- }
- else if (msgid == NULL || strlen (msgid) == 0 ||
- (artHolder = artHolderByMsgId (msgid, cxn->checkRespHead)) == NULL)
- noSuchMessageId (cxn,438,msgid,response) ;
- else
- {
- cxn->checksRefused++ ;
-
- remArtHolder (artHolder, &cxn->checkRespHead, &cxn->articleQTotal) ;
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- hostArticleNotWanted (cxn->myHost, cxn, artHolder->article);
- delArtHolder (artHolder) ;
- }
-
- if (msgid != NULL)
- free (msgid) ;
-}
-
-
-
-
-\f
-/*
- * process the "article transferred ok" response to the TAKETHIS.
- */
-static void processResponse239 (Connection cxn, char *response)
-{
- char *msgid ;
- ArtHolder artHolder ;
-
- if (!cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected streaming response for non-streaming"
- " connection: %s", hostPeerName (cxn->myHost), cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- msgid = getMsgId (response) ;
-
- if (cxn->takeRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,239) ;
- cxnSleepOrDie (cxn) ;
- }
- else if (msgid == NULL || strlen (msgid) == 0 ||
- (artHolder = artHolderByMsgId (msgid, cxn->takeRespHead)) == NULL)
- noSuchMessageId (cxn,239,msgid,response) ;
- else
- {
- cxn->takesOkayed++ ;
- cxn->takesSizeOkayed += artSize(artHolder->article);
-
- remArtHolder (artHolder, &cxn->takeRespHead, &cxn->articleQTotal) ;
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- hostArticleAccepted (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
- }
-
- if (msgid != NULL)
- free (msgid) ;
-}
-
-
-\f
-/*
- * Set the thresholds for no-CHECK mode; negative means leave existing value
- */
-
-void cxnSetCheckThresholds (Connection cxn,
- double lowFilter, double highFilter,
- double lowPassFilter)
-{
- /* Adjust current value for new scaling */
- if (cxn->lowPassFilter > 0.0)
- cxn->filterValue = cxn->filterValue / cxn->lowPassFilter * lowPassFilter;
-
- /* Stick in new values */
- if (highFilter >= 0)
- cxn->onThreshold = highFilter * lowPassFilter / 100.0;
- if (lowFilter >= 0)
- cxn->offThreshold = lowFilter * lowPassFilter / 100.0;
- cxn->lowPassFilter = lowPassFilter;
-}
-
-\f
-/*
- * Blow away the connection gracelessly and immedately clean up
- */
-void cxnNuke (Connection cxn)
-{
- abortConnection (cxn) ;
- hostCxnDead (cxn->myHost,cxn) ;
- delConnection(cxn) ;
-}
-
-\f
-/*
- * process a "article rejected do not try again" response to the
- * TAKETHIS.
- */
-static void processResponse439 (Connection cxn, char *response)
-{
- char *msgid ;
- ArtHolder artHolder ;
-
- if (!cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected streaming response for non-streaming"
- " connection: %s", hostPeerName (cxn->myHost), cxn->ident,
- response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- msgid = getMsgId (response) ;
-
- if (cxn->takeRespHead == NULL) /* peer is confused */
- {
- /* NNTPRelay return 439 for check <messid> if messid is bad */
- if (cxn->checkRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,439) ;
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- if ((artHolder = artHolderByMsgId (msgid, cxn->checkRespHead)) == NULL)
- noSuchMessageId (cxn,439,msgid,response) ;
- else
- {
- cxn->checksRefused++ ;
- remArtHolder (artHolder, &cxn->checkRespHead, &cxn->articleQTotal) ;
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- hostArticleNotWanted (cxn->myHost, cxn, artHolder->article);
- delArtHolder (artHolder) ;
- }
- }
- }
- else if (msgid == NULL || strlen (msgid) == 0 ||
- (artHolder = artHolderByMsgId (msgid, cxn->takeRespHead)) == NULL)
- noSuchMessageId (cxn,439,msgid,response) ;
- else
- {
- cxn->takesRejected++ ;
- cxn->takesSizeRejected += artSize(artHolder->article);
-
- remArtHolder (artHolder, &cxn->takeRespHead, &cxn->articleQTotal) ;
- /* Some(?) hosts return the 439 response even before we're done
- sending */
- if (cxn->articleQTotal == 0 && !writeIsPending(cxn->myEp))
- cxnIdle (cxn) ;
- hostArticleRejected (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
- }
-
- if (msgid != NULL)
- free (msgid) ;
-}
-
-
-
-
-
-\f
-/*
- * process the "article transferred ok" response to the IHAVE-body.
- */
-static void processResponse235 (Connection cxn, char *response UNUSED)
-{
- ArtHolder artHolder ;
-
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- ASSERT (cxn->articleQTotal == 1) ;
- ASSERT (cxn->takeRespHead != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- if (cxn->takeRespHead == NULL) /* peer is confused */
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,235) ;
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- /* now remove the article from the queue and tell the Host to forget
- about it. */
- artHolder = cxn->takeRespHead ;
-
- cxn->takeRespHead = NULL ;
- cxn->articleQTotal = 0 ;
- cxn->takesOkayed++ ;
- cxn->takesSizeOkayed += artSize(artHolder->article);
-
- if (cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
-
- hostArticleAccepted (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
- }
-}
-
-
-
-
-\f
-/*
- * process the "send article to be transfered" reponse to the IHAVE.
- */
-static void processResponse335 (Connection cxn, char *response UNUSED)
-{
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (cxn->checkRespHead == NULL)
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost),cxn->ident,335) ;
- cxnSleepOrDie (cxn) ;
- }
- else
- {
- VALIDATE_CONNECTION (cxn) ;
- /* now move the article into the third queue */
- cxn->takeHead = cxn->checkRespHead ;
- cxn->checkRespHead = NULL ;
-
- issueIHAVEBody (cxn) ;
- }
-}
-
-
-
-
-\f
-/*
- * process the "not accepting articles" response. This could be to any of
- * the IHAVE/CHECK/TAKETHIS command, but not the banner--that's handled
- * elsewhere.
- */
-static void processResponse400 (Connection cxn, char *response)
-{
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- /* We may get a response 400 multiple times when in streaming mode. */
- notice ("%s:%d remote cannot accept articles: %s",
- hostPeerName(cxn->myHost), cxn->ident, response) ;
-
- /* right here there may still be data queued to write and so we'll fail
- trying to issue the quit ('cause a write will be pending). Furthermore,
- the data pending may be half way through an command, and so just
- tossing the buffer is nt sufficient. But figuring out where we are and
- doing a tidy job is hard */
- if (writeIsPending (cxn->myEp))
- cxnSleepOrDie (cxn) ;
- else
- {
- if (cxn->articleQTotal > 0)
- {
- /* Defer the articles here so that cxnFlush() doesn't set up an
- immediate reconnect. */
- deferAllArticles (cxn) ;
- clearTimer (cxn->readBlockedTimerId) ;
- /* XXX - so cxnSleep() doesn't die when it validates the connection */
- cxnIdle (cxn) ;
- }
- /* XXX - it would be nice if we QUIT first, but we'd have to go
- into a state where we just search for the 205 response, and
- only go into the sleep state at that point */
- cxnSleepOrDie (cxn) ;
- }
-}
-
-
-
-
-\f
-/*
- * process the "not wanted" reponse to the IHAVE.
- */
-static void processResponse435 (Connection cxn, char *response UNUSED)
-{
- ArtHolder artHolder ;
-
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- /* Some servers, such as early versions of Diablo, had a bug where they'd
- respond with a 435 code (which should only be used for refusing an
- article before it was offered) after an article has been sent. */
- if (cxn->checkRespHead == NULL)
- {
- warn ("%s:%d cxnsleep response unexpected: %d",
- hostPeerName (cxn->myHost), cxn->ident, 435) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- ASSERT (cxn->articleQTotal == 1) ;
- VALIDATE_CONNECTION (cxn) ;
-
- cxn->articleQTotal-- ;
- cxn->checksRefused++ ;
-
- artHolder = cxn->checkRespHead ;
- cxn->checkRespHead = NULL ;
-
- if (cxn->articleQTotal == 0 && !writeIsPending(cxn->myEp))
- cxnIdle (cxn) ;
-
- hostArticleNotWanted (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
-
-#if 0
- d_printf (1,"%s:%d On exiting 435 article queue total is %d (%d %d %d %d)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->articleQTotal,
- (int) (cxn->checkHead != NULL),
- (int) (cxn->checkRespHead != NULL),
- (int) (cxn->takeHead != NULL),
- (int) (cxn->takeRespHead != NULL));
-#endif
-}
-
-
-
-
-\f
-/*
- * process the "transfer failed" response to the IHAVE-body, (seems this
- * can come from the IHAVE too).
- */
-static void processResponse436 (Connection cxn, char *response UNUSED)
-{
- ArtHolder artHolder ;
-
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- ASSERT (cxn->articleQTotal == 1) ;
- ASSERT (cxn->takeRespHead != NULL || cxn->checkRespHead != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- cxn->articleQTotal-- ;
-
- if (cxn->takeRespHead != NULL) /* IHAVE-body command barfed */
- {
- artHolder = cxn->takeRespHead ;
- cxn->takeRespHead = NULL ;
- }
- else /* IHAVE command barfed */
- {
- artHolder = cxn->checkRespHead ;
- cxn->checkRespHead = NULL ;
- }
-
- if (cxn->articleQTotal == 0 && !writeIsPending(cxn->myEp))
- cxnIdle (cxn) ;
-
- hostArticleDeferred (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
-}
-
-
-
-
-\f
-/*
- * Process the "article rejected do not try again" response to the
- * IHAVE-body.
- */
-static void processResponse437 (Connection cxn, char *response UNUSED)
-{
- ArtHolder artHolder ;
-
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- ASSERT (cxn->articleQTotal == 1) ;
- ASSERT (cxn->takeRespHead != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- cxn->articleQTotal-- ;
- cxn->takesRejected++ ;
-
- artHolder = cxn->takeRespHead ;
- cxn->takeRespHead = NULL ;
- cxn->takesSizeRejected += artSize(artHolder->article);
-
- /* Some servers return the 437 response before we're done sending. */
- if (cxn->articleQTotal == 0 && !writeIsPending (cxn->myEp))
- cxnIdle (cxn) ;
-
- hostArticleRejected (cxn->myHost, cxn, artHolder->article) ;
- delArtHolder (artHolder) ;
-}
-
-
-/* Process the response 480 Transfer permission defined. We're probably
- talking to a remote nnrpd on a system that forgot to put us in
- the hosts.nntp */
-static void processResponse480 (Connection cxn, char *response UNUSED)
-{
- if (cxn->doesStreaming)
- {
- warn ("%s:%d cxnsleep unexpected non-streaming response for"
- " streaming connection: %s", hostPeerName (cxn->myHost),
- cxn->ident,response) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (!(cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- VALIDATE_CONNECTION (cxn) ;
-
- warn ("%s:%d cxnsleep transfer permission denied",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- if (cxn->state == cxnClosingS)
- cxnDead (cxn) ;
- else
- cxnSleep (cxn) ;
-}
-
-
-
-
-\f
-/*
- * Handle the response 503, which means the timeout of nnrpd.
- */
-static void processResponse503 (Connection cxn, char *response UNUSED)
-{
- bool immedRecon ;
-
- VALIDATE_CONNECTION (cxn) ;
-
- if (!(cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnClosingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- if (cxn->articleQTotal != 0)
- notice ("%s:%d flush re-connect failed", hostPeerName (cxn->myHost),
- cxn->ident) ;
-
- cxnLogStats (cxn,true) ;
-
- immedRecon = cxn->immedRecon ;
-
- hostCxnDead (cxn->myHost,cxn) ;
-
- if (cxn->state == cxnFlushingS && immedRecon)
- {
- abortConnection (cxn) ;
- if (!cxnConnect (cxn))
- notice ("%s:%d flush re-connect failed", hostPeerName (cxn->myHost),
- cxn->ident) ;
- }
- else if (cxn->state == cxnFlushingS)
- cxnWait (cxn) ;
- else
- cxnDead (cxn) ;
-
-}
-
-
-
-
-\f
-/****************************************************************************
- *
- * END REPONSE CODE PROCESSING.
- *
- ***************************************************************************/
-
-
-
-
-\f
-/*
- * puts the Connection into the sleep state.
- */
-static void cxnSleep (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state == cxnFlushingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnConnectingS) ;
- VALIDATE_CONNECTION (cxn) ;
-
- abortConnection (cxn) ;
-
- prepareReopenCbk (cxn) ; /* XXX - we don't want to reopen if idle */
- cxn->state = cxnSleepingS ;
-
- /* tell our Host we're asleep so it doesn't try to give us articles */
- hostCxnSleeping (cxn->myHost,cxn) ;
-}
-
-
-
-static void cxnDead (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- abortConnection (cxn) ;
- cxn->state = cxnDeadS ;
-}
-
-
-
-/*
- * Sets the idle timer. If no articles arrive before the timer expires, the
- * connection will be closed.
- */
-static void cxnIdle (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->state == cxnFeedingS || cxn->state == cxnConnectingS ||
- cxn->state == cxnFlushingS || cxn->state == cxnClosingS) ;
- ASSERT (cxn->articleQTotal == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (!writeIsPending (cxn->myEp)) ;
- ASSERT (cxn->sleepTimerId == 0) ;
-
- if (cxn->state == cxnFeedingS || cxn->state == cxnConnectingS)
- {
- if (cxn->articleReceiptTimeout > 0)
- {
- clearTimer (cxn->artReceiptTimerId) ;
- cxn->artReceiptTimerId = prepareSleep (articleTimeoutCbk,
- cxn->articleReceiptTimeout,
- cxn) ;
- }
-
- if (cxn->readTimeout > 0 && cxn->state == cxnFeedingS)
- clearTimer (cxn->readBlockedTimerId) ;
-
- cxn->state = cxnIdleS ;
-ASSERT (cxn->readBlockedTimerId == 0) ;
- }
-}
-
-
-
-
-\f
-/*
- * Called when a response from the remote refers to a non-existant
- * message-id. The network connection is aborted and the Connection
- * object goes into sleep mode.
- */
-static void noSuchMessageId (Connection cxn, unsigned int responseCode,
- const char *msgid, const char *response)
-{
- const char *peerName = hostPeerName (cxn->myHost) ;
-
- if (msgid == NULL || strlen (msgid) == 0)
- warn ("%s:%d cxnsleep message-id missing in reponse code %d: %s",
- peerName, cxn->ident, responseCode, response) ;
- else
- warn ("%s:%d cxnsleep message-id invalid message-id in reponse code"
- " %d: %s", peerName, cxn->ident, responseCode, msgid) ;
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->state != cxnClosingS)
- cxnSleep (cxn) ;
- else
- cxnDead (cxn) ;
-}
-
-
-
-
-\f
-/*
- * a processing error has occured (for example in parsing a response), or
- * we're at the end of the FSM and we're cleaning up.
- */
-static void abortConnection (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- /* cxn->myEp could be NULL if we get here during cxnConnect (via
- cxnWait()) */
- if (cxn->myEp != NULL)
- {
-
- delEndPoint (cxn->myEp) ;
- cxn->myEp = NULL ;
- }
-
- clearTimer (cxn->sleepTimerId) ;
- clearTimer (cxn->artReceiptTimerId) ;
- clearTimer (cxn->readBlockedTimerId) ;
- clearTimer (cxn->writeBlockedTimerId) ;
- clearTimer (cxn->flushTimerId) ;
-
- deferAllArticles (cxn) ; /* give any articles back to Host */
-
- bufferSetDataSize (cxn->respBuffer,0) ;
-
- resetConnection (cxn) ;
-
- if (cxn->state == cxnFeedingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnClosingS)
- hostCxnDead (cxn->myHost,cxn) ;
-}
-
-
-
-
-/*
- * Set up the callback used when the Connection is sleeping (i.e. will try
- * to reopen the connection).
- */
-static void prepareReopenCbk (Connection cxn)
-{
- ASSERT (cxn->sleepTimerId == 0) ;
-
- if (!(cxn->state == cxnConnectingS ||
- cxn->state == cxnIdleS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnFlushingS ||
- cxn->state == cxnStartingS))
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- stateToString (cxn->state)) ;
- cxnSleepOrDie (cxn) ;
- return ;
- }
-
- d_printf (1,"%s:%d Setting up a reopen callback\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- cxn->sleepTimerId = prepareSleep (reopenTimeoutCbk, cxn->sleepTimeout, cxn) ;
-
- /* bump the sleep timer amount each time to wait longer and longer. Gets
- reset in resetConnection() */
- cxn->sleepTimeout *= 2 ;
- if (cxn->sleepTimeout > max_reconnect_period)
- cxn->sleepTimeout = max_reconnect_period ;
-}
-
-
-
-
-\f
-/*
- * (re)set all state variables to inital condition.
- */
-static void resetConnection (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
-
- bufferSetDataSize (cxn->respBuffer,0) ;
-
- cxn->loggedNoCr = false ;
- cxn->maxCheck = 1 ;
- cxn->immedRecon = false ;
- cxn->doesStreaming = false ; /* who knows, next time around maybe... */
- cxn->authenticated = false ;
- cxn->quitWasIssued = false ;
- cxn->needsChecks = true ;
- cxn->timeCon = 0 ;
-
- cxn->artsTaken = 0 ;
- cxn->checksIssued = 0 ;
- cxn->checksRefused = 0 ;
- cxn->takesRejected = 0 ;
- cxn->takesOkayed = 0 ;
- cxn->takesSizeRejected = 0 ;
- cxn->takesSizeOkayed = 0 ;
-
- cxn->filterValue = 0.0 ;
-}
-
-
-\f
-/*
- * Give back all articles that are queued, but not actually in progress.
- * XXX merge come of this with deferAllArticles
- */
-static void deferQueuedArticles (Connection cxn)
-{
- ArtHolder p, q ;
-
- for (q = NULL, p = cxn->checkHead ; p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->checkHead = NULL ;
-
- for (q = NULL, p = cxn->takeHead ; cxn->doesStreaming && p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->takeHead = NULL ;
-}
-
-
-\f
-/*
- * Give back any articles we have to the Host for later retrys.
- */
-static void deferAllArticles (Connection cxn)
-{
- ArtHolder p, q ;
-
- for (q = NULL, p = cxn->checkHead ; p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->checkHead = NULL ;
-
- for (q = NULL, p = cxn->checkRespHead ; p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->checkRespHead = NULL ;
-
- for (q = NULL, p = cxn->takeHead ; p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->takeHead = NULL ;
-
- for (q = NULL, p = cxn->takeRespHead ; p != NULL ; p = q)
- {
- q = p->next ;
- hostTakeBackArticle (cxn->myHost, cxn, p->article) ;
- delArtHolder (p) ;
- cxn->articleQTotal-- ;
- }
- cxn->takeRespHead = NULL ;
-
- ASSERT (cxn->articleQTotal == 0) ;
-}
-
-
-
-
-\f
-/*
- * Called when there's an article to be pushed out to the remote. Even if
- * the Connection has an article it's possible that nothing will be written
- * (e.g. if the article on the queue doesn't exist any more)
- */
-static void doSomeWrites (Connection cxn)
-{
- bool doneSome = false ;
-
- /* If there's a write pending we can't do anything now. */
- if ( writeIsPending (cxn->myEp) )
- return ;
- else if ( writesNeeded (cxn) ) /* something on a queue. */
- {
- if (cxn->doesStreaming)
- doneSome = issueStreamingCommands (cxn) ;
- else
- doneSome = issueIHAVE (cxn) ;
-
- /* doneSome will be false if article(s) were gone, but if the Host
- has something available, then it would have been put on the queue
- for next time around. */
- if (!doneSome)
- {
- if (writesNeeded (cxn)) /* Host gave us something */
- addWorkCallback (cxn->myEp,cxnWorkProc,cxn) ; /* for next time. */
- else if (cxn->articleQTotal == 0)
- {
- /* if we were in cxnFeedingS, then issueStreamingCommands
- already called cxnIdle(). */
- if (cxn->state == cxnClosingS || cxn->state == cxnFlushingS)
- issueQUIT (cxn) ; /* and nothing to wait for... */
- }
- }
- }
- else if (cxn->state == cxnClosingS || cxn->state == cxnFlushingS)
- { /* nothing to do... */
- if (cxn->articleQTotal == 0)
- issueQUIT (cxn) ; /* and nothing to wait for before closing */
- }
-}
-
-
-
-
-\f
-/* Queue up a buffer with the IHAVE command in it for the article at
- * the head of the transmisson queue.
- *
- * If the article is missing, then the Host will be notified and
- * another article may be put on the Connections queue. This new
- * article is ignored for now, but a work callback is registered so
- * that it can be looked at later.
- */
-static bool issueIHAVE (Connection cxn)
-{
- Buffer ihaveBuff, *writeArr ;
- ArtHolder artH ;
- Article article ;
- const char *msgid ;
- char *p ;
- unsigned int tmp ;
- size_t bufLen = 256 ;
- bool rval = false ;
-
- ASSERT (!cxn->doesStreaming) ;
- ASSERT (cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS) ;
- ASSERT (cxn->articleQTotal == 1) ;
- ASSERT (cxn->checkHead != NULL) ;
- ASSERT (writeIsPending (cxn->myEp) == false) ;
- VALIDATE_CONNECTION (cxn) ;
-
- artH = cxn->checkHead ;
- article = cxn->checkHead->article ;
- msgid = artMsgId (artH->article) ;
-
- ASSERT (msgid != NULL) ;
- ASSERT (article != NULL) ;
-
- if ((tmp = (strlen (msgid) + 10)) > bufLen)
- bufLen = tmp ;
-
- ihaveBuff = newBuffer (bufLen) ;
-
- ASSERT (ihaveBuff != NULL) ;
-
- p = bufferBase (ihaveBuff) ;
- sprintf (p, "IHAVE %s\r\n", msgid) ;
- bufferSetDataSize (ihaveBuff, strlen (p)) ;
-
- d_printf (5,"%s:%d Command IHAVE %s\n",
- hostPeerName (cxn->myHost),cxn->ident,msgid) ;
-
- writeArr = makeBufferArray (ihaveBuff, NULL) ;
- if ( !prepareWriteWithTimeout (cxn->myEp, writeArr, commandWriteDone,
- cxn) )
- {
- die ("%s:%d fatal prepare write for IHAVE failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- /* now move the article to the second queue */
- cxn->checkRespHead = cxn->checkHead ;
- cxn->checkHead = NULL ;
-
- cxn->checksIssued++ ;
- hostArticleOffered (cxn->myHost, cxn) ;
-
- rval = true ;
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * Do a prepare write with the article body as the body portion of the
- * IHAVE command
- */
-static void issueIHAVEBody (Connection cxn)
-{
- Buffer *writeArray ;
- Article article ;
-
- ASSERT (cxn != NULL) ;
- ASSERT (!cxn->doesStreaming) ;
- ASSERT (cxn->state == cxnFlushingS ||
- cxn->state == cxnFeedingS ||
- cxn->state == cxnClosingS) ;
- ASSERT (cxn->articleQTotal == 1) ;
- ASSERT (cxn->takeHead != NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- article = cxn->takeHead->article ;
- ASSERT (article != NULL) ;
-
- if (cxn->state != cxnClosingS)
- writeArray = artGetNntpBuffers (article) ;
- else
- writeArray = NULL ;
-
- if (writeArray == NULL)
- {
- /* missing article (expired for example) will get us here. */
- if (dotBuffer == NULL)
- {
- dotBuffer = newBufferByCharP (".\r\n",3,3) ;
- dotFirstBuffer = newBufferByCharP ("\r\n.",3,3) ;
- crlfBuffer = newBufferByCharP ("\r\n",2,2) ;
- }
-
- /* we'll just write the empty buffer and the remote will complain
- with 437 */
- writeArray = makeBufferArray (bufferTakeRef (dotBuffer),NULL) ;
- }
-
-
- if ( !prepareWriteWithTimeout (cxn->myEp, writeArray, ihaveBodyDone, cxn) )
- {
- die ("%s:%d fatal prepare write failed in issueIHAVEBody",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
- else
- {
- d_printf (5,"%s:%d prepared write for IHAVE body.\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- }
-
- /* now move the article to the last queue */
- cxn->takeRespHead = cxn->takeHead ;
- cxn->takeHead = NULL ;
-
- return ;
-}
-
-
-
-
-\f
-/* Process the two command queues. Slaps all the CHECKs together and
- * then does the TAKETHIS commands.
- *
- * If no articles on the queue(s) are valid, then the Host is
- * notified. It may queue up new articles on the Connection, but
- * these are ignored for now. A work proc is registered so the
- * articles can be processed later.
- */
-static bool issueStreamingCommands (Connection cxn)
-{
- Buffer checkBuffer = NULL ; /* the buffer with the CHECK commands in it. */
- Buffer *writeArray = NULL ;
- ArtHolder p, q ;
- bool rval = false ;
-
- ASSERT (cxn != NULL) ;
- ASSERT (cxn->myEp != NULL) ;
- ASSERT (cxn->doesStreaming) ;
- VALIDATE_CONNECTION (cxn) ;
-
- checkBuffer = buildCheckBuffer (cxn) ; /* may be null if none to issue */
-
- if (checkBuffer != NULL)
- {
- /* Now shift the articles to their new queue. */
- for (p = cxn->checkRespHead ; p != NULL && p->next != NULL ; p = p->next)
- /* nada--finding end of queue*/ ;
-
- if (p == NULL)
- cxn->checkRespHead = cxn->checkHead ;
- else
- p->next = cxn->checkHead ;
-
- cxn->checkHead = NULL ;
- }
-
-
- writeArray = buildTakethisBuffers (cxn,checkBuffer) ; /* may be null */
-
- /* If not null, then writeArray will have checkBuffer (if it wasn't NULL)
- in the first spot and the takethis buffers after that. */
- if (writeArray)
- {
- if ( !prepareWriteWithTimeout (cxn->myEp, writeArray,
- commandWriteDone, cxn) )
- {
- die ("%s:%d fatal prepare write for STREAMING commands failed",
- hostPeerName (cxn->myHost), cxn->ident) ;
- }
-
- rval = true ;
-
- /* now shift articles over to their new queue. */
- for (p = cxn->takeRespHead ; p != NULL && p->next != NULL ; p = p->next)
- /* nada--finding end of queue */ ;
-
- if (p == NULL)
- cxn->takeRespHead = cxn->takeHead ;
- else
- p->next = cxn->takeHead ;
-
- cxn->takeHead = NULL ;
- }
-
- /* we defer the missing article notification to here because if there
- was a big backlog of missing articles *and* we're running in
- no-CHECK mode, then the Host would be putting bad articles on the
- queue we're taking them off of. */
- if (cxn->missing && cxn->articleQTotal == 0)
- cxnIdle (cxn) ;
- for (p = cxn->missing ; p != NULL ; p = q)
- {
- hostArticleIsMissing (cxn->myHost, cxn, p->article) ;
- q = p->next ;
- delArtHolder (p) ;
- }
- cxn->missing = NULL ;
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * build up the buffer of all the CHECK commands.
- */
-static Buffer buildCheckBuffer (Connection cxn)
-{
- ArtHolder p ;
- size_t lenBuff = 0 ;
- Buffer checkBuffer = NULL ;
- const char *peerName = hostPeerName (cxn->myHost) ;
-
- p = cxn->checkHead ;
- while (p != NULL)
- {
- Article article = p->article ;
- const char *msgid ;
-
- msgid = artMsgId (article) ;
-
- lenBuff += (8 + strlen (msgid)) ; /* 8 == strlen("CHECK \r\n") */
- p = p->next ;
- }
-
- if (lenBuff > 0)
- lenBuff++ ; /* for the null byte */
-
- /* now build up the single buffer that contains all the CHECK commands */
- if (lenBuff > 0)
- {
- char *t ;
- size_t tlen = 0 ;
-
- checkBuffer = newBuffer (lenBuff) ;
- t = bufferBase (checkBuffer) ;
-
- p = cxn->checkHead ;
- while (p != NULL)
- {
- const char *msgid = artMsgId (p->article) ;
-
- sprintf (t,"CHECK %s\r\n", msgid) ;
- d_printf (5,"%s:%d Command %s\n", peerName, cxn->ident, t) ;
-
- tlen += strlen (t) ;
-
- while ( *t ) t++ ;
-
- cxn->checksIssued++ ;
- hostArticleOffered (cxn->myHost,cxn) ;
-
- p = p->next ;
- }
-
- ASSERT (tlen + 1 == lenBuff) ;
-
- bufferSetDataSize (checkBuffer, tlen) ;
- }
-
- return checkBuffer ;
-}
-
-
-
-
-
-\f
-/*
- * Construct and array of TAKETHIS commands and the command bodies. Any
- * articles on the queue that are missing will be removed and the Host will
- * be informed.
- */
-static Buffer *buildTakethisBuffers (Connection cxn, Buffer checkBuffer)
-{
- size_t lenArray = 0 ;
- ArtHolder p, q ;
- Buffer *rval = NULL ;
- const char *peerName = hostPeerName (cxn->myHost) ;
-
- if (checkBuffer != NULL)
- lenArray++ ;
-
- if (cxn->takeHead != NULL) /* some TAKETHIS commands to be done. */
- {
- Buffer takeBuffer ;
- unsigned int takeBuffLen ;
- unsigned int writeIdx = 0 ;
-
- /* count up all the buffers we'll be writing. One extra each time for
- the TAKETHIS command buffer*/
- for (p = cxn->takeHead ; p != NULL ; p = p->next)
- if (artContentsOk (p->article))
- lenArray += (1 + artNntpBufferCount (p->article)) ;
-
- /* now allocate the array for the buffers and put them all in it */
- /* 1 for the terminator */
- rval = xmalloc (sizeof(Buffer) * (lenArray + 1)) ;
-
- if (checkBuffer != NULL)
- rval [writeIdx++] = checkBuffer ;
-
- q = NULL ;
- p = cxn->takeHead ;
- while (p != NULL)
- {
- char *t ;
- const char *msgid ;
- Article article ;
- Buffer *articleBuffers ;
- int i, nntpLen ;
-
- article = p->article ;
- nntpLen = artNntpBufferCount (article) ;
- msgid = artMsgId (article) ;
-
- if (nntpLen == 0)
- { /* file no longer valid so drop from queue */
- ArtHolder ta = p ;
-
- if (q == NULL) /* it's the first in the queue */
- cxn->takeHead = p->next ;
- else
- q->next = p->next ;
-
- p = p->next ;
- ASSERT (cxn->articleQTotal > 0) ;
- cxn->articleQTotal-- ;
-
- ta->next = cxn->missing ;
- cxn->missing = ta ;
- }
- else
- {
- articleBuffers = artGetNntpBuffers (article) ;
-
- /* set up the buffer with the TAKETHIS command in it.
- 12 == strlen ("TAKETHIS \n\r") */
- takeBuffLen = 12 + strlen (msgid) ;
- takeBuffer = newBuffer (takeBuffLen) ;
- t = bufferBase (takeBuffer) ;
-
- sprintf (t, "TAKETHIS %s\r\n", msgid) ;
- bufferSetDataSize (takeBuffer, strlen (t)) ;
-
- d_printf (5,"%s:%d Command %s\n", peerName, cxn->ident, t) ;
-
- ASSERT (writeIdx <= lenArray) ;
- rval [writeIdx++] = takeBuffer ;
-
- /* now add all the buffers that make up the body of the TAKETHIS
- command */
- for (i = 0 ; i < nntpLen ; i++)
- {
- ASSERT (writeIdx <= lenArray) ;
- rval [writeIdx++] = bufferTakeRef (articleBuffers [i]) ;
- }
-
- freeBufferArray (articleBuffers) ;
-
- if ( !cxn->needsChecks )
- {
- /* this isn't quite right. An article may be counted
- twice if we switch to no-CHECK mode after its
- CHECK was issued, but before its TAKETHIS was done
- just now. I'm not going to worry unless someone
- complains. */
-
- cxn->checksIssued++ ;
- hostArticleOffered (cxn->myHost,cxn) ;
- }
-
- q = p ;
- p = p->next ;
- }
- }
-
- if (writeIdx > 0)
- rval [writeIdx] = NULL ;
- else
- { /* all articles were missing and no CHECKS */
- free (rval) ;
- rval = NULL ;
- }
- }
- else if (checkBuffer != NULL) /* no TAKETHIS to do, but some CHECKS */
- rval = makeBufferArray (checkBuffer, NULL) ;
-
- return rval ;
-}
-
-
-
-
-\f
-/*
- * for one reason or another we need to disconnect gracefully. We send a
- * QUIT command.
- */
-static void issueQUIT (Connection cxn)
-{
- Buffer quitBuffer, *writeArray ;
- const char *peerName = hostPeerName (cxn->myHost) ;
-
- ASSERT (cxn->takeHead == NULL) ;
- ASSERT (cxn->checkHead == NULL) ;
- VALIDATE_CONNECTION (cxn) ;
-
- if (cxn->quitWasIssued)
- return ;
-
- if (writeIsPending (cxn->myEp))
- {
- warn ("%s:%d internal QUIT while write pending", peerName,
- cxn->ident) ;
-
- if (cxn->state == cxnClosingS)
- cxnDead (cxn) ;
- else
- cxnWait (cxn) ;
- }
- else
- {
- quitBuffer = newBuffer (7) ;
- strcpy (bufferBase (quitBuffer), "QUIT\r\n") ;
- bufferSetDataSize (quitBuffer, 6) ;
-
- writeArray = makeBufferArray (quitBuffer, NULL) ;
-
- d_printf (1,"%s:%d Sending a quit command\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- cxn->quitWasIssued = true ; /* not exactly true, but good enough */
-
- if ( !prepareWriteWithTimeout (cxn->myEp, writeArray, quitWritten,
- cxn) )
- {
- die ("%s:%d fatal prepare write for QUIT command failed", peerName,
- cxn->ident) ;
- }
- }
-}
-
-
-
-
-\f
-/*
- * Set up the timer for the blocked reads
- */
-static void initReadBlockedTimeout (Connection cxn)
-{
- ASSERT (cxn != NULL) ;
-ASSERT (cxn->state != cxnIdleS ) ;
-
- /* set up the response timer. */
- clearTimer (cxn->readBlockedTimerId) ;
-
- if (cxn->readTimeout > 0)
- cxn->readBlockedTimerId = prepareSleep (responseTimeoutCbk, cxn->readTimeout, cxn) ;
-}
-
-
-
-
-\f
-/*
- * Set up the timer for the blocked reads
- */
-static int prepareWriteWithTimeout (EndPoint endp,
- Buffer *buffers,
- EndpRWCB done,
- Connection cxn)
-{
- /* Clear the read timer, since we can't expect a response until everything
- is sent.
- XXX - would be nice to have a timeout for reponses if we're sending a
- string of commands. */
- clearTimer (cxn->readBlockedTimerId) ;
-
- /* set up the write timer. */
- clearTimer (cxn->writeBlockedTimerId) ;
-
- if (cxn->writeTimeout > 0)
- cxn->writeBlockedTimerId = prepareSleep (writeTimeoutCbk, cxn->writeTimeout,
- cxn) ;
-
- /* set up the write. */
- return prepareWrite (endp, buffers, writeProgress, done, cxn) ;
-}
-
-
-
-
-\f
-/*
- * Does the actual deletion of a connection and all its private data.
- */
-static void delConnection (Connection cxn)
-{
- bool shutDown;
- Connection c, q;
-
- if (cxn == NULL)
- return ;
-
- d_printf (1,"Deleting connection: %s:%d\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- for (c = gCxnList, q = NULL ; c != NULL ; q = c, c = c->next)
- if (c == cxn)
- {
- if (gCxnList == c)
- gCxnList = gCxnList->next ;
- else
- q->next = c->next ;
- break ;
- }
-
- ASSERT (c != NULL) ;
-
- if (cxn->myEp != NULL)
- delEndPoint (cxn->myEp) ;
-
- ASSERT (cxn->checkHead == NULL) ;
- ASSERT (cxn->checkRespHead == NULL) ;
- ASSERT (cxn->takeHead == NULL) ;
- ASSERT (cxn->takeRespHead == NULL) ;
-
- delBuffer (cxn->respBuffer) ;
-
- /* tell the Host we're outta here. */
- shutDown = hostCxnGone (cxn->myHost, cxn) ;
-
- cxn->ident = 0 ;
- cxn->timeCon = 0 ;
-
- free (cxn->ipName) ;
-
- clearTimer (cxn->artReceiptTimerId) ;
- clearTimer (cxn->readBlockedTimerId) ;
- clearTimer (cxn->writeBlockedTimerId) ;
- clearTimer (cxn->flushTimerId) ;
-
- free (cxn) ;
-
- if (shutDown)
- {
- /* exit program if that was the last connexion for the last host */
- /* XXX what about if there are ever multiple listeners?
- XXX this will be executed if all hosts on only one of the
- XXX listeners have gone */
- time_t now = theTime () ;
- char dateString [30] ;
- char **p = PointersFreedOnExit ;
-
- /* finish out all outstanding memory */
- while (*p)
- free (*p++) ;
- free (PointersFreedOnExit) ;
- freeTimeoutQueue () ;
-
- strlcpy (dateString,ctime (&now), sizeof(dateString)) ;
-
- notice ("ME finishing at %s", dateString) ;
-
- exit (0) ;
- }
-}
-
-
-
-
-\f
-/*
- * Bump up the value of the low pass filter on the connection.
- */
-static void incrFilter (Connection cxn)
-{
- cxn->filterValue *= (1.0 - (1.0 / cxn->lowPassFilter)) ;
- cxn->filterValue += 1.0 ;
-}
-
-
-
-
-\f
-/*
- * decrement the value of the low pass filter on the connection.
- */
-static void decrFilter (Connection cxn)
-{
- cxn->filterValue *= (1.0 - (1.0 / cxn->lowPassFilter)) ;
-}
-
-
-
-
-\f
-/*
- * return true if we have articles we need to issue commands for.
- */
-static bool writesNeeded (Connection cxn)
-{
- return (cxn->checkHead != NULL || cxn->takeHead != NULL ? true : false) ;
-}
-
-
-
-
-\f
-/*
- * do some simple tests to make sure it's OK.
- */
-static void validateConnection (Connection cxn)
-{
- unsigned int i ;
- unsigned int old ;
- ArtHolder p ;
-
- i = 0 ;
-
- /* count up the articles the Connection has and make sure that matches. */
- for (p = cxn->takeHead ; p != NULL ; p = p->next)
- i++ ;
- d_printf (4,"TAKE queue: %d\n",i) ;
- old = i ;
-
- for (p = cxn->takeRespHead ; p != NULL ; p = p->next)
- i++ ;
- d_printf (4,"TAKE response queue: %d\n",i - old) ;
- old = i ;
-
- for (p = cxn->checkHead ; p != NULL ; p = p->next)
- i++ ;
- d_printf (4,"CHECK queue: %d\n",i - old) ;
- old = i ;
-
- for (p = cxn->checkRespHead ; p != NULL ; p = p->next)
- i++ ;
- d_printf (4,"CHECK response queue: %d\n",i - old) ;
-
- ASSERT (i == cxn->articleQTotal) ;
-
- switch (cxn->state)
- {
- case cxnConnectingS:
- ASSERT (cxn->doesStreaming == false) ;
- ASSERT (cxn->articleQTotal <= 1) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- /* ASSERT (cxn->timeCon == 0) ; */
- break ;
-
- case cxnWaitingS:
- ASSERT (cxn->articleQTotal == 0) ;
- ASSERT (cxn->myEp == NULL) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->readBlockedTimerId == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (cxn->flushTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon == 0) ;
- break ;
-
- case cxnFlushingS:
- case cxnClosingS:
- if (!cxn->doesStreaming)
- ASSERT (cxn->articleQTotal <= 1) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->flushTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon != 0) ;
- ASSERT (cxn->doesStreaming || cxn->maxCheck == 1) ;
- break ;
-
- case cxnFeedingS:
- if (cxn->doesStreaming)
- /* Some(?) hosts return the 439 response even before we're done
- sending, so don't go idle until here */
- ASSERT (cxn->articleQTotal > 0 || writeIsPending (cxn->myEp)) ;
- else
- ASSERT (cxn->articleQTotal == 1) ;
- if (cxn->readTimeout > 0 && !writeIsPending (cxn->myEp) &&
- cxn->checkRespHead != NULL && cxn->takeRespHead != NULL)
- ASSERT (cxn->readBlockedTimerId != 0) ;
- if (cxn->writeTimeout > 0 && writeIsPending (cxn->myEp))
- ASSERT (cxn->writeBlockedTimerId != 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon != 0) ;
- ASSERT (cxn->doesStreaming || cxn->maxCheck == 1) ;
- break;
-
- case cxnIdleS:
- ASSERT (cxn->articleQTotal == 0) ;
- if (cxn->articleReceiptTimeout > 0)
- ASSERT (cxn->artReceiptTimerId != 0) ;
- ASSERT (cxn->readBlockedTimerId == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon != 0) ;
- ASSERT (!writeIsPending (cxn->myEp)) ;
- break ;
-
- case cxnIdleTimeoutS:
- ASSERT (cxn->articleQTotal == 0) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon != 0) ;
- ASSERT (!writeIsPending (cxn->myEp)) ;
- break ;
-
- case cxnSleepingS:
- ASSERT (cxn->articleQTotal == 0) ;
- ASSERT (cxn->myEp == NULL) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->readBlockedTimerId == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (cxn->flushTimerId == 0) ;
- ASSERT (cxn->timeCon == 0) ;
- break ;
-
- case cxnStartingS:
- ASSERT (cxn->articleQTotal == 0) ;
- ASSERT (cxn->myEp == NULL) ;
- ASSERT (cxn->artReceiptTimerId == 0) ;
- ASSERT (cxn->readBlockedTimerId == 0) ;
- ASSERT (cxn->writeBlockedTimerId == 0) ;
- ASSERT (cxn->flushTimerId == 0) ;
- ASSERT (cxn->sleepTimerId == 0) ;
- ASSERT (cxn->timeCon == 0) ;
- break ;
-
- case cxnDeadS:
- break ;
- }
-}
-
-
-
-
-\f
-/*
- * Generate a printable string of the parameter.
- */
-static const char *stateToString (CxnState state)
-{
- static char rval [64] ;
-
- switch (state)
- {
- case cxnStartingS:
- strlcpy (rval,"cxnStartingS", sizeof(rval)) ;
- break ;
-
- case cxnWaitingS:
- strlcpy (rval,"cxnWaitingS", sizeof(rval)) ;
- break ;
-
- case cxnConnectingS:
- strlcpy (rval,"cxnConnectingS", sizeof(rval)) ;
- break ;
-
- case cxnIdleS:
- strlcpy (rval,"cxnIdleS", sizeof(rval)) ;
- break ;
-
- case cxnIdleTimeoutS:
- strlcpy (rval,"cxnIdleTimeoutS", sizeof(rval)) ;
- break ;
-
- case cxnFeedingS:
- strlcpy (rval,"cxnFeedingS", sizeof(rval)) ;
- break ;
-
- case cxnSleepingS:
- strlcpy (rval,"cxnSleepingS", sizeof(rval)) ;
- break ;
-
- case cxnFlushingS:
- strlcpy (rval,"cxnFlushingS", sizeof(rval)) ;
- break ;
-
- case cxnClosingS:
- strlcpy (rval,"cxnClosingS", sizeof(rval)) ;
- break ;
-
- case cxnDeadS:
- strlcpy (rval,"cxnDeadS", sizeof(rval)) ;
- break ;
-
- default:
- snprintf (rval,sizeof(rval),"UNKNOWN STATE: %d",state) ;
- break ;
- }
-
- return rval ;
-}
-
-
-
-
-\f
-/****************************************************************************
- *
- * Functions for managing the internal queue of Articles on each Connection.
- *
- ****************************************************************************/
-
-static ArtHolder newArtHolder (Article article)
-{
- ArtHolder a = xmalloc (sizeof(struct art_holder_s)) ;
-
- a->article = article ;
- a->next = NULL ;
-
- return a ;
-}
-
-
-
-
-\f
-/*
- * Deletes the article holder
- */
-static void delArtHolder (ArtHolder artH)
-{
- if (artH != NULL)
- free (artH) ;
-}
-
-
-
-
-\f
-/*
- * remove the article holder from the queue. Adjust the count and if nxtPtr
- * points at the element then adjust that too.
- */
-static bool remArtHolder (ArtHolder artH, ArtHolder *head, unsigned int *count)
-{
- ArtHolder h, i ;
-
- ASSERT (head != NULL) ;
- ASSERT (count != NULL) ;
-
- h = *head ;
- i = NULL ;
- while (h != NULL && h != artH)
- {
- i = h ;
- h = h->next ;
- }
-
- if (h == NULL)
- return false ;
-
- if (i == NULL)
- *head = (*head)->next ;
- else
- i->next = artH->next ;
-
- (*count)-- ;
-
- return true ;
-}
-
-
-
-
-\f
-/*
- * append the ArticleHolder to the queue
- */
-static void appendArtHolder (ArtHolder artH, ArtHolder *head, unsigned int *count)
-{
- ArtHolder p ;
-
- ASSERT (head != NULL) ;
- ASSERT (count != NULL) ;
-
- for (p = *head ; p != NULL && p->next != NULL ; p = p->next)
- /* nada */ ;
-
- if (p == NULL)
- *head = artH ;
- else
- p->next = artH ;
-
- artH->next = NULL ;
- (*count)++ ;
-}
-
-
-
-
-\f
-/*
- * find the article holder on the queue by comparing the message-id.
- */
-static ArtHolder artHolderByMsgId (const char *msgid, ArtHolder head)
-{
- while (head != NULL)
- {
- if (strcmp (msgid, artMsgId (head->article)) == 0)
- return head ;
-
- head = head->next ;
- }
-
- return NULL ;
-}
-
-
-
-/*
- * Randomize a numeber by the given percentage
- */
-
-static int fudgeFactor (int initVal)
-{
- int newValue ;
- static bool seeded ;
-
- if ( !seeded )
- {
- time_t t = theTime () ;
-
- /* this may have been done already in endpoint.c. Is that a problem??? */
- srand (t) ;
- seeded = true ;
- }
-
- newValue = initVal + (initVal / 10 - (rand() % (initVal / 5)));
-
- return newValue ;
-}
+++ /dev/null
-/* $Id: connection.h 6648 2004-01-25 20:07:11Z rra $
-**
-** The public interface to the Connection class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The Connection class encapulates an NNTP protocol endpoint (either regular
-** or extended with the streaming protocol). Each Connection is owned by a
-** single Host object.
-**
-** It manages the network connection (via an EndPoint) the the pumping of
-** articles to the remote host. It gets these articles from its Host object.
-** If the remote doesn't handle the streaming extension, then the Connection
-** will only manage one article at a time. If the remote handles the
-** extension, then the connection will queue up articles while sending the
-** CHECK and TAKETHIS commands.
-**
-** If the network connection drops while the Connection object has articles
-** queued up, then it will hand them back to its Host object.
-*/
-
-#if ! defined ( connection_h__ )
-#define connection_h__
-
-
-#include <time.h>
-#include <stdio.h>
-
-#include "misc.h"
-
-
- /*
- * Create a new Connection.
- *
- * HOST is the host object we're owned by.
- * IDENT is an identifier to be added to syslog entries so we can tell
- * what's happening on different connections to the same peer.
- * IPNAME is the name (or ip address) of the remote)
- * MAXTOUT is the maximum amount of time to wait for a response before
- * considering the remote host dead.
- * PORTNUM is the portnum to contact on the remote end.
- * RESPTIMEOUT is the amount of time to wait for a response from a remote
- * before considering the connection dead.
- * CLOSEPERIOD is the number of seconds after connecting that the
- * connections should be closed down and reinitialized (due to problems
- * with old NNTP servers that hold history files open. Value of 0 means
- * no close down.
- */
-Connection newConnection (Host host,
- unsigned int ident,
- const char *ipname,
- unsigned int artTout,
- unsigned int portNum,
- unsigned int respTimeout,
- unsigned int closePeriod,
- double lowPassLow,
- double lowPassHigh,
- double lowPassFilter) ;
-
- /* Causes the Connection to build the network connection. */
-bool cxnConnect (Connection cxn) ;
-
- /* puts the connection into the wait state (i.e. waits for an article
- before initiating a connect). Can only be called right after
- newConnection returns, or while the Connection is in the (internal)
- Sleeping state. */
-void cxnWait (Connection cxn) ;
-
- /* The Connection will disconnect as if cxnDisconnect were called and then
- it automatically reconnects to the remote. */
-void cxnFlush (Connection cxn) ;
-
- /* The Connection sends remaining articles, then issues a QUIT and then
- deletes itself */
-void cxnClose (Connection cxn) ;
-
- /* The Connection drops all queueed articles, then issues a QUIT and then
- deletes itself */
-void cxnTerminate (Connection cxn) ;
-
- /* Blow away the connection gracelessly and immedately clean up */
-void cxnNuke (Connection cxn) ;
-
- /* Tells the Connection to take the article and handle its
- transmission. If it can't (due to queue size or whatever), then the
- function returns false. The connection assumes ownership of the
- article if it accepts it (returns true). */
-bool cxnTakeArticle (Connection cxn, Article art) ;
-
- /* Tell the Connection to take the article (if it can) for later
- processing. Assumes ownership of it if it takes it. */
-bool cxnQueueArticle (Connection cxn, Article art) ;
-
- /* generate a syslog message for the connections activity. Called by Host. */
-void cxnLogStats (Connection cxn, bool final) ;
-
- /* return the number of articles the connection can be given. This lets
- the host shovel in as many as possible. May be zero. */
-size_t cxnQueueSpace (Connection cxn) ;
-
- /* adjust the mode no-CHECK filter values */
-void cxnSetCheckThresholds (Connection cxn,
- double lowFilter, double highFilter,
- double lowPassFilter) ;
-
- /* print some debugging info. */
-void gPrintCxnInfo (FILE *fp, unsigned int indentAmt) ;
-void printCxnInfo (Connection cxn, FILE *fp, unsigned int indentAmt) ;
-
-/* config file load callback */
-int cxnConfigLoadCbk (void *data) ;
-
-/* check connection state is in cxnWaitingS, cxnConnectingS or cxnIdleS */
-bool cxnCheckstate (Connection cxn) ;
-
-#endif /* connection_h__ */
+++ /dev/null
-/* $Id: endpoint.c 7738 2008-04-06 09:33:33Z iulius $
-**
-** The implementation of the innfeed EndPoint object class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The EndPoint class is what gives the illusion (sort of, kind of) of
-** threading. Basically it controls a select loop and a set of EndPoint
-** objects. Each EndPoint has a file descriptor it is interested in. The
-** users of the EndPoint tell the EndPoints to notify them when a read or
-** write has been completed (or simple if the file descriptor is read or
-** write ready).
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <syslog.h>
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "buffer.h"
-#include "configfile.h"
-#include "endpoint.h"
-#include "host.h"
-
-static const char *const timer_name[] = {
- "idle", "blstats", "stsfile", "newart", "readart", "prepart", "read",
- "write", "cb"
-};
-
-#if ! defined (NSIG)
-#define NSIG 32
-#endif
-
-
- /* This is the structure that is the EndPoint */
-struct endpoint_s
-{
- /* fields for managing multiple reads into the inBuffer. */
- Buffer *inBuffer ; /* list of buffers to read into */
- unsigned int inBufferIdx ; /* where is list we're at. */
- size_t inIndex ; /* where in current read we're at */
- size_t inMinLen ; /* minimum amount to read */
- size_t inAmtRead ; /* amount read so far */
- EndpRWCB inCbk ; /* callback for when read complete */
- void *inClientData ; /* callback data */
-
- /* fields for managing multiple writes from the outBuffer */
- Buffer *outBuffer ; /* list of buffers to write */
- unsigned int outBufferIdx ; /* index into buffer list to start write */
- size_t outIndex ; /* where in current buffer we write from */
- size_t outSize ; /* total of all the buffers */
- size_t outAmtWritten ; /* amount written so far */
- EndpRWCB outProgressCbk ; /* callback when done */
- EndpRWCB outDoneCbk ; /* callback when done */
- void *outClientData ; /* callback data */
-
- EndpWorkCbk workCbk ; /* callback to run if no I/O to do */
- void *workData ; /* data for callback */
-
- int myFd ; /* the file descriptor we're handling */
- int myErrno ; /* the errno when I/O fails */
-
- double selectHits ; /* indicates how often it's ready */
-};
-
-
-
- /* A private structure. These hold the information on the timer callbacks. */
-typedef struct timerqelem_s
-{
- TimeoutId id ; /* the id we gave out */
- time_t when ; /* The time the timer should go off */
- EndpTCB func ; /* the function to call */
- void *data ; /* the client callback data */
- struct timerqelem_s *next ; /* next in the queue */
-} *TimerElem, TimerElemStruct ;
-
-
-
- /* set to 1 elsewhere if you want stderr to get what's also being written
- in doWrite. */
-int debugWrites ;
-
-extern const char *InputFile ;
-
-static EndPoint mainEndPoint ;
-static bool mainEpIsReg = false ;
-static unsigned int stdioFdMax = MAX_STDIO_FD ;
-
-time_t PrivateTime;
-
-
-typedef void (*sigfn) (int) ;
-static sigfn *sigHandlers ;
-
-static volatile sig_atomic_t *sigFlags ;
-
-
-
- /* private functions */
-static IoStatus doRead (EndPoint endp) ;
-static IoStatus doWrite (EndPoint endp) ;
-static IoStatus doExcept (EndPoint endp) ;
-static void pipeHandler (int s) ;
-static void signalHandler (int s) ;
-static int hitCompare (const void *v1, const void *v2) ;
-static void reorderPriorityList (void) ;
-static TimerElem newTimerElem (TimeoutId i, time_t w, EndpTCB f, void *d) ;
-static TimeoutId timerElemAdd (time_t when, EndpTCB func, void *data) ;
-static struct timeval *getTimeout (struct timeval *tout) ;
-static void doTimeout (void) ;
-static void handleSignals (void) ;
-
-#if 0
-static int ff_set (fd_set *set, unsigned int start) ;
-static int ff_free (fd_set *set, unsigned int start) ;
-#endif
-static void endpointCleanup (void) ;
-
-
- /* Private data */
-static size_t maxEndPoints ;
-
-static EndPoint *endPoints ; /* endpoints indexed on fd */
-static EndPoint *priorityList ; /* endpoints indexed on priority */
-
-static int absHighestFd = 0 ; /* never goes down */
-static int highestFd = -1 ;
-static unsigned int endPointCount = 0 ;
-static unsigned int priorityCount = 0 ;
-
-static fd_set rdSet ;
-static fd_set wrSet ;
-static fd_set exSet ;
-
-static int keepSelecting ;
-
-static TimerElem timeoutQueue ;
-static TimerElem timeoutPool ;
-static TimeoutId nextId ;
-static int timeoutQueueLength ;
-
-
-
-
- /* Create a new EndPoint and hook it to the give file descriptor. All
- fields are initialized to appropriate values. On the first time this
- function is called the global data structs that manages lists of
- endpoints are intialized. */
-static bool inited = false ;
-
-EndPoint newEndPoint (int fd)
-{
- EndPoint ep ;
-
- if (!inited)
- {
- inited = true ;
- atexit (endpointCleanup) ;
- }
-
- if (fd < 0)
- return NULL ;
-
- /* try to dup the fd to a larger number to leave lower values free for
- broken stdio implementations. */
- if (stdioFdMax > 0 && ((unsigned int) fd) <= stdioFdMax)
- {
- int newfd = fcntl(fd, F_DUPFD, stdioFdMax + 1);
- if (newfd >= 0)
- {
- d_printf (1,"Dupped fd %d to %d\n",fd,newfd) ;
- if (close (fd) != 0)
- syswarn ("ME oserr close (%d)", fd) ;
- }
- else
- {
- d_printf (1,"Couldn't dup fd %d to above %d\n",fd,stdioFdMax) ;
- newfd = fd ;
- }
-
- fd = newfd ;
- }
-
- if ((unsigned int) fd >= maxEndPoints)
- {
- unsigned int i = maxEndPoints ;
-
- maxEndPoints = (((fd + 256) / 256) * 256); /* round up to nearest 256 */
- if (endPoints == NULL)
- {
- endPoints = xmalloc (sizeof(EndPoint) * maxEndPoints) ;
- priorityList = xmalloc (sizeof(EndPoint) * maxEndPoints) ;
- }
- else
- {
- endPoints = xrealloc (endPoints,sizeof(EndPoint) * maxEndPoints) ;
- priorityList = xrealloc (priorityList,
- sizeof(EndPoint) * maxEndPoints) ;
- }
-
- for ( ; i < maxEndPoints ; i++)
- endPoints [i] = priorityList [i] = NULL ;
- }
-
- ASSERT (endPoints [fd] == NULL) ;
-
- if (fd > absHighestFd)
- {
- static bool sizelogged = false ;
-
-#if defined (FD_SETSIZE)
- if (fd >= FD_SETSIZE)
- {
- sizelogged = true ;
- warn ("ME fd (%d) looks too big (%d -- FD_SETSIZE)", fd,
- FD_SETSIZE) ;
- return NULL ;
- }
-#else
- if (fd > (sizeof (fd_set) * CHAR_BIT))
- {
- sizelogged = true ;
- warn ("ME fd (%d) looks too big (%d -- sizeof (fd_set) * CHAR_BIT)",
- fd, (sizeof (fd_set) * CHAR_BIT)) ;
- return NULL ;
- }
-#endif
-
- absHighestFd = fd ;
- }
-
- ep = xcalloc (1, sizeof(struct endpoint_s)) ;
-
- ep->inBuffer = NULL ;
- ep->inBufferIdx = 0 ;
- ep->inIndex = 0 ;
- ep->inMinLen = 0 ;
- ep->inAmtRead = 0 ;
- ep->inCbk = NULL ;
- ep->inClientData = NULL ;
-
- ep->outBuffer = 0 ;
- ep->outBufferIdx = 0 ;
- ep->outIndex = 0 ;
- ep->outSize = 0 ;
- ep->outProgressCbk = NULL ;
- ep->outDoneCbk = NULL ;
- ep->outClientData = NULL ;
- ep->outAmtWritten = 0 ;
-
- ep->workCbk = NULL ;
- ep->workData = NULL ;
-
- ep->myFd = fd ;
- ep->myErrno = 0 ;
-
- ep->selectHits = 0.0 ;
-
- endPoints [fd] = ep ;
- priorityList [priorityCount++] = ep ;
- endPointCount++ ;
-
- highestFd = (fd > highestFd ? fd : highestFd) ;
-
- return ep ;
-}
-
-
-
-/* Delete the given endpoint. The files descriptor is closed and the two
- Buffer arrays are released. */
-
-void delEndPoint (EndPoint ep)
-{
- unsigned int idx ;
-
- if (ep == NULL)
- return ;
-
- ASSERT (endPoints [ep->myFd] == ep) ;
-
- if (mainEndPoint == ep)
- mainEndPoint = NULL ;
-
- if (ep->inBuffer != NULL)
- freeBufferArray (ep->inBuffer) ;
-
- if (ep->outBuffer != NULL)
- freeBufferArray (ep->outBuffer) ;
-
- close (ep->myFd) ;
-
- /* remove from selectable bits */
- FD_CLR (ep->myFd,&rdSet) ;
- FD_CLR (ep->myFd,&wrSet) ;
- FD_CLR (ep->myFd,&exSet) ;
-
- /* Adjust the global arrays to account for deleted endpoint. */
- endPoints [ep->myFd] = NULL ;
- if (ep->myFd == highestFd)
- while (endPoints [highestFd] == NULL && highestFd >= 0)
- highestFd-- ;
-
- for (idx = 0 ; idx < priorityCount ; idx++)
- if (priorityList [idx] == ep)
- break ;
-
- ASSERT (idx < priorityCount) ; /* i.e. was found */
- ASSERT (priorityList [idx] == ep) ; /* redundant */
-
- /* this hole will removed in the reorder routine */
- priorityList [idx] = NULL ;
-
- endPointCount-- ;
-
- free (ep) ;
-}
-
-int endPointFd (EndPoint endp)
-{
- ASSERT (endp != NULL) ;
-
- return endp->myFd ;
-}
-
-
-
-
-/* Request a read to be done next time there's data. The endpoint
- * ENDP is what will do the read. BUFF is the Buffer the data should
- * go into. FUNC is the callback function to call when the read is
- * complete. CLIENTDATA is the client data to pass back into the
- * callback function. MINLEN is the minimum amount of data to
- * read. If MINLEN is 0 then then BUFF must be filled, otherwise at
- * least MINLEN bytes must be read.
- *
- * BUFF can be null, in which case no read is actually done, but the
- * callback function will be called still. This is useful for
- * listening sockets.
- *
- * Returns 0 if the read couln't be prepared (for example if a read
- * is already outstanding).
- */
-
-int prepareRead (EndPoint endp,
- Buffer *buffers,
- EndpRWCB func,
- void *clientData,
- int minlen)
-{
- int bufferSizeTotal = 0 ;
- int idx ;
-
- ASSERT (endp != NULL) ;
-
- if (endp->inBuffer != NULL || FD_ISSET (endp->myFd,&rdSet))
- return 0 ; /* something already there */
-
- for (idx = 0 ; buffers != NULL && buffers [idx] != NULL ; idx++)
- {
- size_t bs = bufferSize (buffers [idx]) ;
- size_t bds = bufferDataSize (buffers [idx]) ;
-
- bufferSizeTotal += (bs - bds) ;
- }
-
- endp->inBuffer = buffers ;
- endp->inBufferIdx = 0 ;
- endp->inIndex = 0 ;
- endp->inMinLen = (minlen > 0 ? minlen : bufferSizeTotal) ;
- endp->inCbk = func ;
- endp->inAmtRead = 0 ;
- endp->inClientData = clientData ;
-
- FD_SET (endp->myFd, &rdSet) ;
- if ( InputFile == NULL )
- FD_SET (endp->myFd, &exSet) ;
-
- return 1 ;
-}
-
-
-
-/* Request a write to be done at a later point. ENDP is the EndPoint
- * to do the write. BUFF is the Buffer to write from. FUNC is the
- * function to call when the write is complete. CLIENTDATA is some
- * data to hand back to the callback function.
- *
- * If BUFF is null, then no write will actually by done, but the
- * callback function will still be called. This is useful for
- * connecting sockets.
- *
- * Returns 0 if the write couldn't be prepared (like if a write is
- * still in process.
- */
-int prepareWrite (EndPoint endp,
- Buffer *buffers,
- EndpRWCB progress,
- EndpRWCB done,
- void *clientData)
-{
- int bufferSizeTotal = 0 ;
- int idx ;
-
- ASSERT (endp != NULL) ;
-
- if (endp->outBuffer != NULL || FD_ISSET (endp->myFd,&wrSet))
- return 0 ; /* something already there */
-
- for (idx = 0 ; buffers != NULL && buffers [idx] != NULL ; idx++)
- bufferSizeTotal += bufferDataSize (buffers [idx]) ;
-
- endp->outBuffer = buffers ;
- endp->outBufferIdx = 0 ;
- endp->outIndex = 0 ;
- endp->outProgressCbk = progress ;
- endp->outDoneCbk = done ;
- endp->outClientData = clientData ;
- endp->outSize = bufferSizeTotal ;
- endp->outAmtWritten = 0 ;
-
- FD_SET (endp->myFd, &wrSet) ;
- FD_SET (endp->myFd, &exSet) ;
-
- return 1 ;
-}
-
-
-/* Cancel the pending read. */
-void cancelRead (EndPoint endp)
-{
- FD_CLR (endp->myFd,&rdSet) ;
- if (!FD_ISSET (endp->myFd, &wrSet))
- FD_CLR (endp->myFd,&exSet) ;
-
- freeBufferArray (endp->inBuffer) ;
-
- endp->inBuffer = NULL ;
- endp->inBufferIdx = 0 ;
- endp->inIndex = 0 ;
- endp->inMinLen = 0 ;
- endp->inAmtRead = 0 ;
- endp->inCbk = NULL ;
- endp->inClientData = NULL ;
-}
-
-
-/* cancel all pending writes. The first len bytes of the queued write are
- copied to buffer. The number of bytes copied (if it is less than *len) is
- copied to len. If no write was outstanding then len will have 0 stored in
- it. */
-void cancelWrite (EndPoint endp, char *buffer UNUSED, size_t *len UNUSED)
-{
- FD_CLR (endp->myFd, &wrSet) ;
- if (!FD_ISSET (endp->myFd, &rdSet))
- FD_CLR (endp->myFd, &exSet) ;
-
-#if 0
-#error XXX need to copy data to buffer and *len
-#endif
-
- freeBufferArray (endp->outBuffer) ;
-
- endp->outBuffer = NULL ;
- endp->outBufferIdx = 0 ;
- endp->outIndex = 0 ;
- endp->outProgressCbk = NULL ;
- endp->outDoneCbk = NULL ;
- endp->outClientData = NULL ;
- endp->outSize = 0 ;
- endp->outAmtWritten = 0 ;
-}
-
-/* queue up a new timeout request. to go off at a specific time. */
-TimeoutId prepareWake (EndpTCB func, time_t timeToWake, void *clientData)
-{
- TimeoutId id ;
- time_t now = theTime() ;
-
- if (now > timeToWake)
- return 0 ;
-
- id = timerElemAdd (timeToWake,func,clientData) ;
-
-#if 0
- d_printf (1,"Preparing wake %d at date %ld for %d seconds\n",
- (int) id, (long) now, timeToWake - now) ;
-#endif
-
- return id ;
-}
-
-
-/* queue up a new timeout request to off TIMETOSLEEP seconds from now */
-TimeoutId prepareSleep (EndpTCB func, int timeToSleep, void *clientData)
-{
- time_t now = theTime() ;
- TimeoutId id ;
-
- id = timerElemAdd (now + timeToSleep,func,clientData) ;
-
-#if 0
- d_printf (1,"Preparing sleep %d at date %ld for %d seconds\n",
- (int) id, (long) now, timeToSleep) ;
-#endif
-
- return id ;
-}
-
-
-/* Updates a an existing timeout request to go off TIMETOSLEEP seconds from
- now, or queues a new request. Always returns a new ID. */
-TimeoutId updateSleep (TimeoutId tid, EndpTCB func, int timeToSleep,
- void *clientData)
-{
- if (tid == 0)
- return prepareSleep (func, timeToSleep, clientData) ;
- else
- {
- /* XXX - quick and dirty but CPU wasteful implementation */
- removeTimeout (tid) ;
- return prepareSleep (func, timeToSleep, clientData) ;
- }
-}
-
-
-/* Remove a timeout that was previously prepared. 0 is a legal value that
- is just ignored. */
-bool removeTimeout (TimeoutId tid)
-{
- TimerElem n = timeoutQueue ;
- TimerElem p = NULL ;
-
- if (tid == 0)
- return true ;
-
- while (n != NULL && n->id != tid)
- {
- p = n ;
- n = n->next ;
- }
-
- if (n == NULL)
- return false ;
-
- if (p == NULL) /* at the head. */
- timeoutQueue = n->next ;
- else
- p->next = n->next ;
-
- n->next = timeoutPool ;
- timeoutPool = n ;
-
- timeoutQueueLength-- ;
-
- return true ;
-}
-
-
-/* The main routine. This is a near-infinite loop that drives the whole
- program. */
-void Run (void)
-{
- fd_set rSet ;
- fd_set wSet ;
- fd_set eSet ;
- unsigned long last_summary = 0 ;
-
- keepSelecting = 1 ;
- xsignal (SIGPIPE, pipeHandler) ;
-
- while (keepSelecting)
- {
- struct timeval timeout ;
- struct timeval *twait ;
- int sval ;
- unsigned int idx ;
- bool modifiedTime = false ;
-
- twait = getTimeout (&timeout) ;
-
- memcpy (&rSet,&rdSet,sizeof (rdSet)) ;
- memcpy (&wSet,&wrSet,sizeof (wrSet)) ;
- memcpy (&eSet,&exSet,sizeof (exSet)) ;
-
- if (highestFd < 0 && twait == NULL) /* no fds and no timeout */
- break ;
- else if (twait != NULL && (twait->tv_sec != 0 || twait->tv_usec != 0))
- {
- /* if we have any workprocs registered we poll rather than
- block on the fds */
- for (idx = 0 ; idx < priorityCount ; idx++)
- if (priorityList [idx] != NULL &&
- priorityList [idx]->workCbk != NULL)
- {
- modifiedTime = true ;
- twait->tv_sec = 0 ;
- twait->tv_usec = 0 ;
-
- break ;
- }
- }
-
- /* calculate host backlog statistics */
- TMRstart(TMR_BACKLOGSTATS);
- gCalcHostBlStat ();
- TMRstop(TMR_BACKLOGSTATS);
-
- TMRstart(TMR_IDLE);
- sval = select (highestFd + 1, &rSet, &wSet, &eSet, twait) ;
- TMRstop(TMR_IDLE);
-
- timePasses () ;
- if (innconf->timer)
- {
- unsigned long now = TMRnow () ;
- if (last_summary == 0
- || (long) (now - last_summary) > (innconf->timer * 1000))
- {
- TMRsummary ("ME", timer_name) ;
- last_summary = now;
- }
- }
-
- if (sval == 0 && twait == NULL)
- die ("No fd's ready and no timeouts") ;
- else if (sval < 0 && errno == EINTR)
- {
- handleSignals () ;
- }
- else if (sval < 0)
- {
- syswarn ("ME exception: select failed: %d", sval) ;
- stopRun () ;
- }
- else if (sval > 0)
- {
- IoStatus rval ;
- int readyCount = sval ;
- int endpointsServiced = 1 ;
-
- handleSignals() ;
-
- for (idx = 0 ; idx < priorityCount ; idx++)
- {
- EndPoint ep = priorityList [idx] ;
- bool specialCheck = false ;
-
- if (readyCount > 0 && ep != NULL)
- {
- int fd = ep->myFd ;
- int selectHit = 0, readMiss = 0, writeMiss = 0 ;
-
- /* Every SELECT_RATIO times we service an endpoint in this
- loop we check to see if the mainEndPoint fd is ready to
- read or write. If so we process it and do the current
- endpoint next time around. */
- if (((endpointsServiced % (SELECT_RATIO + 1)) == 0) &&
- ep != mainEndPoint && mainEndPoint != NULL &&
- !mainEpIsReg)
- {
- fd_set trSet, twSet ;
- struct timeval tw ;
- int checkRead = FD_ISSET (mainEndPoint->myFd,&rdSet) ;
- int checkWrite = FD_ISSET (mainEndPoint->myFd,&wrSet) ;
-
- endpointsServiced++;
-
- if (checkRead || checkWrite)
- {
- fd = mainEndPoint->myFd ;
-
- tw.tv_sec = tw.tv_usec = 0 ;
- memset (&trSet,0,sizeof (trSet)) ;
- memset (&twSet,0,sizeof (twSet)) ;
-
- if (checkRead)
- FD_SET (fd,&trSet) ;
- if (checkWrite)
- FD_SET (fd,&twSet) ;
-
- sval = select (fd + 1,&trSet,&twSet,0,&tw) ;
-
- if (sval > 0)
- {
- idx-- ;
- ep = mainEndPoint ;
- specialCheck = true ;
- if (checkRead && FD_ISSET (fd,&trSet))
- {
- FD_SET (fd,&rSet) ;
- readyCount++ ;
- }
- if (checkWrite && FD_ISSET (fd,&twSet))
- {
- FD_SET (fd,&wSet) ;
- readyCount++ ;
- }
- }
- else if (sval < 0)
- {
- syswarn ("ME exception: select failed: %d",
- sval) ;
- stopRun () ;
- return ;
- }
- else
- fd = ep->myFd ; /* back to original fd. */
- }
- }
-
- FD_CLR (fd, &exSet) ;
-
- if (FD_ISSET (fd,&rSet))
- {
- readyCount-- ;
- endpointsServiced++ ;
- selectHit = 1 ;
-
- if ((rval = doRead (ep)) != IoIncomplete)
- {
- Buffer *buff = ep->inBuffer ;
-
- FD_CLR (fd, &rdSet) ;
-
- /* incase callback wants to issue read */
- ep->inBuffer = NULL ;
-
- if (ep->inCbk != NULL)
- (*ep->inCbk) (ep,rval,buff,ep->inClientData) ;
- else
- freeBufferArray (buff) ;
- }
- else
- {
- if ( InputFile == NULL )
- FD_SET (ep->myFd, &exSet) ;
- }
- }
- else if (FD_ISSET(fd,&rdSet))
- readMiss = 1;
-
- /* get it again as the read callback may have deleted the */
- /* endpoint */
- if (specialCheck)
- ep = mainEndPoint ;
- else
- ep = priorityList [idx] ;
-
- if (readyCount > 0 && ep != NULL && FD_ISSET (fd,&wSet))
- {
- readyCount-- ;
- endpointsServiced++ ;
- selectHit = 1 ;
-
- if ((rval = doWrite (ep)) != IoIncomplete &&
- rval != IoProgress)
- {
- Buffer *buff = ep->outBuffer ;
-
- FD_CLR (fd, &wrSet) ;
-
- /* incase callback wants to issue a write */
- ep->outBuffer = NULL ;
-
- if (ep->outDoneCbk != NULL)
- (*ep->outDoneCbk) (ep,rval,buff,ep->outClientData) ;
- else
- freeBufferArray (buff) ;
- }
- else if (rval == IoProgress)
- {
- Buffer *buff = ep->outBuffer ;
-
- if (ep->outProgressCbk != NULL)
- (*ep->outProgressCbk) (ep,rval,buff,ep->outClientData) ;
- }
- else
- {
- FD_SET (ep->myFd, &exSet) ;
- }
- }
- else if (FD_ISSET(fd,&wrSet))
- writeMiss = 1;
-
- /* get it again as the write callback may have deleted the */
- /* endpoint */
- if (specialCheck)
- ep = mainEndPoint ;
- else
- ep = priorityList [idx] ;
-
- if (ep != NULL)
- {
- ep->selectHits *= 0.9 ;
- if (selectHit)
- ep->selectHits += 1.0 ;
- else if (readMiss && writeMiss)
- ep->selectHits -= 1.0 ;
- }
-
- if (readyCount > 0 && ep != NULL && FD_ISSET (fd,&eSet))
- doExcept (ep) ;
- }
- }
-
- reorderPriorityList () ;
- }
- else if (sval == 0 && !modifiedTime)
- doTimeout () ;
-
- /* now we're done processing all read fds and/or the
- timeout(s). Next we do the work callbacks for all the endpoints
- whose fds weren't ready. */
- for (idx = 0 ; idx < priorityCount ; idx++)
- {
- EndPoint ep = priorityList [idx] ;
-
- if (ep != NULL)
- {
- int fd = ep->myFd ;
-
- if ( !FD_ISSET (fd,&rSet) && !FD_ISSET (fd,&wSet) )
- if (ep->workCbk != NULL)
- {
- EndpWorkCbk func = ep->workCbk ;
- void *data = ep->workData ;
-
- ep->workCbk = NULL ;
- ep->workData = NULL ;
- TMRstart(TMR_CALLBACK);
- func (ep,data) ;
- TMRstop(TMR_CALLBACK);
- }
-
- }
- }
- }
-}
-
-void *addWorkCallback (EndPoint endp, EndpWorkCbk cbk, void *data)
-{
- void *oldBk = endp->workData ;
-
- endp->workCbk = cbk ;
- endp->workData = data ;
-
- return oldBk ;
-}
-
-/* Tell the Run routine to stop next time around. */
-void stopRun (void)
-{
- keepSelecting = 0 ;
-}
-
-
-int endPointErrno (EndPoint endp)
-{
- return endp->myErrno ;
-}
-
-bool readIsPending (EndPoint endp)
-{
- return (endp->inBuffer != NULL ? true : false) ;
-}
-
-bool writeIsPending (EndPoint endp)
-{
- return (endp->outBuffer != NULL ? true : false) ;
-}
-
-void setMainEndPoint (EndPoint endp)
-{
- struct stat buf ;
-
- mainEndPoint = endp ;
- if (endp->myFd >= 0 && fstat (endp->myFd,&buf) < 0)
- syslog (LOG_ERR,"Can't fstat mainEndPoint fd (%d): %m", endp->myFd) ;
- else if (endp->myFd < 0)
- syslog (LOG_ERR,"Negative fd for mainEndPoint???") ;
- else
- mainEpIsReg = (S_ISREG(buf.st_mode) ? true : false) ;
-}
-
-int getMainEndPointFd (void)
-{
- return(mainEndPoint->myFd) ;
-}
-
-void freeTimeoutQueue (void)
-{
- TimerElem p, n ;
-
- p = timeoutQueue ;
- while (p)
- {
- n = p->next ;
- p->next = timeoutPool ;
- timeoutPool = p;
- p = n ;
- timeoutQueueLength-- ;
- }
-}
-
-
-/***********************************************************************/
-/* STATIC FUNCTIONS BELOW HERE */
-/***********************************************************************/
-
-
-/*
- * called when the file descriptor on this endpoint is read ready.
- */
-static IoStatus doRead (EndPoint endp)
-{
- int i = 0 ;
- unsigned int idx ;
- unsigned int bCount = 0 ;
- struct iovec *vp = NULL ;
- Buffer *buffers = endp->inBuffer ;
- unsigned int currIdx = endp->inBufferIdx ;
- size_t amt = 0 ;
- IoStatus rval = IoIncomplete ;
-
- TMRstart(TMR_READ);
- for (i = currIdx ; buffers && buffers [i] != NULL ; i++)
- bCount++ ;
-
- bCount = (bCount > IOV_MAX ? IOV_MAX : bCount) ;
-
- i = 0 ;
-
- /* now set up the iovecs for the readv */
- if (bCount > 0)
- {
- char *bbase ;
- size_t bds, bs ;
-
- vp = xcalloc (bCount, sizeof(struct iovec)) ;
-
- bbase = bufferBase (buffers[currIdx]) ;
- bds = bufferDataSize (buffers[currIdx]) ;
- bs = bufferSize (buffers [currIdx]) ;
-
- /* inIndex is an index in the virtual array of the read, not directly
- into the buffer. */
- vp[0].iov_base = bbase + bds + endp->inIndex ;
- vp[0].iov_len = bs - bds - endp->inIndex ;
-
- amt = vp[0].iov_len ;
-
- for (idx = currIdx + 1 ; idx < bCount ; idx++)
- {
- bbase = bufferBase (buffers[idx]) ;
- bds = bufferDataSize (buffers[idx]) ;
- bs = bufferSize (buffers [idx]) ;
-
- vp [idx].iov_base = bbase ;
- vp [idx].iov_len = bs - bds ;
- amt += (bs - bds) ;
- }
-
- i = readv (endp->myFd,vp,(int) bCount) ;
-
- if (i > 0)
- {
- size_t readAmt = (size_t) i ;
-
- endp->inAmtRead += readAmt ;
-
- /* check if we filled the first buffer */
- if (readAmt >= (size_t) vp[0].iov_len)
- { /* we did */
- bufferIncrDataSize (buffers[currIdx], vp[0].iov_len) ;
- readAmt -= vp [0].iov_len ;
- endp->inBufferIdx++ ;
- }
- else
- {
- endp->inIndex += readAmt ;
- bufferIncrDataSize (buffers[currIdx], readAmt) ;
- readAmt = 0 ;
- }
-
- /* now check the rest of the buffers */
- for (idx = 1 ; readAmt > 0 ; idx++)
- {
- ASSERT (idx < bCount) ;
-
- bs = bufferSize (buffers [currIdx + idx]) ;
- bbase = bufferBase (buffers [currIdx + idx]) ;
- bds = bufferDataSize (buffers [currIdx + idx]) ;
-
- if (readAmt >= (bs - bds))
- {
- bufferSetDataSize (buffers [currIdx + idx],bs) ;
- readAmt -= bs ;
- endp->inBufferIdx++ ;
- }
- else
- {
- endp->inIndex = readAmt ;
- bufferIncrDataSize (buffers [currIdx + idx], readAmt) ;
- memset (bbase + bds + readAmt, 0, bs - bds - readAmt) ;
- readAmt = 0 ;
- }
- }
-
- if (endp->inAmtRead >= endp->inMinLen)
- {
- endp->inIndex = 0 ;
- rval = IoDone ;
- }
- }
- else if (i < 0 && errno != EINTR && errno != EAGAIN)
- {
- endp->myErrno = errno ;
- rval = IoFailed ;
- }
- else if (i < 0 && errno == EINTR)
- {
- handleSignals () ;
- }
- else if (i == 0)
- rval = IoEOF ;
- else /* i < 0 && errno == EAGAIN */
- rval = IoIncomplete ;
-
- free (vp) ;
- }
- else
- rval = IoDone ;
- TMRstop(TMR_READ);
- return rval ;
-}
-
-/* called when the file descriptor on the endpoint is write ready. */
-static IoStatus doWrite (EndPoint endp)
-{
- unsigned int idx ;
- int i = 0 ;
- size_t amt = 0 ;
- unsigned int bCount = 0 ;
- struct iovec *vp = NULL ;
- Buffer *buffers = endp->outBuffer ;
- unsigned int currIdx = endp->outBufferIdx ;
- IoStatus rval = IoIncomplete ;
-
- TMRstart(TMR_WRITE);
- for (i = currIdx ; buffers && buffers [i] != NULL ; i++)
- bCount++ ;
-
- bCount = (bCount > IOV_MAX ? IOV_MAX : bCount) ;
-
- i = 0 ;
-
- if (bCount > 0)
- {
- vp = xcalloc (bCount, sizeof(struct iovec)) ;
-
- vp[0].iov_base = bufferBase (buffers [currIdx]) ;
- vp[0].iov_base = (char *) vp[0].iov_base + endp->outIndex ;
- vp[0].iov_len = bufferDataSize (buffers [currIdx]) - endp->outIndex ;
-
- amt = vp[0].iov_len ;
-
- for (idx = 1 ; idx < bCount ; idx++)
- {
- vp [idx].iov_base = bufferBase (buffers [idx + currIdx]) ;
- vp [idx].iov_len = bufferDataSize (buffers [idx + currIdx]) ;
- amt += vp[idx].iov_len ;
- }
-
-#if 1
- if (debugWrites)
- {
- /* nasty mixing, but stderr is unbuffered usually. It's debugging only */
- d_printf (5,"About to write this:================================\n") ;
- writev (2,vp,bCount) ;
- d_printf (5,"end=================================================\n") ;
- }
-
-#endif
-
- ASSERT (endp->myFd >= 0) ;
- ASSERT (vp != 0) ;
- ASSERT (bCount > 0) ;
-
- i = writev (endp->myFd,vp,(int) bCount) ;
-
- if (i > 0)
- {
- size_t writeAmt = (size_t) i ;
-
- endp->outAmtWritten += writeAmt ;
-
- /* now figure out which buffers got completely written */
- for (idx = 0 ; writeAmt > 0 ; idx++)
- {
- if (writeAmt >= (size_t) vp[idx].iov_len)
- {
- endp->outBufferIdx++ ;
- endp->outIndex = 0 ;
- writeAmt -= vp [idx].iov_len ;
- }
- else
- {
- /* this buffer was not completly written */
- endp->outIndex += writeAmt ;
- writeAmt = 0 ;
- }
- }
-
- if (endp->outAmtWritten == endp->outSize)
- rval = IoDone ;
- else
- rval = IoProgress ;
- }
- else if (i < 0 && errno == EINTR)
- {
- handleSignals () ;
- }
- else if (i < 0 && errno == EAGAIN)
- {
- rval = IoIncomplete ;
- }
- else if (i < 0)
- {
- endp->myErrno = errno ;
- rval = IoFailed ;
- }
- else
- d_printf (1,"Wrote 0 bytes in doWrite()?\n") ;
-
- free (vp) ;
- }
- else
- rval = IoDone ;
-
- TMRstop(TMR_WRITE);
- return rval ;
-}
-
-
-static IoStatus doExcept (EndPoint endp)
-{
- int optval;
- socklen_t size ;
- int fd = endPointFd (endp) ;
-
- if (getsockopt (fd, SOL_SOCKET, SO_ERROR,
- (char *) &optval, &size) != 0)
- syswarn ("ME exception: getsockopt (%d)", fd) ;
- else if (optval != 0)
- {
- errno = optval ;
- syswarn ("ME exception: fd %d", fd) ;
- }
- else
- syswarn ("ME exception: fd %d: Unknown error", fd) ;
-
-#if 0
- sleep (5) ;
- abort () ;
-#endif
-
- /* Not reached */
- return IoFailed ;
-}
-
-#if 0
-static void endPointPrint (EndPoint ep, FILE *fp)
-{
- fprintf (fp,"EndPoint [%p]: fd [%d]\n",(void *) ep, ep->myFd) ;
-}
-#endif
-
-static void signalHandler (int s)
-{
- sigFlags[s] = 1 ;
-#ifndef HAVE_SIGACTION
- xsignal (s, signalHandler) ;
-#endif
-}
-
-
-static void pipeHandler (int s)
-{
- xsignal (s, pipeHandler) ;
-}
-
-
-/* compare the hit ratio of two endpoint for qsort. We're sorting the
- endpoints on their relative activity */
-static int hitCompare (const void *v1, const void *v2)
-{
- const struct endpoint_s *e1 = *((const struct endpoint_s * const *) v1) ;
- const struct endpoint_s *e2 = *((const struct endpoint_s * const *) v2) ;
- double e1Hit = e1->selectHits ;
- double e2Hit = e2->selectHits ;
-
- if (e1 == mainEndPoint)
- return -1 ;
- else if (e2 == mainEndPoint)
- return 1 ;
- else if (e1Hit < e2Hit)
- return 1 ;
- else if (e1Hit > e2Hit)
- return -1 ;
-
- return 0 ;
-}
-
-
-
-/* We maintain the endpoints in order of the percent times they're ready
- for read/write when they've been selected. This helps us favour the more
- active endpoints. */
-static void reorderPriorityList (void)
-{
- unsigned int i, j ;
- static int thisTime = 4;
-
- /* only sort every 4th time since it's so expensive */
- if (--thisTime > 0)
- return ;
-
- thisTime = 4;
-
- for (i = j = 0; i < priorityCount; i++)
- if (priorityList [i] != NULL)
- {
- if (i != j)
- priorityList [j] = priorityList [i] ;
- j++ ;
- }
-
- for (i = j; i < priorityCount; i++)
- priorityList [ i ] = NULL;
-
- priorityCount = j;
-
- qsort (priorityList, (size_t)priorityCount, sizeof (EndPoint), &hitCompare);
-}
-
-
-#define TIMEOUT_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (TimerElemStruct)))
-
-/* create a new timeout data structure properly initialized. */
-static TimerElem newTimerElem (TimeoutId i, time_t w, EndpTCB f, void *d)
-{
- TimerElem p ;
-
- if (timeoutPool == NULL)
- {
- unsigned int j ;
-
- timeoutPool = xmalloc (sizeof(TimerElemStruct) * TIMEOUT_POOL_SIZE) ;
-
- for (j = 0; j < TIMEOUT_POOL_SIZE - 1; j++)
- timeoutPool[j] . next = &(timeoutPool [j + 1]) ;
- timeoutPool [TIMEOUT_POOL_SIZE-1] . next = NULL ;
- }
-
- p = timeoutPool ;
- timeoutPool = timeoutPool->next ;
-
- ASSERT (p != NULL) ;
-
- p->id = i ;
- p->when = w ;
- p->func = f ;
- p->data = d ;
- p->next = NULL ;
-
- return p ;
-}
-
-
-
-/* add a new timeout structure to the global list. */
-static TimeoutId timerElemAdd (time_t when, EndpTCB func, void *data)
-{
- TimerElem p = newTimerElem (++nextId ? nextId : ++nextId,when,func,data) ;
- TimerElem n = timeoutQueue ;
- TimerElem q = NULL ;
-
- while (n != NULL && n->when <= when)
- {
- q = n ;
- n = n->next ;
- }
-
- if (n == NULL && q == NULL) /* empty list so put at head */
- timeoutQueue = p ;
- else if (q == NULL) /* put at head of list */
- {
- p->next = timeoutQueue ;
- timeoutQueue = p ;
- }
- else if (n == NULL) /* put at end of list */
- q->next = p ;
- else /* in middle of list */
- {
- p->next = q->next ;
- q->next = p ;
- }
-
- timeoutQueueLength++ ;
-
- return p->id ;
-}
-
-
-/* Fills in TOUT with the timeout to use on the next call to
- * select. Returns TOUT. If there is no timeout, then returns NULL. If the
- * timeout has already passed, then it calls the timeout handling routine
- * first.
- */
-static struct timeval *getTimeout (struct timeval *tout)
-{
- struct timeval *rval = NULL ;
-
- if (timeoutQueue != NULL)
- {
- time_t now = theTime() ;
-
- while (timeoutQueue && now > timeoutQueue->when)
- doTimeout () ;
-
- if (timeoutQueue != NULL && now == timeoutQueue->when)
- {
- tout->tv_sec = 0 ;
- tout->tv_usec = 0 ;
- rval = tout ;
- }
- else if (timeoutQueue != NULL)
- {
- tout->tv_sec = timeoutQueue->when - now ;
- tout->tv_usec = 0 ;
- rval = tout ;
- }
- }
-
- return rval ;
-}
-
-
-
-
-
-
-static void doTimeout (void)
-{
- EndpTCB cbk = timeoutQueue->func ;
- void *data = timeoutQueue->data ;
- TimerElem p = timeoutQueue ;
- TimeoutId tid = timeoutQueue->id ;
-
- timeoutQueue = timeoutQueue->next ;
-
- p->next = timeoutPool ;
- timeoutPool = p ;
-
- timeoutQueueLength-- ;
-
- if (cbk)
- (*cbk) (tid, data) ; /* call the callback function */
-}
-
-
-
-
-
-#if defined (WANT_MAIN)
-
-
-#define BUFF_SIZE 100
-
-
-void timerCallback (void *cd) ;
-void timerCallback (void *cd)
-{
- d_printf (1,"Callback \n") ;
-}
-
-
-void lineIsWritten (EndPoint ep, IoStatus status, Buffer *buffer, void *data);
-void lineIsWritten (EndPoint ep, IoStatus status, Buffer *buffer, void *data)
-{
- int i ;
-
- if (status == IoDone)
- d_printf (1,"LINE was written\n") ;
- else
- {
- int oldErrno = errno ;
-
- errno = endPointErrno (ep) ;
- perror ("write failed") ;
- errno = oldErrno ;
- }
-
- for (i = 0 ; buffer && buffer [i] ; i++)
- delBuffer (buffer [i]) ;
-}
-
-void lineIsRead (EndPoint myEp, IoStatus status, Buffer *buffer, void *data);
-void lineIsRead (EndPoint myEp, IoStatus status, Buffer *buffer, void *d)
-{
- Buffer *writeBuffers, *readBuffers ;
- Buffer newBuff1, newBuff2 ;
- Buffer newInputBuffer ;
- char *data, *p ;
- size_t len ;
-
- if (status == IoFailed)
- {
- int oldErrno = errno ;
-
- errno = endPointErrno (myEp) ;
- perror ("read failed") ;
- errno = oldErrno ;
-
- return ;
- }
- else if (status == IoEOF)
- {
- d_printf (1,"EOF on endpoint.\n") ;
- delEndPoint (myEp) ;
-
- return ;
- }
-
-
- data = bufferBase (buffer[0]) ;
- len = bufferDataSize (buffer[0]) ;
-
- if (data [len - 1] == '\r' || data [len - 1] == '\n')
- bufferDecrDataSize (buffer [0],1) ;
- if (data [len - 1] == '\r' || data [len - 1] == '\n')
- bufferDecrDataSize (buffer [0],1) ;
-
- data [len] = '\0' ;
-
- d_printf (1,"Got a line: %s\n", data) ;
-
- newBuff1 = newBuffer (len + 50) ;
- newBuff2 = newBuffer (len + 50) ;
- newInputBuffer = newBuffer (BUFF_SIZE) ;
-
- p = bufferBase (newBuff1) ;
- strcpy (p, "Thanks for that \"") ;
- bufferSetDataSize (newBuff1,strlen (p)) ;
-
- p = bufferBase (newBuff2) ;
- strcpy (p,"\" very tasty\n") ;
- bufferSetDataSize (newBuff2,strlen (p)) ;
-
- writeBuffers = makeBufferArray (newBuff1,buffer[0],newBuff2,NULL) ;
- readBuffers = makeBufferArray (newInputBuffer,NULL) ;
-
- prepareWrite (myEp,writeBuffers,lineIsWritten,NULL) ;
- prepareRead (myEp,readBuffers,lineIsRead,NULL,1) ;
-
-#if 0
- myEp->registerWake (&timerCallback,theTime() + 7,0) ;
-#endif
-}
-
-
-static void printDate (TimeoutId tid, void *data) ;
-static void printDate (TimeoutId tid, void *data)
-{
- time_t t ;
-
- t = theTime() ;
-
- d_printf (1,"Timeout (%d) time now is %ld %s",
- (int) tid,(long) t,ctime(&t)) ;
-
- if (timeoutQueue == NULL)
- {
- int ti = (rand () % 10) + 1 ;
-
- prepareSleep (printDate,ti,data) ;
- }
-}
-
-TimeoutId rm ;
-
-static void Timeout (TimeoutId tid, void *data) ;
-static void Timeout (TimeoutId tid, void *data)
-{
- static int seeded ;
- static int howMany ;
- static int i ;
- time_t t = theTime() ;
-
- if ( !seeded )
- {
- srand (t) ;
- seeded = 1 ;
- }
-
- d_printf (1,"Timeout (%d) time now is %ld %s",
- (int) tid, (long) t,ctime(&t)) ;
-
- if (timeoutQueue != NULL && timeoutQueue->next != NULL)
- d_printf (1,"%s timeout id %d\n",
- (removeTimeout (rm) ? "REMOVED" : "FAILED TO REMOVE"), rm) ;
- rm = 0 ;
-
- howMany = (rand() % 10) + (timeoutQueue == NULL ? 1 : 0) ;
-
- for (i = 0 ; i < howMany ; i++ )
- {
- TimeoutId id ;
- int count = (rand () % 30) + 1 ;
-
- id = (i % 2 == 0 ? prepareSleep (Timeout,count,data)
- : prepareWake (Timeout,t + count,data)) ;
-
- if (rm == 0)
- rm = id ;
- }
-}
-
-
-void newConn (EndPoint ep, IoStatus status, Buffer *buffer, void *d) ;
-void newConn (EndPoint ep, IoStatus status, Buffer *buffer, void *d)
-{
- EndPoint newEp ;
- struct sockaddr_in in ;
- Buffer *readBuffers ;
- Buffer newBuff = newBuffer (BUFF_SIZE) ;
- int len = sizeof (in) ;
- int fd ;
-
- memset (&in, 0, sizeof (in)) ;
-
- fd = accept (ep->myFd, (struct sockaddr *) &in, &len) ;
-
- if (fd < 0)
- {
- perror ("::accept") ;
- return ;
- }
-
- newEp = newEndPoint (fd) ;
-
- prepareRead (ep, NULL, newConn,NULL,0) ;
-
- readBuffers = makeBufferArray (newBuff,NULL) ;
-
- prepareRead (newEp, readBuffers, lineIsRead, NULL, 1) ;
-
- d_printf (1,"Set up a new connection\n");
-}
-
-
-int main (int argc, char **argv)
-{
- EndPoint accConn ;
- struct sockaddr_in accNet ;
- int accFd = socket (AF_INET,SOCK_STREAM,0) ;
- unsigned short port = atoi (argc > 1 ? argv[1] : "10000") ;
- time_t t = theTime() ;
-
-
- program = strrchr (argv[0],'/') ;
-
- if (!program)
- program = argv [0] ;
- else
- program++ ;
-
- ASSERT (accFd >= 0) ;
-
- memset (&accNet,0,sizeof (accNet)) ;
- accNet.sin_family = AF_INET ;
- accNet.sin_addr.s_addr = htonl (INADDR_ANY) ;
- accNet.sin_port = htons (port) ;
-
-#ifdef LOG_PERROR
- openlog (program, LOG_PERROR | LOG_PID, LOG_NEWS) ;
-#else
- openlog (program, LOG_PID, LOG_NEWS) ;
-#endif
-
- if (bind (accFd, (struct sockaddr *) &accNet, sizeof (accNet)) < 0)
- {
- perror ("bind: %m") ;
- exit (1) ;
- }
-
- listen (accFd,5) ;
-
- accConn = newEndPoint (accFd) ;
-
- prepareRead (accConn,NULL,newConn,NULL,0) ;
-
- prepareSleep (Timeout,5,(void *) 0x10) ;
-
- t = theTime() ;
- d_printf (1,"Time now is %s",ctime(&t)) ;
-
- prepareWake (printDate,t + 16,NULL) ;
-
- Run () ;
-
- return 0;
-}
-#endif /* WANT_MAIN */
-
-/* Probably doesn't do the right thing for SIGCHLD */
-void setSigHandler (int signum, void (*ptr)(int))
-{
- unsigned int i ;
-
- if (sigHandlers == NULL)
- {
- sigHandlers = xmalloc (sizeof(sigfn) * NSIG) ;
- sigFlags = xmalloc (sizeof(sig_atomic_t) * NSIG) ;
- for (i = 0 ; i < NSIG ; i++)
- {
- sigHandlers [i] = NULL ;
- sigFlags [i] = 0 ;
- }
- }
-
- if (signum >= NSIG)
- {
- syslog (LOG_ERR,"ME signal number bigger than NSIG: %d vs %d",
- signum,NSIG) ;
- return ;
- }
-
- if (xsignal (signum, signalHandler) == SIG_ERR)
- die ("signal failed: %s", strerror(errno)) ;
-
- sigHandlers[signum] = ptr ;
-}
-
-static void handleSignals (void)
-{
- int i ;
-#if defined(USE_SIGVEC)
- int mask ;
-#endif
-
- for (i = 1; i < NSIG; i++)
- {
- if (sigFlags[i])
- {
-#if defined(USE_SIGACTION)
- sigset_t set, oset ;
-
- if (sigemptyset (&set) != 0 || sigaddset (&set, i) != 0)
- die ("sigemptyset or sigaddset failed") ;
- if (sigprocmask (SIG_BLOCK, &set, &oset) != 0)
- die ("sigprocmask failed: %s", strerror(errno)) ;
-#elif defined(USE_SIGVEC)
-# ifndef sigmask
-# define sigmask(s) (1 << ((s) - 1))
-# endif
- int mask ;
-
- mask = sigblock (sigmask(i)) ;
-#elif defined(USE_SIGSET)
- if (sighold (i) != 0)
- die ("sighold failed: %s", strerror(errno)) ;
-#else
- /* hope for the best */
-#endif
-
- sigFlags[i] = 0;
-
- if (sigHandlers[i] != NULL &&
- sigHandlers[i] != SIG_IGN &&
- sigHandlers[i] != SIG_DFL)
- (sigHandlers[i])(i) ;
-
-#if defined(USE_SIGACTION)
- if (sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL) != 0)
- die ("sigprocmask failed: %s", strerror(errno)) ;
-#elif defined(USE_SIGVEC)
- sigsetmask (mask) ;
-#elif defined(USE_SIGSET)
- if (sigrelse (i) != 0)
- die ("sigrelse failed: %s", strerror(errno)) ;
-#else
- /* hope for the best */
-#endif
- }
- }
-}
-
-
-int endpointConfigLoadCbk (void *data)
-{
- FILE *fp = (FILE *) data ;
- long ival ;
- int rval = 1 ;
-
- if (getInteger (topScope,"stdio-fdmax",&ival,NO_INHERIT))
- {
- stdioFdMax = ival ;
-
-#if ! defined (FD_SETSIZE)
-
- if (stdioFdMax > 0)
- {
- logOrPrint (LOG_ERR,fp,NO_STDIO_FDMAX) ;
- stdioFdMax = 0 ;
- rval = 0 ;
- }
-
-#else
-
- if (stdioFdMax > FD_SETSIZE)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s is higher"
- " than maximum of %ld. Using %ld","stdio-fdmax",
- ival,"global scope",
- (long) FD_SETSIZE, (long) FD_SETSIZE) ;
- stdioFdMax = FD_SETSIZE ;
- rval = 0 ;
- }
-
-#endif
-
- }
- else
- stdioFdMax = 0 ;
-
- return rval ;
-}
-
-
-
-#if 0
-/* definitely not the fastest, but the most portable way to find the first
- set bit in a mask */
-static int ff_set (fd_set *set,unsigned int start)
-{
- unsigned int i ;
-
- for (i = start ; i < FD_SETSIZE ; i++)
- if (FD_ISSET (i,set))
- return (int) i ;
-
- return -1 ;
-}
-
-
-static int ff_free (fd_set *set, unsigned int start)
-{
- unsigned int i ;
-
- for (i = start ; i < FD_SETSIZE ; i++)
- if (!FD_ISSET (i,set))
- return i ;
-
-
- return -1 ;
-}
-#endif
-
-
-static void endpointCleanup (void)
-{
- free (endPoints) ;
- free (priorityList) ;
- free (sigHandlers) ;
- endPoints = NULL ;
- priorityList = NULL ;
- sigHandlers = NULL ;
-}
+++ /dev/null
-/* $Id: endpoint.h 6648 2004-01-25 20:07:11Z rra $
-**
-** The public interface to the Endpoint class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The EndPoint objects are encapsulations of file descriptors that normally
-** do blocking i/o (i.e. NOT fd's hooked to a disk file). The EndPoint class
-** provides methods for reqesting read/writes to happen when next possible
-** and for the requestor to be notified when the i/o is complete (or failed
-** for some reason). Facilities for timeout notifications are provided too.
-**
-** We should add a way to cancel prepared read/write.
-*/
-
-#if ! defined ( endpoint_h__ )
-#define endpoint_h__
-
-#include "misc.h"
-
-
-#define clearTimer(timerId) \
- do {\
- if((timerId)!=0) { \
- removeTimeout(timerId); \
- timerId=0; \
- } \
- }while(0)
-
-
-
-/* These typedefs really lives in misc.h
- *
- *****************************************
- *
- * The basic (opqaue to the outside world) type.
- *
- * typedef struct endpoint_s *EndPoint ;
- *
- *****************************************
- *
- * The returns status of an IO request
- *
- * typedef enum {
- * IoDone, i/o completed successfully
- * IoIncomplete, i/o still got more to read/write
- * IoProgress, i/o still got more to read/write
- * IoFailed i/o failed
- * } IoStatus ;
- *
- * The completion callbacks are never called with the status IoIncomplete or
- * IoProgress.
- *
- *****************************************
- *
- * typedef for function callback when IO is complete (or failed).
- * E is the EndPoint
- * I is the status of the IO
- * B is the buffer the IO was to read to or write from.
- * D is the client data originally given to prepare{Write,Read}
- *
- * typedef void (*EndpRWCB) (EndPoint e, IoStatus i, Buffer b, void *d) ;
- *
- *****************************************
- *
- * typedef for function callback when a timer has gone off. D is the client
- * data given to prepare{Sleep,Wake}
- *
- * typedef void (*EndpTCB) (void *d) ;
- *
- */
-
-/* create a new EndPoint hooked up to the given file descriptor */
-EndPoint newEndPoint (int fd) ;
-
-/* shutdown the file descriptor and delete the endpoint. */
-void delEndPoint (EndPoint endp) ;
-
-/* return the file descriptor the endpoint is managing */
-int endPointFd (EndPoint endp) ;
-
-/* Request a read when available. Reads MINLEN bytes into the
- * buffers in BUFFS. BUFFS is an array of Buffers, the last of which
- * must be NULL. Note that ownership of BUFFS is never asserted, but
- * the ownership of the Buffers in it is. So if an EndPoint is
- * deleted while a read is pending the Buffers will be released, but
- * the array won't be. If MINLEN is 0 then the buffers must be
- * filled. The FUNC function gets called when the read is
- * complete. CLIENTDATA is simply passed back to the
- * callback. Returns non-zero if can be scheduled for processing.
- */
-int prepareRead (EndPoint endp,
- Buffer *buffs,
- EndpRWCB func,
- void *clientData,
- int minlen) ;
-
-/* Request a write when possible. All the data in the buffers in
- * BUFFS will be written out the endpoint. BUFFS is a NULL
- * terminated array of Buffers. See prepareWrite for a discussion on
- * the ownership of BUFFS and the Buffers inside BUFFS. The PROGRESS
- * callback function will be called and the CLIENTDATA value will be
- * passed through to it whenever any data is written except for the
- * final write. The DONE callback function will be called and the
- * CLIENTDATA value will be passed through to it after the final write.
- * Returns non-zero if scheduled succesfully.
- */
-int prepareWrite (EndPoint endp,
- Buffer *buffs,
- EndpRWCB progress,
- EndpRWCB done,
- void *clientData) ;
-
-/* cancel any outstanding reads. */
-void cancelRead (EndPoint endp) ;
-
-/* cancel any outstanding writes. */
-void cancelWrite (EndPoint endp, char *buffer, size_t *len) ;
-
-/* return true if prepareRead has been called, but not serviced yet */
-bool readIsPending (EndPoint endp) ;
-
-/* Request a wakeup at a given time. */
-TimeoutId prepareWake (EndpTCB func,
- time_t timeToWake,
- void *clientData) ;
-
-/* return true if prepareWrite has been called, but not serviced yet */
-bool writeIsPending (EndPoint endp) ;
-
-/* Requests a wakeup TIMETOSLEEP seconds from now. */
-TimeoutId prepareSleep (EndpTCB func,
- int timeToSleep,
- void *clientData) ;
-
-/* Updates tid to wakeup TIMETOSLEEP seconds from now. */
-TimeoutId updateSleep (TimeoutId tid,
- EndpTCB func,
- int timeToSleep,
- void *clientData) ;
-
- /* Set up a function to be called whenever the endpoint's file descriptor
- is NOT ready. This is called after all other fd-ready endpoints have
- been serviced. */
-void *addWorkCallback (EndPoint endp, EndpWorkCbk cbk, void *data) ;
-
-void setSigHandler (int sig, void (*)(int)) ;
-
-/* remove the timeout that was previously requested. Retuesn true if
- succesfully removed, false otherwise. 0 is a legal parameter value, in
- which case the function simply returns. */
-bool removeTimeout (TimeoutId tid) ;
-
-/* start the select loop. An initial prepare(Read|Write) or a timeout
- better have been setup. Doesn't return unless stopRun called */
-void Run (void) ;
-
-/* stops the Run loop and makes Run() return */
-void stopRun (void) ;
-
-/* returns the errno the endpoint got. */
-int endPointErrno (EndPoint endp) ;
-
-/* Tell the EndPoint class that the given EndPoint should always be
- considered first for servicing (i.e. the EndPoint connectied to innd) */
-void setMainEndPoint (EndPoint endp) ;
-
-/* returns the fd of the main endpoint */
-int getMainEndPointFd (void) ;
-
-void freeTimeoutQueue (void) ;
-
-int endpointConfigLoadCbk (void *data) ;
-
-
-/*
- * kre's cool idea for reducing the number of times time() is called.
- */
-extern time_t PrivateTime;
-
-#define theTime() (PrivateTime ? PrivateTime : time(&PrivateTime))
-#define timePasses() (PrivateTime = 0)
-
-#endif /* endpoint_h__ */
+++ /dev/null
-/* $Id: host.c 7833 2008-05-18 20:04:35Z iulius $
-**
-** The implementation of the innfeed Host class.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <float.h>
-#include <math.h>
-#include <netdb.h>
-#include <syslog.h>
-#include <sys/param.h>
-
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "configfile.h"
-#include "connection.h"
-#include "endpoint.h"
-#include "host.h"
-#include "innlistener.h"
-#include "tape.h"
-
-#define REQ 1
-#define NOTREQ 0
-#define NOTREQNOADD 2
-
-#define VALUE_OK 0
-#define VALUE_TOO_HIGH 1
-#define VALUE_TOO_LOW 2
-#define VALUE_MISSING 3
-#define VALUE_WRONG_TYPE 4
-
-#define METHOD_STATIC 0
-#define METHOD_APS 1
-#define METHOD_QUEUE 2
-#define METHOD_COMBINED 3
-
-/* the limit of number of connections open when a host is
- set to 0 to mean "infinite" */
-#define MAXCON 500
-#define MAXCONLIMIT(xx) ((xx==0)?MAXCON:xx)
-
-#define BACKLOGFILTER 0.7
-#define BACKLOGLWM 20.0
-#define BACKLOGHWM 50.0
-
-/* time between retrying blocked hosts in seconds */
-#define TRYBLOCKEDHOSTPERIOD 120
-
-extern char *configFile ;
-#if defined(hpux) || defined(__hpux) || defined(_SCO_DS)
-extern int h_errno;
-#endif
-
-/* the host keeps a couple lists of these */
-typedef struct proc_q_elem
-{
- Article article ;
- struct proc_q_elem *next ;
- struct proc_q_elem *prev ;
- time_t whenToRequeue ;
-} *ProcQElem ;
-
-typedef struct host_param_s
-{
- char *peerName;
- char *ipName;
- struct sockaddr_in *bindAddr;
-#ifdef HAVE_INET6
- struct sockaddr_in6 *bindAddr6;
-#endif
- int family;
- unsigned int articleTimeout;
- unsigned int responseTimeout;
- unsigned int initialConnections;
- unsigned int absMaxConnections;
- unsigned int maxChecks;
- unsigned short portNum;
- bool forceIPv4;
- unsigned int closePeriod;
- unsigned int dynamicMethod;
- bool wantStreaming;
- bool dropDeferred;
- bool minQueueCxn;
- double lowPassLow; /* as percentages */
- double lowPassHigh;
- double lowPassFilter;
- unsigned int backlogLimit ;
- unsigned int backlogLimitHigh ;
- double backlogFactor ;
- double dynBacklogFilter ;
- double dynBacklogLowWaterMark ;
- double dynBacklogHighWaterMark ;
- bool backlogFeedFirst ;
- char *username;
- char *password;
-} *HostParams ;
-
-struct host_s
-{
- InnListener listener ; /* who created me. */
- struct sockaddr **ipAddrs ; /* the ip addresses of the remote */
- int nextIpAddr ; /* the next ip address to hand out */
-
- Connection *connections ; /* NULL-terminated list of all connections */
- bool *cxnActive ; /* true if the corresponding cxn is active */
- bool *cxnSleeping ; /* true if the connection is sleeping */
- unsigned int maxConnections; /* maximum no of cxns controlled by method */
- unsigned int activeCxns ; /* number of connections currently active */
- unsigned int sleepingCxns ; /* number of connections currently sleeping */
- Connection blockedCxn ; /* the first connection to get the 400 banner*/
- Connection notThisCxn ; /* don't offer articles to this connection */
-
- HostParams params; /* Parameters from config file */
-
- bool remoteStreams ; /* true if remote supports streaming */
-
- ProcQElem queued ; /* articles done nothing with yet. */
- ProcQElem queuedTail ;
-
- ProcQElem processed ; /* articles given to a Connection */
- ProcQElem processedTail ;
-
- ProcQElem deferred ; /* articles which have been deferred by */
- ProcQElem deferredTail ; /* a connection */
-
- TimeoutId statsId ; /* timeout id for stats logging. */
- TimeoutId ChkCxnsId ; /* timeout id for dynamic connections */
- TimeoutId deferredId ; /* timeout id for deferred articles */
-
- Tape myTape ;
-
- bool backedUp ; /* set to true when all cxns are full */
- unsigned int backlog ; /* number of arts in `queued' queue */
- unsigned int deferLen ; /* number of arts in `deferred' queue */
-
- bool loggedModeOn ; /* true if we logged going into no-CHECK mode */
- bool loggedModeOff ; /* true if we logged going out of no-CHECK mode */
-
- bool loggedBacklog ; /* true if we already logged the fact */
- bool notifiedChangedRemBlckd ; /* true if we logged a new response 400 */
- bool removeOnReload ; /* true if host should be removed at end of
- * config reload
- */
- bool isDynamic; /* true if host created dynamically */
-
- /* these numbers get reset periodically (after a 'final' logging). */
- unsigned int artsOffered ; /* # of articles we offered to remote. */
- unsigned int artsAccepted ; /* # of articles succesfully transferred */
- unsigned int artsNotWanted ; /* # of articles remote already had */
- unsigned int artsRejected ; /* # of articles remote rejected */
- unsigned int artsDeferred ; /* # of articles remote asked us to retry */
- unsigned int artsMissing ; /* # of articles whose file was missing. */
- unsigned int artsToTape ; /* # of articles given to tape */
- unsigned int artsQueueOverflow ; /* # of articles that overflowed `queued' */
- unsigned int artsCxnDrop ; /* # of articles caught in dead cxn */
- unsigned int artsHostSleep ; /* # of articles spooled by sleeping host */
- unsigned int artsHostClose ; /* # of articles caught by closing host */
- unsigned int artsFromTape ; /* # of articles we pulled off tape */
- double artsSizeAccepted ; /* size of articles succesfully transferred */
- double artsSizeRejected ; /* size of articles remote rejected */
-
- /* Dynamic Peerage - MGF */
- unsigned int artsProcLastPeriod ; /* # of articles processed in last period */
- unsigned int secsInLastPeriod ; /* Number of seconds in last period */
- unsigned int lastCheckPoint ; /* total articles at end of last period */
- unsigned int lastSentCheckPoint ; /* total articles sent end of last period */
- unsigned int lastTotalCheckPoint ; /* total articles total end of last period */
- bool maxCxnChk ; /* check for maxConnections */
- time_t lastMaxCxnTime ; /* last time a maxConnections increased */
- time_t lastChkTime; /* last time a check was made for maxConnect */
- unsigned int nextCxnTimeChk ; /* next check for maxConnect */
-
- double backlogFilter; /* IIR filter for size of backlog */
-
- /* These numbers are as above, but for the life of the process. */
- unsigned int gArtsOffered ;
- unsigned int gArtsAccepted ;
- unsigned int gArtsNotWanted ;
- unsigned int gArtsRejected ;
- unsigned int gArtsDeferred ;
- unsigned int gArtsMissing ;
- unsigned int gArtsToTape ;
- unsigned int gArtsQueueOverflow ;
- unsigned int gArtsCxnDrop ;
- unsigned int gArtsHostSleep ;
- unsigned int gArtsHostClose ;
- unsigned int gArtsFromTape ;
- double gArtsSizeAccepted ;
- double gArtsSizeRejected ;
- unsigned int gCxnQueue ;
- unsigned int gNoQueue ;
-
- time_t firstConnectTime ; /* time of first connect. */
- time_t connectTime ; /* the time the first connection was fully
- set up (MODE STREAM and everything
- else). */
- time_t spoolTime ; /* the time the Host had to revert to
- spooling articles to tape. */
- time_t lastSpoolTime ; /* the time the last time the Host had to
- revert to spooling articles to tape. */
- time_t nextIpLookup ; /* time of last IP name resolution */
-
- char *blockedReason ; /* what the 400 from the remote says. */
-
- Host next ; /* for global list of hosts. */
-
- unsigned long dlAccum ; /* cumulative deferLen */
- unsigned int blNone ; /* number of times the backlog was 0 */
- unsigned int blFull ; /* number of times the backlog was full */
- unsigned int blQuartile[4] ; /* number of times in each quartile */
- unsigned long blAccum ; /* cumulative backlog for computing mean */
- unsigned int blCount ; /* the sample count */
-};
-
-/* A holder for the info we got out of the config file, but couldn't create
- the Host object for (normally due to lock-file problems).*/
-
-typedef struct host_holder_s
-{
- HostParams params;
- struct host_holder_s *next ;
-} *HostHolder ;
-
-
-/* These numbers are as above, but for all hosts over
- the life of the process. */
-long procArtsOffered ;
-long procArtsAccepted ;
-long procArtsNotWanted ;
-long procArtsRejected ;
-long procArtsDeferred ;
-long procArtsMissing ;
-double procArtsSizeAccepted ;
-double procArtsSizeRejected ;
-long procArtsToTape ;
-long procArtsFromTape ;
-
-static HostParams defaultParams=NULL;
-
-static HostHolder blockedHosts ; /* lists of hosts we can't lock */
-static TimeoutId tryBlockedHostsId = 0 ;
-static time_t lastStatusLog ;
-
- /*
- * Host object private methods.
- */
-static void articleGone (Host host, Connection cxn, Article article) ;
-static void hostStopSpooling (Host host) ;
-static void hostStartSpooling (Host host) ;
-static void hostLogStats (Host host, bool final) ;
-static void hostStatsTimeoutCbk (TimeoutId tid, void *data) ;
-static void hostDeferredArtCbk (TimeoutId tid, void *data) ;
-static void backlogToTape (Host host) ;
-static void queuesToTape (Host host) ;
-static bool amClosing (Host host) ;
-static void hostLogStatus (void) ;
-static void hostPrintStatus (Host host, FILE *fp) ;
-static int validateBool (FILE *fp, const char *name,
- int required, bool setval,
- scope * sc, unsigned int inh);
-static int validateReal (FILE *fp, const char *name, double low,
- double high, int required, double setval,
- scope * sc, unsigned int inh);
-static int validateInteger (FILE *fp, const char *name,
- long low, long high, int required, long setval,
- scope * sc, unsigned int inh);
-
-static HostParams newHostParams(HostParams p);
-static void freeHostParams(HostParams params);
-
-static HostHolder FindBlockedHost(const char *name);
-static void addBlockedHost(HostParams params);
-static void tryBlockedHosts(TimeoutId tid, void *data);
-static Host newHost (InnListener listener, HostParams p);
-
-static HostParams getHostInfo (void);
-static HostParams hostDetails (scope *s,
- char *name,
- bool isDefault,
- FILE *fp);
-
-static Host findHostByName (char *name) ;
-static void hostCleanup (void) ;
-static void hostAlterMaxConnections(Host host,
- unsigned int absMaxCxns, unsigned int maxCxns,
- bool makeConnect);
-
-/* article queue management functions */
-static Article remHead (ProcQElem *head, ProcQElem *tail) ;
-static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
- time_t when) ;
-static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail) ;
-
-
-
-
-
-/*
- * Host class data
- */
-
-/* if true then when a Host logs its stats, it has all its connections
- log theirs too. */
-static bool logConnectionStats = (bool) LOG_CONNECTION_STATS ;
-
-/* The frequency in seconds with which a Host will log its stats. */
-static time_t statsPeriod = STATS_PERIOD ;
-static time_t statsResetPeriod = STATS_RESET_PERIOD ;
-
-static Host gHostList = NULL ;
-
-static unsigned int gHostCount = 0 ;
-
-static unsigned int maxIpNameLen = 0 ;
-static unsigned int maxPeerNameLen = 0 ;
-
-static unsigned int hostHighwater = HOST_HIGHWATER ;
-static time_t start ;
-static char startTime [30] ; /* for ctime(3) */
-static pid_t myPid ;
-
-static char *statusFile = NULL ;
-static unsigned int dnsRetPeriod ;
-static unsigned int dnsExpPeriod ;
-
-bool genHtml = false ;
-
-/*******************************************************************/
-/* PUBLIC FUNCTIONS */
-/*******************************************************************/
-
-
-/* function called when the config file is loaded */
-int hostConfigLoadCbk (void *data)
-{
- int rval = 1, bval ;
- long iv ;
- FILE *fp = (FILE *) data ;
- char *p ;
-
-
- d_printf(1,"hostConfigLoadCbk\n");
-
- if (defaultParams)
- {
- freeHostParams(defaultParams);
- defaultParams=NULL;
- }
-
- /* get optional global defaults */
- if (getInteger (topScope,"dns-retry",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld","dns-retry",
- iv,"global scope",(long)DNS_RETRY_PERIOD) ;
- iv = DNS_RETRY_PERIOD ;
- }
- }
- else
- iv = DNS_RETRY_PERIOD ;
- dnsRetPeriod = (unsigned int) iv ;
-
-
- if (getInteger (topScope,"dns-expire",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld","dns-expire",iv,
- "global scope",(long)DNS_EXPIRE_PERIOD) ;
- iv = DNS_EXPIRE_PERIOD ;
- }
- }
- else
- iv = DNS_EXPIRE_PERIOD ;
- dnsExpPeriod = (unsigned int) iv ;
-
- if (getBool (topScope,"gen-html",&bval,NO_INHERIT))
- genHtml = (bval ? true : false) ;
- else
- genHtml = GEN_HTML ;
-
- if (getString (topScope,"status-file",&p,NO_INHERIT))
- {
- hostSetStatusFile (p) ;
- free (p) ;
- }
- else
- hostSetStatusFile (INNFEED_STATUS) ;
-
-
- if (getBool (topScope,"connection-stats",&bval,NO_INHERIT))
- logConnectionStats = (bval ? true : false) ;
- else
- logConnectionStats = (LOG_CONNECTION_STATS ? true : false) ;
-
-
- if (getInteger (topScope,"host-queue-highwater", &iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld","host-queue-highwater",
- iv,"global scope",(long) HOST_HIGHWATER) ;
- iv = HOST_HIGHWATER ;
- }
- }
- else
- iv = HOST_HIGHWATER ;
- hostHighwater = (unsigned int) iv ;
-
- if (getInteger (topScope,"stats-period",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld","stats-period",
- iv,"global scope",(long)STATS_PERIOD) ;
- iv = STATS_PERIOD ;
- }
- }
- else
- iv = STATS_PERIOD ;
- statsPeriod = (unsigned int) iv ;
-
-
- if (getInteger (topScope,"stats-reset",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld","stats-reset",iv,
- "global scope",(long)STATS_RESET_PERIOD) ;
- iv = STATS_RESET_PERIOD ;
- }
- }
- else
- iv = STATS_RESET_PERIOD ;
- statsResetPeriod = (unsigned int) iv ;
-
- defaultParams=hostDetails(topScope, NULL, true, fp);
- ASSERT(defaultParams!=NULL);
-
- return rval ;
-}
-
-/*
- * make a new HostParams structure copying an existing one
- * or from compiled defaults
- */
-
-HostParams newHostParams(HostParams p)
-{
- HostParams params;
-
- params = xmalloc (sizeof(struct host_param_s)) ;
-
- if (p != NULL)
- {
- /* Copy old stuff in */
- memcpy ((char *) params, (char *) p, sizeof(struct host_param_s));
- if (params->peerName)
- params->peerName = xstrdup(params->peerName);
- if (params->ipName)
- params->ipName = xstrdup(params->ipName);
- if (params->bindAddr)
- {
- struct sockaddr_in *s = params->bindAddr;
- params->bindAddr = xmalloc(sizeof(*s));
- memcpy(params->bindAddr, s, sizeof(*s));
- }
-#ifdef HAVE_INET6
- if (params->bindAddr6)
- {
- struct sockaddr_in6 *s = params->bindAddr6;
- params->bindAddr6 = xmalloc(sizeof(*s));
- memcpy(params->bindAddr6, s, sizeof(*s));
- }
-#endif
- }
- else
- {
- /* Fill in defaults */
- params->peerName=NULL;
- params->ipName=NULL;
- params->bindAddr=NULL;
-#ifdef HAVE_INET6
- params->bindAddr6=NULL;
-#endif
- params->family = 0;
- params->articleTimeout=ARTTOUT;
- params->responseTimeout=RESPTOUT;
- params->initialConnections=INIT_CXNS;
- params->absMaxConnections=MAX_CXNS;
- params->maxChecks=MAX_Q_SIZE;
- params->portNum=PORTNUM;
- params->forceIPv4=FORCE_IPv4;
- params->closePeriod=CLOSE_PERIOD;
- params->dynamicMethod=METHOD_STATIC;
- params->wantStreaming=STREAM;
- params->dropDeferred=false;
- params->minQueueCxn=false;
- params->lowPassLow=NOCHECKLOW;
- params->lowPassHigh=NOCHECKHIGH;
- params->lowPassFilter=FILTERVALUE;
- params->backlogLimit=BLOGLIMIT;
- params->backlogLimitHigh=BLOGLIMIT_HIGH ;
- params->backlogFactor=LIMIT_FUDGE ;
- params->dynBacklogFilter = BACKLOGFILTER ;
- params->dynBacklogLowWaterMark = BACKLOGLWM;
- params->dynBacklogHighWaterMark = BACKLOGHWM;
- params->backlogFeedFirst=false;
- params->username=NULL;
- params->password=NULL;
- }
- return (params);
-}
-
-/*
- * Free up a param structure
- */
-
-void freeHostParams(HostParams params)
-{
- ASSERT(params != NULL);
- if (params->peerName)
- free (params->peerName) ;
- if (params->ipName)
- free (params->ipName) ;
- if (params->bindAddr)
- free (params->bindAddr) ;
-#ifdef HAVE_INET6
- if (params->bindAddr6)
- free (params->bindAddr6) ;
-#endif
- free (params) ;
-}
-
-static void hostReconfigure(Host h, HostParams params)
-{
- unsigned int i, absMaxCxns ;
- double oldBacklogFilter ;
-
- if (strcmp(h->params->ipName, params->ipName) != 0)
- {
- free (h->params->ipName) ;
- h->params->ipName = xstrdup (params->ipName) ;
- h->nextIpLookup = theTime () ;
- }
-
- /* Put in new parameters
- Unfortunately we can't blat on top of absMaxConnections
- as we need to do some resizing here
- */
-
- ASSERT (h->params != NULL);
-
- oldBacklogFilter = h->params->dynBacklogFilter;
- i = h->params->absMaxConnections; /* keep old value */
- absMaxCxns = params->absMaxConnections;
- /* Use this set of params and allocate, and free
- * up the old
- */
- freeHostParams(h->params);
- h->params = params;
- h->params->absMaxConnections = i; /* restore old value */
-
- /* If the backlog filter value has changed, reset the
- * filter as the value therein will be screwy
- */
- if (h->params->dynBacklogFilter != oldBacklogFilter)
- h->backlogFilter = ((h->params->dynBacklogLowWaterMark
- + h->params->dynBacklogHighWaterMark)
- /200.0 /(1.0-h->params->dynBacklogFilter));
-
- /* We call this anyway - it does nothing if the values
- * haven't changed. This is because doing things like
- * just changing "dynamic-method" requires this call
- * to be made
- */
- hostAlterMaxConnections(h, absMaxCxns, h->maxConnections, false);
-
- for ( i = 0 ; i < MAXCONLIMIT(h->params->absMaxConnections) ; i++ )
- if (h->connections[i] != NULL)
- cxnSetCheckThresholds (h->connections[i],
- h->params->lowPassLow,
- h->params->lowPassHigh,
- h->params->lowPassFilter) ;
-
- /* XXX how to handle initCxns change? */
-}
-
-
-void configHosts (bool talkSelf)
-{
- Host nHost, h, q ;
- HostHolder hh, hi ;
- HostParams params;
-
- /* Remove the current blocked host list */
- for (hh = blockedHosts, hi = NULL ; hh != NULL ; hh = hi)
- {
- freeHostParams(hh->params);
- hi = hh->next ;
- free (hh) ;
- }
- blockedHosts = NULL ;
-
- closeDroppedArticleFile () ;
- openDroppedArticleFile () ;
-
- while ((params = getHostInfo ()) !=NULL )
- {
- h = findHostByName (params->peerName) ;
- /* We know the host isn't blocked as we cleared the blocked list */
- /* Have we already got this host up and running ?*/
- if ( h != NULL )
- {
- hostReconfigure(h, params);
- h->removeOnReload = false ; /* Don't remove at the end */
- }
- else
- {
-
- /* It's a host we haven't seen from the config file before */
- nHost = newHost (mainListener, params);
-
- if (nHost == NULL)
- {
- addBlockedHost(params);
-
- warn ("ME locked cannot setup peer %s", params->peerName) ;
- }
- else
- {
- if (params->initialConnections == 0 && talkSelf)
- notice ("%s config ignored batch mode with initial"
- " connection count of 0", params->peerName) ;
-
- if ( !listenerAddPeer (mainListener,nHost) )
- die ("failed to add a new peer\n") ;
- }
- }
-
- }
-
-
- for (h = gHostList; h != NULL; h = q)
- {
- q = h->next ;
- if (h->removeOnReload)
- {
- if (h->isDynamic)
- {
- /* change to the new default parameters */
- params = newHostParams(defaultParams);
- ASSERT(params->peerName == NULL);
- ASSERT(params->ipName == NULL);
- ASSERT(h->params->peerName != NULL);
- ASSERT(h->params->ipName != NULL);
- params->peerName = xstrdup(h->params->peerName);
- params->ipName = xstrdup(h->params->ipName);
- hostReconfigure(h, params);
- h->removeOnReload = true;
- }
- else
- hostClose (h) ; /* h may be deleted in here. */
- }
- else
- /* prime it for the next config file read */
- h->removeOnReload = true ;
- }
-
- hostLogStatus () ;
-}
-
-
-void hostAlterMaxConnections(Host host,
- unsigned int absMaxCxns, unsigned int maxCxns,
- bool makeConnect)
-{
- unsigned int lAbsMaxCxns;
- unsigned int i;
-
- /* Fix 0 unlimited case */
- lAbsMaxCxns = MAXCONLIMIT(absMaxCxns);
-
- /* Don't accept 0 for maxCxns */
- maxCxns=MAXCONLIMIT(maxCxns);
-
- if ( host->params->dynamicMethod == METHOD_STATIC)
- {
- /* If running static, ignore the maxCxns passed in, we'll
- just use absMaxCxns
- */
- maxCxns = lAbsMaxCxns;
- }
-
- if ( maxCxns > lAbsMaxCxns)
- {
- /* ensure maxCxns is of the correct form */
- maxCxns = lAbsMaxCxns;
- }
-
- if ((maxCxns < host->maxConnections) && (host->connections != NULL))
- {
- /* We are going to have to nuke some connections, as the current
- max is now greater than the new max
- */
- for ( i = host->maxConnections ; i > maxCxns ; i-- )
- {
- /* XXX this is harsh, and arguably there could be a
- cleaner way of doing it. the problem being addressed
- by doing it this way is that eventually a connection
- closed cleanly via cxnClose can end up ultimately
- calling hostCxnDead after h->maxConnections has
- been lowered and the relevant arrays downsized.
- If trashing the old, unallocated space in
- hostCxnDead doesn't kill the process, the
- ASSERT against h->maxConnections surely will.
- */
- if (host->connections[i - 1] != NULL)
- {
- cxnLogStats (host->connections [i-1], true) ;
- cxnNuke (host->connections[i-1]) ;
- host->connections[i-1] = NULL;
- }
- }
- host->maxConnections = maxCxns ;
- }
-
- if (host->connections)
- for (i = host->maxConnections ; i <= MAXCONLIMIT(host->params->absMaxConnections) ; i++)
- {
- /* Ensure we've got an empty values only beyond the maxConnection
- water mark.
- */
- ASSERT (host->connections[i] == NULL);
- }
-
- if ((lAbsMaxCxns != MAXCONLIMIT(host->params->absMaxConnections)) ||
- (host->connections == NULL))
- {
- /* we need to change the size of the connection array */
- if (host->connections == NULL)
- {
- /* not yet allocated */
-
- host->connections = xcalloc (lAbsMaxCxns + 1, sizeof(Connection)) ;
-
- ASSERT (host->cxnActive == NULL);
- host->cxnActive = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
-
- ASSERT (host->cxnSleeping == NULL) ;
- host->cxnSleeping = xcalloc (lAbsMaxCxns, sizeof(bool)) ;
-
- for (i = 0 ; i < lAbsMaxCxns ; i++)
- {
- host->connections [i] = NULL ;
- host->cxnActive[i] = false ;
- host->cxnSleeping[i] = false ;
- }
- host->connections[lAbsMaxCxns] = NULL;
- }
- else
- {
- host->connections =
- xrealloc (host->connections,
- sizeof(Connection) * (lAbsMaxCxns + 1));
- host->cxnActive = xrealloc (host->cxnActive,
- sizeof(bool) * lAbsMaxCxns) ;
- host->cxnSleeping = xrealloc (host->cxnSleeping,
- sizeof(bool) * lAbsMaxCxns) ;
-
- if (lAbsMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
- {
- for (i = MAXCONLIMIT(host->params->absMaxConnections) ;
- i < lAbsMaxCxns ; i++)
- {
- host->connections[i+1] = NULL; /* array always 1 larger */
- host->cxnActive[i] = false ;
- host->cxnSleeping[i] = false ;
- }
- }
- }
- host->params->absMaxConnections = absMaxCxns;
- }
- /* if maximum was raised, establish the new connexions
- (but don't start using them).
- */
- if ( maxCxns > host->maxConnections)
- {
- i = host->maxConnections ;
- /* need to set host->maxConnections before cxnWait() */
- host->maxConnections = maxCxns;
-
- while ( i < maxCxns )
- {
- host->cxnActive [i] = false ;
- host->cxnSleeping [i] = false ;
- /* create a new connection */
- host->connections [i] =
- newConnection (host, i,
- host->params->ipName,
- host->params->articleTimeout,
- host->params->portNum,
- host->params->responseTimeout,
- host->params->closePeriod,
- host->params->lowPassLow,
- host->params->lowPassHigh,
- host->params->lowPassFilter) ;
-
- /* connect if low enough numbered, or we were forced to */
- if ((i < host->params->initialConnections) || makeConnect)
- cxnConnect (host->connections [i]) ;
- else
- cxnWait (host->connections [i]) ;
- i++ ;
- }
- }
-
-}
-
-/*
- * Find a host on the blocked host list
- */
-
-static HostHolder FindBlockedHost(const char *name)
-{
- HostHolder hh = blockedHosts;
- while (hh != NULL)
- if ((hh->params) && (hh->params->peerName) &&
- (strcmp(name,hh->params->peerName) == 0))
- return hh;
- else
- hh=hh->next;
- return NULL;
-}
-
-static void addBlockedHost(HostParams params)
-{
- HostHolder hh;
-
- hh = xmalloc (sizeof(struct host_holder_s)) ;
- /* Use this set of params */
-
- hh->params = params;
-
- hh->next = blockedHosts ;
- blockedHosts = hh ;
-}
-
-/*
- * We iterate through the blocked host list and try and reconnect ones
- * where we couldn't get a lock
- */
-static void tryBlockedHosts(TimeoutId tid UNUSED , void *data UNUSED )
-{
- HostHolder hh,hi;
- HostParams params;
-
- hh = blockedHosts; /* Get start of our queue */
- blockedHosts = NULL ; /* remove them all from the queue of hosts */
-
- while (hh != NULL)
- {
- params = hh->params;
- hi= hh->next;
- free(hh);
- hh = hi;
-
- if (params && params->peerName)
- {
- if (findHostByName(params->peerName)!=NULL)
- {
- /* Wierd, someone's managed to start it when it's on
- * the blocked list. Just silently discard.
- */
- freeHostParams(params);
- }
- else
- {
- Host nHost;
- nHost = newHost (mainListener, params);
-
- if (nHost == NULL)
- {
- addBlockedHost(params);
-
- warn ("ME locked cannot setup peer %s", params->peerName) ;
- }
- else
- {
- d_printf(1,"Unblocked host %s\n",params->peerName);
-
- if (params->initialConnections == 0 &&
- listenerIsDummy(mainListener) /*talk to self*/)
- notice ("%s config ignored batch mode with initial"
- " connection count of 0", params->peerName) ;
-
- if ( !listenerAddPeer (mainListener,nHost) )
- die ("failed to add a new peer\n") ;
- }
- }
- }
- }
- tryBlockedHostsId = prepareSleep(tryBlockedHosts,
- TRYBLOCKEDHOSTPERIOD, NULL);
-}
-
-
-/*
- * Create a new Host object with default parameters. Called by the
- * InnListener.
- */
-
-Host newDefaultHost (InnListener listener,
- const char *name)
-{
- HostParams p;
- Host h = NULL;
-
- if (FindBlockedHost(name)==NULL)
- {
-
- p=newHostParams(defaultParams);
- ASSERT(p!=NULL);
-
- /* relies on fact listener and names are null in default*/
- p->peerName=xstrdup(name);
- p->ipName=xstrdup(name);
-
- h=newHost (listener,p);
- if (h==NULL)
- {
- /* Couldn't get a lock - add to list of blocked peers */
- addBlockedHost(p);
-
- warn ("ME locked cannot setup peer %s", p->peerName);
-
- return NULL;
- }
-
- h->isDynamic = true;
- h->removeOnReload = true;
-
- notice ("ME unconfigured peer %s added", p->peerName) ;
- }
- return h;
-}
-
-/*
- * Create a new host and attach the supplied param structure
- */
-
-static bool inited = false ;
-Host newHost (InnListener listener, HostParams p)
-{
- Host nh ;
-
- ASSERT (p->maxChecks > 0) ;
-
- if (!inited)
- {
- inited = true ;
- atexit (hostCleanup) ;
- }
-
- /*
- * Once only, init the first blocked host check
- */
- if (tryBlockedHostsId==0)
- tryBlockedHostsId = prepareSleep(tryBlockedHosts,
- TRYBLOCKEDHOSTPERIOD, NULL);
-
- nh = xcalloc (1, sizeof(struct host_s)) ;
-
- nh->params = p;
- nh->listener = listener;
-
- nh->connections = NULL; /* We'll get these allocated later */
- nh->cxnActive = NULL;
- nh->cxnSleeping = NULL;
-
- nh->activeCxns = 0 ;
- nh->sleepingCxns = 0 ;
-
- nh->blockedCxn = NULL ;
- nh->notThisCxn = NULL ;
-
- nh->queued = NULL ;
- nh->queuedTail = NULL ;
-
- nh->processed = NULL ;
- nh->processedTail = NULL ;
-
- nh->deferred = NULL ;
- nh->deferredTail = NULL ;
-
- nh->statsId = 0 ;
- nh->ChkCxnsId = 0 ;
- nh->deferredId = 0;
-
- nh->myTape = newTape (nh->params->peerName,
- listenerIsDummy (nh->listener)) ;
- if (nh->myTape == NULL)
- { /* tape couldn't be locked, probably */
- free (nh->connections) ;
- free (nh->cxnActive) ;
- free (nh->cxnSleeping) ;
-
- free (nh) ;
- return NULL ; /* note we don't free up p */
- }
-
- nh->backedUp = false ;
- nh->backlog = 0 ;
- nh->deferLen = 0 ;
-
- nh->loggedBacklog = false ;
- nh->loggedModeOn = false ;
- nh->loggedModeOff = false ;
- nh->notifiedChangedRemBlckd = false ;
- nh->removeOnReload = false ; /* ready for config file reload */
- nh->isDynamic = false ;
-
- nh->artsOffered = 0 ;
- nh->artsAccepted = 0 ;
- nh->artsNotWanted = 0 ;
- nh->artsRejected = 0 ;
- nh->artsDeferred = 0 ;
- nh->artsMissing = 0 ;
- nh->artsToTape = 0 ;
- nh->artsQueueOverflow = 0 ;
- nh->artsCxnDrop = 0 ;
- nh->artsHostSleep = 0 ;
- nh->artsHostClose = 0 ;
- nh->artsFromTape = 0 ;
- nh->artsSizeAccepted = 0 ;
- nh->artsSizeRejected = 0 ;
-
- nh->artsProcLastPeriod = 0;
- nh->secsInLastPeriod = 0;
- nh->lastCheckPoint = 0;
- nh->lastSentCheckPoint = 0;
- nh->lastTotalCheckPoint = 0;
- nh->maxCxnChk = true;
- nh->lastMaxCxnTime = time(0);
- nh->lastChkTime = time(0);
- nh->nextCxnTimeChk = 30;
- nh->backlogFilter = ((nh->params->dynBacklogLowWaterMark
- + nh->params->dynBacklogHighWaterMark)
- /200.0 /(1.0-nh->params->dynBacklogFilter));
-
- nh->gArtsOffered = 0 ;
- nh->gArtsAccepted = 0 ;
- nh->gArtsNotWanted = 0 ;
- nh->gArtsRejected = 0 ;
- nh->gArtsDeferred = 0 ;
- nh->gArtsMissing = 0 ;
- nh->gArtsToTape = 0 ;
- nh->gArtsQueueOverflow = 0 ;
- nh->gArtsCxnDrop = 0 ;
- nh->gArtsHostSleep = 0 ;
- nh->gArtsHostClose = 0 ;
- nh->gArtsFromTape = 0 ;
- nh->gArtsSizeAccepted = 0 ;
- nh->gArtsSizeRejected = 0 ;
- nh->gCxnQueue = 0 ;
- nh->gNoQueue = 0 ;
-
- nh->firstConnectTime = 0 ;
- nh->connectTime = 0 ;
-
- nh->spoolTime = 0 ;
-
- nh->blNone = 0 ;
- nh->blFull = 0 ;
- nh->blQuartile[0] = nh->blQuartile[1] = nh->blQuartile[2] =
- nh->blQuartile[3] = 0 ;
- nh->dlAccum = 0;
- nh->blAccum = 0;
- nh->blCount = 0;
-
-
- nh->maxConnections = 0; /* we currently have no connections allocated */
-
- /* Note that the following will override the initialCxns specified as
- maxCxns if we are on non-dyamic feed
- */
- hostAlterMaxConnections(nh, nh->params->absMaxConnections,
- nh->params->initialConnections, false);
-
- nh->next = gHostList ;
- gHostList = nh ;
- gHostCount++ ;
-
- if (maxIpNameLen == 0)
- {
- start = theTime() ;
- strlcpy (startTime,ctime (&start),sizeof (startTime)) ;
- myPid = getpid() ;
- }
-
- if (strlen (nh->params->ipName) > maxIpNameLen)
- maxIpNameLen = strlen (nh->params->ipName) ;
- if (strlen (nh->params->peerName) > maxPeerNameLen)
- maxPeerNameLen = strlen (nh->params->peerName) ;
-
- return nh ;
-}
-
-struct sockaddr *hostIpAddr (Host host, int family)
-{
- int i ;
- struct sockaddr **newIpAddrPtrs = NULL;
- struct sockaddr_storage *newIpAddrs = NULL;
- struct sockaddr *returnAddr;
-
- ASSERT(host->params != NULL);
-
- /* check to see if need to look up the host name */
- if (host->nextIpLookup <= theTime())
- {
-#ifdef HAVE_INET6
- int gai_ret;
- struct addrinfo *res, *p;
- struct addrinfo hints;
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = family ? family : AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
-#ifdef AI_ADDRCONFIG
- hints.ai_flags = AI_ADDRCONFIG;
-#endif
- if((gai_ret = getaddrinfo(host->params->ipName, NULL, &hints, &res)) != 0
- || res == NULL)
- {
- warn ("%s can't resolve hostname %s: %s", host->params->peerName,
- host->params->ipName, gai_ret == 0 ? "no addresses returned"
- : gai_strerror(gai_ret)) ;
- }
- else
- {
- /* figure number of pointers that need space */
- i = 0;
- for ( p = res ; p ; p = p->ai_next ) ++i;
-
- newIpAddrPtrs = (struct sockaddr **)
- xmalloc ( (i + 1) * sizeof(struct sockaddr *) );
-
- newIpAddrs = (struct sockaddr_storage *)
- xmalloc ( i * sizeof(struct sockaddr_storage) );
-
- i = 0;
- /* copy the addresses from the getaddrinfo linked list */
- for( p = res ; p ; p = p->ai_next )
- {
- memcpy( &newIpAddrs[i], p->ai_addr, p->ai_addrlen );
- newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
- ++i;
- }
- newIpAddrPtrs[i] = NULL ;
- freeaddrinfo( res );
- }
-#else
- struct hostent *hostEnt ;
- struct in_addr ipAddr;
-
- /* see if the ipName we're given is a dotted quad */
- if ( !inet_aton (host->params->ipName,&ipAddr) )
- {
- if ((hostEnt = gethostbyname (host->params->ipName)) == NULL)
- {
- warn ("%s can't resolve hostname %s: %s", host->params->peerName,
- host->params->ipName, hstrerror(h_errno)) ;
- }
- else
- {
- /* figure number of pointers that need space */
- for (i = 0 ; hostEnt->h_addr_list[i] ; i++)
- ;
-
- newIpAddrPtrs = xmalloc ((i + 1) * sizeof(struct sockaddr *));
- newIpAddrs = xmalloc (i * sizeof(struct sockaddr_storage));
-
- /* copy the addresses from gethostbyname() static space */
- i = 0;
- for (i = 0 ; hostEnt->h_addr_list[i] ; i++)
- {
- make_sin( (struct sockaddr_in *)(&newIpAddrs[i]),
- (struct in_addr *)(hostEnt->h_addr_list[i]) );
- newIpAddrPtrs[i] = (struct sockaddr *)(&newIpAddrs[i]);
- }
- newIpAddrPtrs[i] = NULL ;
- }
- }
- else
- {
- newIpAddrPtrs = (struct sockaddr **)
- xmalloc ( 2 * sizeof( struct sockaddr * ) );
- newIpAddrs = (struct sockaddr_storage *)
- xmalloc ( sizeof( struct sockaddr_storage ) );
-
- make_sin( (struct sockaddr_in *)newIpAddrs, &ipAddr );
- newIpAddrPtrs[0] = (struct sockaddr *)newIpAddrs;
- newIpAddrPtrs[1] = NULL;
- }
-#endif
-
- if (newIpAddrs)
- {
- if (host->ipAddrs)
- {
- if(host->ipAddrs[0])
- free (host->ipAddrs[0]);
- free (host->ipAddrs) ;
- }
- host->ipAddrs = newIpAddrPtrs ;
- host->nextIpAddr = 0 ;
- host->nextIpLookup = theTime () + dnsExpPeriod ;
- }
- else
- {
- /* failed to setup new addresses */
- host->nextIpLookup = theTime () + dnsRetPeriod ;
- }
- }
-
- if (host->ipAddrs)
- returnAddr = host->ipAddrs[host->nextIpAddr] ;
- else
- returnAddr = NULL ;
-
- return returnAddr ;
-}
-
-
-#ifdef HAVE_INET6
-/*
- * Delete IPv4 addresses from the address list.
- */
-void hostDeleteIpv4Addr (Host host)
-{
- int i, j;
-
- if (!host->ipAddrs)
- return;
- for (i = 0, j = 0; host->ipAddrs[i]; i++) {
- if (host->ipAddrs[i]->sa_family != AF_INET)
- host->ipAddrs[j++] = host->ipAddrs[i];
- }
- host->ipAddrs[j] = 0;
- if (host->nextIpAddr >= j)
- host->nextIpAddr = 0;
-}
-#endif
-
-
-void hostIpFailed (Host host)
-{
- if (host->ipAddrs)
- if (host->ipAddrs[++host->nextIpAddr] == NULL)
- host->nextIpAddr = 0 ;
-}
-
-
-void gPrintHostInfo (FILE *fp, unsigned int indentAmt)
-{
- Host h ;
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Host list : (count %d) {\n",indent,gHostCount) ;
-
- for (h = gHostList ; h != NULL ; h = h->next)
- printHostInfo (h,fp,indentAmt + INDENT_INCR) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void printHostInfo (Host host, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
- ProcQElem qe ;
- double cnt = (host->blCount) ? (host->blCount) : 1.0;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sHost : %p {\n",indent,(void *) host) ;
-
- if (host == NULL)
- {
- fprintf (fp,"%s}\n",indent) ;
- return ;
- }
-
- fprintf (fp,"%s peer-name : %s\n",indent,host->params->peerName) ;
- fprintf (fp,"%s ip-name : %s\n",indent,host->params->ipName) ;
-#ifdef HAVE_INET6
- if (host->params->family == AF_INET6)
- {
- fprintf (fp,"%s bindaddress : none\n",indent);
- }
- else
-#endif
- {
- fprintf (fp,"%s bindaddress : %s\n",indent,
- host->params->bindAddr == NULL ||
- host->params->bindAddr->sin_addr.s_addr == 0 ? "any" :
- inet_ntoa(host->params->bindAddr->sin_addr));
- }
-#ifdef HAVE_INET6
- if (host->params->family == AF_INET)
- {
- fprintf (fp,"%s bindaddress6 : none\n",indent);
- }
- else
- {
- char buf[128];
- fprintf (fp,"%s bindaddress6 : %s\n",indent,
- host->params->bindAddr6 == NULL ? "any" :
- inet_ntop(AF_INET6, &host->params->bindAddr6->sin6_addr,
- buf, sizeof(buf)));
- }
-#endif
- fprintf (fp,"%s abs-max-connections : %d\n",indent,
- host->params->absMaxConnections) ;
- fprintf (fp,"%s active-connections : %d\n",indent,host->activeCxns) ;
- fprintf (fp,"%s sleeping-connections : %d\n",indent,host->sleepingCxns) ;
- fprintf (fp,"%s initial-connections : %d\n",indent,
- host->params->initialConnections) ;
- fprintf (fp,"%s want-streaming : %s\n",indent,
- boolToString (host->params->wantStreaming)) ;
- fprintf (fp,"%s drop-deferred : %s\n",indent,
- boolToString (host->params->dropDeferred)) ;
- fprintf (fp,"%s min-queue-connection : %s\n",indent,
- boolToString (host->params->minQueueCxn)) ;
- fprintf (fp,"%s remote-streams : %s\n",indent,
- boolToString (host->remoteStreams)) ;
- fprintf (fp,"%s max-checks : %d\n",indent,host->params->maxChecks) ;
- fprintf (fp,"%s article-timeout : %d\n",indent,
- host->params->articleTimeout) ;
- fprintf (fp,"%s response-timeout : %d\n",indent,
- host->params->responseTimeout) ;
- fprintf (fp,"%s close-period : %d\n",indent,
- host->params->closePeriod) ;
- fprintf (fp,"%s port : %d\n",indent,host->params->portNum) ;
- fprintf (fp,"%s dynamic-method : %d\n",indent,
- host->params->dynamicMethod) ;
- fprintf (fp,"%s dynamic-backlog-filter : %2.1f\n",indent,
- host->params->dynBacklogFilter) ;
- fprintf (fp,"%s dynamic-backlog-lwm : %2.1f\n",indent,
- host->params->dynBacklogLowWaterMark) ;
- fprintf (fp,"%s dynamic-backlog-hwm : %2.1f\n",indent,
- host->params->dynBacklogHighWaterMark) ;
- fprintf (fp,"%s no-check on : %2.1f\n",indent,
- host->params->lowPassHigh) ;
- fprintf (fp,"%s no-check off : %2.1f\n",indent,
- host->params->lowPassLow) ;
- fprintf (fp,"%s no-check filter : %2.1f\n",indent,
- host->params->lowPassFilter) ;
- fprintf (fp,"%s backlog-limit : %d\n",indent,
- host->params->backlogLimit) ;
- fprintf (fp,"%s backlog-limit-high : %d\n",indent,
- host->params->backlogLimitHigh) ;
- fprintf (fp,"%s backlog-factor : %2.1f\n",indent,
- host->params->backlogFactor) ;
- fprintf (fp,"%s max-connections : %d\n",indent,
- host->maxConnections) ;
- fprintf (fp,"%s backlog-feed-first : %s\n",indent,
- boolToString (host->params->backlogFeedFirst)) ;
-
-
- fprintf (fp,"%s statistics-id : %d\n",indent,host->statsId) ;
- fprintf (fp,"%s ChkCxns-id : %d\n",indent,host->ChkCxnsId) ;
- fprintf (fp,"%s deferred-id : %d\n",indent,host->deferredId) ;
- fprintf (fp,"%s backed-up : %s\n",indent,boolToString (host->backedUp));
- fprintf (fp,"%s backlog : %d\n",indent,host->backlog) ;
- fprintf (fp,"%s deferLen : %d\n",indent,host->deferLen) ;
- fprintf (fp,"%s loggedModeOn : %s\n",indent,
- boolToString (host->loggedModeOn)) ;
- fprintf (fp,"%s loggedModeOff : %s\n",indent,
- boolToString (host->loggedModeOff)) ;
- fprintf (fp,"%s logged-backlog : %s\n",indent,
- boolToString (host->loggedBacklog)) ;
- fprintf (fp,"%s streaming-type changed : %s\n",indent,
- boolToString (host->notifiedChangedRemBlckd)) ;
- fprintf (fp,"%s articles offered : %d\n",indent,host->artsOffered) ;
- fprintf (fp,"%s articles accepted : %d\n",indent,host->artsAccepted) ;
- fprintf (fp,"%s articles not wanted : %d\n",indent,
- host->artsNotWanted) ;
- fprintf (fp,"%s articles rejected : %d\n",indent,host->artsRejected);
- fprintf (fp,"%s articles deferred : %d\n",indent,host->artsDeferred) ;
- fprintf (fp,"%s articles missing : %d\n",indent,host->artsMissing) ;
- fprintf (fp,"%s articles spooled : %d\n",indent,host->artsToTape) ;
- fprintf (fp,"%s because of queue overflow : %d\n",indent,
- host->artsQueueOverflow) ;
- fprintf (fp,"%s when the we closed the host : %d\n",indent,
- host->artsHostClose) ;
- fprintf (fp,"%s because the host was asleep : %d\n",indent,
- host->artsHostSleep) ;
- fprintf (fp,"%s articles unspooled : %d\n",indent,host->artsFromTape) ;
- fprintf (fp,"%s articles requeued from dropped connections : %d\n",indent,
- host->artsCxnDrop) ;
-
- fprintf (fp,"%s process articles offered : %d\n",indent,
- host->gArtsOffered) ;
- fprintf (fp,"%s process articles accepted : %d\n",indent,
- host->gArtsAccepted) ;
- fprintf (fp,"%s process articles not wanted : %d\n",indent,
- host->gArtsNotWanted) ;
- fprintf (fp,"%s process articles rejected : %d\n",indent,
- host->gArtsRejected);
- fprintf (fp,"%s process articles deferred : %d\n",indent,
- host->gArtsDeferred) ;
- fprintf (fp,"%s process articles missing : %d\n",indent,
- host->gArtsMissing) ;
- fprintf (fp,"%s process articles spooled : %d\n",indent,
- host->gArtsToTape) ;
- fprintf (fp,"%s because of queue overflow : %d\n",indent,
- host->gArtsQueueOverflow) ;
- fprintf (fp,"%s when the we closed the host : %d\n",indent,
- host->gArtsHostClose) ;
- fprintf (fp,"%s because the host was asleep : %d\n",indent,
- host->gArtsHostSleep) ;
- fprintf (fp,"%s process articles unspooled : %d\n",indent,
- host->gArtsFromTape) ;
- fprintf (fp,"%s process articles requeued from dropped connections : %d\n",
- indent, host->gArtsCxnDrop) ;
-
- fprintf (fp,"%s average (mean) defer length : %.1f\n", indent,
- (double) host->dlAccum / cnt) ;
- fprintf (fp,"%s average (mean) queue length : %.1f\n", indent,
- (double) host->blAccum / cnt) ;
- fprintf (fp,"%s percentage of the time empty : %.1f\n", indent,
- 100.0 * host->blNone / cnt) ;
- fprintf (fp,"%s percentage of the time >0%%-25%% : %.1f\n", indent,
- 100.0 * host->blQuartile[0] / cnt) ;
- fprintf (fp,"%s percentage of the time 25%%-50%% : %.1f\n", indent,
- 100.0 * host->blQuartile[1] / cnt) ;
- fprintf (fp,"%s percentage of the time 50%%-75%% : %.1f\n", indent,
- 100.0 * host->blQuartile[2] / cnt) ;
- fprintf (fp,"%s percentage of the time 75%%-<100%% : %.1f\n", indent,
- 100.0 * host->blQuartile[3] / cnt) ;
- fprintf (fp,"%s percentage of the time full : %.1f\n", indent,
- 100.0 * host->blFull / cnt) ;
- fprintf (fp,"%s number of samples : %u\n", indent, host->blCount) ;
-
- fprintf (fp,"%s firstConnectTime : %s",indent,
- ctime (&host->firstConnectTime));
- fprintf (fp,"%s connectTime : %s",indent,ctime (&host->connectTime));
- fprintf (fp,"%s spoolTime : %s",indent,ctime (&host->spoolTime)) ;
- fprintf (fp,"%s last-spool-time : %s",indent,
- ctime (&host->lastSpoolTime)) ;
-
-#if 0
- fprintf (fp,"%s tape {\n",indent) ;
- printTapeInfo (host->myTape,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-#else
- fprintf (fp,"%s tape : %p\n",indent,(void *) host->myTape) ;
-#endif
-
- fprintf (fp,"%s QUEUED articles {\n",indent) ;
- for (qe = host->queued ; qe != NULL ; qe = qe->next)
- {
-#if 0
- printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s IN PROCESS articles {\n",indent) ;
- for (qe = host->processed ; qe != NULL ; qe = qe->next)
- {
-#if 0
- printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
- fprintf (fp,"%s DEFERRED articles {\n",indent) ;
- for (qe = host->deferred ; qe != NULL ; qe = qe->next)
- {
-#if 0
- printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
- fprintf (fp,"%s DEFERRED articles {\n",indent) ;
- for (qe = host->deferred ; qe != NULL ; qe = qe->next)
- {
-#if 0
- printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) qe->article) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
-
-
-
- fprintf (fp,"%s Connections {\n",indent) ;
- for (i = 0 ; i < host->maxConnections ; i++)
- {
-#if 0
- if (host->connections[i] != NULL)
- printCxnInfo (*cxn,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) host->connections[i]) ;
-#endif
- }
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s Active Connections {\n%s ",indent,indent) ;
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->cxnActive[i])
- fprintf (fp," [%d:%p]",i,(void *) host->connections[i]) ;
- fprintf (fp,"\n%s }\n",indent) ;
-
- fprintf (fp,"%s Sleeping Connections {\n%s ",indent,indent) ;
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->cxnSleeping[i])
- fprintf (fp," [%d:%p]",i,(void *) host->connections[i]) ;
- fprintf (fp,"\n%s }\n",indent) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-
-
-\f
-/* close down all the connections of the Host. All articles that are in
- * processes are still pushed out and then a QUIT is issued. The Host will
- * also spool all inprocess articles to tape incase the process is about to
- * be killed (they'll be refused next time around). When all Connections
- * report that they're gone, then the Host will delete itself.
- */
-void hostClose (Host host)
-{
- unsigned int i ;
- unsigned int cxnCount ;
-
- d_printf (1,"Closing host %s\n",host->params->peerName) ;
-
- queuesToTape (host) ;
- delTape (host->myTape) ;
- host->myTape = NULL ;
-
- hostLogStats (host,true) ;
-
- clearTimer (host->statsId) ;
- clearTimer (host->ChkCxnsId) ;
- clearTimer (host->deferredId) ;
-
- host->connectTime = 0 ;
-
- /* when we call cxnTerminate() on the last Connection, the Host objects
- will end up getting deleted out from under us (via hostCxnGone()). If
- we are running with a malloc that scribbles over memory after freeing
- it, then we'd fail in the second for loop test. Trying to access
- host->maxConnections. */
- for (i = 0, cxnCount = 0 ; i < host->maxConnections ; i++)
- cxnCount += (host->connections [i] != NULL ? 1 : 0) ;
- for (i = 0 ; i < cxnCount ; i++)
- if (host->connections[i] != NULL)
- cxnTerminate (host->connections [i]) ;
-}
-
-\f
-/*
- * check if host should get more connections opened, or some closed...
- */
-void hostChkCxns(TimeoutId tid UNUSED, void *data) {
- Host host = (Host) data;
- unsigned int currArticles, currSentArticles, currTotalArticles, newMaxCxns ;
- double lastAPS, currAPS, percentTaken, ratio ;
- double backlogRatio, backlogMult;
-
- if(!host->maxCxnChk)
- return;
-
- ASSERT(host->params != NULL);
-
- if(host->secsInLastPeriod > 0)
- lastAPS = host->artsProcLastPeriod / (host->secsInLastPeriod * 1.0);
- else
- lastAPS = host->artsProcLastPeriod * 1.0;
-
- newMaxCxns = host->maxConnections;
-
- currArticles = (host->gArtsAccepted + host->gArtsRejected +
- (host->gArtsNotWanted / 4)) - host->lastCheckPoint ;
-
- host->lastCheckPoint = (host->gArtsAccepted + host->gArtsRejected +
- (host->gArtsNotWanted / 4));
-
- currSentArticles = host->gArtsAccepted + host->gArtsRejected
- - host->lastSentCheckPoint ;
-
- host->lastSentCheckPoint = host->gArtsAccepted + host->gArtsRejected;
-
- currTotalArticles = host->gArtsAccepted + host->gArtsRejected
- + host->gArtsRejected + host->gArtsQueueOverflow
- - host->lastTotalCheckPoint ;
-
- host->lastTotalCheckPoint = host->gArtsAccepted + host->gArtsRejected
- + host->gArtsRejected + host->gArtsQueueOverflow ;
-
- currAPS = currArticles / (host->nextCxnTimeChk * 1.0) ;
-
- percentTaken = currSentArticles * 1.0 /
- ((currTotalArticles==0)?1:currTotalArticles);
-
- /* Get how full the queue is currently */
- backlogRatio = (host->backlog * 1.0 / hostHighwater);
- backlogMult = 1.0/(1.0-host->params->dynBacklogFilter);
-
- d_printf(1,"%s hostChkCxns - entry filter=%3.3f blmult=%3.3f blratio=%3.3f\n",host->params->peerName,host->backlogFilter, backlogMult, backlogRatio);
-
- ratio = 0.0; /* ignore APS by default */
-
- switch (host->params->dynamicMethod)
- {
- case METHOD_COMBINED:
- /* When a high % of articles is being taken, take notice of the
- * APS values. However for smaller %s, quickly start to ignore this
- * and concentrate on queue sizes
- */
- ratio = percentTaken * percentTaken;
- /* nobreak; */
- case METHOD_QUEUE:
- /* backlogFilter is an IIR filtered version of the backlogRatio.
- */
- host->backlogFilter *= host->params->dynBacklogFilter;
- /* Penalise anything over the backlog HWM twice as severely
- * (otherwise we end up feeding some sites constantly
- * just below the HWM. This way random noise makes
- * such sites jump to one more connection
- *
- * Use factor (1-ratio) so if ratio is near 1 we ignore this
- */
- if (backlogRatio>host->params->dynBacklogLowWaterMark/100.0)
- host->backlogFilter += (backlogRatio+1.0)/2.0 * (1.0-ratio);
- else
- host->backlogFilter += backlogRatio * (1.0-ratio);
-
- /*
- * Now bump it around for APS too
- */
- if ((currAPS - lastAPS) >= 0.1)
- host->backlogFilter += ratio*((currAPS - lastAPS) + 1.0);
- else if ((currAPS - lastAPS) < -.2)
- host->backlogFilter -= ratio;
-
- d_printf(1,"%s hostChkCxns - entry hwm=%3.3f lwm=%3.3f new=%3.3f [%3.3f,%3.3f]\n",
- host->params->peerName,host->params->dynBacklogHighWaterMark,
- host->params->dynBacklogLowWaterMark,host->backlogFilter,
- (host->params->dynBacklogLowWaterMark * backlogMult / 100.0),
- (host->params->dynBacklogHighWaterMark * backlogMult / 100.0));
-
- if (host->backlogFilter <
- (host->params->dynBacklogLowWaterMark * backlogMult / 100.0))
- newMaxCxns--;
- else if (host->backlogFilter >
- (host->params->dynBacklogHighWaterMark * backlogMult / 100.0))
- newMaxCxns++;
- break;
- case METHOD_STATIC:
- /* well not much to do, just check maxConnection = absMaxConnections */
- ASSERT (host->maxConnections == MAXCONLIMIT(host->params->absMaxConnections));
- break;
- case METHOD_APS:
- if ((currAPS - lastAPS) >= 0.1)
- newMaxCxns += (int)(currAPS - lastAPS) + 1 ;
- else if ((currAPS - lastAPS) < -.2)
- newMaxCxns--;
- break;
- }
-
- d_printf(1, "hostChkCxns: Chngs %f\n", currAPS - lastAPS);
-
- if (newMaxCxns < 1) newMaxCxns=1;
- if (newMaxCxns > MAXCONLIMIT(host->params->absMaxConnections))
- newMaxCxns = MAXCONLIMIT(host->params->absMaxConnections);
-
- if (newMaxCxns != host->maxConnections)
- {
- notice ("%s hostChkCxns - maxConnections was %d now %d",
- host->params->peerName, host->maxConnections,newMaxCxns);
-
- host->backlogFilter= ((host->params->dynBacklogLowWaterMark
- + host->params->dynBacklogHighWaterMark)
- /200.0 * backlogMult);
- host->artsProcLastPeriod = currArticles ;
- host->secsInLastPeriod = host->nextCxnTimeChk ;
-
- /* Alter MaxConnections and in doing so ensure we connect new
- cxns immediately if we are adding stuff
- */
- hostAlterMaxConnections(host, host->params->absMaxConnections,
- newMaxCxns, true);
- }
-
- if(host->nextCxnTimeChk <= 240) host->nextCxnTimeChk *= 2;
- else host->nextCxnTimeChk = 300;
- d_printf(1, "prepareSleep hostChkCxns, %d\n", host->nextCxnTimeChk);
- host->ChkCxnsId = prepareSleep(hostChkCxns, host->nextCxnTimeChk, host);
-}
-
-\f
-/*
- * have the Host transmit the Article if possible.
- */
-void hostSendArticle (Host host, Article article)
-{
- ASSERT(host->params != NULL);
- if (host->spoolTime > 0)
- { /* all connections are asleep */
- host->artsHostSleep++ ;
- host->gArtsHostSleep++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape, article) ;
- return ;
- }
-
- /* at least one connection is feeding or waiting and there's no backlog */
- if (host->queued == NULL)
- {
- unsigned int idx ;
- Article extraRef ;
- Connection cxn = NULL ;
-
- extraRef = artTakeRef (article) ; /* the referrence we give away */
-
- /* stick on the queue of articles we've handed off--we're hopeful. */
- queueArticle (article,&host->processed,&host->processedTail, 0) ;
-
- if (host->params->minQueueCxn) {
- Connection x_cxn = NULL ;
- unsigned int x_queue = host->params->maxChecks + 1 ;
-
- for (idx = 0 ; x_queue > 0 && idx < host->maxConnections ; idx++)
- if ((cxn = host->connections[idx]) != host->notThisCxn) {
- if (!host->cxnActive [idx]) {
- if (!host->cxnSleeping [idx]) {
- if (cxnTakeArticle (cxn, extraRef)) {
- host->gNoQueue++ ;
- return ;
- } else
- d_printf (1,"%s Inactive connection %d refused an article\n",
- host->params->peerName,idx) ;
- }
- } else {
- unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) ;
- if (queue < x_queue) {
- x_queue = queue ;
- x_cxn = cxn ;
- }
- }
- }
-
- if (x_cxn != NULL && cxnTakeArticle (x_cxn, extraRef)) {
- if (x_queue == 0) host->gNoQueue++ ;
- else host->gCxnQueue += x_queue ;
- return ;
- }
-
- } else {
-
- /* first we try to give it to one of our active connections. We
- simply start at the bottom and work our way up. This way
- connections near the end of the list will get closed sooner from
- idleness. */
- for (idx = 0 ; idx < host->maxConnections ; idx++)
- {
- if (host->cxnActive [idx] &&
- (cxn = host->connections[idx]) != host->notThisCxn &&
- cxnTakeArticle (cxn, extraRef)) {
- unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
- if (queue == 0) host->gNoQueue++ ;
- else host->gCxnQueue += queue ;
- return ;
- }
- }
-
- /* Wasn't taken so try to give it to one of the waiting connections. */
- for (idx = 0 ; idx < host->maxConnections ; idx++)
- if (!host->cxnActive [idx] && !host->cxnSleeping [idx] &&
- (cxn = host->connections[idx]) != host->notThisCxn)
- {
- if (cxnTakeArticle (cxn, extraRef)) {
- unsigned int queue = host->params->maxChecks - cxnQueueSpace (cxn) - 1;
- if (queue == 0) host->gNoQueue++ ;
- else host->gCxnQueue += queue ;
- return ;
- } else
- d_printf (1,"%s Inactive connection %d refused an article\n",
- host->params->peerName,idx) ;
- }
- }
-
- /* this'll happen if all connections are feeding and all
- their queues are full, or if those not feeding are asleep. */
- d_printf (1, "Couldn't give the article to a connection\n") ;
-
- delArticle (extraRef) ;
-
- remArticle (article,&host->processed,&host->processedTail) ;
- if (!cxnCheckstate (cxn))
- {
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,article) ;
- return ;
- }
- }
-
- /* either all the per connection queues were full or we already had
- a backlog, so there was no sense in checking. */
- queueArticle (article,&host->queued,&host->queuedTail, 0) ;
-
- host->backlog++ ;
- backlogToTape (host) ;
-}
-
-
-
-
-
-
-\f
-/*
- * called by the Host's connection when the remote is refusing postings
- * from us becasue we're not allowed (banner code 400).
- */
-void hostCxnBlocked (Host host, Connection cxn, char *reason)
-{
- ASSERT(host->params != NULL);
-#ifndef NDEBUG
- {
- unsigned int i ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- ASSERT (host->cxnActive [i] == false) ;
- }
-#endif
-
- if (host->blockedReason == NULL)
- host->blockedReason = xstrdup (reason) ;
-
- if (host->activeCxns == 0 && host->spoolTime == 0)
- {
- host->blockedCxn = cxn ; /* to limit log notices */
- notice ("%s remote cannot accept articles initial: %s",
- host->params->peerName, reason) ;
- }
- else if (host->activeCxns > 0 && !host->notifiedChangedRemBlckd)
- {
- notice ("%s remote cannot accept articles change: %s",
- host->params->peerName, reason) ;
- host->notifiedChangedRemBlckd = true ;
- }
- else if (host->spoolTime != 0 && host->blockedCxn == cxn)
- {
- notice ("%s remote cannot accept articles still: %s",
- host->params->peerName, reason) ;
- }
-
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it gets a response back to the MODE
- * STREAM command. It's now that we consider the connection usable.
- */
-void hostRemoteStreams (Host host, Connection cxn, bool doesStreaming)
-{
- unsigned int i ;
-
- host->blockedCxn = NULL ;
- if (host->blockedReason != NULL)
- free (host->blockedReason) ;
- host->blockedReason = NULL ;
-
- /* we may have told the connection to quit while it was in the middle
- of connecting */
- if (amClosing (host))
- return ;
-
- if (host->connectTime == 0) /* first connection for this cycle. */
- {
- if (doesStreaming && host->params->wantStreaming)
- notice ("%s remote MODE STREAM", host->params->peerName) ;
- else if (doesStreaming)
- notice ("%s remote MODE STREAM disabled", host->params->peerName) ;
- else
- notice ("%s remote MODE STREAM failed", host->params->peerName) ;
-
- if (host->spoolTime > 0)
- hostStopSpooling (host) ;
-
- /* set up the callback for statistics logging. */
- if (host->statsId != 0)
- clearTimer (host->statsId) ;
- host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-
- if (host->ChkCxnsId != 0)
- clearTimer (host->ChkCxnsId);
- host->ChkCxnsId = prepareSleep (hostChkCxns, 30, host) ;
-
- host->remoteStreams = (host->params->wantStreaming ? doesStreaming : false) ;
-
- host->connectTime = theTime() ;
- if (host->firstConnectTime == 0)
- host->firstConnectTime = host->connectTime ;
- }
- else if (host->remoteStreams != doesStreaming && host->params->wantStreaming)
- notice ("%s remote MODE STREAM change", host->params->peerName) ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- {
- host->cxnActive [i] = true ;
- if (host->cxnSleeping [i])
- host->sleepingCxns-- ;
- host->cxnSleeping [i] = false ;
- break ;
- }
-
- ASSERT (i != host->maxConnections) ;
-
- host->activeCxns++ ;
-
- hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the connection when it is no longer connected to the
- * remote. Perhaps due to getting a code 400 to an IHAVE, or due to a
- * periodic close.
- */
-void hostCxnDead (Host host, Connection cxn)
-{
- unsigned int i ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- {
- if (host->cxnActive [i]) /* won't be active if got 400 on banner */
- {
- host->cxnActive [i] = false ;
- host->activeCxns-- ;
-
- if (!amClosing (host) && host->activeCxns == 0)
- {
- clearTimer (host->statsId) ;
- clearTimer (host->ChkCxnsId) ;
- hostLogStats (host,true) ;
- host->connectTime = 0 ;
- }
- }
- else if (host->cxnSleeping [i]) /* cxnNuke can be called on sleepers */
- {
- host->cxnSleeping [i] = false ;
- host->sleepingCxns-- ;
- }
-
- break ;
- }
-
- ASSERT (i < host->maxConnections) ;
- hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it is going to sleep so the Host won't
- * bother trying to give it Articles
- */
-void hostCxnSleeping (Host host, Connection cxn)
-{
- unsigned int i ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- {
- if (!host->cxnSleeping [i])
- {
- host->cxnSleeping [i] = true ;
- host->sleepingCxns++ ;
- }
-
- if (host->spoolTime == 0 && host->sleepingCxns >= host->maxConnections)
- hostStartSpooling (host) ;
-
- break ;
- }
-
- ASSERT (i < host->maxConnections) ;
-
- hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it goes into the waiting state.
- */
-void hostCxnWaiting (Host host, Connection cxn)
-{
- unsigned int i ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- {
- if (host->cxnSleeping [i])
- host->sleepingCxns-- ;
- host->cxnSleeping [i] = false ;
- break ;
- }
-
- ASSERT (i < host->maxConnections) ;
-
- if (host->spoolTime > 0)
- hostStopSpooling (host) ;
-
- hostLogStatus () ;
-}
-
-
-
-
-
-
-\f
-/*
- * Called by the Connection when it is about to delete itself.
- */
-bool hostCxnGone (Host host, Connection cxn)
-{
- unsigned int i;
- bool oneThere = false ;
- char msgstr[SMBUF] ;
-
- /* forget about the Connection and see if we are still holding any live
- connections still. */
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] == cxn)
- {
- if (!amClosing (host))
- {
- warn ("%s:%d connection vanishing", host->params->peerName, i) ;
- }
- host->connections [i] = NULL ;
- if (host->cxnActive [i])
- {
- host->cxnActive [i] = false ;
- host->activeCxns-- ;
- }
- else if (host->cxnSleeping [i])
- {
- host->cxnSleeping [i] = false ;
- host->sleepingCxns-- ;
- }
- }
- else if (host->connections [i] != NULL)
- oneThere = true ;
-
- /* remove the host if it has no connexions */
- if ( !oneThere )
- {
- time_t now = theTime() ;
- unsigned int hostsLeft ;
-
- if (host->firstConnectTime > 0) {
- snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
- host->gArtsSizeAccepted, host->gArtsSizeRejected);
- notice ("%s global seconds %ld offered %d accepted %d refused %d"
- " rejected %d missing %d %s spooled %d unspooled %d",
- host->params->peerName, (long) (now - host->firstConnectTime),
- host->gArtsOffered, host->gArtsAccepted,
- host->gArtsNotWanted, host->gArtsRejected,
- host->gArtsMissing, msgstr,
- host->gArtsToTape, host->gArtsFromTape) ;
- }
-
- hostsLeft = listenerHostGone (host->listener, host) ;
- delHost (host) ;
-
- if (hostsLeft == 0) {
- snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
- procArtsSizeAccepted, procArtsSizeRejected);
- notice ("ME global seconds %ld offered %ld accepted %ld refused %ld"
- " rejected %ld missing %ld %s spooled %ld unspooled %ld",
- (long) (now - start),
- procArtsOffered, procArtsAccepted,
- procArtsNotWanted,procArtsRejected,
- procArtsMissing, msgstr,
- procArtsToTape, procArtsFromTape) ;
- }
-
- /* return true if that was the last host */
- return (hostsLeft == 0 ? true : false) ;
- }
-
- /* return false because there is still at least one host (this one) */
- return false ;
-}
-
-
-
-
-
-
-\f
-/*
- * The connections has offered an article to the remote.
- */
-void hostArticleOffered (Host host, Connection cxn UNUSED)
-{
- host->artsOffered++ ;
- host->gArtsOffered++ ;
- procArtsOffered++ ;
-}
-
-
-
-
-
-
-\f
-/*
- * Article was succesfully transferred.
- */
-void hostArticleAccepted (Host host, Connection cxn, Article article)
-{
- const char *filename = artFileName (article) ;
- const char *msgid = artMsgId (article) ;
- double len = artSize (article);
-
- d_printf (5,"Article %s (%s) was transferred\n", msgid, filename) ;
-
- host->artsAccepted++ ;
- host->gArtsAccepted++ ;
- procArtsAccepted++ ;
- host->artsSizeAccepted += len ;
- host->gArtsSizeAccepted += len ;
- procArtsSizeAccepted += len ;
-
- /* host has two references to the article here... the parameter `article'
- and the queue */
-
- delArticle (article) ; /* drop the parameter reference */
-
- if (!amClosing (host))
- articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/*
- * remote said no thanks to an article.
- */
-void hostArticleNotWanted (Host host, Connection cxn, Article article)
-{
- const char *filename = artFileName (article) ;
- const char *msgid = artMsgId (article) ;
-
- d_printf (5,"Article %s (%s) was not wanted\n", msgid, filename) ;
-
- host->artsNotWanted++ ;
- host->gArtsNotWanted++ ;
- procArtsNotWanted++ ;
-
-
- /* host has two references to the article here... `article' and the
- queue */
-
- delArticle (article) ; /* drop the `article' reference */
-
- if (!amClosing (host))
- articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/*
- * remote rejected the article after it was was transferred
- */
-void hostArticleRejected (Host host, Connection cxn, Article article)
-{
- const char *filename = artFileName (article) ;
- const char *msgid = artMsgId (article) ;
- double len = artSize (article);
-
- d_printf (5,"Article %s (%s) was rejected\n", msgid, filename) ;
-
- host->artsRejected++ ;
- host->gArtsRejected++ ;
- procArtsRejected++ ;
- host->artsSizeRejected += len ;
- host->gArtsSizeRejected += len ;
- procArtsSizeRejected += len ;
-
- /* host has two references to the article here... `article' and the queue */
-
- delArticle (article) ; /* drop the `article' reference */
-
- if (!amClosing (host))
- articleGone (host,cxn,article) ;
-}
-
-
-
-
-
-
-\f
-/*
- * The remote wants us to retry the article later.
- */
-void hostArticleDeferred (Host host, Connection cxn, Article article)
-{
- host->artsDeferred++ ;
- host->gArtsDeferred++ ;
- procArtsDeferred++ ;
-
-
- if (!amClosing (host))
- {
- Article extraRef ;
- int deferTimeout = 5 ; /* XXX - should be tunable */
- time_t now = theTime() ;
-
- extraRef = artTakeRef (article) ; /* hold a reference until requeued */
- articleGone (host,cxn,article) ; /* drop from the queue */
-
- if (host->deferred == NULL)
- {
- if (host->deferredId != 0)
- clearTimer (host->deferredId) ;
- host->deferredId = prepareSleep (hostDeferredArtCbk, deferTimeout,
- host) ;
- }
-
- queueArticle (article,&host->deferred,&host->deferredTail,
- now + deferTimeout) ;
- host->deferLen++ ;
- backlogToTape (host) ;
- delArticle (extraRef) ;
- }
- else
- delArticle(article); /*drop parameter reference if not sent to tape*/
-}
-
-
-
-
-
-
-\f
-/*
- * The Connection is giving the article back to the Host, but it doesn't
- * want a new one in return.
- */
-void hostTakeBackArticle (Host host, Connection cxn UNUSED, Article article)
-{
- if (!amClosing (host))
- {
- Article extraRef ;
-
- host->artsCxnDrop++ ;
- host->gArtsCxnDrop++ ;
- extraRef = artTakeRef (article) ; /* hold a reference until requeued */
- articleGone (host,NULL,article) ; /* drop from the queue */
- host->notThisCxn = cxn;
- hostSendArticle (host, article) ; /* requeue it */
- host->notThisCxn = NULL;
- delArticle (extraRef) ;
- }
- else
- delArticle(article); /*drop parameter reference if not sent to tape*/
-
-}
-
-
-
-
-
-
-\f
-/*
- * The disk file for the article is no longer valid
- */
-void hostArticleIsMissing (Host host, Connection cxn, Article article)
-{
- const char *filename = artFileName (article) ;
- const char *msgid = artMsgId (article) ;
-
- d_printf (5, "%s article is missing %s %s\n", host->params->peerName, msgid, filename) ;
-
- host->artsMissing++ ;
- host->gArtsMissing++ ;
- procArtsMissing++ ;
-
- /* host has two references to the article here... `article' and the
- queue */
-
- delArticle (article) ; /* drop the `article' reference */
-
- if (!amClosing (host))
- articleGone (host,cxn,article) ; /* and the one in the queue */
-}
-
-
-
-
-
-
-\f
-/* The Connection wants something to do. This is called by the Connection
- * after it has transferred an article. This is what keeps the pipes full
- * of data off the tapes if the input from inn is idle.
- */
-bool hostGimmeArticle (Host host, Connection cxn)
-{
- Article article = NULL ;
- bool gaveSomething = false ;
- size_t amtToGive = cxnQueueSpace (cxn) ; /* may be more than one */
- int feed = 0 ;
-
- if (amClosing (host))
- {
- d_printf (5,"%s no article to give due to closing\n",host->params->peerName) ;
-
- return false ;
- }
-
- if (amtToGive == 0)
- d_printf (5,"%s Queue space is zero....\n",host->params->peerName) ;
-
- while (amtToGive > 0)
- {
- bool tookIt ;
- unsigned int queue = host->params->maxChecks - amtToGive ;
-
- if (host->params->backlogFeedFirst) {
- if ((article = getArticle (host->myTape)) != NULL)
- feed = 2;
- else if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
- feed = 1;
- else
- feed = 3;
- }
- else {
- if ((article = remHead (&host->queued,&host->queuedTail)) != NULL)
- feed = 1;
- else if ((article = getArticle (host->myTape)) != NULL)
- feed = 2;
- else
- feed = 3;
- }
-
- switch (feed) {
- case 1:
- host->backlog-- ;
- tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
-
- ASSERT (tookIt == true) ;
-
- if (queue == 0) host->gNoQueue++ ;
- else host->gCxnQueue += queue ;
-
- queueArticle (article,&host->processed,&host->processedTail, 0) ;
- amtToGive-- ;
-
- gaveSomething = true ;
- break ;
-
- case 2:
- /* go to the tapes */
- tookIt = cxnQueueArticle (cxn,artTakeRef (article)) ;
-
- ASSERT (tookIt == true) ;
-
- if (queue == 0) host->gNoQueue++ ;
- else host->gCxnQueue += queue ;
-
- host->artsFromTape++ ;
- host->gArtsFromTape++ ;
- procArtsFromTape++ ;
- queueArticle (article,&host->processed,&host->processedTail, 0) ;
- amtToGive-- ;
-
- gaveSomething = true ;
-
- break ;
-
- case 3:
- /* we had nothing left to give... */
-
- if (host->processed == NULL) /* and if nothing outstanding... */
- listenerHostIsIdle (host->listener,host) ; /* tell our owner */
-
- amtToGive = 0 ;
-
- break ;
- }
- }
-
- return gaveSomething ;
-}
-
-
-
-
-
-
-\f
-/*
- * get the name that INN uses for this host
- */
-const char *hostPeerName (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->peerName ;
-}
-
-/*
- * get the IPv4 bindaddress
- */
-const struct sockaddr_in *hostBindAddr (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->bindAddr ;
-}
-
-#ifdef HAVE_INET6
-/*
- * get the IPv6 bindaddress
- */
-const struct sockaddr_in6 *hostBindAddr6 (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->bindAddr6 ;
-}
-
-/*
- * get the address family
- */
-int hostAddrFamily (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->family ;
-}
-#endif
-
-/*
- * get the username and password for authentication
- */
-const char *hostUsername (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->username ;
-}
-const char *hostPassword (Host host)
-{
- ASSERT (host != NULL) ;
-
- return host->params->password ;
-}
-
-
-/* return true if the Connections for this host should attempt to do
- streaming. */
-bool hostWantsStreaming (Host host)
-{
- return host->params->wantStreaming ;
-}
-
-unsigned int hostMaxChecks (Host host)
-{
- return host->params->maxChecks ;
-}
-
-bool hostDropDeferred (Host host)
-{
- return host->params->dropDeferred ;
-}
-
-
-
-
-
-
-\f
-/**********************************************************************/
-/** CLASS FUNCTIONS **/
-/**********************************************************************/
-
-/*
- * Set the state of whether each Connection is told to log its stats when
- * its controlling Host logs its stats.
- */
-void hostLogConnectionStats (bool val)
-{
- logConnectionStats = val ;
-}
-
-
-bool hostLogConnectionStatsP (void)
-{
- return logConnectionStats ;
-}
-
-
-
-/*
- * Called by one of the Host's Connection's when it (the Connection)
- * switches into or out of no-CHECK mode.
- */
-void hostLogNoCheckMode (Host host, bool on, double low, double cur, double high)
-{
- if (on && host->loggedModeOn == false)
- {
- notice ("%s mode no-CHECK entered [%.2f,%.2f,%.2f]",
- host->params->peerName, low, cur, high) ;
- host->loggedModeOn = true ;
- }
- else if (!on && host->loggedModeOff == false)
- {
- notice ("%s mode no-CHECK exited [%.2f,%.2f,%.2f]",
- host->params->peerName, low, cur, high) ;
- host->loggedModeOff = true ;
- }
-}
-
-
-
-void hostSetStatusFile (const char *filename)
-{
- FILE *fp ;
-
- if (filename == NULL)
- die ("Can't set status file name with a NULL filename\n") ;
- else if (*filename == '\0')
- die ("Can't set status file name with a empty string\n") ;
-
- if (*filename == '/')
- statusFile = xstrdup (filename) ;
- else
- statusFile = concatpath (innconf->pathlog,filename) ;
-
- if ((fp = fopen (statusFile,"w")) == NULL)
- {
- syslog (LOG_ERR,"Status file is not a valid pathname: %s",
- statusFile) ;
- free (statusFile) ;
- statusFile = NULL ;
- }
- else
- fclose (fp) ;
-}
-
-void gHostStats (void)
-{
- Host h ;
- time_t now = theTime() ;
- char msgstr[SMBUF] ;
-
- for (h = gHostList ; h != NULL ; h = h->next)
- if (h->firstConnectTime > 0) {
- snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
- h->gArtsSizeAccepted, h->gArtsSizeRejected);
- notice ("%s global seconds %ld offered %d accepted %d refused %d"
- " rejected %d missing %d %s spooled %d unspooled %d",
- h->params->peerName,
- (long) (now - h->firstConnectTime),
- h->gArtsOffered, h->gArtsAccepted,
- h->gArtsNotWanted, h->gArtsRejected,
- h->gArtsMissing, msgstr,
- h->gArtsToTape, h->gArtsFromTape) ;
- }
-}
-
-
-
-/**********************************************************************/
-/** PRIVATE FUNCTIONS **/
-/**********************************************************************/
-
-
-
-
-#define INHERIT 1
-#define NO_INHERIT 0
-
-\f
-static HostParams hostDetails (scope *s,
- char *name,
- bool isDefault,
- FILE *fp)
-{
- long iv ;
- int bv, vival, inherit ;
- HostParams p;
- char * q;
- double rv, l, h ;
- value * v;
-
- p=newHostParams(isDefault?NULL:defaultParams);
-
- if (isDefault)
- {
- ASSERT (name==NULL);
- }
- else
- {
- if (name)
- {
- p->peerName=xstrdup(name);
- }
-
- if (s != NULL)
- {
- if (getString (s,IP_NAME,&q,NO_INHERIT))
- p->ipName = q ;
- else
- p->ipName = xstrdup (name) ;
- }
-
- if (getString (s,"username",&q,NO_INHERIT))
- p->username = q;
- if (getString (s,"password",&q,NO_INHERIT))
- p->password = q;
-
- if (p->username != NULL && p->password == NULL)
- logOrPrint (LOG_ERR,fp,"cannot find password for %s",p->peerName);
- if (p->username == NULL && p->password != NULL)
- logOrPrint (LOG_ERR,fp,"cannot find username for %s",p->peerName);
-
- }
-
-#ifdef HAVE_INET6
- if (getString(s,"bindaddress6",&q,isDefault?NO_INHERIT:INHERIT))
- {
- struct addrinfo *res, hints;
-
- if (strcmp(q, "none") == 0)
- p->family = AF_INET;
- else if (p->family == AF_INET)
- p->family = 0;
-
- if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
- strcmp(q, "none") != 0)
- {
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_flags = AI_NUMERICHOST;
- if( getaddrinfo( q, NULL, &hints, &res ) )
- {
- logOrPrint (LOG_ERR, fp,
- "unable to determine IPv6 bind address for %s",
- p->peerName) ;
- }
- else
- {
- p->bindAddr6 = (struct sockaddr_in6 *) xmalloc (res->ai_addrlen);
- memcpy( p->bindAddr6, res->ai_addr, res->ai_addrlen );
- }
- }
- }
-#endif
-
- if (getString(s,"bindaddress",&q,isDefault?NO_INHERIT:INHERIT))
- {
- struct in_addr addr ;
-
-#ifdef HAVE_INET6
- if (strcmp(q, "none") == 0) {
- if (p->family) {
- logOrPrint (LOG_ERR,fp,"cannot set both bindaddress and bindaddress6"
- " to \"none\" -- ignoring them for %s",p->peerName);
- p->family = 0;
- } else {
- p->family = AF_INET6;
- }
- } else if (p->family == AF_INET6)
- p->family = 0;
-#endif
-
- if (strcmp(q, "any") != 0 && strcmp(q, "all") != 0 &&
- strcmp(q, "none") != 0)
- {
- if (!inet_aton(q,&addr))
- {
- logOrPrint (LOG_ERR, fp,
- "unable to determine IPv4 bind address for %s",
- p->peerName) ;
- }
- else
- {
- p->bindAddr = (struct sockaddr_in *)
- xmalloc (sizeof(struct sockaddr_in));
- make_sin( (struct sockaddr_in *)p->bindAddr, &addr );
- }
- }
- }
-
- /* check required global defaults are there and have good values */
-
-
-#define GETINT(sc,f,n,min,max,req,val,inh) \
- vival = validateInteger(f,n,min,max,req,val,sc,inh); \
- if (isDefault) do{ \
- if(vival==VALUE_WRONG_TYPE) \
- { \
- logOrPrint(LOG_CRIT,fp,"cannot continue"); \
- exit(1); \
- } \
- else if(vival != VALUE_OK) \
- val = 0; \
- } while(0); \
- iv = 0 ; \
- getInteger (sc,n,&iv,inh) ; \
- val = (unsigned int) iv ;
-
-#define GETREAL(sc,f,n,min,max,req,val,inh) \
- vival = validateReal(f,n,min,max,req,val,sc,inh); \
- if (isDefault) do{ \
- if(vival==VALUE_WRONG_TYPE) \
- { \
- logOrPrint(LOG_CRIT,fp,"cannot continue"); \
- exit(1); \
- } \
- else if(vival != VALUE_OK) \
- rv = 0; \
- } while(0); \
- rv = 0 ; \
- getReal (sc,n,&rv,inh) ; \
- val = rv ;
-
-#define GETBOOL(sc,f,n,req,val,inh) \
- vival = validateBool(f,n,req,val,sc,inh); \
- if (isDefault) do{ \
- if(vival==VALUE_WRONG_TYPE) \
- { \
- logOrPrint(LOG_CRIT,fp,"cannot continue"); \
- exit(1); \
- } \
- else if(vival != VALUE_OK) \
- bv = 0; \
- } while(0); \
- bv = 0 ; \
- getBool (sc,n,&bv,inh) ; \
- val = (bv ? true : false);
-
- inherit = isDefault?NO_INHERIT:INHERIT;
- GETINT(s,fp,"article-timeout",0,LONG_MAX,REQ,p->articleTimeout, inherit);
- GETINT(s,fp,"response-timeout",0,LONG_MAX,REQ,p->responseTimeout, inherit);
- GETINT(s,fp,"close-period",0,LONG_MAX,REQ,p->closePeriod, inherit);
- GETINT(s,fp,"initial-connections",0,LONG_MAX,REQ,p->initialConnections, inherit);
- GETINT(s,fp,"max-connections",0,LONG_MAX,REQ,p->absMaxConnections, inherit);
- GETINT(s,fp,"max-queue-size",1,LONG_MAX,REQ,p->maxChecks, inherit);
- GETBOOL(s,fp,"streaming",REQ,p->wantStreaming, inherit);
- GETBOOL(s,fp,"drop-deferred",REQ,p->dropDeferred, inherit);
- GETBOOL(s,fp,"min-queue-connection",REQ,p->minQueueCxn, inherit);
- GETREAL(s,fp,"no-check-high",0.0,100.0,REQ,p->lowPassHigh, inherit);
- GETREAL(s,fp,"no-check-low",0.0,100.0,REQ,p->lowPassLow, inherit);
- GETREAL(s,fp,"no-check-filter",0.1,DBL_MAX,REQ,p->lowPassFilter, inherit);
- GETINT(s,fp,"port-number",0,LONG_MAX,REQ,p->portNum, inherit);
- GETINT(s,fp,"backlog-limit",0,LONG_MAX,REQ,p->backlogLimit, inherit);
-
-#ifdef HAVE_INET6
- GETBOOL(s,fp,"force-ipv4",NOTREQ,p->forceIPv4,inherit);
- if (p->forceIPv4)
- p->family = AF_INET;
-#endif
-
- if (findValue (s,"backlog-factor",inherit) == NULL &&
- findValue (s,"backlog-limit-high",inherit) == NULL)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: must define at least one of backlog-factor"
- " and backlog-limit-high. Adding %s: %f", "backlog-factor",
- LIMIT_FUDGE) ;
- addReal (s,"backlog-factor",LIMIT_FUDGE) ;
- rv = 0 ;
- }
-
- GETBOOL(s,fp,"backlog-feed-first",NOTREQ,p->backlogFeedFirst, inherit);
-
- /* Innfeed should emit a warning if backlog-feed-first is set
- to "true" for any peer that doesn't have max-connections and
- initial-connections both set to "1" */
- if ((p->backlogFeedFirst)
- && ((p->initialConnections <= 1) || (p->absMaxConnections != 1)))
- {
- if (p->peerName != NULL)
- logOrPrint (LOG_WARNING,fp,
- "ME config: innfeed will make more than one connection"
- " to peer %s, but backlog-feed-first is set", p->peerName);
- else
- logOrPrint (LOG_WARNING,fp,
- "ME config: innfeed will make more than one connection"
- " to peer, but backlog-feed-first is set");
- }
-
- GETINT(s,fp,"backlog-limit-high",0,LONG_MAX,NOTREQNOADD,p->backlogLimitHigh, inherit);
- GETREAL(s,fp,"backlog-factor",1.0,DBL_MAX,NOTREQNOADD,p->backlogFactor, inherit);
-
- GETINT(s,fp,"dynamic-method",0,3,REQ,p->dynamicMethod, inherit);
- GETREAL(s,fp,"dynamic-backlog-filter",0.0,DBL_MAX,REQ,p->dynBacklogFilter, inherit);
- GETREAL(s,fp,"dynamic-backlog-low",0.0,100.0,REQ,p->dynBacklogLowWaterMark, inherit);
- GETREAL(s,fp,"dynamic-backlog-high",0.0,100.0,REQ,p->dynBacklogHighWaterMark, inherit);
-
- l=p->lowPassLow;
- h=p->lowPassHigh;
- if (l > h)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: no-check-low value greater than no-check-high"
- " (%f vs %f). Setting to %f and %f", l, h, NOCHECKLOW,
- NOCHECKHIGH) ;
- rv = 0 ;
- v = findValue (s,"no-check-low",NO_INHERIT) ;
- v->v.real_val = p->lowPassLow = NOCHECKLOW ;
- v = findValue (s,"no-check-high",NO_INHERIT) ;
- v->v.real_val = p->lowPassHigh = NOCHECKHIGH ;
- }
- else if (h - l < 5.0)
- logOrPrint (LOG_WARNING,fp,
- "ME config: no-check-low and no-check-high are close"
- " together (%f vs %f)",l,h) ;
-
- return p;
-}
-
-
-
-
-static HostParams getHostInfo (void)
-{
- static int idx = 0 ;
- value *v ;
- scope *s ;
- HostParams p=NULL;
-
- bool isGood = false ;
-
- if (topScope == NULL)
- return p;
-
- while ((v = getNextPeer (&idx)) != NULL)
- {
- if (!ISPEER (v))
- continue ;
-
- s = v->v.scope_val ;
-
- p=hostDetails(s,v->name,false,NULL);
-
- isGood = true ;
-
- break ;
- }
-
- if (v == NULL)
- idx = 0 ; /* start over next time around */
-
- return p;
-}
-
-
-/*
- * fully delete and clean up the Host object.
- */
-void delHost (Host host)
-{
- Host h,q ;
-
- for (h = gHostList, q = NULL ; h != NULL ; q = h, h = h->next)
- if (h == host)
- {
- if (gHostList == h)
- gHostList = gHostList->next ;
- else
- q->next = h->next ;
- break ;
- }
-
- ASSERT (h != NULL) ;
-
- delTape (host->myTape) ;
-
- free (host->connections) ;
- free (host->cxnActive) ;
- free (host->cxnSleeping) ;
- free (host->params->peerName) ;
- free (host->params->ipName) ;
-
- if (host->ipAddrs)
- {
- if(host->ipAddrs[0])
- free (host->ipAddrs[0]);
- free (host->ipAddrs) ;
- }
-
- free (host) ;
- gHostCount-- ;
-}
-
-
-\f
-static Host findHostByName (char *name)
-{
- Host h;
-
- for (h = gHostList; h != NULL; h = h->next)
- if ( strcmp(h->params->peerName, name) == 0 )
- return h;
-
- return NULL;
-}
-
-
-\f
-/*
- * the article can be dropped from the process queue and the connection can
- * take a new article if there are any to be had.
- */
-static void articleGone (Host host, Connection cxn, Article article)
-{
- if ( !remArticle (article,&host->processed,&host->processedTail) )
- die ("remArticle in articleGone failed") ;
-
- delArticle (article) ;
-
- if (cxn != NULL)
- hostGimmeArticle (host,cxn) ; /* may not give anything over */
-}
-
-
-
-
-
-
-\f
-/*
- * One of the Connections for this Host has reestablished itself, so stop
- * spooling article info to disk.
- */
-static void hostStopSpooling (Host host)
-{
- ASSERT (host->spoolTime != 0) ;
-
- clearTimer (host->statsId) ;
- hostLogStats (host,true) ;
-
- host->spoolTime = 0 ;
-}
-
-
-
-
-
-
-\f
-/*
- * No connections are active and we're getting response 201 or 400 (or some
- * such) so that we need to start spooling article info to disk.
- */
-static void hostStartSpooling (Host host)
-{
- ASSERT (host->spoolTime == 0) ;
-
- queuesToTape (host) ;
-
- hostLogStats (host,true) ;
-
- host->spoolTime = theTime() ;
- if (host->firstConnectTime == 0)
- host->firstConnectTime = host->spoolTime ;
-
- /* don't want to log too frequently */
- if (SPOOL_LOG_PERIOD > 0 &&
- (host->spoolTime - host->lastSpoolTime) > SPOOL_LOG_PERIOD)
- {
- notice ("%s spooling no active connections", host->params->peerName) ;
- host->lastSpoolTime = host->spoolTime ;
- }
-
- host->connectTime = 0 ;
-
- host->notifiedChangedRemBlckd = false ;
-
- clearTimer (host->statsId) ;
- host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-}
-
-
-
-
-
-
-\f
-/*
- * Time to log the statistics for the Host. If FINAL is true then the
- * counters will be reset.
- */
-static void hostLogStats (Host host, bool final)
-{
- time_t now = theTime() ;
- time_t *startPeriod ;
- double cnt = (host->blCount) ? (host->blCount) : 1.0;
- char msgstr[SMBUF] ;
-
- if (host->spoolTime == 0 && host->connectTime == 0)
- return ; /* host has never connected and never started spooling*/
-
- startPeriod = (host->spoolTime != 0 ? &host->spoolTime : &host->connectTime);
-
- if (now - *startPeriod >= statsResetPeriod)
- final = true ;
-
- if (host->spoolTime != 0)
- notice ("%s %s seconds %ld spooled %d on_close %d sleeping %d",
- host->params->peerName, (final ? "final" : "checkpoint"),
- (long) (now - host->spoolTime), host->artsToTape,
- host->artsHostClose, host->artsHostSleep) ;
- else {
- snprintf(msgstr, sizeof(msgstr), "accsize %.0f rejsize %.0f",
- host->artsSizeAccepted, host->artsSizeRejected);
- notice ("%s %s seconds %ld offered %d accepted %d refused %d rejected %d"
- " missing %d %s spooled %d on_close %d unspooled %d"
- " deferred %d/%.1f requeued %d"
- " queue %.1f/%d:%.0f,%.0f,%.0f,%.0f,%.0f,%.0f",
- host->params->peerName, (final ? "final" : "checkpoint"),
- (long) (now - host->connectTime),
- host->artsOffered, host->artsAccepted,
- host->artsNotWanted, host->artsRejected,
- host->artsMissing, msgstr,
- host->artsToTape,
- host->artsHostClose, host->artsFromTape,
- host->artsDeferred, (double)host->dlAccum/cnt,
- host->artsCxnDrop,
- (double)host->blAccum/cnt, hostHighwater,
- (100.0*host->blNone)/cnt,
- (100.0*host->blQuartile[0])/cnt, (100.0*host->blQuartile[1])/cnt,
- (100.0*host->blQuartile[2])/cnt, (100.0*host->blQuartile[3])/cnt,
- (100.0*host->blFull)/cnt) ;
- }
-
- if (logConnectionStats)
- {
- unsigned int i ;
-
- for (i = 0 ; i < host->maxConnections ; i++)
- if (host->connections [i] != NULL && host->cxnActive [i])
- cxnLogStats (host->connections [i],final) ;
- }
-
- /* one 'spooling backlog' message per stats logging period */
- host->loggedBacklog = false ;
- host->loggedModeOn = host->loggedModeOff = false ;
-
- if (final)
- {
- host->artsOffered = 0 ;
- host->artsAccepted = 0 ;
- host->artsNotWanted = 0 ;
- host->artsRejected = 0 ;
- host->artsDeferred = 0 ;
- host->artsMissing = 0 ;
- host->artsToTape = 0 ;
- host->artsQueueOverflow = 0 ;
- host->artsCxnDrop = 0 ;
- host->artsHostSleep = 0 ;
- host->artsHostClose = 0 ;
- host->artsFromTape = 0 ;
- host->artsSizeAccepted = 0 ;
- host->artsSizeRejected = 0 ;
-
- *startPeriod = theTime () ; /* in of case STATS_RESET_PERIOD */
- }
-
- /* reset these each log period */
- host->blNone = 0 ;
- host->blFull = 0 ;
- host->blQuartile[0] = host->blQuartile[1] = host->blQuartile[2] =
- host->blQuartile[3] = 0;
- host->dlAccum = 0;
- host->blAccum = 0;
- host->blCount = 0;
-
-#if 0
- /* XXX turn this section on to get a snapshot at each log period. */
- if (gPrintInfo != NULL)
- gPrintInfo () ;
-#endif
-}
-
-
-
-
-
-
-\f
-
-static double
-convsize(double size, char **tsize)
-{
- double dsize;
- static char tTB[]="TB";
- static char tGB[]="GB";
- static char tMB[]="MB";
- static char tKB[]="KB";
- static char tB []="B";
-
- if (size/((double)1024*1024*1024*1000)>=1.) {
- dsize=size/((double)1024*1024*1024*1024);
- *tsize=tTB;
- } else if (size/(1024*1024*1000)>=1.) {
- dsize=size/(1024*1024*1024);
- *tsize=tGB;
- } else if (size/(1024*1000)>=1.) {
- dsize=size/(1024*1024);
- *tsize=tMB;
- } else if (size/1000>=1.) {
- dsize=size/1024;
- *tsize=tKB;
- } else {
- dsize=size;
- *tsize=tB;
- }
- return dsize;
-}
-
-
-/*
- * Log the status of the Hosts.
- */
-extern char *versionInfo ;
-static void hostLogStatus (void)
-{
- FILE *fp = NULL ;
- Host h ;
- bool anyToLog = false ;
- unsigned int peerNum = 0, actConn = 0, slpConn = 0, maxcon = 0 ;
- static bool logged = false ;
- static bool flogged = false ;
-
- if (statusFile == NULL && !logged)
- {
- syslog (LOG_ERR,"No status file to write to") ;
- logged = true ;
- return ;
- }
-
- logged = false ;
-
- for (h = gHostList ; h != NULL ; h = h->next)
- if (h->myTape != NULL) /* the host deletes its tape when it's closing */
- {
- anyToLog = true ;
- peerNum++ ;
- actConn += h->activeCxns ;
- slpConn += h->sleepingCxns ;
- maxcon += h->maxConnections ;
- }
-
- if (!anyToLog)
- return ;
-
- lastStatusLog = theTime() ;
-
- TMRstart(TMR_STATUSFILE);
- if ((fp = fopen (statusFile,"w")) == NULL)
- {
- if ( !flogged )
- syswarn ("ME oserr status file open: %s", statusFile) ;
- flogged = true ;
- }
- else
- {
- char timeString [30] ;
- time_t now ;
- long sec ;
- long offered ;
- double size, totalsize;
- char *tsize;
-
- flogged = false ;
-
- now = time (NULL) ;
- sec = (long) (now - start) ;
- strlcpy (timeString,ctime (&now),sizeof (timeString)) ;
-
- if (genHtml)
- {
- fprintf (fp, "<HTML>\n"
- "<HEAD>\n"
- "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"300;\">\n"
- "</HEAD>\n"
- "<BODY>\n") ;
- fprintf (fp, "\n");
- fprintf (fp, "<PRE>\n");
- }
-
- fprintf (fp,"%s\npid %d started %s\nUpdated: %s",
- versionInfo,(int) myPid,startTime,timeString) ;
- fprintf (fp,"(peers: %d active-cxns: %d sleeping-cxns: %d idle-cxns: %d)\n\n",
- peerNum, actConn, slpConn,(maxcon - (actConn + slpConn))) ;
-
- fprintf (fp,"Configuration file: %s\n\n",configFile) ;
-
- if (genHtml)
- {
- fprintf (fp, "</PRE>\n");
- fprintf (fp,"<UL>\n");
- for (h = gHostList ; h != NULL ; h = h->next)
- fprintf (fp,"<LI><A href=\"#%s\">%s</A></LI>\n",
- h->params->peerName, h->params->peerName);
- fprintf (fp,"</UL>\n\n");
- fprintf (fp,"<PRE>\n");
- }
-
- mainLogStatus (fp) ;
- listenerLogStatus (fp) ;
-
-/*
-Default peer configuration parameters:
- article timeout: 600 initial connections: 1
- response timeout: 300 max connections: 5
- close period: 6000 max checks: 25
- want streaming: true dynamic method: 1
- no-check on: 95.0% dynamic backlog low: 25%
- no-check off: 90.0% dynamic backlog high: 50%
- no-check filter: 50.0 dynamic backlog filter: 0.7
- backlog low limit: 1024 port num: 119
- backlog high limit: 1280 backlog feed first: false
- backlog factor: 1.1
-*/
- fprintf(fp,"%sDefault peer configuration parameters:%s\n",
- genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
- fprintf(fp," article timeout: %-5d initial connections: %d\n",
- defaultParams->articleTimeout,
- defaultParams->initialConnections) ;
- fprintf(fp," response timeout: %-5d max connections: %d\n",
- defaultParams->responseTimeout,
- defaultParams->absMaxConnections) ;
- fprintf(fp," close period: %-5d max checks: %d\n",
- defaultParams->closePeriod,
- defaultParams->maxChecks) ;
- fprintf(fp," want streaming: %-5s dynamic method: %d\n",
- defaultParams->wantStreaming ? "true " : "false",
- defaultParams->dynamicMethod) ;
- fprintf(fp," no-check on: %-2.1f%% dynamic backlog low: %-2.1f%%\n",
- defaultParams->lowPassHigh,
- defaultParams->dynBacklogLowWaterMark) ;
- fprintf(fp," no-check off: %-2.1f%% dynamic backlog high: %-2.1f%%\n",
- defaultParams->lowPassLow,
- defaultParams->dynBacklogHighWaterMark) ;
- fprintf(fp," no-check filter: %-2.1f dynamic backlog filter: %-2.1f\n",
- defaultParams->lowPassFilter,
- defaultParams->dynBacklogFilter) ;
- fprintf(fp," backlog limit low: %-7d drop-deferred: %s\n",
- defaultParams->backlogLimit,
- defaultParams->dropDeferred ? "true " : "false");
- fprintf(fp," backlog limit high: %-7d min-queue-cxn: %s\n",
- defaultParams->backlogLimitHigh,
- defaultParams->minQueueCxn ? "true " : "false");
- fprintf(fp," backlog feed first: %s\n",
- defaultParams->backlogFeedFirst ? "true " : "false");
- fprintf(fp," backlog factor: %1.1f\n\n",
- defaultParams->backlogFactor);
-
- tapeLogGlobalStatus (fp) ;
-
- fprintf (fp,"\n") ;
- fprintf(fp,"%sglobal (process)%s\n",
- genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
-
- fprintf (fp, " seconds: %ld\n", sec) ;
- if (sec == 0) sec = 1 ;
- offered = procArtsOffered ? procArtsOffered : 1 ;
- totalsize = procArtsSizeAccepted+procArtsSizeRejected ;
- if (totalsize == 0) totalsize = 1. ;
-
- fprintf (fp, " offered: %-5ld\t%6.2f art/s\n",
- procArtsOffered,
- (double)procArtsOffered/sec) ;
- fprintf (fp, " accepted: %-5ld\t%6.2f art/s\t%5.1f%%\n",
- procArtsAccepted,
- (double)procArtsAccepted/sec,
- (double)procArtsAccepted*100./offered) ;
- fprintf (fp, " refused: %-5ld\t%6.2f art/s\t%5.1f%%\n",
- procArtsNotWanted,
- (double)procArtsNotWanted/sec,
- (double)procArtsNotWanted*100./offered) ;
- fprintf (fp, " rejected: %-5ld\t%6.2f art/s\t%5.1f%%\n",
- procArtsRejected,
- (double)procArtsRejected/sec,
- (double)procArtsRejected*100./offered) ;
- fprintf (fp, " missing: %-5ld\t%6.2f art/s\t%5.1f%%\n",
- procArtsMissing,
- (double)procArtsMissing/sec,
- (double)procArtsMissing*100./offered) ;
- fprintf (fp, " deferred: %-5ld\t%6.2f art/s\t%5.1f%%\n",
- procArtsDeferred,
- (double)procArtsDeferred/sec,
- (double)procArtsDeferred*100./offered) ;
-
- size=convsize(procArtsSizeAccepted, &tsize);
- fprintf (fp, "accpt size: %.3g %s", size, tsize) ;
- size=convsize(procArtsSizeAccepted/sec, &tsize);
- fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
- size, tsize,
- procArtsSizeAccepted*100./totalsize) ;
-
- size=convsize(procArtsSizeRejected, &tsize);
- fprintf (fp, "rejct size: %.3g %s", size, tsize) ;
- size=convsize(procArtsSizeRejected/sec, &tsize);
- fprintf (fp, " \t%6.3g %s/s\t%5.1f%%\n",
- size, tsize,
- procArtsSizeRejected*100./totalsize) ;
-
- fprintf (fp, "\n");
-
- for (h = gHostList ; h != NULL ; h = h->next)
- hostPrintStatus (h,fp) ;
-
- if (genHtml)
- {
- fprintf (fp,"</PRE>\n") ;
- fprintf (fp,"</BODY>\n") ;
- fprintf (fp,"</HTML>\n") ;
- }
-
- fclose (fp) ;
- }
- TMRstop(TMR_STATUSFILE);
-}
-
-/*
- * This prints status information for each host. An example of the
- * format of the output is:
- *
- * sitename
- * seconds: 351 art. timeout: 400 ip name: foo.bar
- * offered: 1194 resp. timeout: 240 port: 119
- * accepted: 178 want streaming: yes active cxns: 6
- * refused: 948 is streaming: yes sleeping cxns: 0
- * rejected: 31 max checks: 25 initial cxns: 5
- * missing: 0 no-check on: 95.0% idle cxns: 4
- * deferred: 0 no-check off: 95.0% max cxns: 8/10
- * requeued: 0 no-check fltr: 50.0 queue length: 0.0/200
- * spooled: 0 dynamic method: 0 empty: 100.0%
- *[overflow]: 0 dyn b'log low: 25% >0%-25%: 0.0%
- *[on_close]: 0 dyn b'log high: 50% 25%-50%: 0.0%
- *[sleeping]: 0 dyn b'log stat: 37% 50%-75%: 0.0%
- * unspooled: 0 dyn b'log fltr: 0.7 75%-<100%: 0.0%
- * no queue: 1234 avr.cxns queue: 0.0 full: 0.0%
- *accpt size: 121.1 MB drop-deferred: false defer length: 0
- *rejct size: 27.1 MB min-queue-cxn: false
- * backlog low limit: 1000000
- * backlog high limit: 2000000 (factor 2.0)
- * backlog shrinkage: 0 bytes (from current file)
- * offered: 1.13 art/s accepted: 0.69 art/s (101.71 KB/s)
- * refused: 0.01 art/s rejected: 0.42 art/s (145.11 KB/s)
- * missing 0 spooled 0
- *
- */
-static void hostPrintStatus (Host host, FILE *fp)
-{
- time_t now = theTime() ;
- double cnt = (host->blCount) ? (host->blCount) : 1.0;
- double size;
- char *tsize;
- char buf[]="1234.1 MB";
-
- ASSERT (host != NULL) ;
- ASSERT (fp != NULL) ;
-
- if (genHtml)
- fprintf (fp,"<A name=\"%s\"><B>%s</B></A>",host->params->peerName,
- host->params->peerName);
- else
- fprintf (fp,"%s",host->params->peerName);
-
- if (host->blockedReason != NULL)
- fprintf (fp," (remote status: ``%s'')",host->blockedReason) ;
-
- fputc ('\n',fp) ;
-
- fprintf (fp, " seconds: %-7ld art. timeout: %-5d ip name: %s\n",
- host->firstConnectTime > 0 ? (long)(now - host->firstConnectTime) : 0,
- host->params->articleTimeout, host->params->ipName) ;
-
- fprintf (fp, " offered: %-7ld resp. timeout: %-5d port: %d\n",
- (long) host->gArtsOffered, host->params->responseTimeout,
- host->params->portNum);
-
- fprintf (fp, " accepted: %-7ld want streaming: %s active cxns: %d\n",
- (long) host->gArtsAccepted,
- (host->params->wantStreaming ? "yes" : "no "),
- host->activeCxns) ;
-
- fprintf (fp, " refused: %-7ld is streaming: %s sleeping cxns: %d\n",
- (long) host->gArtsNotWanted,
- (host->remoteStreams ? "yes" : "no "),
- host->sleepingCxns) ;
-
- fprintf (fp, " rejected: %-7ld max checks: %-5d initial cxns: %d\n",
- (long) host->gArtsRejected, host->params->maxChecks,
- host->params->initialConnections) ;
-
- fprintf (fp, " missing: %-7ld no-check on: %-3.1f%% idle cxns: %d\n",
- (long) host->gArtsMissing, host->params->lowPassHigh,
- host->maxConnections - (host->activeCxns + host->sleepingCxns)) ;
-
- fprintf (fp, " deferred: %-7ld no-check off: %-3.1f%% max cxns: %d/%d\n",
- (long) host->gArtsDeferred, host->params->lowPassLow,
- host->maxConnections, host->params->absMaxConnections) ;
-
- fprintf (fp, " requeued: %-7ld no-check fltr: %-3.1f queue length: %-3.1f/%d\n",
- (long) host->gArtsCxnDrop, host->params->lowPassFilter,
- (double)host->blAccum / cnt, hostHighwater) ;
-
- fprintf (fp, " spooled: %-7ld dynamic method: %-5d empty: %-3.1f%%\n",
- (long) host->gArtsToTape,
- host->params->dynamicMethod,
- 100.0 * host->blNone / cnt) ;
-
- fprintf (fp, "[overflow]: %-7ld dyn b'log low: %-3.1f%% >0%%-25%%: %-3.1f%%\n",
- (long) host->gArtsQueueOverflow,
- host->params->dynBacklogLowWaterMark,
- 100.0 * host->blQuartile[0] / cnt) ;
-
- fprintf (fp, "[on_close]: %-7ld dyn b'log high: %-3.1f%% 25%%-50%%: %-3.1f%%\n",
- (long) host->gArtsHostClose,
- host->params->dynBacklogHighWaterMark,
- 100.0 * host->blQuartile[1] / cnt) ;
-
- fprintf (fp, "[sleeping]: %-7ld dyn b'log stat: %-3.1f%% 50%%-75%%: %-3.1f%%\n",
- (long) host->gArtsHostSleep,
- host->backlogFilter*100.0*(1.0-host->params->dynBacklogFilter),
- 100.0 * host->blQuartile[2] / cnt) ;
-
- fprintf (fp, " unspooled: %-7ld dyn b'log fltr: %-3.1f 75%%-<100%%: %-3.1f%%\n",
- (long) host->gArtsFromTape,
- host->params->dynBacklogLowWaterMark,
- 100.0 * host->blQuartile[3] / cnt) ;
-
- fprintf (fp, " no queue: %-7ld avr.cxns queue: %-3.1f full: %-3.1f%%\n",
- (long) host->gNoQueue,
- (double) host->gCxnQueue / (host->gArtsOffered ? host->gArtsOffered :1) ,
- 100.0 * host->blFull / cnt) ;
- size=convsize(host->gArtsSizeAccepted, &tsize);
- snprintf(buf,sizeof(buf),"%.3g %s", size, tsize);
- fprintf (fp, "accpt size: %-8s drop-deferred: %-5s defer length: %-3.1f\n",
- buf, host->params->dropDeferred ? "true " : "false",
- (double)host->dlAccum / cnt) ;
- size=convsize(host->gArtsSizeRejected, &tsize);
- snprintf(buf,sizeof(buf),"%.3g %s", size, tsize);
- fprintf (fp, "rejct size: %-8s min-queue-cxn: %s\n",
- buf, host->params->minQueueCxn ? "true " : "false");
-
- tapeLogStatus (host->myTape,fp) ;
-
- {
- time_t sec = (time_t) (now - host->connectTime);
- double or, ar, rr, jr;
- double ars, jrs;
- char *tars, *tjrs;
- if (sec != 0) {
- or = (double) host->artsOffered / (double) sec;
- ar = (double) host->artsAccepted / (double) sec;
- rr = (double) host->artsNotWanted / (double) sec;
- jr = (double) host->artsRejected / (double) sec;
- ars = convsize (host->artsSizeAccepted/sec, &tars);
- jrs = convsize (host->artsSizeRejected/sec, &tjrs);
- fprintf(fp, " offered: %5.2f art/s accepted: %5.2f art/s, %.3g %s/s\n",
- or, ar, ars, tars);
- fprintf(fp, " refused: %5.2f art/s rejected: %5.2f art/s, %.3g %s/s\n",
- rr, jr, jrs, tjrs);
- }
- fprintf(fp, " missing %d spooled %d\n",
- host->artsMissing, host->artsToTape);
- }
-
-#ifdef XXX_STATSHACK
- {
- time_t now = time(NULL), sec = (long) (now - host->connectTime);
- float or, ar, rr, jr;
-
- if (sec != 0) {
- or = (float) host->artsOffered / (float) sec;
- ar = (float) host->artsAccepted / (float) sec;
- rr = (float) host->artsNotWanted / (float) sec;
- jr = (float) host->artsRejected / (float) sec;
- fprintf(fp, "\t\tor %02.2f ar %02.2f rr %02.2f jr %02.2f\n",
- or, ar, rr, jr);
- }
- fprintf(fp, "\tmissing %d spooled %d\n",
- host->artsMissing,host->backlogSpooled);
- }
-#endif /* XXX_STATSHACK */
-
- fprintf (fp, "\n\n");
-}
-
-
-
-
-
-
-\f
-/*
- * The callback function for the statistics timer to call.
- */
-static void hostStatsTimeoutCbk (TimeoutId tid UNUSED, void *data)
-{
- Host host = (Host) data ;
- time_t now = theTime () ;
-
- ASSERT (tid == host->statsId) ;
-
- if (!amClosing (host))
- hostLogStats (host, false) ;
-
- if (now - lastStatusLog >= statsPeriod)
- hostLogStatus () ;
-
- host->statsId = prepareSleep (hostStatsTimeoutCbk, statsPeriod, host) ;
-}
-
-
-/*
- * The callback function for the deferred article timer to call.
- */
-static void hostDeferredArtCbk (TimeoutId tid UNUSED, void *data)
-{
- Host host = (Host) data ;
- time_t now = theTime () ;
- Article article ;
-
- ASSERT (tid == host->deferredId) ;
-
- while (host->deferred && host->deferred->whenToRequeue <= now)
- {
- article = remHead (&host->deferred,&host->deferredTail) ;
- host->deferLen-- ;
- hostSendArticle (host, article) ; /* requeue it */
- }
-
- if (host->deferred)
- host->deferredId = prepareSleep (hostDeferredArtCbk,
- host->deferred->whenToRequeue - now,
- host) ;
- else
- host->deferredId = 0;
-}
-
-
-/* if the host has too many unprocessed articles so we send some to the tape. */
-static void backlogToTape (Host host)
-{
- Article article ;
-
- while ((host->backlog + host->deferLen) > hostHighwater)
- {
- if (!host->loggedBacklog)
- {
- host->loggedBacklog = true ;
- }
-
- if (host->deferred != NULL)
- {
- article = remHead (&host->deferred,&host->deferredTail) ;
- host->deferLen--;
- }
- else
- {
- article = remHead (&host->queued,&host->queuedTail) ;
- host->backlog--;
- }
-
- ASSERT(article != NULL);
-
- host->artsQueueOverflow++ ;
- host->gArtsQueueOverflow++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,article) ;
- }
-}
-
-
-
-
-
-
-\f
-/*
- * Returns true of the Host is in the middle of closing down.
- */
-static bool amClosing (Host host)
-{
- return (host->myTape == NULL ? true : false) ;
-}
-
-
-
-
-
-
-\f
-/*
- * flush all queued articles all the way out to disk.
- */
-static void queuesToTape (Host host)
-{
- Article art ;
-
- while ((art = remHead (&host->processed,&host->processedTail)) != NULL)
- {
- host->artsHostClose++ ;
- host->gArtsHostClose++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,art) ;
- }
-
- while ((art = remHead (&host->queued,&host->queuedTail)) != NULL)
- {
- host->backlog-- ;
- host->artsHostClose++ ;
- host->gArtsHostClose++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,art) ;
- }
-
- while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
- {
- host->deferLen-- ;
- host->artsHostClose++ ;
- host->gArtsHostClose++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,art) ;
- }
-
- while ((art = remHead (&host->deferred,&host->deferredTail)) != NULL)
- {
- host->deferLen-- ;
- host->artsHostClose++ ;
- host->gArtsHostClose++ ;
- host->artsToTape++ ;
- host->gArtsToTape++ ;
- procArtsToTape++ ;
- tapeTakeArticle (host->myTape,art) ;
- }
-}
-
-
-
-
-
-
-\f
-#define QUEUE_ELEM_POOL_SIZE ((4096 - 2 * (sizeof (void *))) / (sizeof (struct proc_q_elem)))
-
-static ProcQElem queueElemPool ;
-
-/*
- * Add an article to the given queue.
- */
-static void queueArticle (Article article, ProcQElem *head, ProcQElem *tail,
- time_t when)
-{
- ProcQElem elem ;
-
- if (queueElemPool == NULL)
- {
- unsigned int i ;
-
- queueElemPool =
- xmalloc (sizeof(struct proc_q_elem) * QUEUE_ELEM_POOL_SIZE) ;
-
- for (i = 0; i < QUEUE_ELEM_POOL_SIZE - 1; i++)
- queueElemPool[i] . next = &(queueElemPool [i + 1]) ;
- queueElemPool [QUEUE_ELEM_POOL_SIZE-1] . next = NULL ;
- }
-
- elem = queueElemPool ;
- ASSERT (elem != NULL) ;
- queueElemPool = queueElemPool->next ;
-
- elem->article = article ;
- elem->next = NULL ;
- elem->prev = *tail ;
- elem->whenToRequeue = when ;
- if (*tail != NULL)
- (*tail)->next = elem ;
- else
- *head = elem ;
- *tail = elem ;
-}
-
-
-
-
-
-
-\f
-/*
- * remove the article from the queue
- */
-static bool remArticle (Article article, ProcQElem *head, ProcQElem *tail)
-{
- ProcQElem elem ;
-
- ASSERT (head != NULL) ;
- ASSERT (tail != NULL) ;
-
- /* we go backwards down the list--probably faster */
- elem = *tail ;
- while (elem != NULL && elem->article != article)
- elem = elem->prev ;
-
- if (elem != NULL)
- {
- if (elem->prev != NULL)
- elem->prev->next = elem->next ;
- if (elem->next != NULL)
- elem->next->prev = elem->prev ;
- if (*head == elem)
- *head = elem->next ;
- if (*tail == elem)
- *tail = elem->prev ;
-
- elem->next = queueElemPool ;
- queueElemPool = elem ;
-
- return true ;
- }
- else
- return false ;
-}
-
-
-
-
-
-
-\f
-/*
- * remove the article that's at the head of the queue and return
- * it. Returns NULL if the queue is empty.
- */
-static Article remHead (ProcQElem *head, ProcQElem *tail)
-{
- ProcQElem elem ;
- Article art ;
-
- ASSERT (head != NULL) ;
- ASSERT (tail != NULL) ;
- ASSERT ((*head == NULL && *tail == NULL) ||
- (*head != NULL && *tail != NULL)) ;
-
- if (*head == NULL)
- return NULL ;
-
- elem = *head ;
- art = elem->article ;
- *head = elem->next ;
- if (elem->next != NULL)
- elem->next->prev = NULL ;
-
- if (*tail == elem)
- *tail = NULL ;
-
- elem->next = queueElemPool ;
- queueElemPool = elem ;
-
- return art ;
-}
-
-
-
-static int validateInteger (FILE *fp, const char *name,
- long low, long high, int required, long setval,
- scope * sc, unsigned int inh)
-{
- int rval = VALUE_OK ;
- value *v ;
- scope *s ;
- char *p = strrchr (name,':') ;
-
- v = findValue (sc,name,inh) ;
- if (v == NULL && required != NOTREQNOADD)
- {
- s = findScope (sc,name,0) ;
- addInteger (s,p ? p + 1 : name,setval) ;
- if (required == REQ)
- {
- rval = VALUE_MISSING ;
- logOrPrint (LOG_ERR,fp,
- "ME config: no definition for required key %s",name) ;
- }
- else if (required)
- logOrPrint (LOG_INFO,fp,
- "ME config: adding missing key/value %s: %ld",name
- ,setval) ;
- }
- else if (v != NULL && v->type != intval)
- {
- rval = VALUE_WRONG_TYPE ;
- logOrPrint (LOG_ERR,fp,"ME config: value of %s is not an integer",name) ;
- }
- else if (v != NULL && low != LONG_MIN && v->v.int_val < low)
- {
- rval = VALUE_TOO_LOW ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s is lower than minimum"
- " of %ld. Using %ld",name,v->v.int_val,
- "global scope",low,low) ;
- v->v.int_val = low ;
- }
- else if (v != NULL && high != LONG_MAX && v->v.int_val > high)
- {
- rval = VALUE_TOO_HIGH ;
- logOrPrint(LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s is higher than maximum"
- " of %ld. Using %ld",name,v->v.int_val,
- "global scope",high,high);
- v->v.int_val = high ;
- }
-
- return rval ;
-}
-
-
-
-static int validateReal (FILE *fp, const char *name, double low,
- double high, int required, double setval,
- scope * sc, unsigned int inh)
-{
- int rval = VALUE_OK ;
- value *v ;
- scope *s ;
- char *p = strrchr (name,':') ;
-
- v = findValue (sc,name,inh) ;
- if (v == NULL && required != NOTREQNOADD)
- {
- s = findScope (sc,name,0) ;
- addReal (s,p ? p + 1 : name,setval) ;
- if (required == REQ)
- {
- rval = VALUE_MISSING ;
- logOrPrint (LOG_ERR,fp,
- "ME config: no definition for required key %s",name) ;
- }
- else
- logOrPrint (LOG_INFO,fp,
- "ME config: adding missing key/value %s: %f",name,
- setval) ;
- }
- else if (v != NULL && v->type != realval)
- {
- rval = VALUE_WRONG_TYPE ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s is not a floating point number",
- name) ;
- }
- else if (v != NULL && low != -DBL_MAX && v->v.real_val < low)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%f) is lower than minimum of %f",
- name,v->v.real_val,low) ;
- v->v.real_val = setval ;
- }
- else if (v != NULL && high != DBL_MAX && v->v.real_val > high)
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%f) is higher than maximum of %f",
- name,v->v.real_val,high) ;
- v->v.real_val = setval ;
- }
-
- return rval ;
-}
-
-
-
-static int validateBool (FILE *fp, const char *name, int required, bool setval,
- scope * sc, unsigned int inh)
-{
- int rval = VALUE_OK ;
- value *v ;
- scope *s ;
- char *p = strrchr (name,':') ;
-
- v = findValue (sc,name,inh) ;
- if (v == NULL && required != NOTREQNOADD)
- {
- s = findScope (sc,name,0) ;
- addBoolean (s,p ? p + 1 : name, setval ? 1 : 0) ;
- if (required == REQ)
- {
- rval = VALUE_MISSING ;
- logOrPrint (LOG_ERR,fp,
- "ME config: no definition for required key %s",name) ;
- }
- else
- logOrPrint (LOG_INFO,fp,
- "ME config: adding missing key/value %s: %s",name,
- (setval ? "true" : "false")) ;
- }
- else if (v != NULL && v->type != boolval)
- {
- rval = VALUE_WRONG_TYPE ;
- logOrPrint (LOG_ERR,fp,"ME config: value of %s is not a boolean",name) ;
- }
-
- return rval ;
-}
-
-
-void gCalcHostBlStat (void)
-{
- Host h ;
-
- for (h = gHostList ; h != NULL ; h = h->next)
- {
- h->dlAccum += h->deferLen ;
- h->blAccum += h->backlog ;
- if (h->backlog == 0)
- h->blNone++ ;
- else if (h->backlog >= (hostHighwater - h->deferLen))
- h->blFull++ ;
- else
- h->blQuartile[(4*h->backlog) / (hostHighwater - h->deferLen)]++ ;
- h->blCount++ ;
- }
-}
-static void hostCleanup (void)
-{
- if (statusFile != NULL)
- free (statusFile) ;
- statusFile = NULL ;
-}
+++ /dev/null
-/* $Id: host.h 7778 2008-04-17 21:27:22Z iulius $
-**
-** The public interface to the Host class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The Host class represents the remote news system that we're feeding. A
-** Host object has possibly multiple connections to the remote system which
-** it sends articles down. It is given the articles by other objects
-** (typically the InnListener), and once taken it assumes all responsibility
-** for transmission or temporary storage on network failures etc.
-*/
-
-#if ! defined ( host_h__ )
-#define host_h__
-
-
-#include <stdio.h>
-
-#include "misc.h"
-
-/*
- * Functions from elsewhere used by host.c
- */
-
-extern void mainLogStatus (FILE *fp) ;
-
-
-/*
- * Functions used by the InnListener
- */
-
-
-/*
- * Create a new Host object.
- *
- * NAME is the name that INN uses.
- * IPNAME is the name the networking code uses (or the ascii dotted quad
- * IP address).
- * ARTTIMEOUT is the max amount of time we'll wait for a new article
- * from INN before considering the connection unused and we'll close
- * down.
- * RESPTIMEOUT is the max amount of time we'll wait for any reponse
- * from a remote. Past this we'll close down the network connection.
- * INITIALCXNS is the number of Connections to create at Host creation time.
- * MAXCXNS is the maximum number of parallel connections to the
- * remote host we can run at any one time.
- * MAXCHECK is the maximum number of nntp CHECK commands to be outstanding
- * on a connection before opening up a new connection (or refusing
- * new articles if we get to MAXCXNS).
- * PORTNUM is the port number on the remote host we should talk to.
- * CLOSEPERIOD is the number of seconds after connecting that the
- * connections should be closed down and reinitialized (due to problems
- * with old NNTP servers that hold history files open. Value of 0 means
- * dont close down.
- * STREAMING is a boolean flag to tell if the Host wants its Connections to
- * do streaming or not.
- * LOWPASSHIGH is the high value for the low-pass filter.
- * LOWPASSLOW is the low value for the low-pass filter.
- */
-
-void configHosts (bool talkSelf) ;
-
-/* print some debugging info. */
-void gPrintHostInfo (FILE *fp, unsigned int indentAmt) ;
-void printHostInfo (Host host, FILE *fp, unsigned int indentAmt) ;
-
-/* Delete the host object. Drops all the active connections immediately
- (i.e. no QUIT) . */
-void delHost (Host host) ;
-
-/* Get a new default host object */
-Host newDefaultHost (InnListener listener,
- const char *name);
-
-/* gently close down all the host's connections (issue QUITs). */
-void hostClose (Host host) ;
-
-/* gently close down all active connections (issue QUITs) and recreate
- them immediately */
-void hostFlush (Host host) ;
-
-/* have the HOST transmit the ARTICLE, or, failing that, store article
- information for later attempts. */
-void hostSendArticle (Host host, Article article) ;
-
-/* return an IP address for the host */
-struct sockaddr *hostIpAddr (Host host, int family) ;
-
-/* Delete all IPv4 addresses from the address list */
-void hostDeleteIpv4Addr (Host host);
-
-/* mark the current IP address as failed and rotate to the next one */
-void hostIpFailed (Host host) ;
-
-/*
- * Functions used by the Connection to indicate Connection state.
- */
-
-/* called by the Host's connection when the remote is refusing
- postings. Code 400 in the banner */
-void hostCxnBlocked (Host host, Connection cxn, char *reason) ;
-
-/* called by the Connection when it has determined if the remote supports
- the streaming extension or not. */
-void hostRemoteStreams (Host host, Connection cxn, bool doesStream) ;
-
-/* Called by the connection when it is no longer connected to the
- remote. Perhaps due to getting a code 400 to an IHAVE. */
-void hostCxnDead (Host host, Connection cxn) ;
-
-/* Called when the Connection deletes itself */
-bool hostCxnGone (Host host, Connection cxn) ;
-
-/* Called when the Connection goes to sleep. */
-void hostCxnSleeping (Host host, Connection cxn) ;
-
-/* Called when the Connection starts waiting for articles. */
-void hostCxnWaiting (Host host, Connection cxn) ;
-
-
-
-/* Called when the connection has sent an IHAVE or a CHECK, or a TAKETHIS
- when in no-check mode.*/
-void hostArticleOffered (Host host, Connection cxn) ;
-
-/* called by the Connection when the article was transferred. */
-void hostArticleAccepted (Host host, Connection cxn, Article article) ;
-
-/* Called by the connection when the remote answered 435 or 438 */
-void hostArticleNotWanted (Host host, Connection cxn, Article article) ;
-
-/* Called by the connection when the remote answered 437 or 439 */
-void hostArticleRejected (Host host, Connection cxn, Article article) ;
-
-/* Called when the connection when the remote answered 400 or 431 or 436 */
-void hostArticleDeferred (Host host, Connection cxn, Article article) ;
-
-/* Called by the connection if it discovers the file is gone. */
-void hostArticleIsMissing (Host host, Connection cxn, Article article) ;
-
-
-/* Called by the connection when it wants to defer articles, but it
- doesn't want the Host to queue any news on it. */
-void hostTakeBackArticle (Host host, Connection cxn, Article article) ;
-
-
-/* called by the Connection when it is idle and wants to get things
- moving. Returns true if there was something to do and the Host called
- cxnQueueArticle() . */
-bool hostGimmeArticle (Host host, Connection cxn) ;
-
-/* get the name that INN uses for this host */
-const char *hostPeerName (Host host) ;
-
-/* get the bindaddress */
-const struct sockaddr_in *hostBindAddr(Host host) ;
-#ifdef HAVE_INET6
-const struct sockaddr_in6 *hostBindAddr6(Host host) ;
-int hostAddrFamily (Host host);
-#endif
-
-/* get the username and password for authentication */
-const char *hostUsername (Host host) ;
-const char *hostPassword (Host host) ;
-
-/* if VAL is true then each time the host logs its stats all its
- connections will too. */
-void hostLogConnectionStats (bool val) ;
-bool hostLogConnectionStatsP (void) ;
-
-#if 0
-/* Set the frequency (in seconds) with which we log statistics */
-void hostSetStatsPeriod (unsigned int period) ;
-#endif
-
-/* return whether or not the Connections should attempt to stream. */
-bool hostWantsStreaming (Host host) ;
-
-/* return maxChecks */
-unsigned int hostmaxChecks (Host host);
-
-/* return if we should drop deferred articles */
-bool hostDropDeferred (Host host);
-
-/* return the maximum number of CHECKs that can be outstanding */
-unsigned int hostMaxChecks (Host host) ;
-
-/* Called by the Host's connections when they go into (true) or out of
- (false) no-CHECK mode. */
-void hostLogNoCheckMode (Host host, bool on, double low, double cur, double high) ;
-
-/* calculate host backlog statistics */
-void gCalcHostBlStat (void) ;
-
-/* calculate host global statistics */
-void gHostStats (void) ;
-
-/* set the pathname of the file to use instead of innfeed.status */
-void hostSetStatusFile (const char *filename) ;
-
-/* function called when config file is loaded. */
-int hostConfigLoadCbk (void *data) ;
-
-void hostChkCxns(TimeoutId tid, void *data);
-
-#endif /* host_h__ */
+++ /dev/null
-/* $Id: imap_connection.c 7103 2004-12-23 22:36:27Z rra $
-**
-** Feed articles to an IMAP server via LMTP and IMAP.
-**
-** Written by Tim Martin.
-**
-** Instead of feeding articles via nntp to another host this feeds the
-** messages via lmtp to a host and the control messages (cancel's etc..) it
-** performs via IMAP. This means it has 2 active connections at any given
-** time and 2 queues.
-**
-** When an article comes in it is immediatly placed in the lmtp queue. When
-** an article is picked off the lmtp queue for processing first check if it's
-** a control message. If so, place it in the IMAP queue. If not, attempt to
-** deliver via LMTP.
-**
-** This attempts to follow the exact same api as connection.c.
-**
-** TODO:
-**
-** feed to smtp
-** security layers? <--punt on for now
-** authname/password per connection object
-** untagged IMAP messages
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <ctype.h>
-#include <errno.h>
-#include <netdb.h>
-#include <netdb.h>
-#include <time.h>
-#include <syslog.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "buffer.h"
-#include "connection.h"
-#include "endpoint.h"
-#include "host.h"
-#include "innfeed.h"
-#include "article.h"
-#include "configfile.h"
-
-#ifdef HAVE_SASL
-# include <sasl/sasl.h>
-#endif
-
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 1024
-#endif
-
-#define IMAP_PORT 143
-
-#ifdef SMTPMODE
-# define LMTP_PORT 25
-#else
-# define LMTP_PORT 2003
-#endif
-
-#define IMAP_TAGLENGTH 6
-
-#define QUEUE_MAX_SIZE 250
-
-#define DOSOMETHING_TIMEOUT 60
-
-
-
-/* external */
-extern char *deliver_username;
-extern char *deliver_authname;
-extern char *deliver_password;
-extern char *deliver_realm;
-extern char *deliver_rcpt_to;
-extern char *deliver_to_header;
-
-
-char hostname[MAXHOSTNAMELEN];
-char *mailfrom_name = NULL; /* default to no return path */
-
-#ifdef HAVE_SASL
-static int initialized_sasl = 0; /* weather sasl_client_init() has been called */
-#endif
-
-/* states the imap connection may be in */
-typedef enum {
-
- IMAP_DISCONNECTED = 1,
- IMAP_WAITING,
-
- IMAP_CONNECTED_NOTAUTH,
-
- IMAP_READING_INTRO,
-
- IMAP_WRITING_CAPABILITY,
- IMAP_READING_CAPABILITY,
-
- IMAP_WRITING_STARTAUTH,
- IMAP_READING_STEPAUTH,
- IMAP_WRITING_STEPAUTH,
-
- IMAP_IDLE_AUTHED,
- IMAP_WRITING_NOOP,
- IMAP_READING_NOOP,
-
- IMAP_WRITING_CREATE,
- IMAP_READING_CREATE,
-
- IMAP_WRITING_DELETE,
- IMAP_READING_DELETE,
-
- IMAP_WRITING_SELECT,
- IMAP_READING_SELECT,
-
- IMAP_WRITING_SEARCH,
- IMAP_READING_SEARCH,
-
- IMAP_WRITING_STORE,
- IMAP_READING_STORE,
-
- IMAP_WRITING_CLOSE,
- IMAP_READING_CLOSE,
-
- IMAP_WRITING_QUIT,
- IMAP_READING_QUIT
-
-} imap_state_t;
-
-typedef enum {
- LMTP_DISCONNECTED = 1,
- LMTP_WAITING,
-
- LMTP_CONNECTED_NOTAUTH,
-
- LMTP_READING_INTRO,
-
- LMTP_WRITING_LHLO,
- LMTP_READING_LHLO,
-
- LMTP_WRITING_STARTAUTH,
- LMTP_READING_STEPAUTH,
- LMTP_WRITING_STEPAUTH,
-
- LMTP_AUTHED_IDLE,
- LMTP_WRITING_NOOP,
- LMTP_READING_NOOP,
-
- LMTP_READING_RSET,
- LMTP_READING_MAILFROM,
- LMTP_READING_RCPTTO,
- LMTP_READING_DATA,
- LMTP_READING_CONTENTS,
-
- LMTP_WRITING_UPTODATA,
- LMTP_WRITING_CONTENTS,
-
- LMTP_WRITING_QUIT,
- LMTP_READING_QUIT
-
-} lmtp_state_t;
-
-typedef struct imap_capabilities_s {
-
- int imap4; /* does server support imap4bis? */
- int logindisabled; /* does the server allow the login command? */
-
- char *saslmechs; /* supported SASL mechanisms */
-
-} imap_capabilities_t;
-
-typedef struct lmtp_capabilities_s {
-
- int Eightbitmime;
- int EnhancedStatusCodes;
- int pipelining;
-
- char *saslmechs;
-
-} lmtp_capabilities_t;
-
-typedef enum {
- STAT_CONT = 0,
- STAT_NO = 1,
- STAT_OK = 2,
- STAT_FAIL = 3
-} imt_stat;
-
-/* Message types */
-typedef enum {
- DELIVER,
- CREATE_FOLDER,
- CANCEL_MSG,
- DELETE_FOLDER
-} control_type_t;
-
-typedef struct control_item_s {
-
- Article article;
- char *folder;
- char *msgid; /* only for cancel's */
- unsigned long uid; /* only for cancel's */
-
-} control_item_t;
-
-typedef struct article_queue_s {
-
- control_type_t type;
-
- time_t arrived;
- time_t nextsend; /* time we should next try to send article */
-
- int trys;
-
- int counts_toward_size;
-
- union {
- Article article;
- control_item_t *control;
- void *generic;
- } data;
-
- struct article_queue_s *next;
-
-} article_queue_t;
-
-typedef struct Q_s {
-
- article_queue_t *head;
-
- article_queue_t *tail;
-
- int size;
-
-} Q_t;
-
-typedef struct connection_s {
-
- /* common stuff */
- char *ServerName;
-
- char *lmtp_respBuffer; /* buffer all responses are read into */
- Buffer lmtp_rBuffer; /* buffer all responses are read into */
-
- Host myHost ; /* the host who owns the connection */
-
- time_t timeCon ; /* the time the connect happened
- (last auth succeeded) */
-
- int issue_quit; /* Three states:
- * 0 - don't do anything
- * 1 - after issue quit enter wait state
- * 2 - after issue quit reconnect
- * 3 - after issue quit delete connection
- * 4 - nuke cxn
- */
-
- /* Statistics */
- int lmtp_succeeded;
- int lmtp_failed;
-
- int cancel_succeeded;
- int cancel_failed;
-
- int create_succeeded;
- int create_failed;
-
- int remove_succeeded;
- int remove_failed;
-
-
- /* LMTP stuff */
- int lmtp_port;
- lmtp_state_t lmtp_state;
-#ifdef HAVE_SASL
- sasl_conn_t *saslconn_lmtp;
-#endif /* HAVE_SASL */
- int sockfd_lmtp;
-
- time_t lmtp_timeCon ;
-
- EndPoint lmtp_endpoint;
- unsigned int ident ; /* an identifier for syslogging. */
-
- lmtp_capabilities_t *lmtp_capabilities;
-
- int lmtp_disconnects;
- char *lmtp_tofree_str;
-
- article_queue_t *current_article;
- Buffer *current_bufs;
- int current_rcpts_issued;
- int current_rcpts_okayed;
-
- /* Timer for the max amount of time to wait for a response from the
- remote */
- unsigned int lmtp_readTimeout ;
- TimeoutId lmtp_readBlockedTimerId ;
-
- /* Timer for the max amount of time to wait for a any amount of data
- to be written to the remote */
- unsigned int lmtp_writeTimeout ;
- TimeoutId lmtp_writeBlockedTimerId ;
-
- /* Timer for the number of seconds to sleep before attempting a
- reconnect. */
- unsigned int lmtp_sleepTimeout ;
- TimeoutId lmtp_sleepTimerId ;
-
- /* Timer for max amount between queueing some articles and trying to send them */
- unsigned int dosomethingTimeout ;
- TimeoutId dosomethingTimerId ;
-
- Q_t lmtp_todeliver_q;
-
-
-
- /* IMAP stuff */
- int imap_port;
-#ifdef HAVE_SASL
- sasl_conn_t *imap_saslconn;
-#endif /* HAVE_SASL */
-
- char *imap_respBuffer;
- Buffer imap_rBuffer;
- EndPoint imap_endpoint;
-
- imap_capabilities_t *imap_capabilities;
-
- int imap_sockfd;
-
- time_t imap_timeCon ;
-
- imap_state_t imap_state;
- int imap_disconnects;
- char *imap_tofree_str;
-
- char imap_currentTag[IMAP_TAGLENGTH];
- int imap_tag_num;
-
- /* Timer for the max amount of time to wait for a response from the
- remote */
- unsigned int imap_readTimeout ;
- TimeoutId imap_readBlockedTimerId ;
-
- /* Timer for the max amount of time to wait for a any amount of data
- to be written to the remote */
- unsigned int imap_writeTimeout ;
- TimeoutId imap_writeBlockedTimerId ;
-
- /* Timer for the number of seconds to sleep before attempting a
- reconnect. */
- unsigned int imap_sleepTimeout ;
- TimeoutId imap_sleepTimerId ;
-
- Q_t imap_controlMsg_q;
-
- article_queue_t *current_control;
-
- struct connection_s *next;
-
-} connection_t;
-
-static Connection gCxnList = NULL ;
-static unsigned int gCxnCount= 0 ;
-static unsigned int max_reconnect_period = MAX_RECON_PER ;
-static unsigned int init_reconnect_period = INIT_RECON_PER;
-
-typedef enum {
- RET_OK = 0,
- RET_FAIL = 1,
- RET_QUEUE_EMPTY,
- RET_EXCEEDS_SIZE,
- RET_NO_FULLLINE,
- RET_NO,
- RET_ARTICLE_BAD
-} conn_ret;
-
-
-/********** Private Function Declarations *************/
-
-static void lmtp_readCB (EndPoint e, IoStatus i, Buffer *b, void *d);
-static void imap_readCB (EndPoint e, IoStatus i, Buffer *b, void *d);
-static void imap_writeCB (EndPoint e, IoStatus i, Buffer *b, void *d);
-static void lmtp_writeCB (EndPoint e, IoStatus i, Buffer *b, void *d);
-
-static conn_ret lmtp_Connect(connection_t *cxn);
-static conn_ret imap_Connect(connection_t *cxn);
-
-static void prepareReopenCbk (Connection cxn, int type);
-
-static void lmtp_readTimeoutCbk (TimeoutId id, void *data);
-static void imap_readTimeoutCbk (TimeoutId id, void *data);
-
-static void dosomethingTimeoutCbk (TimeoutId id, void *data);
-
-static conn_ret WriteToWire_imapstr(connection_t *cxn, char *str, int slen);
-static conn_ret WriteToWire_lmtpstr(connection_t *cxn, char *str, int slen);
-
-static conn_ret WriteToWire(connection_t *cxn, EndpRWCB callback,
- EndPoint endp, Buffer *array);
-static void lmtp_sendmessage(connection_t *cxn, Article justadded);
-static void imap_ProcessQueue(connection_t *cxn);
-
-static conn_ret FindHeader(Buffer *bufs, const char *header, char **start, char **end);
-static conn_ret PopFromQueue(Q_t *q, article_queue_t **item);
-
-enum failure_type {
- MSG_SUCCESS = 0,
- MSG_FAIL_DELIVER = 1,
- MSG_GIVE_BACK = 2,
- MSG_MISSING = 3
-};
-
-static void QueueForgetAbout(connection_t *cxn, article_queue_t *item,
- enum failure_type failed);
-
-static void delConnection (Connection cxn);
-static void DeleteIfDisconnected(Connection cxn);
-static void DeferAllArticles(connection_t *cxn, Q_t *q);
-
-static void lmtp_Disconnect(connection_t *cxn);
-static void imap_Disconnect(connection_t *cxn);
-static conn_ret imap_listenintro(connection_t *cxn);
-
-static void imap_writeTimeoutCbk (TimeoutId id, void *data);
-static void lmtp_writeTimeoutCbk (TimeoutId id, void *data);
-
-/******************** PRIVATE FUNCTIONS ***************************/
-
-static const char *imap_stateToString(int state)
-{
- switch (state)
- {
- case IMAP_DISCONNECTED: return "disconnected";
- case IMAP_WAITING: return "waiting";
- case IMAP_CONNECTED_NOTAUTH: return "connected (unauthenticated)";
- case IMAP_READING_INTRO: return "reading intro";
- case IMAP_WRITING_CAPABILITY: return "writing CAPABILITY";
- case IMAP_READING_CAPABILITY: return "reading CAPABILITY";
- case IMAP_WRITING_STARTAUTH: return "writing AUTHENTICATE";
- case IMAP_READING_STEPAUTH: return "reading stepauth";
- case IMAP_WRITING_STEPAUTH: return "writing stepauth";
- case IMAP_IDLE_AUTHED: return "idle (authenticated)";
- case IMAP_WRITING_NOOP: return "writing NOOP";
- case IMAP_READING_NOOP: return "reading NOOP response";
- case IMAP_WRITING_CREATE: return "writing CREATE";
- case IMAP_READING_CREATE: return "reading CREATE response";
- case IMAP_WRITING_DELETE: return "writing DELETE command";
- case IMAP_READING_DELETE: return "reading DELETE response";
- case IMAP_WRITING_SELECT: return "writing SELECT";
- case IMAP_READING_SELECT: return "reading SELECT response";
- case IMAP_WRITING_SEARCH: return "writing SEARCH";
- case IMAP_READING_SEARCH: return "reading SEARCH response";
- case IMAP_WRITING_STORE: return "writing STORE";
- case IMAP_READING_STORE: return "reading STORE response";
- case IMAP_WRITING_CLOSE: return "writing CLOSE";
- case IMAP_READING_CLOSE: return "reading CLOSE response";
- case IMAP_WRITING_QUIT: return "writing LOGOUT";
- case IMAP_READING_QUIT: return "reading LOGOUT response";
- default: return "Unknown state";
- }
-}
-
-static const char *lmtp_stateToString(int state)
-{
- switch(state)
- {
- case LMTP_DISCONNECTED: return "disconnected";
- case LMTP_WAITING: return "waiting";
- case LMTP_CONNECTED_NOTAUTH: return "connected (unauthenticated)";
- case LMTP_READING_INTRO: return "reading intro";
- case LMTP_WRITING_LHLO: return "writing LHLO";
- case LMTP_READING_LHLO: return "reading LHLO response";
- case LMTP_WRITING_STARTAUTH: return "writing AUTH";
- case LMTP_READING_STEPAUTH: return "reading stepauth";
- case LMTP_WRITING_STEPAUTH: return "writing stepauth";
- case LMTP_AUTHED_IDLE: return "idle (authenticated)";
- case LMTP_WRITING_NOOP: return "writing NOOP";
- case LMTP_READING_NOOP: return "reading NOOP response";
- case LMTP_READING_RSET: return "reading RSET response";
- case LMTP_READING_MAILFROM: return "reading MAIL FROM response";
- case LMTP_READING_RCPTTO: return "reading RCPT TO response";
- case LMTP_READING_DATA: return "reading DATA response";
- case LMTP_READING_CONTENTS: return "reading contents response";
- case LMTP_WRITING_UPTODATA:
- return "writing RSET, MAIL FROM, RCPT TO, DATA commands";
- case LMTP_WRITING_CONTENTS: return "writing contents of message";
- case LMTP_WRITING_QUIT: return "writing QUIT";
- case LMTP_READING_QUIT: return "reading QUIT";
- default: return "unknown state";
- }
-}
-
-/******************************* Queue functions ***********************************/
-
-/*
- * Add a message to a generic queue
- *
- * q - the queue adding to
- * item - the data to add to the queue
- * type - the type of item it is (i.e. cancel,lmtp,etc..)
- * addsmsg - weather this should be counted toward the queue size
- * this is for control msg's that create multiple queue items.
- * For example a cancel message canceling a message in multiple
- * newsgroups will create >1 queue item but we only want it to count
- * once towards the queue
- * must - wheather we must take it even though it may put us over our max size
- */
-
-static conn_ret AddToQueue(Q_t *q, void *item,
- control_type_t type, int addsmsg, bool must)
-{
- article_queue_t *newentry;
-
- if (must == false)
- {
- if (q->size >= QUEUE_MAX_SIZE)
- {
- return RET_EXCEEDS_SIZE;
- }
- } else {
- if (q->size >= QUEUE_MAX_SIZE * 10)
- {
- d_printf(0, "Queue has grown way too much. Dropping article\n");
- return RET_FAIL;
- }
- }
-
- /* add to the end of our queue */
- newentry = xmalloc(sizeof(article_queue_t));
-
- newentry->type = type;
-
- /* send as soon as possible */
- newentry->nextsend = newentry->arrived = time(NULL);
-
- newentry->trys = 0;
-
- newentry->data.generic = item;
- newentry->next = NULL;
- newentry->counts_toward_size = addsmsg;
-
- /* add to end of queue */
- if (q->tail == NULL)
- {
- q->head = newentry;
- q->tail = newentry;
- } else {
-
- q->tail->next = newentry;
- q->tail = newentry;
- }
-
- q->size+=addsmsg;
-
- return RET_OK;
-}
-
-/*
- * Pop an item from the queue
- *
- * q - the queue to pop from
- * item - where the item shall be placed upon sucess
- *
- */
-
-static conn_ret PopFromQueue(Q_t *q, article_queue_t **item)
-{
- /* if queue empty return error */
- if ( q->head == NULL)
- {
- return RET_QUEUE_EMPTY;
- }
-
- /* set what we return */
- *item = q->head;
-
- q->head = q->head->next;
- if (q->head == NULL) q->tail = NULL;
-
- q->size-=(*item)->counts_toward_size;
-
- return RET_OK;
-}
-
-/*
- * ReQueue an item. Will either put it back in the queue for another try
- * or forget about it
- *
- * cxn - our connection object (needed so forget about things)
- * q - the queue to requeue to
- * entry - the item to put back
- */
-
-static void ReQueue(connection_t *cxn, Q_t *q, article_queue_t *entry)
-{
- /* look at the time it's been here */
- entry->nextsend = time(NULL) + (entry->trys *30); /* xxx better formula? */
-
- entry->trys++;
-
- /* give up after 5 tries xxx configurable??? */
- if (entry->trys >= 5)
- {
- QueueForgetAbout(cxn, entry, MSG_FAIL_DELIVER);
- return;
- }
-
-
- /* ok let's add back to the end of the queue */
- entry->next = NULL;
-
- /* add to end of queue */
- if (q->tail == NULL)
- {
- q->head = entry;
- q->tail = entry;
- } else {
- q->tail->next = entry;
- q->tail = entry;
- }
-
- q->size+=entry->counts_toward_size;
-}
-
-
-
-/*
- * Forget about an item. Tells host object if we succeeded/failed/etc with the message
- *
- * cxn - connection object
- * item - item
- * failed - type of failure (see below)
- *
- * failed:
- * 0 - succeeded delivering message
- * 1 - failed delivering message
- * 2 - Try to give back to host
- * 3 - Article missing (i.e. can't find on disk)
- */
-static void QueueForgetAbout(connection_t *cxn, article_queue_t *item,
- enum failure_type failed)
-{
- Article art = NULL;
-
- switch (item->type)
- {
- case DELIVER:
- if (failed>0)
- cxn->lmtp_failed++;
- art = item->data.article;
- break;
-
- case CANCEL_MSG:
- if (failed>0)
- cxn->cancel_failed++;
- free(item->data.control->msgid);
- free(item->data.control->folder);
-
- if (item->counts_toward_size == 1)
- art = item->data.control->article;
-
- free(item->data.control );
- break;
-
- case CREATE_FOLDER:
- if (failed>0)
- cxn->create_failed++;
- free(item->data.control->folder);
-
- art = item->data.control->article;
-
- free(item->data.control );
- break;
-
- case DELETE_FOLDER:
- if (failed>0)
- cxn->remove_failed++;
- free(item->data.control->folder);
-
- art = item->data.control->article;
-
- free(item->data.control );
- break;
-
- default:
- d_printf(0, "%s:%d QueueForgetAbout(): "
- "Unknown type to forget about\n",
- hostPeerName (cxn->myHost), cxn->ident);
- break;
- }
-
- if (art!=NULL) {
- switch (failed) {
- case MSG_SUCCESS:
- hostArticleAccepted (cxn->myHost, cxn, art);
- break;
-
- case MSG_FAIL_DELIVER:
- hostArticleRejected (cxn->myHost, cxn, art);
- break;
-
- case MSG_GIVE_BACK:
- hostTakeBackArticle (cxn->myHost, cxn, art);
- break;
-
- case MSG_MISSING:
- hostArticleIsMissing(cxn->myHost, cxn, art);
- break;
- default:
- d_printf(0,"%s:%d QueueForgetAbout(): failure type unknown\n",
- hostPeerName (cxn->myHost), cxn->ident);
- break;
- }
- }
-
- free(item);
-}
-
-/*
- * How much space is available in the queue
- */
-
-static int QueueSpace(Q_t *q)
-{
- int ret = QUEUE_MAX_SIZE - q->size;
- if (ret < 0) ret = 0;
- return ret;
-}
-
-/*
- * How many items are in the queue
- */
-
-static int QueueItems(Q_t *q)
-{
- return q->size;
-}
-
-
-/***************************** END Queue functions ***********************************/
-
-/***************************** Generic Parse Functions *******************************/
-
-/* returns the end of the header */
-
-static char *GetUntil(char *str)
-{
- while (((*str) != '\0') && ( (*str) != '\r') && ( (*str) != '\n'))
- {
- str++;
- }
-
- return str;
-}
-
-static char *GotoNextLine(char *str)
-{
- while (((*str) != '\0') && ( (*str) != '\r') && ( (*str) != '\n'))
- {
- str++;
- }
-
- if (*str == '\r') str++;
- if (*str == '\n') str++;
-
- return str;
-}
-
-/*
- * Finds the given header in the message
- * Returns NULL if not found
- */
-static conn_ret FindHeader(Buffer *bufs, const char *header, char **start,
- char **end)
-{
- Buffer b;
- int size;
- char *str_base;
- char *str;
- int headerlen = strlen(header);
-
- if (bufs==NULL)
- {
- if (start)
- *start=NULL;
- return RET_ARTICLE_BAD;
- }
-
- b = bufs[0];
- size = bufferSize(b);
- str_base = bufferBase(b);
- str = str_base;
-
- while ((str - str_base) < size - headerlen)
- {
- if (*str == header[0])
- {
- if ((strncasecmp(header, str, headerlen)==0) && ( *(str + headerlen)==':'))
- {
-
- if (start)
- {
- *start = str+headerlen+1;
-
- /* get rid of leading whitespace */
- while ( isspace((int) **start))
- (*start)++;
- }
-
- if (end)
- *end = GetUntil(str+headerlen+1);
-
- return RET_OK;
- }
- } else if (*str == '\n') {
- /* end of headers */
- return RET_NO;
- }
- str = GotoNextLine(str);
- }
-
- return RET_NO;
-}
-
-static conn_ret GetLine(char *buf, char *ret, int retmaxsize)
-{
- char *str_base;
- char *str;
-
- int size = strlen(buf);
- str_base = buf;
- str = str_base;
-
- while ( (*str) != '\0')
- {
- if ((*str) == '\n')
- {
- if (str-str_base > retmaxsize)
- {
- d_printf(0, "Max size exceeded! %s\n",str_base);
- return RET_FAIL;
- }
-
- /* fill in the return string */
- memcpy(ret, str_base, str-str_base);
- ret[ str - str_base -1] = '\0';
-
- memcpy( str_base, str_base + (str-str_base)+1, size - (str-str_base));
- str_base[size - (str-str_base)]='\0';
-
- return RET_OK;
- }
-
- str++;
- }
-
- /* couldn't find a full line */
- return RET_NO_FULLLINE;
-}
-
-
-
-/************************** END Generic Parse Functions *******************************/
-
-/************************ Writing to Network functions *****************/
-
-static conn_ret WriteToWire(connection_t *cxn, EndpRWCB callback,
- EndPoint endp, Buffer *array)
-{
-
- if (array == NULL) return RET_FAIL;
-
- prepareWrite (endp,
- array,
- NULL,
- callback,
- cxn);
-
- return RET_OK;
-}
-
-static conn_ret WriteToWire_str(connection_t *cxn, EndpRWCB callback,
- EndPoint endp, char *str, int slen)
-{
- conn_ret result;
- Buffer buff;
- Buffer *writeArr;
-
- if (slen==-1) slen = strlen(str);
-
- buff = newBufferByCharP(str, slen+1, slen);
- ASSERT (buff != NULL);
-
- writeArr = makeBufferArray (buff, NULL) ;
-
- result = WriteToWire(cxn, callback, endp, writeArr);
-
- return result;
-}
-
-static conn_ret WriteToWire_imapstr(connection_t *cxn, char *str, int slen)
-{
- /* prepare the timeouts */
- clearTimer (cxn->imap_readBlockedTimerId) ;
-
- /* set up the write timer. */
- clearTimer (cxn->imap_writeBlockedTimerId) ;
-
- if (cxn->imap_writeTimeout > 0)
- cxn->imap_writeBlockedTimerId = prepareSleep (imap_writeTimeoutCbk, cxn->imap_writeTimeout,
- cxn);
- cxn->imap_tofree_str = str;
- return WriteToWire_str(cxn, imap_writeCB, cxn->imap_endpoint, str, slen);
-}
-
-static conn_ret WriteToWire_lmtpstr(connection_t *cxn, char *str, int slen)
-{
- /* prepare the timeouts */
- clearTimer (cxn->lmtp_readBlockedTimerId) ;
-
- /* set up the write timer. */
- clearTimer (cxn->lmtp_writeBlockedTimerId) ;
-
- if (cxn->lmtp_writeTimeout > 0)
- cxn->lmtp_writeBlockedTimerId = prepareSleep (lmtp_writeTimeoutCbk, cxn->lmtp_writeTimeout,
- cxn) ;
-
-
-
- cxn->lmtp_tofree_str = str;
- return WriteToWire_str(cxn, lmtp_writeCB, cxn->lmtp_endpoint, str, slen);
-}
-
-static conn_ret WriteArticle(connection_t *cxn, Buffer *array)
-{
- int array_len = bufferArrayLen (array);
- int lup=0;
- int result;
-
- for (lup=0;lup<array_len;lup++)
- {
- int current_size;
- Buffer current_buf;
- char *current_start;
-
- current_buf = array[lup];
-
- current_size = bufferDataSize( current_buf );
-
- current_start = bufferBase( current_buf );
-
- }
-
- /* just call writetowire since it's easy */
- result = WriteToWire(cxn, lmtp_writeCB, cxn->lmtp_endpoint, array);
-
- if (result!=RET_OK)
- {
- return result;
- }
-
- cxn->lmtp_state = LMTP_WRITING_CONTENTS;
-
- return RET_OK;
-}
-
-/************************ END Writing to Network functions *****************/
-
-
-
-/*
- * Adds a cancel item to the control queue
- * Cancel item to delete message with <msgid> in <folder>
- *
- * cxn - connection object
- * folder - pointer to start of folder string (this is a pointer into the actual message buffer)
- * folderlen - length of folder string
- * msgid - pointer to start of msgid string (this is a pointer into the actual message buffer)
- * msgidlen - length of msgid string
- * art - the article for this control message (NULL if this cancel object lacks one)
- * must - if must be accepted into queue
- */
-
-static conn_ret addCancelItem(connection_t *cxn,
- char *folder, int folderlen,
- char *msgid, int msgidlen,
- Article art, int must)
-{
- control_item_t *item;
- conn_ret result;
- int i;
-
- ASSERT(folder); ASSERT(msgid); ASSERT(cxn);
-
- /* sanity check folder, msgid */
- for (i = 0; i < folderlen; i++) ASSERT(!isspace((int) folder[i]));
- for (i = 0; i < msgidlen; i++) ASSERT(!isspace((int) msgid[i]));
-
- /* create the object */
- item = xcalloc (1, sizeof(control_item_t));
-
- item->folder = xcalloc(folderlen+1, 1);
- memcpy(item->folder, folder, folderlen);
- item->folder[folderlen] = '\0';
-
- item->msgid = xcalloc (msgidlen+1, 1);
- memcpy(item->msgid, msgid, msgidlen);
- item->msgid[msgidlen] = '\0';
-
- item->article = art;
-
- /* try to add to the queue (counts if art isn't null) */
- result = AddToQueue(&(cxn->imap_controlMsg_q), item, CANCEL_MSG, (art != NULL), must);
- if (result != RET_OK) {
- d_printf(1,"%s:%d addCancelItem(): "
- "I thought we had in space in [imap] queue "
- "but apparently not\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- /* cleanup */
- free(item->folder);
- free(item->msgid);
- free(item);
-
- return result;
- }
-
- return RET_OK;
-}
-
-static conn_ret AddControlMsg(connection_t *cxn,
- Article art,
- Buffer *bufs,
- char *control_header,
- char *control_header_end,
- bool must)
-{
- char *rcpt_list = NULL, *rcpt_list_end;
- control_item_t *item;
- conn_ret res = RET_OK;
- int t;
-
- /* make sure contents ok; this also should load it into memory */
- if (!artContentsOk (art)) {
- d_printf(0, "%s:%d AddControlMsg(): "
- "artContentsOk() said article was bad\n",
- hostPeerName (cxn->myHost), cxn->ident);
- hostArticleIsMissing (cxn->myHost, cxn, art);
- return RET_FAIL;
- }
-
- res = RET_OK;
- /* now let's look at the control to see what it is */
- if (!strncasecmp(control_header,"newgroup",8)) {
- control_header += 8;
- t = CREATE_FOLDER;
- } else if (!strncasecmp(control_header,"rmgroup",7)) {
- /* jump past "rmgroup" */
- control_header += 7;
- t = DELETE_FOLDER;
- } else if (!strncasecmp(control_header,"cancel",6)) {
- t = CANCEL_MSG;
- control_header += 6;
- } else {
- /* unrecognized type */
- char tmp[100];
- char *endstr;
- size_t clen;
-
- endstr = strchr(control_header,'\n');
- clen = endstr - control_header;
-
- if (clen > sizeof(tmp)-1) clen = sizeof(tmp)-1;
-
- memcpy(tmp,control_header, clen);
- tmp[clen]='\0';
-
- d_printf(0,"%s:%d Don't understand control header [%s]\n",
- hostPeerName (cxn->myHost), cxn->ident,tmp);
- return RET_FAIL;
- }
-
- switch (t) {
- case CREATE_FOLDER:
- case DELETE_FOLDER:
- {
- int folderlen;
-
- /* go past all white space */
- while ((*control_header == ' ') &&
- (control_header != control_header_end)) {
- control_header++;
- }
-
- /* trim trailing whitespace */
- while (control_header_end[-1] == ' ') {
- control_header_end--;
- }
-
- if (control_header >= control_header_end) {
- d_printf(0,"%s:%d addControlMsg(): "
- "newgroup/rmgroup header has no group specified\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- folderlen = control_header_end - control_header;
-
- item = xcalloc(1, sizeof(control_item_t));
-
- item->folder = xcalloc(folderlen + 1, 1);
- memcpy(item->folder, control_header, folderlen);
- item->folder[folderlen] = '\0';
-
- item->article = art;
-
- if (AddToQueue(&(cxn->imap_controlMsg_q), item, t, 1, must) != RET_OK) {
- d_printf(1,"%s:%d addCancelItem(): "
- "I thought we had in space in [imap] queue"
- " but apparently not\n",
- hostPeerName (cxn->myHost), cxn->ident);
- free(item->folder);
- free(item);
- return RET_FAIL;
- }
-
- break;
- }
-
- case CANCEL_MSG:
- {
- char *str, *laststart;
-
- while (((*control_header) == ' ') &&
- (control_header != control_header_end))
- {
- control_header++;
- }
-
- if (control_header == control_header_end)
- {
- d_printf(0, "%s:%d Control header contains cancel "
- "with no msgid specified\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- if (FindHeader(bufs, "Newsgroups", &rcpt_list, &rcpt_list_end)!=RET_OK)
- {
- d_printf(0,"%s:%d Cancel msg contains no newsgroups header\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- str = rcpt_list;
- laststart = rcpt_list;
-
- while (str != rcpt_list_end)
- {
- if (*str == ',') {
- /* eliminate leading whitespace */
- while (((*laststart) ==' ') || ((*laststart)=='\t'))
- {
- laststart++;
- }
-
- res = addCancelItem(cxn, laststart,
- str - laststart,
- control_header,
- control_header_end - control_header,
- NULL, must);
- if (res!=RET_OK) return res;
-
- laststart = str+1;
- }
-
- str++;
- }
-
- if (laststart<str)
- {
-
- res = addCancelItem(cxn, laststart, str - laststart,
- control_header,
- control_header_end - control_header,
- art, must);
- if (res!=RET_OK) return res;
- }
- break;
- }
- default:
- /* huh?!? */
- d_printf(0, "%s:%d internal error in addControlMsg()\n",
- hostPeerName (cxn->myHost), cxn->ident);
- }
- return RET_FAIL;
-}
-
-/*
- * Show msg handling statistics
- */
-
-static void show_stats(connection_t *cxn)
-{
- d_printf(0, "%s:%d\n",hostPeerName (cxn->myHost), cxn->ident);
- d_printf(0, " imap queue = %d lmtp queue = %d\n",
- QueueItems(&(cxn->imap_controlMsg_q)),
- QueueItems(&(cxn->lmtp_todeliver_q)));
- d_printf(0," imap state = %s\n", imap_stateToString(cxn->imap_state));
- d_printf(0," lmtp state = %s\n", lmtp_stateToString(cxn->lmtp_state));
- d_printf(0," delivered: yes: %d no: %d\n",
- cxn->lmtp_succeeded,
- cxn->lmtp_failed);
- d_printf(0," cancel: yes: %d no: %d\n",
- cxn->cancel_succeeded, cxn->cancel_failed);
- d_printf(0," create: yes: %d no: %d\n",
- cxn->create_succeeded, cxn->create_failed);
- d_printf(0," remove: yes: %d no: %d\n",
- cxn->remove_succeeded, cxn->remove_failed);
-}
-
-/**************************** SASL helper functions ******************************/
-
-#ifdef HAVE_SASL
-/* callback to get userid or authid */
-static int getsimple(void *context __attribute__((unused)),
- int id,
- const char **result,
- unsigned *len)
-{
- char *username;
- char *authid;
-
- if (! result)
- return SASL_BADPARAM;
-
-
- switch (id) {
- case SASL_CB_GETREALM:
- *result = deliver_realm;
- if (len)
- *len = deliver_realm ? strlen(deliver_realm) : 0;
- break;
-
- case SASL_CB_USER:
- *result = deliver_username;
- if (len)
- *len = deliver_username ? strlen(deliver_username) : 0;
- break;
- case SASL_CB_AUTHNAME:
- authid=deliver_authname;
- *result = authid;
- if (len)
- *len = authid ? strlen(authid) : 0;
- break;
- case SASL_CB_LANGUAGE:
- *result = NULL;
- if (len)
- *len = 0;
- break;
- default:
- return SASL_BADPARAM;
- }
- return SASL_OK;
-}
-
-/* callback to get password */
-static int
-getsecret(sasl_conn_t *conn,
- void *context __attribute__((unused)),
- int id,
- sasl_secret_t **psecret)
-{
- size_t passlen;
-
- if (! conn || ! psecret || id != SASL_CB_PASS)
- return SASL_BADPARAM;
-
- if (deliver_password==NULL)
- {
- d_printf(0,"SASL requested a password but I don't have one\n");
- return SASL_FAIL;
- }
-
- passlen = strlen(deliver_password);
- *psecret = xmalloc(sizeof(sasl_secret_t) + passlen + 1);
- if (! *psecret)
- return SASL_FAIL;
-
- strlcpy((*psecret)->data, deliver_password, passlen + 1);
- (*psecret)->len = passlen;
-
- return SASL_OK;
-}
-
-
-/* callbacks we support */
-static sasl_callback_t saslcallbacks[] = {
- {
- SASL_CB_GETREALM, &getsimple, NULL
- }, {
- SASL_CB_USER, &getsimple, NULL
- }, {
- SASL_CB_AUTHNAME, &getsimple, NULL
- }, {
- SASL_CB_PASS, &getsecret, NULL
- }, {
- SASL_CB_LIST_END, NULL, NULL
- }
-};
-
-static sasl_security_properties_t *make_secprops(int min,int max)
-{
- sasl_security_properties_t *ret=
- xmalloc(sizeof(sasl_security_properties_t));
-
- ret->maxbufsize=1024;
- ret->min_ssf=min;
- ret->max_ssf=max;
-
- ret->security_flags=0;
- ret->property_names=NULL;
- ret->property_values=NULL;
-
- return ret;
-}
-
-#ifndef NI_WITHSCOPEID
-#define NI_WITHSCOPEID 0
-#endif
-#ifndef NI_MAXHOST
-#define NI_MAXHOST 1025
-#endif
-#ifndef NI_MAXSERV
-#define NI_MAXSERV 32
-#endif
-
-static int iptostring(const struct sockaddr *addr, socklen_t addrlen,
- char *out, unsigned outlen) {
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
-
- if(!addr || !out) return SASL_BADPARAM;
-
- getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
- NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV);
-
- if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
- return SASL_BUFOVER;
-
- snprintf(out, outlen, "%s;%s", hbuf, pbuf);
-
- return SASL_OK;
-}
-
-static conn_ret SetSASLProperties(sasl_conn_t *conn, int sock, int minssf, int maxssf)
-{
- int saslresult;
- sasl_security_properties_t *secprops=NULL;
- int addrsize=sizeof(struct sockaddr_in);
- char localip[60], remoteip[60];
- struct sockaddr_in saddr_l;
- struct sockaddr_in saddr_r;
-
- /* create a security structure and give it to sasl */
- secprops = make_secprops(minssf, maxssf);
- if (secprops != NULL)
- {
- sasl_setprop(conn, SASL_SEC_PROPS, secprops);
- free(secprops);
- }
-
- if (getpeername(sock,(struct sockaddr *)&saddr_r,&addrsize)!=0)
- return RET_FAIL;
-
- if (iptostring((struct sockaddr *)&saddr_r, sizeof(struct sockaddr_in),
- remoteip, sizeof(remoteip)))
- return RET_FAIL;
-
- if (sasl_setprop(conn, SASL_IPREMOTEPORT, remoteip)!=SASL_OK)
- return RET_FAIL;
-
- addrsize=sizeof(struct sockaddr_in);
- if (getsockname(sock,(struct sockaddr *) &saddr_l,&addrsize)!=0)
- return RET_FAIL;
-
- if (iptostring((struct sockaddr *)&saddr_l, sizeof(struct sockaddr_in),
- localip, sizeof(localip)))
- return RET_FAIL;
-
- if (sasl_setprop(conn, SASL_IPLOCALPORT, localip)!=SASL_OK)
- return RET_FAIL;
-
- return RET_OK;
-}
-#endif /* HAVE_SASL */
-
-/************************** END SASL helper functions ******************************/
-
-/************************* Startup functions **********************************/
-
-static conn_ret Initialize(connection_t *cxn, int respTimeout)
-{
-#ifdef HAVE_SASL
- conn_ret saslresult;
-#endif /* HAVE_SASL */
-
- d_printf(1,"%s:%d initializing....\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
-#ifdef HAVE_SASL
- /* only call sasl_client_init() once */
- if (initialized_sasl == 0)
- {
- /* Initialize SASL */
- saslresult=sasl_client_init(saslcallbacks);
-
- if (saslresult!=SASL_OK)
- {
- d_printf(0,
- "%s:%d Error initializing SASL (sasl_client_init) (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult, NULL, NULL));
- return RET_FAIL;
- } else {
- initialized_sasl = 1;
- }
- }
-#endif /* HAVE_SASL */
-
- cxn->lmtp_rBuffer = newBuffer(4096);
- if (cxn->lmtp_rBuffer == NULL)
- {
- d_printf(0, "%s:%d Failure allocating buffer for lmtp_rBuffer\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
- bufferAddNullByte(cxn->lmtp_rBuffer);
-
-
- cxn->imap_rBuffer = newBuffer(4096);
- if (cxn->imap_rBuffer == NULL)
- {
- d_printf(0, "%s:%d Failure allocating buffer for imap_rBuffer \n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
- bufferAddNullByte(cxn->imap_rBuffer);
-
- /* Initialize timeouts */
- cxn->lmtp_writeTimeout = respTimeout;
- cxn->lmtp_readTimeout = respTimeout;
- cxn->imap_writeTimeout = respTimeout;
- cxn->imap_readTimeout = respTimeout;
- cxn->lmtp_sleepTimerId = 0 ;
- cxn->lmtp_sleepTimeout = init_reconnect_period ;
- cxn->imap_sleepTimerId = 0 ;
- cxn->imap_sleepTimeout = init_reconnect_period ;
-
- cxn->dosomethingTimeout = DOSOMETHING_TIMEOUT;
-
- /* set up the write timer. */
- clearTimer (cxn->dosomethingTimerId) ;
-
- if (cxn->dosomethingTimeout > 0)
- cxn->dosomethingTimerId = prepareSleep (dosomethingTimeoutCbk,
- cxn->dosomethingTimeout, cxn);
-
-
-
- return RET_OK;
-}
-
-
-/* initialize the network */
-static conn_ret init_net(char *serverFQDN,
- int port,
- int *sock)
-{
- struct sockaddr_in addr;
- struct hostent *hp;
-
- if ((hp = gethostbyname(serverFQDN)) == NULL) {
- d_printf(0, "gethostbyname(): %s\n", strerror(errno));
- return RET_FAIL;
- }
-
- if (( (*sock) = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- d_printf(0, "socket(): %s\n", strerror(errno));
- return RET_FAIL;
- }
-
- addr.sin_family = AF_INET;
- memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
- addr.sin_port = htons(port);
-
- if (connect( (*sock), (struct sockaddr *) &addr, sizeof (addr)) < 0) {
- d_printf(0,"connect(): %s\n",
- strerror(errno));
- return RET_FAIL;
- }
-
- return RET_OK;
-}
-
-
-
-static conn_ret SetupLMTPConnection(connection_t *cxn,
- char *serverName,
- int port)
-{
-#ifdef HAVE_SASL
- int saslresult;
-#endif /* HAVE_SASL */
- conn_ret result;
-
- cxn->lmtp_port = port;
-
- if (serverName==NULL)
- {
- d_printf(0, "%s:%d serverName is null\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
-#ifdef HAVE_SASL
- /* Free the SASL connection if we already had one */
- if (cxn->saslconn_lmtp!=NULL)
- {
- sasl_dispose(&cxn->saslconn_lmtp);
- }
-
- /* Start SASL */
- saslresult=sasl_client_new("lmtp",
- serverName,
- NULL,
- NULL,
- NULL,
- 0,
- &cxn->saslconn_lmtp);
-
- if (saslresult != SASL_OK)
- {
-
- d_printf(0, "%s:%d:LMTP Error creating a new SASL connection (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult,NULL,NULL));
- return RET_FAIL;
- }
-#endif /* HAVE_SASL */
-
- /* Connect the Socket */
- result = init_net(serverName,
- LMTP_PORT, /*port,*/
- &(cxn->sockfd_lmtp));
-
- if (result != RET_OK)
- {
- d_printf(0, "%s:%d unable to connect to lmtp host\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- if (cxn->lmtp_respBuffer) free(cxn->lmtp_respBuffer);
- cxn->lmtp_respBuffer = xmalloc (4096);
- cxn->lmtp_respBuffer[0]='\0';
-
- /* Free if we had an existing one */
- if (cxn->lmtp_endpoint != NULL)
- {
- delEndPoint(cxn->lmtp_endpoint);
- cxn->lmtp_endpoint = NULL;
- }
-
- cxn->lmtp_endpoint = newEndPoint(cxn->sockfd_lmtp);
- if (cxn->lmtp_endpoint == NULL)
- {
- d_printf(0, "%s:%d:LMTP failure creating endpoint\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
-#ifdef HAVE_SASL
- /* Set the SASL properties */
- result = SetSASLProperties(cxn->saslconn_lmtp, cxn->sockfd_lmtp,
- 0, 0);
-
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d:LMTP error setting SASL properties\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-#endif /* HAVE_SASL */
-
-
- return RET_OK;
-}
-
-static conn_ret SetupIMAPConnection(connection_t *cxn,
- char *serverName,
- int port)
-{
-#ifdef HAVE_SASL
- int saslresult;
-#endif /* HAVE_SASL */
- conn_ret result;
-
- cxn->imap_port = port;
-
- if (serverName==NULL)
- {
- d_printf(0,"%s:%d:IMAP Servername is null",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
-#ifdef HAVE_SASL
- /* Free the SASL connection if we already had one */
- if (cxn->imap_saslconn!=NULL)
- {
- sasl_dispose(&cxn->imap_saslconn);
- }
-
- /* Start SASL */
- saslresult=sasl_client_new("imap",
- serverName,
- NULL,
- NULL,
- NULL,
- 0,
- &cxn->imap_saslconn);
-
- if (saslresult != SASL_OK)
- {
- d_printf(0,"%s:%d:IMAP Error creating a new SASL connection (%s)",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult,NULL,NULL));
- return RET_FAIL;
- }
-#endif /* HAVE_SASL */
-
- /* Connect the Socket */
- result = init_net(serverName,
- port,
- &(cxn->imap_sockfd));
-
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d:IMAP Unable to start network connection for IMAP",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- if (cxn->imap_respBuffer) free(cxn->imap_respBuffer);
- cxn->imap_respBuffer = xmalloc (4096);
- cxn->imap_respBuffer[0]='\0';
-
- /* Free if we had an existing one */
- if (cxn->imap_endpoint != NULL)
- {
- delEndPoint(cxn->imap_endpoint);
- cxn->imap_endpoint = NULL;
- }
-
- cxn->imap_endpoint = newEndPoint(cxn->imap_sockfd);
- if (cxn->imap_endpoint == NULL)
- {
- d_printf(0,"%s:%d:IMAP Failure creating imap endpoint\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
-#ifdef HAVE_SASL
- /* Set the SASL properties */
- result = SetSASLProperties(cxn->imap_saslconn, cxn->imap_sockfd,
- 0, 0);
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d:IMAP Error setting sasl properties",
- hostPeerName (cxn->myHost), cxn->ident);
- return result;
- }
-#endif /* HAVE_SASL */
-
-
- return RET_OK;
-}
-
-/************************* END Startup functions **********************************/
-
-/* Return the response code for this line
- -1 if it doesn't seem to have one
-*/
-static int ask_code(char *str)
-{
- int ret = 0;
-
- if (str==NULL) return -1;
-
- if (strlen(str) < 3) return -1;
-
- /* check to make sure 0-2 are digits */
- if ((isdigit((int) str[0])==0) ||
- (isdigit((int) str[1])==0) ||
- (isdigit((int) str[2])==0))
- {
- d_printf(0,
- "Parse error: response does not begin with a code [%s]\n",
- str);
- return -1;
- }
-
-
- ret = ((str[0]-'0')*100)+
- ((str[1]-'0')*10)+
- (str[2]-'0');
-
- return ret;
-}
-
-/* is this a continuation or not?
- 220-fdfsd is (1)
- 220 fdsfs is not (0)
- */
-
-static int ask_keepgoing(char *str)
-{
- if (str==NULL) return 0;
- if (strlen(str) < 4) return 0;
-
- if (str[3]=='-') return 1;
-
- return 0;
-}
-
-
-static conn_ret lmtp_listenintro(connection_t *cxn)
-{
- Buffer *readBuffers;
-
- /* set up to receive */
- readBuffers = makeBufferArray (bufferTakeRef (cxn->lmtp_rBuffer), NULL) ;
- prepareRead(cxn->lmtp_endpoint, readBuffers, lmtp_readCB, cxn, 5);
-
- cxn->lmtp_state = LMTP_READING_INTRO;
-
- return RET_OK;
-}
-
-
-
-/************************** IMAP functions ***********************/
-
-static conn_ret imap_Connect(connection_t *cxn)
-{
- conn_ret result;
-
- ASSERT(cxn->imap_sleepTimerId == 0);
-
- /* make the IMAP connection */
- result = SetupIMAPConnection(cxn,
- cxn->ServerName,
- IMAP_PORT);
-
- /* Listen to the intro and start the authenticating process */
- result = imap_listenintro(cxn);
-
- return result;
-}
-
-/*
- * This is called when the data write timeout for the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void imap_writeTimeoutCbk (TimeoutId id UNUSED, void *data)
-{
- connection_t *cxn = (Connection) data ;
- const char *peerName ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- syslog (LOG_WARNING, "timeout for %s", peerName);
- d_printf(0, "%s: shutting down non-responsive IMAP connection (%s)\n",
- hostPeerName (cxn->myHost),
- imap_stateToString(cxn->imap_state));
-
- cxnLogStats (cxn,true) ;
-
- imap_Disconnect(cxn);
-}
-
-/*
- * This is called when the timeout for the reponse from the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void imap_readTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
- const char *peerName ;
-
- ASSERT (id == cxn->imap_readBlockedTimerId) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- warn ("%s:%d cxnsleep non-responsive connection", peerName, cxn->ident) ;
- d_printf(0, "%s:%d shutting down non-responsive IMAP connection (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- imap_stateToString(cxn->imap_state));
-
- cxnLogStats (cxn,true);
-
- if (cxn->imap_state == IMAP_DISCONNECTED)
- {
- imap_Disconnect(cxn);
- lmtp_Disconnect(cxn);
- delConnection (cxn) ;
- }
- else {
- imap_Disconnect(cxn);
- }
-}
-
-/*
- * Called by the EndPoint class when the timer goes off
- */
-static void imap_reopenTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
-
- ASSERT (id == cxn->imap_sleepTimerId) ;
-
- cxn->imap_sleepTimerId = 0 ;
-
- d_printf(1,"%s:%d:IMAP Reopen timer rang. Try to make new connection now\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- if (cxn->imap_state != IMAP_DISCONNECTED)
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- imap_stateToString (cxn->imap_state)) ;
- }
- else {
- if (imap_Connect(cxn) != RET_OK)
- prepareReopenCbk(cxn, 0);
- }
-}
-
-static void imap_Disconnect(connection_t *cxn)
-{
- clearTimer (cxn->imap_sleepTimerId) ;
- cxn->imap_sleepTimerId = 0;
- clearTimer (cxn->imap_readBlockedTimerId) ;
- clearTimer (cxn->imap_writeBlockedTimerId) ;
-
- DeferAllArticles(cxn, &(cxn->imap_controlMsg_q)) ; /* give any articles back to Host */
-
- cxn->imap_state = IMAP_DISCONNECTED;
-
- cxn->imap_disconnects++;
-
- cxn->imap_respBuffer[0]='\0';
-
- if (cxn->issue_quit == 0)
- prepareReopenCbk(cxn,0);
-
- DeleteIfDisconnected(cxn);
-}
-
-/************************** END IMAP functions ***********************/
-
-/************************ LMTP functions **************************/
-
-/*
- * Create a network lmtp connection
- * and start listening for the intro string
- *
- */
-
-static conn_ret lmtp_Connect(connection_t *cxn)
-{
- conn_ret result;
-
- ASSERT(cxn->lmtp_sleepTimerId == 0);
-
- /* make the LMTP connection */
- result = SetupLMTPConnection(cxn,
- cxn->ServerName,
- LMTP_PORT);
-
- if (result!=RET_OK) return result;
-
- /* Listen to the intro */
- result = lmtp_listenintro(cxn);
-
- return result;
-}
-
-
-
-static void lmtp_Disconnect(connection_t *cxn)
-{
- clearTimer (cxn->lmtp_sleepTimerId) ;
- cxn->lmtp_sleepTimerId = 0;
- clearTimer (cxn->lmtp_readBlockedTimerId) ;
- clearTimer (cxn->lmtp_writeBlockedTimerId) ;
-
- /* give any articles back to Host */
- DeferAllArticles(cxn, &(cxn->lmtp_todeliver_q)) ;
-
- cxn->lmtp_state = LMTP_DISCONNECTED;
-
- cxn->lmtp_disconnects++;
-
- cxn->lmtp_respBuffer[0]='\0';
-
- if (cxn->issue_quit == 0)
- prepareReopenCbk(cxn,1);
-
- DeleteIfDisconnected(cxn);
-}
-
-
-
-/*
- * Called by the EndPoint class when the timer goes off
- */
-static void lmtp_reopenTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
-
- ASSERT (id == cxn->lmtp_sleepTimerId) ;
-
- cxn->lmtp_sleepTimerId = 0 ;
-
- d_printf(1,"%s:%d:LMTP Reopen timer rang. Try to make new connection now\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- if (cxn->lmtp_state != LMTP_DISCONNECTED)
- {
- warn ("%s:%d cxnsleep connection in bad state: %s",
- hostPeerName (cxn->myHost), cxn->ident,
- lmtp_stateToString (cxn->lmtp_state)) ;
- }
- else {
- if (lmtp_Connect(cxn) != RET_OK)
- prepareReopenCbk(cxn, 1);
- }
-}
-
-/*
- * Set up the callback used when the Connection is sleeping (i.e. will try
- * to reopen the connection).
- *
- * type (0 = imap, 1 = lmtp)
- */
-static void prepareReopenCbk (Connection cxn, int type)
-{
- /* xxx check state */
-
-
-
- if (type == 0) {
-
- cxn->imap_sleepTimerId = prepareSleep (imap_reopenTimeoutCbk,
- cxn->imap_sleepTimeout, cxn) ;
- d_printf (1,"%s:%d IMAP connection error\n"
- " will try to reconnect in %d seconds\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->imap_sleepTimeout) ;
- } else {
- cxn->lmtp_sleepTimerId = prepareSleep (lmtp_reopenTimeoutCbk,
- cxn->lmtp_sleepTimeout, cxn) ;
- d_printf (1,"%s:%d:LMTP connection error\n"
- "will try to reconnect in %d seconds\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->lmtp_sleepTimeout) ;
- }
-
- /* bump the sleep timer amount each time to wait longer and longer. Gets
- reset in resetConnection() */
- if (type == 0) {
- cxn->imap_sleepTimeout *= 2 ;
- if (cxn->imap_sleepTimeout > max_reconnect_period)
- cxn->imap_sleepTimeout = max_reconnect_period ;
- } else {
- cxn->lmtp_sleepTimeout *= 2 ;
- if (cxn->lmtp_sleepTimeout > max_reconnect_period)
- cxn->lmtp_sleepTimeout = max_reconnect_period ;
- }
-}
-
-/*
- * This is called when the timeout for the reponse from the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void lmtp_readTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
- const char *peerName ;
-
- ASSERT (id == cxn->lmtp_readBlockedTimerId) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- warn ("%s:%d cxnsleep non-responsive connection", peerName, cxn->ident) ;
- d_printf(0,"%s:%d shutting down non-responsive LMTP connection (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- lmtp_stateToString(cxn->lmtp_state));
-
- cxnLogStats (cxn,true) ;
-
- if (cxn->lmtp_state == LMTP_DISCONNECTED) {
- imap_Disconnect(cxn);
- lmtp_Disconnect(cxn);
- delConnection (cxn) ;
- } else {
- lmtp_Disconnect(cxn);
- }
-}
-
-
-
-/*
- * This is called when the data write timeout for the remote
- * goes off. We tear down the connection and notify our host.
- */
-static void lmtp_writeTimeoutCbk (TimeoutId id UNUSED, void *data)
-{
- connection_t *cxn = (Connection) data ;
- const char *peerName ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- syslog (LOG_WARNING, "timeout for %s", peerName);
- d_printf(0, "%s:%d shutting down non-responsive LMTP connection (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- lmtp_stateToString(cxn->lmtp_state)) ;
-
- cxnLogStats (cxn,true);
-
- lmtp_Disconnect(cxn);
-}
-
-/************************ END LMTP functions **************************/
-
-/************************** LMTP write functions ********************/
-
-static conn_ret lmtp_noop(connection_t *cxn)
-{
- int result;
- char *p;
-
- p = xstrdup("NOOP\r\n");
- result = WriteToWire_lmtpstr(cxn, p, strlen(p));
- if (result!=RET_OK) return result;
-
- cxn->lmtp_state = LMTP_WRITING_NOOP;
-
- return RET_OK;
-}
-
-static conn_ret lmtp_IssueQuit(connection_t *cxn)
-{
- int result;
- char *p;
-
- p = xstrdup("QUIT\r\n");
- result = WriteToWire_lmtpstr(cxn, p, strlen(p));
- if (result!=RET_OK) return result;
-
- cxn->lmtp_state = LMTP_WRITING_QUIT;
-
- return RET_OK;
-}
-
-static conn_ret lmtp_getcapabilities(connection_t *cxn)
-{
- int result;
- char *p;
-
- if (cxn->lmtp_capabilities != NULL)
- {
- if (cxn->lmtp_capabilities->saslmechs) {
- free( cxn->lmtp_capabilities->saslmechs);
- }
- free( cxn->lmtp_capabilities );
- cxn->lmtp_capabilities = NULL;
- }
-
- cxn->lmtp_capabilities = xcalloc (1, sizeof(lmtp_capabilities_t));
- cxn->lmtp_capabilities->saslmechs = NULL;
-
-#ifdef SMTPMODE
- p = concat("EHLO ", hostname, "\r\n", (char *) 0);
-#else
- p = concat("LHLO ", hostname, "\r\n", (char *) 0);
-#endif /* SMTPMODE */
-
- result = WriteToWire_lmtpstr(cxn, p, strlen(p));
- if (result!=RET_OK) return result;
-
- cxn->lmtp_state = LMTP_WRITING_LHLO;
-
- return RET_OK;
-}
-
-#ifdef HAVE_SASL
-static conn_ret lmtp_authenticate(connection_t *cxn)
-{
- int saslresult;
-
- const char *mechusing;
- const char *out;
- unsigned int outlen;
- char *inbase64;
- int inbase64len;
- int status;
- int result;
-
- char *p;
-
- sasl_interact_t *client_interact=NULL;
-
-
- saslresult=sasl_client_start(cxn->saslconn_lmtp,
- cxn->lmtp_capabilities->saslmechs,
- &client_interact,
- &out, &outlen,
- &mechusing);
-
-
-
- if ((saslresult != SASL_OK) &&
- (saslresult != SASL_CONTINUE)) {
-
- d_printf(0,"%s:%d:LMTP Error calling sasl_client_start (%s)\n",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult, NULL, NULL));
- return RET_FAIL;
- }
-
- d_printf(1,"%s:%d:LMTP Decided to try to authenticate with SASL mechanism=%s\n",
- hostPeerName (cxn->myHost), cxn->ident,mechusing);
-
- if (!out)
- {
- /* no initial client response */
- p = concat("AUTH ", mechusing, "\r\n", (char *) 0);
- } else if (!outlen) {
- /* empty initial client response */
- p = concat("AUTH ", mechusing, " =\r\n", (char *) 0);
- } else {
- /* initial client response - convert to base64 */
- inbase64 = xmalloc(outlen*2+10);
-
- saslresult = sasl_encode64(out, outlen,
- inbase64, outlen*2+10,
- (unsigned *) &inbase64len);
- if (saslresult != SASL_OK) return RET_FAIL;
- p = concat("AUTH ", mechusing, " ", inbase64, "\r\n", (char *) 0);
- free(inbase64);
- }
-
- result = WriteToWire_lmtpstr(cxn, p, strlen(p));
-
- cxn->lmtp_state = LMTP_WRITING_STARTAUTH;
-
- return RET_OK;
-}
-
-static imt_stat lmtp_getauthline(char *str, char **line, int *linelen)
-{
- char buf[4096];
- int saslresult;
- int response_code = -1;
-
- response_code = ask_code(str);
-
- if (response_code == 334) {
-
- /* continue */
-
- } else if (response_code == 235) {
-
- /* woohoo! authentication complete */
- return STAT_OK;
-
- } else {
- /* failure of some sort */
- d_printf(0,"?:?:LMTP Authentication failure (%d) [%s]\n",
- response_code,str);
- return STAT_NO;
- }
-
- str += 4; /* jump past the "334 " */
-
- *line = xmalloc(strlen(str)+30);
- if ((*line)==NULL) {
- return STAT_NO;
- }
-
- /* decode this line */
- saslresult = sasl_decode64(str, strlen(str),
- *line, strlen(str)+1, (unsigned *) linelen);
- if (saslresult != SASL_OK) {
- d_printf(0,"?:?:LMTP base64 decoding error\n");
- return STAT_NO;
- }
-
- return STAT_CONT;
-}
-#endif /* HAVE_SASL */
-
-static void lmtp_writeCB (EndPoint e UNUSED, IoStatus i UNUSED, Buffer *b,
- void *d)
-{
- connection_t *cxn = (connection_t *) d;
- Buffer *readBuffers;
-
- clearTimer (cxn->lmtp_writeBlockedTimerId) ;
-
- /* Free the string that was written */
- freeBufferArray (b);
- if (cxn->lmtp_tofree_str!=NULL)
- {
- free(cxn->lmtp_tofree_str);
- cxn->lmtp_tofree_str=NULL;
- }
-
- /* set up to receive */
- readBuffers = makeBufferArray (bufferTakeRef (cxn->lmtp_rBuffer), NULL) ;
- prepareRead(cxn->lmtp_endpoint, readBuffers, lmtp_readCB, cxn, 5);
-
- /* set up the response timer. */
- clearTimer (cxn->lmtp_readBlockedTimerId) ;
-
- if (cxn->lmtp_readTimeout > 0)
- cxn->lmtp_readBlockedTimerId = prepareSleep (lmtp_readTimeoutCbk,
- cxn->lmtp_readTimeout, cxn) ;
-
-
- switch (cxn->lmtp_state)
- {
-
- case LMTP_WRITING_LHLO:
- cxn->lmtp_state = LMTP_READING_LHLO;
- break;
-
- case LMTP_WRITING_STARTAUTH:
- case LMTP_WRITING_STEPAUTH:
-
- cxn->lmtp_state = LMTP_READING_STEPAUTH;
-
- break;
-
- case LMTP_WRITING_UPTODATA:
- /* expect result to rset */
- cxn->lmtp_state = LMTP_READING_RSET;
- break;
-
- case LMTP_WRITING_CONTENTS:
- /* so we sent the whole DATA command
- let's see what the server responded */
-
- cxn->lmtp_state = LMTP_READING_CONTENTS;
-
- break;
-
- case LMTP_WRITING_NOOP:
- cxn->lmtp_state = LMTP_READING_NOOP;
- break;
-
- case LMTP_WRITING_QUIT:
- cxn->lmtp_state = LMTP_READING_QUIT;
- break;
-
- default:
-
- d_printf(0,"%s:%d:LMTP Unknown state. Internal error\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- break;
- }
-}
-
-/************************** END LMTP write functions ********************/
-
-/************************** IMAP sending functions ************************/
-
-
-static void imap_writeCB (EndPoint e UNUSED, IoStatus i UNUSED, Buffer *b,
- void *d)
-{
- connection_t *cxn = (connection_t *) d;
- Buffer *readBuffers;
-
- clearTimer (cxn->imap_writeBlockedTimerId) ;
-
- /* free the string we just wrote out */
- freeBufferArray (b);
- if (cxn->imap_tofree_str!=NULL)
- {
- free(cxn->imap_tofree_str);
- cxn->imap_tofree_str=NULL;
- }
-
- /* set up to receive */
- readBuffers = makeBufferArray (bufferTakeRef (cxn->imap_rBuffer), NULL) ;
- prepareRead(cxn->imap_endpoint, readBuffers, imap_readCB, cxn, 5);
-
- /* set up the response timer. */
- clearTimer (cxn->imap_readBlockedTimerId) ;
-
- if (cxn->imap_readTimeout > 0)
- cxn->imap_readBlockedTimerId = prepareSleep(imap_readTimeoutCbk,
- cxn->imap_readTimeout,
- cxn);
-
- switch (cxn->imap_state) {
- case IMAP_WRITING_CAPABILITY:
- cxn->imap_state = IMAP_READING_CAPABILITY;
- break;
-
- case IMAP_WRITING_STEPAUTH:
- case IMAP_WRITING_STARTAUTH:
- cxn->imap_state = IMAP_READING_STEPAUTH;
- break;
-
- case IMAP_WRITING_CREATE:
- cxn->imap_state = IMAP_READING_CREATE;
- break;
-
- case IMAP_WRITING_DELETE:
- cxn->imap_state = IMAP_READING_DELETE;
- break;
-
- case IMAP_WRITING_SELECT:
- cxn->imap_state = IMAP_READING_SELECT;
- break;
-
- case IMAP_WRITING_SEARCH:
- cxn->imap_state = IMAP_READING_SEARCH;
- break;
-
- case IMAP_WRITING_STORE:
- cxn->imap_state = IMAP_READING_STORE;
- break;
-
- case IMAP_WRITING_CLOSE:
- cxn->imap_state = IMAP_READING_CLOSE;
- break;
-
- case IMAP_WRITING_NOOP:
- cxn->imap_state = IMAP_READING_NOOP;
- break;
-
- case IMAP_WRITING_QUIT:
- cxn->imap_state = IMAP_READING_QUIT;
- break;
-
- default:
- d_printf(0,"%s:%d:IMAP invalid connection state\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
- imap_Disconnect(cxn);
- break;
- }
-}
-
-/*
- * Tag is already allocated
- */
-
-static void imap_GetTag(connection_t *cxn)
-{
- sprintf(cxn->imap_currentTag,"%06d",cxn->imap_tag_num);
- cxn->imap_tag_num++;
- if (cxn->imap_tag_num >= 999999)
- {
- cxn->imap_tag_num = 0;
- }
-}
-
-#ifdef HAVE_SASL
-static conn_ret imap_sendAuthStep(connection_t *cxn, char *str)
-{
- conn_ret result;
- int saslresult;
- char in[4096];
- unsigned int inlen;
- const char *out;
- unsigned int outlen;
- char *inbase64;
- unsigned int inbase64len;
-
- /* base64 decode it */
-
- saslresult = sasl_decode64(str, strlen(str),
- in, strlen(str)+1, &inlen);
- if (saslresult != SASL_OK) {
- d_printf(0,"%s:%d:IMAP base64 decoding error\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
- return RET_FAIL;
- }
-
- saslresult=sasl_client_step(cxn->imap_saslconn,
- in,
- inlen,
- NULL,
- &out,
- &outlen);
-
- /* check if sasl succeeded */
- if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) {
-
- d_printf(0,"%s:%d:IMAP sasl_client_step failed with %s\n",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult,NULL,NULL));
- cxn->imap_state = IMAP_CONNECTED_NOTAUTH;
- return RET_FAIL;
- }
-
- inbase64 = xmalloc(outlen * 2 + 10);
-
- /* convert to base64 */
- saslresult = sasl_encode64(out, outlen,
- inbase64, outlen*2, (unsigned *) &inbase64len);
-
- if (saslresult != SASL_OK) return RET_FAIL;
-
- /* append endline */
- strlcpy(inbase64 + inbase64len, "\r\n", outlen * 2 + 10 - inbase64len);
- inbase64len+=2;
-
- /* send to server */
- result = WriteToWire_imapstr(cxn,inbase64, inbase64len);
-
- cxn->imap_state = IMAP_WRITING_STEPAUTH;
-
- return result;
-}
-#endif /* HAVE_SASL */
-
-static conn_ret imap_sendAuthenticate(connection_t *cxn)
-{
- int result;
-
- char *p;
-
-#ifdef HAVE_SASL
- const char *mechusing;
- char *inbase64;
- int inbase64len;
- int saslresult=SASL_NOMECH;
-
- sasl_interact_t *client_interact=NULL;
-
- if (cxn->imap_capabilities->saslmechs) {
- saslresult=sasl_client_start(cxn->imap_saslconn,
- cxn->imap_capabilities->saslmechs,
- &client_interact,
- NULL, NULL,
- &mechusing);
- }
-
-
-
- /* If no mechs try "login" */
- if (saslresult == SASL_NOMECH)
- {
-
-#else /* HAVE_SASL */
-
- { /* always do login */
-
-#endif /* HAVE_SASL */
- d_printf(1,"%s:%d:IMAP No mechanism found. Trying login method\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
-
- if (cxn->imap_capabilities->logindisabled==1)
- {
- d_printf(0,"%s:%d:IMAP Login command w/o security layer not allowed on this server\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return RET_FAIL;
- }
-
- if (deliver_authname==NULL)
- {
- d_printf(0,"%s:%d:IMAP Unable to log in because can't find a authname\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
- return RET_FAIL;
- }
-
- if (deliver_password==NULL)
- {
- d_printf(0,"%s:%d:IMAP Unable to log in because can't find a password\n",
- hostPeerName (cxn->myHost), cxn->ident) ;
- return RET_FAIL;
- }
-
- imap_GetTag(cxn);
-
- p = concat(cxn->imap_currentTag, " LOGIN ", deliver_authname, " \"",
- deliver_password, "\"\r\n", (char *) 0);
-
- result = WriteToWire_imapstr(cxn, p, strlen(p));
-
- cxn->imap_state = IMAP_WRITING_STARTAUTH;
-
- return RET_OK;
- }
-
-#ifdef HAVE_SASL
- if ((saslresult != SASL_OK) &&
- (saslresult != SASL_CONTINUE)) {
-
- d_printf(0,"%s:%d:IMAP Error calling sasl_client_start (%s) mechusing = %s\n",
- hostPeerName (cxn->myHost), cxn->ident,
- sasl_errstring(saslresult, NULL, NULL), mechusing);
- return RET_FAIL;
- }
-
- d_printf(1,"%s:%d:IMAP Trying to authenticate to imap with %s mechanism\n",
- hostPeerName (cxn->myHost), cxn->ident,
- mechusing);
-
- imap_GetTag(cxn);
-
- p = concat(cxn->imap_currentTag, " AUTHENTICATE ", mechusing, "\r\n",
- (char *) 0);
- result = WriteToWire_imapstr(cxn, p, strlen(p));
-
- cxn->imap_state = IMAP_WRITING_STARTAUTH;
-
- return RET_OK;
-#endif /* HAVE_SASL */
-}
-
-static conn_ret imap_CreateGroup(connection_t *cxn, char *bboard)
-{
- conn_ret result;
- char *tosend;
-
- d_printf(1,"%s:%d:IMAP Ok creating group [%s]\n",
- hostPeerName (cxn->myHost), cxn->ident,
- bboard);
-
- imap_GetTag(cxn);
-
- tosend = concat(cxn->imap_currentTag, " CREATE ", bboard, "\r\n",
- (char *) 0);
-
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result!=RET_OK) return result;
-
- cxn->imap_state = IMAP_WRITING_CREATE;
-
- return RET_OK;
-}
-
-static conn_ret imap_DeleteGroup(connection_t *cxn, char *bboard)
-{
- conn_ret result;
- char *tosend;
-
- d_printf(1,"%s:%d:IMAP Ok removing bboard [%s]\n",
- hostPeerName (cxn->myHost), cxn->ident, bboard);
-
- imap_GetTag(cxn);
-
- tosend = concat(cxn->imap_currentTag, " DELETE ", bboard, "\r\n",
- (char *) 0);
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result!=RET_OK) return result;
-
- cxn->imap_state = IMAP_WRITING_DELETE;
-
- return RET_OK;
-}
-
-static conn_ret imap_CancelMsg(connection_t *cxn, char *newsgroup)
-{
- conn_ret result;
- char *tosend;
-
- ASSERT(newsgroup);
-
- imap_GetTag(cxn);
-
- /* select mbox */
- tosend = concat(cxn->imap_currentTag, " SELECT ", newsgroup, "\r\n",
- (char *) 0);
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result != RET_OK) return result;
-
- cxn->imap_state = IMAP_WRITING_SELECT;
-
- hostArticleOffered (cxn->myHost, cxn);
-
- return RET_OK;
-}
-
-static conn_ret imap_sendSearch(connection_t *cxn, char *msgid)
-{
- conn_ret result;
- char *tosend;
-
- ASSERT(msgid);
-
- imap_GetTag(cxn);
-
- /* preform search */
- tosend = concat(cxn->imap_currentTag,
- " UID SEARCH header \"Message-ID\" \"", msgid, "\"\r\n",
- (char *) 0);
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result != RET_OK) return result;
-
- cxn->imap_state = IMAP_WRITING_SEARCH;
-
- return RET_OK;
-}
-
-static conn_ret imap_sendKill(connection_t *cxn, unsigned uid)
-{
- conn_ret result;
- char *tosend;
- size_t length;
-
- imap_GetTag(cxn);
-
- length = 7 + 50 + 20;
- tosend = xmalloc(length);
- snprintf(tosend,length,"%s UID STORE %d +FLAGS.SILENT (\\Deleted)\r\n",
- cxn->imap_currentTag, uid);
-
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result != RET_OK) return result;
-
- cxn->imap_state = IMAP_WRITING_STORE;
-
- return RET_OK;
-}
-
-static conn_ret imap_sendSimple(connection_t *cxn, const char *atom, int st)
-{
- char *tosend;
- conn_ret result;
-
- imap_GetTag(cxn);
- tosend = concat(cxn->imap_currentTag, " ", atom, "\r\n", (char *) 0);
-
- result = WriteToWire_imapstr(cxn, tosend, -1);
- if (result != RET_OK) return result;
-
- cxn->imap_state = st;
-
- return RET_OK;
-}
-
-static conn_ret imap_sendClose(connection_t *cxn)
-{
- return imap_sendSimple(cxn, "CLOSE", IMAP_WRITING_CLOSE);
-}
-
-static conn_ret imap_sendQuit(connection_t *cxn)
-{
- return imap_sendSimple(cxn, "LOGOUT", IMAP_WRITING_QUIT);
-}
-
-static conn_ret imap_noop(connection_t *cxn)
-{
- return imap_sendSimple(cxn, "NOOP", IMAP_WRITING_NOOP);
-}
-
-
-static conn_ret imap_sendCapability(connection_t *cxn)
-{
- return imap_sendSimple(cxn, "CAPABILITY", IMAP_WRITING_CAPABILITY);
-}
-
-/************************** END IMAP sending functions ************************/
-
-/************************** IMAP reading functions ***************************/
-
-static conn_ret imap_listenintro(connection_t *cxn)
-{
- Buffer *readBuffers;
-
- /* set up to receive */
- readBuffers = makeBufferArray (bufferTakeRef (cxn->imap_rBuffer), NULL) ;
- prepareRead(cxn->imap_endpoint, readBuffers, imap_readCB, cxn, 5);
-
- cxn->imap_state = IMAP_READING_INTRO;
-
- return RET_OK;
-}
-
-static conn_ret imap_ParseCapability(char *string, imap_capabilities_t **caps)
-{
- char *str = string;
- char *start = str;
- size_t mechlen;
-
- /* allocate the caps structure if it doesn't already exist */
- if ( (*caps) == NULL)
- (*caps) = xcalloc(1, sizeof(imap_capabilities_t));
-
- while ( (*str) != '\0')
- {
-
- while (((*str) != '\0') && ((*str)!=' '))
- {
- str++;
- }
-
- if ( (*str) != '\0')
- {
- *str = '\0';
- str++;
- }
-
- if ( strcasecmp(start,"IMAP4")==0)
- {
- (*caps)->imap4 = 1;
- } else if (strcasecmp(start,"LOGINDISABLED")==0) {
- (*caps)->logindisabled = 1;
- } else if ( strncmp(start, "AUTH=", 5)==0) {
-
- if ( (*caps)->saslmechs == NULL)
- {
- (*caps)->saslmechs = xstrdup (start + 5);
- } else {
- mechlen = strlen((*caps)->saslmechs) + 1;
- mechlen += strlen(start + 5) + 1;
- (*caps)->saslmechs = xrealloc((*caps)->saslmechs, mechlen);
- strlcat((*caps)->saslmechs, " ", mechlen);
- strlcat((*caps)->saslmechs, start + 5, mechlen);
- }
- }
-
- start = str;
-
- }
-
- if ((*caps)->saslmechs) {
- d_printf(1,"?:?:IMAP parsed capabilities: saslmechs = %s\n",
- (*caps)->saslmechs);
- }
-
- return RET_OK;
-}
-
-
-static void imap_readCB (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- connection_t *cxn = (connection_t *) d;
- Buffer *readBuffers ;
-
- int okno;
- char *str;
- char strbuf[4096];
- char *linestart;
- conn_ret ret;
- char *p;
-
- p = bufferBase(b[0]);
-
- /* Add what we got to our internal read buffer */
- bufferAddNullByte (b[0]) ;
-
- if (i != IoDone) {
- errno = endPointErrno(e);
-
- syslog(LOG_ERR, "%s:%d IMAP i/o failed: %m",
- hostPeerName (cxn->myHost), cxn->ident);
- freeBufferArray (b);
- imap_Disconnect(cxn);
- return;
- }
-
- if (strchr (p, '\n') == NULL) {
- /* partial read. expand buffer and retry */
-
- if (expandBuffer (b[0], BUFFER_EXPAND_AMOUNT)==false) {
- d_printf(0,"%s:%d:IMAP expanding buffer returned false\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- imap_Disconnect(cxn);
- return;
- }
- readBuffers = makeBufferArray (bufferTakeRef (b[0]), NULL) ;
-
- if (!prepareRead (e, readBuffers, imap_readCB, cxn, 1)) {
- imap_Disconnect(cxn);
- }
-
- freeBufferArray (b);
- return;
- }
-
- clearTimer (cxn->imap_readBlockedTimerId) ;
-
- /* we got something. add to our buffer and free b */
-
- strcat(cxn->imap_respBuffer, p);
-
- bufferSetDataSize( b[0], 0);
-
- freeBufferArray (b);
-
-
-
- /* goto here to take another step */
- reset:
-
- /* see if we have a full line */
- ret = GetLine( cxn->imap_respBuffer , strbuf, sizeof(strbuf));
- str = strbuf;
- linestart = str;
-
- /* if we don't have a full line */
- if ( ret == RET_NO_FULLLINE)
- {
-
- readBuffers = makeBufferArray (bufferTakeRef (cxn->imap_rBuffer), NULL) ;
-
- if ( !prepareRead (e, readBuffers, imap_readCB, cxn, 1) )
- {
- imap_Disconnect(cxn);
- }
- return;
-
- } else if (ret!=RET_OK)
- {
- return;
- }
-
- /* if untagged */
- if ((str[0]=='*') && (str[1]==' '))
- {
- str+=2;
-
- /* now figure out what kind of untagged it is */
- if (strncasecmp(str,"CAPABILITY ",11)==0)
- {
- str+=11;
-
- imap_ParseCapability(str,&(cxn->imap_capabilities));
-
- } else if (strncasecmp(str,"SEARCH",6)==0) {
-
- str+=6;
-
- if ( (*str) == ' ')
- {
- str++;
-
- cxn->current_control->data.control->uid = atoi(str);
-
- d_printf(1,"%s:%d:IMAP i think the UID = %ld\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->current_control->data.control->uid);
- } else {
- /* it's probably a blank uid (i.e. message doesn't exist) */
- cxn->current_control->data.control->uid = (unsigned long)-1;
- }
-
-
- } else if (strncasecmp(str,"OK ",3)==0) {
-
- if (cxn->imap_state==IMAP_READING_INTRO)
- {
- imap_sendCapability(cxn); /* xxx errors */
- return;
-
- } else {
-
- }
-
-
- } else {
- /* untagged command not understood */
- }
-
- /* always might be more to look at */
- goto reset;
-
- } else if ((str[0]=='+') && (str[1]==' ')) {
-
- str+=2;
-
- if (cxn->imap_state == IMAP_READING_STEPAUTH)
- {
-#ifdef HAVE_SASL
- if (imap_sendAuthStep(cxn, str)!=RET_OK)
- {
- imap_Disconnect(cxn);
- }
-#else
- d_printf(0,"%s:%d:IMAP got a '+ ...' without SASL. Something's wrong\n",
- hostPeerName (cxn->myHost), cxn->ident);
- imap_Disconnect(cxn);
-#endif /* HAVE_SASL */
-
- return;
- } else {
- d_printf(0,"%s:%d:IMAP got a '+ ...' in state where not expected\n",
- hostPeerName (cxn->myHost), cxn->ident);
- imap_Disconnect(cxn);
- return;
- }
-
-
-
- } else if (strncmp(str, cxn->imap_currentTag, IMAP_TAGLENGTH)==0) {
- /* matches our tag */
- str += IMAP_TAGLENGTH;
-
- if (str[0]!=' ')
- {
- d_printf(0,"%s:%d:IMAP Parse error: tag with no space afterward\n",
- hostPeerName (cxn->myHost), cxn->ident);
- imap_Disconnect(cxn);
- return;
- }
- str++;
-
- /* should be OK/NO */
- if (strncmp(str,"OK",2)==0)
- {
- okno = 1;
- } else {
- okno = 0;
- }
-
- switch(cxn->imap_state)
- {
- case IMAP_READING_CAPABILITY:
-
- if (okno==1) {
- if (imap_sendAuthenticate(cxn)!=RET_OK)
- {
- d_printf(0,"%s:%d:IMAP sendauthenticate failed\n",
- hostPeerName (cxn->myHost), cxn->ident);
- imap_Disconnect(cxn);
- }
- return;
- } else {
- d_printf(0,"%s:%d:IMAP CAPABILITY gave a NO response\n",
- hostPeerName (cxn->myHost), cxn->ident);
- imap_Disconnect(cxn);
- }
- return;
-
- break;
- case IMAP_READING_STEPAUTH:
-
- if (okno == 1) {
-
- cxn->imap_sleepTimeout = init_reconnect_period ;
-
- cxn->imap_timeCon = theTime () ;
- cxn->timeCon = theTime () ;
-
- d_printf(0,"%s:%d IMAP authentication succeeded\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- cxn->imap_disconnects=0;
-
- cxn->imap_state = IMAP_IDLE_AUTHED;
-
- /* try to send a message if we have one */
-
- imap_ProcessQueue(cxn);
- } else {
- d_printf(0,"%s:%d:IMAP Authentication failed with [%s]\n",
- hostPeerName (cxn->myHost), cxn->ident,str);
- imap_Disconnect(cxn);
- }
-
- return;
-
- break;
-
- case IMAP_READING_CREATE:
-
- if (okno==1) {
-
- d_printf(1,"%s:%d:IMAP Create of bboard successful\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- cxn->create_succeeded++;
-
- /* we can delete article now */
- QueueForgetAbout(cxn, cxn->current_control,
- MSG_SUCCESS);
- } else {
- d_printf(1,"%s:%d:IMAP Create failed with [%s] for %s\n",
- hostPeerName (cxn->myHost), cxn->ident,str,
- cxn->current_control->data.control->folder);
-
- ReQueue(cxn, &(cxn->imap_controlMsg_q), cxn->current_control);
- }
-
- imap_ProcessQueue(cxn);
-
- break;
-
- case IMAP_READING_DELETE:
-
- if (okno==1) {
- d_printf(1,"%s:%d:IMAP Delete successful\n",
- hostPeerName (cxn->myHost), cxn->ident);
- cxn->remove_succeeded++;
-
- /* we can delete article now */
- QueueForgetAbout(cxn, cxn->current_control,
- MSG_SUCCESS);
- } else {
- d_printf(1,"%s:%d:IMAP Delete mailbox failed with [%s] for %s\n",
- hostPeerName (cxn->myHost), cxn->ident,str,
- cxn->current_control->data.control->folder);
-
- ReQueue(cxn, &(cxn->imap_controlMsg_q), cxn->current_control);
-
- }
-
- imap_ProcessQueue(cxn);
- return;
-
- break;
-
- case IMAP_READING_SELECT:
-
- if (okno==1) {
-
- imap_sendSearch(cxn, cxn->current_control->data.control->msgid);
- return;
-
- } else {
- d_printf(1,"%s:%d:IMAP Select failed with [%s] for %s\n",
- hostPeerName (cxn->myHost), cxn->ident,str,
- cxn->current_control->data.control->folder);
-
- ReQueue(cxn, &(cxn->imap_controlMsg_q), cxn->current_control);
-
- cxn->imap_state = IMAP_IDLE_AUTHED;
-
- imap_ProcessQueue(cxn);
- return;
- }
-
- break;
-
- case IMAP_READING_SEARCH:
- /* if no message let's forget about it */
- if (cxn->current_control->data.control->uid
- == (unsigned long)-1) {
- d_printf(2, "%s:%d:IMAP Search didn't find the message\n",
- hostPeerName (cxn->myHost), cxn->ident);
- QueueForgetAbout(cxn, cxn->current_control,
- MSG_FAIL_DELIVER);
- if (imap_sendClose(cxn) != RET_OK)
- imap_Disconnect(cxn);
- return;
- }
-
- if (okno==1) {
- /* we got a uid. let's delete it */
- if (imap_sendKill(cxn,
- cxn->current_control->data.control->uid)
- != RET_OK)
- imap_Disconnect(cxn);
- return;
- } else {
- d_printf(0, "%s:%d IMAP Received NO response to SEARCH\n",
- hostPeerName (cxn->myHost), cxn->ident);
- ReQueue(cxn, &(cxn->imap_controlMsg_q),
- cxn->current_control);
-
- if (imap_sendClose(cxn) != RET_OK)
- imap_Disconnect(cxn);
- return;
- }
- break;
-
- case IMAP_READING_STORE:
-
- if (okno==1) {
-
- d_printf(1,"%s:%d:IMAP Processed a Cancel fully\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- /* we can delete article now */
- QueueForgetAbout(cxn, cxn->current_control,
- MSG_SUCCESS);
-
- cxn->cancel_succeeded++;
-
- if (imap_sendClose(cxn) != RET_OK)
- imap_Disconnect(cxn);
- return;
-
- } else {
-
- d_printf(1,"%s:%d:IMAP Store failed\n",
- hostPeerName (cxn->myHost), cxn->ident);
- ReQueue(cxn, &(cxn->imap_controlMsg_q), cxn->current_control);
-
- if (imap_sendClose(cxn) != RET_OK)
- imap_Disconnect(cxn);
- return;
- }
-
- break;
-
- case IMAP_READING_NOOP:
- cxn->imap_state = IMAP_IDLE_AUTHED;
- return;
- break;
-
- case IMAP_READING_CLOSE:
- if (!okno) {
- /* we can't do anything about it */
- d_printf(1,"%s:%d:IMAP Close failed\n",
- hostPeerName (cxn->myHost), cxn->ident);
- }
-
- cxn->imap_state = IMAP_IDLE_AUTHED;
-
- imap_ProcessQueue(cxn);
- return;
- break;
-
- case IMAP_READING_QUIT:
-
- /* we don't care if the server said OK or NO just
- that it said something */
-
- d_printf(1,"%s:%d:IMAP Read quit response\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- cxn->imap_state = IMAP_DISCONNECTED;
-
- DeleteIfDisconnected(cxn);
- break;
-
-
- default:
- d_printf(0,"%s:%d:IMAP I don't understand state %d [%s]\n",
- hostPeerName (cxn->myHost), cxn->ident,
- cxn->imap_state,str);
- imap_Disconnect(cxn);
- break;
- }
-
-
- } else {
- d_printf(0,"%s:%d:IMAP tag (%s) doesn't match what we gave (%s). What's up with that??\n",
- hostPeerName (cxn->myHost), cxn->ident, str, cxn->imap_currentTag);
- imap_Disconnect(cxn);
- }
-
-}
-
-/************************** END IMAP reading functions ***************************/
-
-/*************************** LMTP reading functions ****************************/
-
-static void lmtp_readCB (EndPoint e, IoStatus i, Buffer *b, void *d)
-{
- connection_t *cxn = (connection_t *) d;
- char str[4096];
- Buffer *readBuffers;
- int result;
- int response_code;
- conn_ret ret;
-#ifdef HAVE_SASL
- int inlen;
- char *in;
- int outlen;
- const char *out;
- char *inbase64;
- int inbase64len;
- imt_stat status;
- int saslresult;
- sasl_interact_t *client_interact=NULL;
-#endif /* HAVE_SASL */
-
- char *p = bufferBase(b[0]);
-
- bufferAddNullByte (b[0]) ;
-
- if (i != IoDone) {
- errno = endPointErrno(e);
- syslog(LOG_ERR, "%s:%d LMTP i/o failed: %m",
- hostPeerName (cxn->myHost), cxn->ident);
-
- freeBufferArray (b);
- lmtp_Disconnect(cxn);
- return;
- }
-
- if (strchr (p, '\n') == NULL)
- {
- /* partial read. expand buffer and retry */
-
- d_printf(0,"%s:%d:LMTP Partial. retry\n",
- hostPeerName (cxn->myHost),cxn->ident);
- expandBuffer (b[0], BUFFER_EXPAND_AMOUNT) ;
- readBuffers = makeBufferArray (bufferTakeRef (b[0]), NULL) ;
-
- if ( !prepareRead (e, readBuffers, lmtp_readCB, cxn, 1) )
- {
- lmtp_Disconnect(cxn);
- }
-
- freeBufferArray (b);
- return;
- }
-
- clearTimer (cxn->lmtp_readBlockedTimerId) ;
-
- /* Add what we got to our internal read buffer */
- strcat(cxn->lmtp_respBuffer, p);
-
- bufferSetDataSize( b[0], 0);
-
- freeBufferArray (b);
-
- reset:
- /* see if we have a full line */
- ret = GetLine( cxn->lmtp_respBuffer, str, sizeof(str));
-
- /* get a line */
- if (ret!=RET_OK)
- {
- if (ret!=RET_NO_FULLLINE)
- {
- /* was a more serious error */
- d_printf(0,"%s:%d:LMTP Internal error getting line from server\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* set up to receive some more */
- readBuffers = makeBufferArray (bufferTakeRef (cxn->lmtp_rBuffer), NULL) ;
- prepareRead(cxn->lmtp_endpoint, readBuffers, lmtp_readCB, cxn, 5);
- return;
- }
-
- switch (cxn->lmtp_state)
- {
-
- case LMTP_READING_INTRO:
-
- if (ask_code(str)!=220)
- {
- d_printf(0,"%s:%d:LMTP Initial server msg does not start with 220 (began with %d)\n",
- hostPeerName (cxn->myHost),cxn->ident,
- ask_code(str));
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* the initial intro could have many lines via
- continuations. see if we need to read more */
- if (ask_keepgoing(str)==1)
- {
- goto reset;
- }
-
- result = lmtp_getcapabilities(cxn);
-
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d:LMTP lmtp_getcapabilities() failure\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
-
- break;
-
- case LMTP_READING_LHLO:
- /* recieve the response(s) */
- response_code = ask_code(str);
-
- if (response_code != 250) /* was none */
- {
- d_printf(0,"%s:%d:LMTP Response code unexpected (%d)\n",
- hostPeerName (cxn->myHost),cxn->ident,
- response_code);
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* look for one we know about; ignore all others */
- if (strncmp(str+4,"8BITMIME",strlen("8BITMIME"))==0)
- {
- cxn->lmtp_capabilities->Eightbitmime = 1;
- } else if (strncmp(str+4, "ENHANCEDSTATUSCODES",
- strlen("ENHANCEDSTATUSCODES"))==0) {
- cxn->lmtp_capabilities->EnhancedStatusCodes = 1;
- } else if (strncmp(str+4, "AUTH",4)==0) {
- cxn->lmtp_capabilities->saslmechs = xstrdup(str + 4 + 5);
- } else if (strncmp(str+4,"PIPELINING",strlen("PIPELINING"))==0) {
- cxn->lmtp_capabilities->pipelining = 1;
- } else {
- /* don't care; ignore */
- }
-
- /* see if this is the last line of the capability */
- if (ask_keepgoing(str)==1)
- {
- goto reset;
- } else {
- /* we require a few capabilities */
- if (!cxn->lmtp_capabilities->pipelining) {
- d_printf(0,"%s:%d:LMTP We require PIPELINING\n",
- hostPeerName (cxn->myHost),cxn->ident);
-
- lmtp_Disconnect(cxn);
- return;
- }
-#ifdef HAVE_SASL
- if (cxn->lmtp_capabilities->saslmechs) {
- /* start the authentication */
- result = lmtp_authenticate(cxn);
-
- if (result != RET_OK) {
- d_printf(0,"%s:%d:LMTP lmtp_authenticate() error\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
-#else
- if (0) {
- /* noop */
-#endif
- } else {
- /* either we can't authenticate or the remote server
- doesn't support it */
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
- d_printf(1,"%s:%d:LMTP Even though we can't authenticate"
- " we're going to try to feed anyway\n",
- hostPeerName (cxn->myHost),cxn->ident);
- /* We just assume we don't need to authenticate
- (great assumption huh?) */
- hostRemoteStreams (cxn->myHost, cxn, true) ;
-
- cxn->lmtp_timeCon = theTime () ;
- cxn->timeCon = theTime () ;
-
- /* try to send a message if we have one */
- lmtp_sendmessage(cxn,NULL);
- return;
- }
- }
- break;
-
-#ifdef HAVE_SASL
- case LMTP_READING_STEPAUTH:
- inlen = 0;
- status = lmtp_getauthline(str, &in, &inlen);
-
- switch (status)
- {
-
- case STAT_CONT:
-
- saslresult=sasl_client_step(cxn->saslconn_lmtp,
- in,
- inlen,
- &client_interact,
- &out,
- &outlen);
-
- free(in);
-
- /* check if sasl succeeded */
- if (saslresult != SASL_OK && saslresult != SASL_CONTINUE) {
- d_printf(0,"%s:%d:LMTP sasl_client_step(): %s\n",
- hostPeerName (cxn->myHost),cxn->ident,
- sasl_errstring(saslresult,NULL,NULL));
-
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* convert to base64 */
- inbase64 = xmalloc(outlen*2+10);
-
- saslresult = sasl_encode64(out, outlen,
- inbase64, outlen*2+10,
- (unsigned *) &inbase64len);
-
- if (saslresult != SASL_OK)
- {
- d_printf(0,"%s:%d:LMTP sasl_encode64(): %s\n",
- hostPeerName (cxn->myHost),cxn->ident,
- sasl_errstring(saslresult,NULL,NULL));
-
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* add an endline */
- strlcpy(inbase64 + inbase64len, "\r\n", outlen * 2 + 10);
-
- /* send to server */
- result = WriteToWire_lmtpstr(cxn,inbase64, inbase64len+2);
-
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d:LMTP WriteToWire() failure\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
-
- cxn->lmtp_state = LMTP_WRITING_STEPAUTH;
- break;
-
- case STAT_OK:
- cxn->lmtp_sleepTimeout = init_reconnect_period ;
-
- d_printf(0,"%s:%d LMTP authentication succeeded\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- cxn->lmtp_disconnects=0;
-
- hostRemoteStreams (cxn->myHost, cxn, true) ;
-
- cxn->lmtp_timeCon = theTime () ;
- cxn->timeCon = theTime () ;
-
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
-
-
- /* try to send a message if we have one */
- lmtp_sendmessage(cxn,NULL);
- return;
-
- break;
-
- default:
- d_printf(0,"%s:%d:LMTP failed authentication\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
- break;
-#endif /* HAVE_SASL */
-
- case LMTP_READING_RSET:
- if (ask_keepgoing(str)) {
- goto reset;
- }
- if (ask_code(str) != 250) {
- d_printf(0,"%s:%d:LMTP RSET failed with (%d)\n",
- hostPeerName (cxn->myHost),cxn->ident,
- ask_code(str));
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* we pipelined so next we recieve the mail from response */
- cxn->lmtp_state = LMTP_READING_MAILFROM;
- goto reset;
-
- case LMTP_READING_MAILFROM:
- if (ask_keepgoing(str)) {
- goto reset;
- }
- if (ask_code(str) != 250) {
- d_printf(0,"%s:%d:LMTP MAILFROM failed with (%d)\n",
- hostPeerName (cxn->myHost),cxn->ident,
- ask_code(str));
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* we pipelined so next we recieve the rcpt's */
- cxn->lmtp_state = LMTP_READING_RCPTTO;
- goto reset;
- break;
-
- case LMTP_READING_RCPTTO:
- if (ask_keepgoing(str)) {
- goto reset;
- }
- if (ask_code(str)!=250) {
- d_printf(1,"%s:%d:LMTP RCPT TO failed with (%d) %s\n",
- hostPeerName (cxn->myHost),cxn->ident,
- ask_code(str), str);
-
- /* if got a 5xx don't try to send anymore */
- cxn->current_article->trys=100;
-
- cxn->current_rcpts_issued--;
- } else {
- cxn->current_rcpts_okayed++;
- }
-
- /* if issued equals number okayed then we're done */
- if ( cxn->current_rcpts_okayed == cxn->current_rcpts_issued) {
- cxn->lmtp_state = LMTP_READING_DATA;
- } else {
- /* stay in same state */
- }
- goto reset;
- break;
-
- case LMTP_READING_DATA:
- if (ask_keepgoing(str)) {
- goto reset;
- }
- if (cxn->current_rcpts_issued == 0) {
- if (cxn->current_article->trys < 100) {
- d_printf(1, "%s:%d:LMTP None of the rcpts "
- "were accepted for this message. Re-queueing\n",
- hostPeerName (cxn->myHost),cxn->ident);
- }
-
- ReQueue(cxn, &(cxn->lmtp_todeliver_q), cxn->current_article);
-
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
- lmtp_sendmessage(cxn,NULL);
- } else {
- if (WriteArticle(cxn, cxn->current_bufs) != RET_OK)
- {
- d_printf(0, "%s:%d:LMTP Error writing article\n",
- hostPeerName (cxn->myHost),cxn->ident);
- lmtp_Disconnect(cxn);
- return;
- }
-
- cxn->lmtp_state = LMTP_WRITING_CONTENTS;
- }
-
- break;
-
- case LMTP_READING_CONTENTS:
- if (ask_keepgoing(str)) {
- goto reset;
- }
-
- /* need 1 response from server for every rcpt */
- cxn->current_rcpts_issued--;
-
- if (ask_code(str) != 250) {
- d_printf(1, "%s:%d:LMTP DATA failed with %d (%s)\n",
- hostPeerName (cxn->myHost),cxn->ident,
- ask_code(str), str);
- cxn->current_rcpts_okayed--;
- }
-
- if (cxn->current_rcpts_issued>0) {
- goto reset;
- }
-
- /*
- * current_rcpts_okayed is number that succeeded
- *
- */
- if (cxn->current_rcpts_okayed == 0) {
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
- } else {
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
- cxn->lmtp_succeeded++;
- d_printf(1, "%s:%d:LMTP Woohoo! message accepted\n",
- hostPeerName (cxn->myHost),cxn->ident);
- }
-
- /* we can delete article now */
- QueueForgetAbout(cxn, cxn->current_article, MSG_SUCCESS);
-
- /* try to send another if we have one and we're still idle
- * forgetting the msg might have made us unidle
- */
- if (cxn->lmtp_state == LMTP_AUTHED_IDLE) {
- lmtp_sendmessage(cxn,NULL);
- }
-
- break;
-
- case LMTP_READING_NOOP:
- if (ask_keepgoing(str)) {
- goto reset;
- }
- cxn->lmtp_state = LMTP_AUTHED_IDLE;
- break;
-
- case LMTP_READING_QUIT:
- d_printf(1,"%s:%d:LMTP read quit\n",
- hostPeerName (cxn->myHost),cxn->ident);
-
- cxn->lmtp_state = LMTP_DISCONNECTED;
-
- DeleteIfDisconnected(cxn);
- break;
-
- default:
-
- d_printf(0,"%s:%d:LMTP Bad state in lmtp_readCB %d\n",
- hostPeerName (cxn->myHost),cxn->ident,
- cxn->lmtp_state);
- lmtp_Disconnect(cxn);
- return;
- }
-
-
-}
-
-/*
- * Add a rcpt to:<foo> to the string
- *
- */
-
-static void addrcpt(char *newrcpt, int newrcptlen, char **out, int *outalloc)
-{
- int size = strlen(*out);
- int fsize = size;
- int newsize = size + 9+strlen(deliver_rcpt_to)+newrcptlen+3;
- char c;
-
- /* see if we need to grow the string */
- if (newsize > *outalloc) {
- (*outalloc) = newsize;
- (*out) = xrealloc(*out, *outalloc);
- }
-
- strlcpy((*out) + size,"RCPT TO:<", newsize - size);
- size += 9;
-
- c = newrcpt[newrcptlen];
- newrcpt[newrcptlen] = '\0';
- size += snprintf((*out) + size, newsize - size, deliver_rcpt_to, newrcpt);
- newrcpt[newrcptlen] = c;
-
- strlcpy((*out) + size, ">\r\n", newsize - size);
-
- /* has embedded '\n' */
- d_printf(2, "Attempting to send to: %s", (*out) + fsize);
-}
-
-/*
- * Takes the newsgroups header value and makes it into a list of RCPT TO:'s we can send over the wire
- *
- * in - newsgroups header start
- * in_end - end of newsgroups header
- * num - number of rcpt's we created
- */
-
-static char *ConvertRcptList(char *in, char *in_end, int *num)
-{
- int retalloc = 400;
- char *ret = xmalloc(retalloc);
- char *str = in;
- char *laststart = in;
-
- (*num) = 0;
-
- /* start it off empty */
- strlcpy(ret, "", retalloc);
-
- while ( str != in_end)
- {
- if ((*str) == ',')
- {
- /* eliminate leading whitespace */
- while (((*laststart) ==' ') || ((*laststart)=='\t'))
- {
- laststart++;
- }
-
-#ifndef SMTPMODE
- addrcpt(laststart, str - laststart, &ret, &retalloc);
- (*num)++;
-#endif /* SMTPMODE */
- laststart = str+1;
- }
-
- str++;
- }
-
- if (laststart<str)
- {
- addrcpt(laststart, str - laststart, &ret, &retalloc);
- (*num)++;
- }
-
- return ret;
-}
-
-static void addto(char *newrcpt, int newrcptlen, const char *sep,
- char **out, int *outalloc)
-{
- int size = strlen(*out);
- int newsize = size + strlen(sep)+1+strlen(deliver_to_header)+newrcptlen+1;
- char c;
-
- /* see if we need to grow the string */
- if (newsize > *outalloc) {
- (*outalloc) = newsize;
- (*out) = xrealloc(*out, *outalloc);
- }
-
- size += snprintf((*out) + size, newsize - size, "%s<", sep);
-
- c = newrcpt[newrcptlen];
- newrcpt[newrcptlen] = '\0';
- size += snprintf((*out) + size, newsize - size, deliver_to_header,newrcpt);
- newrcpt[newrcptlen] = c;
-
- strlcpy((*out) + size, ">", newsize - size);
-}
-
-/*
- * Takes the newsgroups header value and makes it into a To: header
- *
- * in - newsgroups header start
- * in_end - end of newsgroups header
- */
-
-static char *BuildToHeader(char *in, char *in_end)
-{
- int retalloc = 400;
- char *ret = xmalloc(retalloc);
- char *str = in;
- char *laststart = in;
- const char *sep = "";
-
- /* start it off with the header name */
- strlcpy(ret,"To: ", retalloc);
-
- while ( str != in_end)
- {
- if ((*str) == ',')
- {
- /* eliminate leading whitespace */
- while (((*laststart) ==' ') || ((*laststart)=='\t'))
- {
- laststart++;
- }
-
- addto(laststart, str - laststart, sep, &ret, &retalloc);
- laststart = str+1;
-
- /* separate multiple addresses with a comma */
- sep = ", ";
- }
-
- str++;
- }
-
- if (laststart<str)
- {
- addto(laststart, str - laststart, sep, &ret, &retalloc);
- }
-
- /* terminate the header */
- strlcat(ret, "\n\r", retalloc);
- return ret;
-}
-
-/*************************** END LMTP reading functions ****************************/
-
-
-
-/*
- * Process the control message queue. If we run out ask the host for more.
- *
- * cxn - connection object
- */
-
-static void imap_ProcessQueue(connection_t *cxn)
-{
- article_queue_t *item;
- int result;
-
- retry:
-
- /* pull an article off the queue */
- result = PopFromQueue(&(cxn->imap_controlMsg_q), &item);
-
- if (result==RET_QUEUE_EMPTY)
- {
- if (cxn->issue_quit)
- {
- imap_sendQuit(cxn);
- return;
- }
-
- cxn->imap_state = IMAP_IDLE_AUTHED;
-
- /* now we wait for articles from our Host, or we have some
- articles already. On infrequently used connections, the
- network link is torn down and rebuilt as needed. So we may
- be rebuilding the connection here in which case we have an
- article to send. */
-
- /* make sure imap has _lots_ of space too */
- if ((QueueItems(&(cxn->lmtp_todeliver_q)) == 0) &&
- (QueueItems(&(cxn->imap_controlMsg_q)) == 0))
- {
- if (hostGimmeArticle (cxn->myHost,cxn)==true)
- goto retry;
- }
-
- return;
- }
-
- cxn->current_control = item;
-
- switch (item->type)
- {
- case CREATE_FOLDER:
- imap_CreateGroup(cxn, item->data.control->folder);
- break;
-
- case CANCEL_MSG:
- imap_CancelMsg(cxn, item->data.control->folder);
- break;
-
- case DELETE_FOLDER:
- imap_DeleteGroup(cxn, item->data.control->folder);
- break;
- default:
- break;
- }
-
- return;
-}
-
-
-
-/*
- *
- * Pulls a message off the queue and trys to start sending it. If the
- * message is a control message put it in the control queue and grab
- * another message. If the message doesn't exist on disk or something
- * is wrong with it tell the host and try again. If we run out of
- * messages to get tell the host we want more
- *
- * cxn - connection object
- * justadded - the article that was just added to the queue
- */
-
-static void lmtp_sendmessage(connection_t *cxn, Article justadded)
-{
- bool res;
- conn_ret result;
- char *p;
- Buffer *bufs;
- char *control_header = NULL;
- char *control_header_end = NULL;
-
- article_queue_t *item;
- char *rcpt_list, *rcpt_list_end;
-
- /* retry point */
- retry:
-
- /* pull an article off the queue */
- result = PopFromQueue(&(cxn->lmtp_todeliver_q), &item);
-
- if (result==RET_QUEUE_EMPTY)
- {
- if (cxn->issue_quit) {
- lmtp_IssueQuit(cxn);
- return;
- }
- /* now we wait for articles from our Host, or we have some
- articles already. On infrequently used connections, the
- network link is torn down and rebuilt as needed. So we may
- be rebuilding the connection here in which case we have an
- article to send. */
-
- /* make sure imap has space too */
- d_printf(1,"%s:%d stalled waiting for articles\n",
- hostPeerName (cxn->myHost),cxn->ident);
- if ((QueueItems(&(cxn->lmtp_todeliver_q)) == 0) &&
- (QueueItems(&(cxn->imap_controlMsg_q)) == 0)) {
- if (hostGimmeArticle (cxn->myHost,cxn)==true)
- goto retry;
- }
-
- return;
- }
-
- /* make sure contents ok; this also should load it into memory */
- res = artContentsOk (item->data.article);
- if (res==false)
- {
- if (justadded == item->data.article) {
- ReQueue(cxn, &(cxn->lmtp_todeliver_q), item);
- return;
- } else {
- /* tell to reject taking this message */
- QueueForgetAbout(cxn,item, MSG_MISSING);
- }
-
- goto retry;
- }
-
- /* Check if it's a control message */
- bufs = artGetNntpBuffers (item->data.article);
- if (bufs == NULL)
- {
- /* tell to reject taking this message */
- QueueForgetAbout(cxn,item, MSG_MISSING);
- goto retry;
- }
-
- result = FindHeader(bufs, "Control", &control_header, &control_header_end);
- if (result == RET_OK) {
- result = AddControlMsg(cxn, item->data.article, bufs,
- control_header,control_header_end, 1);
- if (result != RET_OK) {
- d_printf(1,"%s:%d Error adding to [imap] control queue\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- ReQueue(cxn, &(cxn->lmtp_todeliver_q), item);
- return;
- }
-
- switch(cxn->imap_state) {
- case IMAP_IDLE_AUTHED:
- /* we're idle. let's process the queue */
- imap_ProcessQueue(cxn);
- break;
- case IMAP_DISCONNECTED:
- case IMAP_WAITING:
- /* Let's connect. Once we're connected we can
- worry about the message */
- if (cxn->imap_sleepTimerId == 0) {
- if (imap_Connect(cxn) != RET_OK) prepareReopenCbk(cxn,0);
- }
- break;
- default:
- /* we're doing something right now */
- break;
- }
-
- /* all we did was add a control message.
- we still want to get an lmtp message */
- goto retry;
- }
-
- if (cxn->current_bufs != NULL) {
- /* freeBufferArray(cxn->current_bufs); */
- cxn->current_bufs = NULL;
- }
- cxn->current_bufs = bufs;
- cxn->current_article = item;
-
- /* we make use of pipelining here
- send:
- rset
- mail from
- rcpt to
- data
- */
-
- /* find out who it's going to */
- result = FindHeader(cxn->current_bufs, "Newsgroups",
- &rcpt_list, &rcpt_list_end);
-
- if ((result != RET_OK) || (rcpt_list == NULL)) {
- d_printf(1,"%s:%d Didn't find Newsgroups header\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- QueueForgetAbout(cxn, cxn->current_article, MSG_FAIL_DELIVER);
- goto retry;
- }
-
- /* free's original rcpt_list */
- rcpt_list = ConvertRcptList(rcpt_list, rcpt_list_end,
- &cxn->current_rcpts_issued);
- cxn->current_rcpts_okayed = 0;
-
- if(mailfrom_name == NULL)
- mailfrom_name = xstrdup("");
- p = concat("RSET\r\n"
- "MAIL FROM:<", mailfrom_name, ">\r\n",
- rcpt_list,
- "DATA\r\n", (char *) 0);
-
- cxn->lmtp_state = LMTP_WRITING_UPTODATA;
- result = WriteToWire_lmtpstr(cxn, p, strlen(p));
-
- if (result != RET_OK) {
- d_printf(0,"%s:%d failed trying to write\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
- lmtp_Disconnect(cxn);
- return;
- }
-
- /* prepend To: header to article */
- if (deliver_to_header) {
- char *to_list, *to_list_end;
- int i, len;
-
- result = FindHeader(cxn->current_bufs, "Followup-To",
- &to_list, &to_list_end);
-
- if ((result != RET_OK) || (to_list == NULL)) {
- result = FindHeader(cxn->current_bufs, "Newsgroups",
- &to_list, &to_list_end);
- }
-
- /* free's original to_list */
- to_list = BuildToHeader(to_list, to_list_end);
-
- len = bufferArrayLen(cxn->current_bufs);
- cxn->current_bufs = xrealloc(cxn->current_bufs,
- sizeof(Buffer) * (len+2));
- cxn->current_bufs[len+1] = NULL;
-
- for (i = len; i > 0; i--) {
- cxn->current_bufs[i] = cxn->current_bufs[i-1];
- }
-
- cxn->current_bufs[0] = newBufferByCharP(to_list, strlen(to_list+1),
- strlen(to_list));
- }
-
- hostArticleOffered (cxn->myHost, cxn);
-}
-
-/*
- * Called by the EndPoint class when the timer goes off
- */
-static void dosomethingTimeoutCbk (TimeoutId id, void *data)
-{
- Connection cxn = (Connection) data ;
-
- ASSERT (id == cxn->dosomethingTimerId) ;
-
- show_stats(cxn);
-
- /* we're disconnected but there are things to send */
- if ((cxn->lmtp_state == LMTP_DISCONNECTED) &&
- (cxn->lmtp_sleepTimerId == 0) &&
- QueueItems(&(cxn->lmtp_todeliver_q)) > 0)
- {
- if (lmtp_Connect(cxn) != RET_OK)
- prepareReopenCbk(cxn, 1);
- }
-
- if ((cxn->imap_state == IMAP_DISCONNECTED) &&
- (cxn->imap_sleepTimerId == 0) &&
- (QueueItems(&(cxn->imap_controlMsg_q)) > 0))
- {
- if (imap_Connect(cxn) != RET_OK)
- prepareReopenCbk(cxn, 0);
- }
-
-
- /* if we're idle and there are items to send let's send them */
- if ((cxn->lmtp_state == LMTP_AUTHED_IDLE) &&
- QueueItems(&(cxn->lmtp_todeliver_q)) > 0) {
- lmtp_sendmessage(cxn,NULL);
- } else if (cxn->lmtp_state == LMTP_AUTHED_IDLE) {
- lmtp_noop(cxn);
- }
-
- if ((cxn->imap_state == IMAP_IDLE_AUTHED) &&
- (QueueItems(&(cxn->imap_controlMsg_q)) > 0)) {
- imap_ProcessQueue(cxn);
- } else if (cxn->imap_state == IMAP_IDLE_AUTHED) {
- imap_noop(cxn);
- }
-
- /* set up the timer. */
- clearTimer (cxn->dosomethingTimerId) ;
-
- cxn->dosomethingTimerId = prepareSleep (dosomethingTimeoutCbk,
- cxn->dosomethingTimeout, cxn);
-}
-
-/* Give all articles in the queue back to the host. We're probably
- * going to exit soon.
- * */
-
-static void DeferAllArticles(connection_t *cxn, Q_t *q)
-{
- article_queue_t *cur;
- conn_ret ret;
-
- while (1)
- {
- ret = PopFromQueue(q, &cur);
- if (ret == RET_QUEUE_EMPTY) return;
-
- if (ret == RET_OK)
- {
- QueueForgetAbout(cxn, cur, MSG_GIVE_BACK);
- } else {
- d_printf(0,"%s:%d Error emptying queue (deffering all articles)\n",
- hostPeerName (cxn->myHost),cxn->ident);
- return;
- }
- }
-}
-
-/*
- * Does the actual deletion of a connection and all its private data.
- */
-static void delConnection (Connection cxn)
-{
- bool shutDown;
- Connection c, q;
-
- if (cxn == NULL)
- return ;
-
- d_printf (1,"Deleting connection: %s:%d\n",
- hostPeerName (cxn->myHost),cxn->ident) ;
-
- for (c = gCxnList, q = NULL ; c != NULL ; q = c, c = c->next)
- if (c == cxn)
- {
- if (gCxnList == c)
- gCxnList = gCxnList->next ;
- else
- q->next = c->next ;
- break ;
- }
-
- ASSERT (c != NULL) ;
-
- if (cxn->lmtp_endpoint != NULL)
- delEndPoint (cxn->lmtp_endpoint) ;
- if (cxn->imap_endpoint != NULL)
- delEndPoint (cxn->imap_endpoint) ;
-
- delBuffer (cxn->imap_rBuffer) ;
- delBuffer (cxn->lmtp_rBuffer) ;
-
- /* tell the Host we're outta here. */
- shutDown = hostCxnGone (cxn->myHost, cxn) ;
-
- cxn->ident = 0 ;
- cxn->timeCon = 0 ;
-
- free (cxn->ServerName) ;
-
- clearTimer (cxn->imap_readBlockedTimerId) ;
- clearTimer (cxn->imap_writeBlockedTimerId) ;
- clearTimer (cxn->lmtp_readBlockedTimerId) ;
- clearTimer (cxn->lmtp_writeBlockedTimerId) ;
-
- clearTimer (cxn->imap_sleepTimerId);
- cxn->imap_sleepTimerId = 0;
- clearTimer (cxn->lmtp_sleepTimerId);
- cxn->lmtp_sleepTimerId = 0;
-
- clearTimer (cxn->dosomethingTimerId);
-
- free (cxn->imap_respBuffer);
- free (cxn->lmtp_respBuffer);
-
- free (cxn) ;
-
- if (shutDown)
- {
- /* exit program if that was the last connexion for the last host */
- /* XXX what about if there are ever multiple listeners?
- XXX this will be executed if all hosts on only one of the
- XXX listeners have gone */
- time_t now = theTime () ;
- char dateString [30] ;
-
- strlcpy (dateString,ctime (&now),sizeof (dateString)) ;
- dateString [24] = '\0' ;
-
- notice ("ME finishing at %s", dateString) ;
-
- exit (0) ;
- }
-}
-
-
-/******************** PUBLIC FUNCTIONS ****************************/
-
-
-
- /*
- * Create a new Connection.
- *
- * HOST is the host object we're owned by.
- * IDENT is an identifier to be added to syslog entries so we can tell
- * what's happening on different connections to the same peer.
- * IPNAME is the name (or ip address) of the remote)
- * MAXTOUT is the maximum amount of time to wait for a response before
- * considering the remote host dead.
- * PORTNUM is the portnum to contact on the remote end.
- * RESPTIMEOUT is the amount of time to wait for a response from a remote
- * before considering the connection dead.
- * CLOSEPERIOD is the number of seconds after connecting that the
- * connections should be closed down and reinitialized (due to problems
- * with old NNTP servers that hold history files open. Value of 0 means
- * no close down.
- */
-
-Connection newConnection (Host host,
- unsigned int ident,
- const char *ipname,
- unsigned int artTout UNUSED,
- unsigned int portNum UNUSED,
- unsigned int respTimeout,
- unsigned int closePeriod UNUSED,
- double lowPassLow UNUSED,
- double lowPassHigh UNUSED,
- double lowPassFilter UNUSED)
-{
- Connection cxn;
- /* check arguments */
-
- /* allocate connection structure */
- cxn = xcalloc (1, sizeof(connection_t)) ;
-
- cxn->ident = ident ;
- cxn->ServerName = xstrdup (ipname) ;
- cxn->myHost = host ;
-
- /* setup mailfrom user */
- if (gethostname(hostname, MAXHOSTNAMELEN)!=0)
- {
- d_printf(0,"%s gethostname failed\n",ipname);
- return NULL;
- }
-
-
- mailfrom_name = concat("news@", hostname, (char *) 0);
-
- cxn->next = gCxnList ;
- gCxnList = cxn ;
- gCxnCount++ ;
-
- /* init stuff */
- Initialize(cxn, respTimeout);
-
- return cxn;
-}
-
-
-/* Causes the Connection to build the network connection. */
-bool cxnConnect (Connection cxn)
-{
- /* make the lmtp connection */
- if (lmtp_Connect(cxn) != RET_OK) return false;
-
- if (imap_Connect(cxn) != RET_OK) return false;
-
- return true;
-}
-
-
-static void QuitIfIdle(Connection cxn)
-{
- if ((cxn->lmtp_state == LMTP_AUTHED_IDLE) &&
- (QueueItems(&(cxn->lmtp_todeliver_q))<=0)) {
- lmtp_IssueQuit(cxn);
- }
- if ((cxn->imap_state == IMAP_IDLE_AUTHED) &&
- (QueueItems(&(cxn->imap_controlMsg_q))<=0)) {
- imap_sendQuit(cxn);
- }
-}
-
-static void DeleteIfDisconnected(Connection cxn)
-{
- /* we want to shut everything down. if both connections disconnected now we can */
- if ((cxn->issue_quit >= 1) &&
- (cxn->lmtp_state == LMTP_DISCONNECTED) &&
- (cxn->imap_state == IMAP_DISCONNECTED))
- {
-
- switch (cxn->issue_quit)
- {
- case 1:
- if (cxn->lmtp_state == LMTP_DISCONNECTED)
- {
- cxn->lmtp_state = LMTP_WAITING;
- cxn->imap_state = IMAP_WAITING;
- cxn->issue_quit = 0;
- hostCxnWaiting (cxn->myHost,cxn) ; /* tell our Host we're waiting */
- }
- break;
- case 2:
- if (cxn->lmtp_state == LMTP_DISCONNECTED)
- {
- cxn->issue_quit = 0;
-
- if (imap_Connect(cxn)!=RET_OK) prepareReopenCbk(cxn,0);
- if (lmtp_Connect(cxn)!=RET_OK) prepareReopenCbk(cxn,1);
- }
- break;
- case 3:
- if (cxn->lmtp_state == LMTP_DISCONNECTED)
- {
- hostCxnDead (cxn->myHost,cxn) ;
- delConnection(cxn);
- }
- break;
-
- }
- }
-}
-
- /* puts the connection into the wait state (i.e. waits for an article
- before initiating a connect). Can only be called right after
- newConnection returns, or while the Connection is in the (internal)
- Sleeping state. */
-void cxnWait (Connection cxn)
-{
- cxn->issue_quit = 1;
-
- QuitIfIdle(cxn);
-}
-
- /* The Connection will disconnect as if cxnDisconnect were called and then
- it automatically reconnects to the remote. */
-void cxnFlush (Connection cxn)
-{
- cxn->issue_quit = 2;
-
- QuitIfIdle(cxn);
-}
-
-
-
- /* The Connection sends remaining articles, then issues a QUIT and then
- deletes itself */
-void cxnClose (Connection cxn)
-{
- d_printf(0,"%s:%d Closing cxn\n",hostPeerName (cxn->myHost), cxn->ident);
- cxn->issue_quit = 3;
-
- QuitIfIdle(cxn);
-
- DeleteIfDisconnected(cxn);
-}
-
- /* The Connection drops all queueed articles, then issues a QUIT and then
- deletes itself */
-void cxnTerminate (Connection cxn)
-{
- d_printf(0,"%s:%d Terminate\n",hostPeerName (cxn->myHost), cxn->ident);
-
- cxn->issue_quit = 3;
-
- /* give any articles back to host in both queues */
- DeferAllArticles(cxn, &(cxn->lmtp_todeliver_q));
- DeferAllArticles(cxn, &(cxn->imap_controlMsg_q));
-
- QuitIfIdle(cxn);
-}
-
- /* Blow away the connection gracelessly and immedately clean up */
-void cxnNuke (Connection cxn)
-{
- d_printf(0,"%s:%d Nuking connection\n",cxn->ServerName, cxn->ident);
-
- cxn->issue_quit = 4;
-
- /* give any articles back to host in both queues */
- DeferAllArticles(cxn, &(cxn->lmtp_todeliver_q));
- DeferAllArticles(cxn, &(cxn->imap_controlMsg_q));
-
- imap_Disconnect(cxn);
- lmtp_Disconnect(cxn);
-
- hostCxnDead (cxn->myHost,cxn);
- delConnection(cxn);
-}
-
-/*
- * must
- * true - must queue article. Don't try sending
- * false - queue of article may fail. Try sending
- *
- * Always adds to lmtp queue even if control message
- *
- */
-
-static bool ProcessArticle(Connection cxn, Article art, bool must)
-{
- conn_ret result;
-
- /* Don't accept any articles when we're closing down the connection */
- if (cxn->issue_quit > 1) {
- return false;
- }
-
- /* if it's a regular message let's add it to the queue */
- result = AddToQueue(&(cxn->lmtp_todeliver_q), art, DELIVER,1,must);
-
- if (result == RET_EXCEEDS_SIZE) {
- return false;
- }
-
- if (result != RET_OK)
- {
- d_printf(0,"%s:%d Error adding to delivery queue\n",
- hostPeerName (cxn->myHost), cxn->ident);
- return must;
- }
-
- if (must == true) return true;
-
- switch (cxn->lmtp_state)
- {
- case LMTP_WAITING:
- case LMTP_DISCONNECTED:
- if (cxn->lmtp_sleepTimerId == 0)
- if (lmtp_Connect(cxn) != RET_OK) prepareReopenCbk(cxn,1);
- break;
-
- case LMTP_AUTHED_IDLE:
- lmtp_sendmessage(cxn,art);
- break;
- default:
- /* currently doing something */
- break;
- }
-
- return true;
-}
-
- /* Tells the Connection to take the article and handle its
- transmission. If it can't (due to queue size or whatever), then the
- function returns false. The connection assumes ownership of the
- article if it accepts it (returns true). */
-bool cxnTakeArticle (Connection cxn, Article art)
-{
- /* if we're closing down always refuse */
- if (cxn->issue_quit == 1) return false;
-
- return ProcessArticle (cxn,art,false);
-}
-
- /* Tell the Connection to take the article (if it can) for later
- processing. Assumes ownership of it if it takes it. */
-bool cxnQueueArticle (Connection cxn, Article art)
-{
- return ProcessArticle (cxn,art,true);
-}
-
-/* generate a syslog message for the connections activity. Called by Host. */
-void cxnLogStats (Connection cxn, bool final)
-{
- const char *peerName ;
- time_t now = theTime() ;
- int total, good, bad;
-
- ASSERT (cxn != NULL) ;
-
- peerName = hostPeerName (cxn->myHost) ;
-
- total = cxn->lmtp_succeeded + cxn->lmtp_failed;
- total += cxn->cancel_succeeded + cxn->cancel_failed;
- total += cxn->create_succeeded + cxn->create_failed;
- total += cxn->remove_succeeded + cxn->remove_failed;
-
- good = cxn->lmtp_succeeded;
- good += cxn->cancel_succeeded;
- good += cxn->create_succeeded;
- good += cxn->remove_succeeded;
-
- bad = cxn->lmtp_failed;
- bad += cxn->cancel_failed;
- bad += cxn->create_failed;
- bad += cxn->remove_failed;
- notice ("%s:%d %s seconds %ld accepted %d refused %d rejected %d",
- peerName, cxn->ident, (final ? "final" : "checkpoint"),
- (long) (now - cxn->timeCon), total, 0, bad);
- show_stats(cxn);
-
- if (final) {
- cxn->lmtp_succeeded = 0;
- cxn->lmtp_failed = 0;
- cxn->cancel_succeeded = 0;
- cxn->cancel_failed = 0;
- cxn->create_succeeded = 0;
- cxn->create_failed = 0;
- cxn->remove_succeeded = 0;
- cxn->remove_failed = 0;
-
- if (cxn->timeCon > 0)
- cxn->timeCon = theTime() ;
- }
-
-}
-
- /* return the number of articles the connection can be given. This lets
- the host shovel in as many as possible. May be zero. */
-size_t cxnQueueSpace (Connection cxn)
-{
- int lmtpsize;
- int imapsize;
-
- lmtpsize = QueueSpace(&(cxn->lmtp_todeliver_q));
- imapsize = QueueSpace(&(cxn->imap_controlMsg_q));
-
- if (lmtpsize >=1) lmtpsize--;
- if (imapsize >=1) imapsize--;
-
- d_printf(1,"%s:%d Q Space lmtp size = %d state = %d\n",
- hostPeerName (cxn->myHost), cxn->ident,
- lmtpsize,cxn->lmtp_state);
- d_printf(1,"%s:%d Q Space imap size = %d state = %d\n",
- hostPeerName (cxn->myHost), cxn->ident,
- imapsize,cxn->imap_state);
-
- /* return the smaller of our 2 queues */
- if (lmtpsize < imapsize)
- return lmtpsize;
- else
- return imapsize;
-}
-
- /* adjust the mode no-CHECK filter values */
-void cxnSetCheckThresholds (Connection cxn,
- double lowFilter UNUSED,
- double highFilter UNUSED,
- double lowPassFilter UNUSED)
-{
- d_printf(1,"%s:%d Threshold change. This means nothing to me\n",
- hostPeerName (cxn->myHost), cxn->ident);
-}
-
-/* print some debugging info. */
-void gPrintCxnInfo (FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
- Connection cxn ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Connection list : (count %d) {\n",
- indent,gCxnCount) ;
- for (cxn = gCxnList ; cxn != NULL ; cxn = cxn->next)
- printCxnInfo (cxn,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s}\n",indent) ;
-}
-
-void printCxnInfo (Connection cxn, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
- article_queue_t *artH ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sConnection : %p {\n",indent, (void *) cxn) ;
- fprintf (fp,"%s host : %p\n",indent, (void *) cxn->myHost) ;
- fprintf (fp,"%s endpoint (imap): %p\n",indent, (void *) cxn->imap_endpoint) ;
- fprintf (fp,"%s endpoint (lmtp): %p\n",indent, (void *) cxn->lmtp_endpoint) ;
- fprintf (fp,"%s state (imap) : %s\n",indent, imap_stateToString (cxn->imap_state)) ;
- fprintf (fp,"%s state (lmtp) : %s\n",indent, lmtp_stateToString (cxn->lmtp_state)) ;
- fprintf (fp,"%s ident : %d\n",indent,cxn->ident) ;
- fprintf (fp,"%s ip-name (imap): %s\n", indent, cxn->ServerName) ;
- fprintf (fp,"%s ip-name (lmtp): %s\n", indent, cxn->ServerName) ;
- fprintf (fp,"%s port-number (imap) : %d\n",indent,cxn->imap_port) ;
- fprintf (fp,"%s port-number (lmtp) : %d\n",indent,cxn->lmtp_port) ;
-
- fprintf (fp,"%s Issuing Quit : %d\n",indent, cxn->issue_quit) ;
-
- fprintf (fp,"%s time-connected (imap) : %ld\n",indent,(long) cxn->imap_timeCon) ;
- fprintf (fp,"%s time-connected (lmtp) : %ld\n",indent,(long) cxn->lmtp_timeCon) ;
- fprintf (fp,"%s articles from INN : %d\n",indent,
- cxn->lmtp_succeeded+
- cxn->lmtp_failed+
- cxn->cancel_succeeded+
- cxn->cancel_failed+
- cxn->create_succeeded+
- cxn->create_failed+
- cxn->remove_succeeded+
- cxn->remove_failed+
- QueueSpace(&(cxn->lmtp_todeliver_q))+
- QueueSpace(&(cxn->imap_controlMsg_q))
- );
- fprintf(fp,"%s LMTP STATS: yes: %d no: %d\n",indent,
- cxn->lmtp_succeeded, cxn->lmtp_failed);
- fprintf(fp,"%s control: yes: %d no: %d\n",indent,
- cxn->cancel_succeeded, cxn->cancel_failed);
- fprintf(fp,"%s create: yes: %d no: %d\n",indent,
- cxn->create_succeeded, cxn->create_failed);
- fprintf(fp,"%s remove: yes: %d no: %d\n",indent,
- cxn->remove_succeeded, cxn->remove_failed);
-
- fprintf (fp,"%s response-timeout : %d\n",indent,cxn->imap_readTimeout) ;
- fprintf (fp,"%s response-callback : %d\n",indent,cxn->imap_readBlockedTimerId) ;
-
- fprintf (fp,"%s write-timeout : %d\n",indent,cxn->imap_writeTimeout) ;
- fprintf (fp,"%s write-callback : %d\n",indent,cxn->imap_writeBlockedTimerId) ;
-
- fprintf (fp,"%s reopen wait : %d\n",indent,cxn->imap_sleepTimeout) ;
- fprintf (fp,"%s reopen id : %d\n",indent,cxn->imap_sleepTimerId) ;
-
- fprintf (fp,"%s IMAP queue {\n",indent) ;
- for (artH = cxn->imap_controlMsg_q.head; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->data.article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s LMTP queue {\n",indent) ;
- for (artH = cxn->lmtp_todeliver_q.head ; artH != NULL ; artH = artH->next)
- printArticleInfo (artH->data.control->article,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-/* config file load callback */
-int cxnConfigLoadCbk (void *data UNUSED)
-{
- long iv ;
- int rval = 1 ;
- FILE *fp = (FILE *) data ;
-
- if (getInteger (topScope,"max-reconnect-time",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld", "max-reconnect-time",
- iv,"global scope",(long) MAX_RECON_PER);
- iv = MAX_RECON_PER ;
- }
- }
- else
- iv = MAX_RECON_PER ;
- max_reconnect_period = (unsigned int) iv ;
-
- if (getInteger (topScope,"initial-reconnect-time",&iv,NO_INHERIT))
- {
- if (iv < 1)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 1. Using %ld", "initial-reconnect-time",
- iv,"global scope",(long)INIT_RECON_PER);
- iv = INIT_RECON_PER ;
- }
- }
- else
- iv = INIT_RECON_PER ;
- init_reconnect_period = (unsigned int) iv ;
-
- return rval ;
-}
-
-/* check connection state is in cxnWaitingS, cxnConnectingS or cxnIdleS */
-bool cxnCheckstate (Connection cxn)
-{
- d_printf(5, "%s:%d Being asked to check state\n",
- hostPeerName (cxn->myHost), cxn->ident);
-
- /* return false if either connection is doing something */
- if (cxn->imap_state > IMAP_IDLE_AUTHED) return false;
- if (cxn->lmtp_state > LMTP_AUTHED_IDLE) return false;
-
- return true;
-}
+++ /dev/null
-#! /usr/bin/perl
-#
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Sun, 19 Jan 1997 21:19:24 +0100
-# Project: INN (innfeed)
-# File: innfeed-convcfg.in
-# RCSId: $Id: innfeed-convcfg.in 2680 1999-11-15 06:37:43Z rra $
-# Description: Read in a old version of innfeed.conf on the command line
-# or on stdin, and write a new version on stdout.
-#
-
-require 'ctime.pl' ;
-
-
-@keyorder = (
-'pid-file',
-'debug-level',
-'use-mmap',
-'log-file',
-'stdio-fdmax',
-'backlog-directory',
-'backlog-rotate-period',
-'backlog-ckpt-period',
-'backlog-newfile-period',
-'dns-retry',
-'dns-expire',
-'close-period',
-'gen-html',
-'status-file',
-'connection-stats',
-'host-queue-highwater',
-'stats-period',
-'stats-reset',
-'max-reconnect-time',
-'initial-reconnect-time',
-'article-timeout',
-'response-timeout',
-'initial-connections',
-'max-connections',
-'max-queue-size',
-'streaming',
-'no-check-high',
-'no-check-low',
-'port-number',
-'backlog-limit',
-'backlog-factor',
-'backlog-limit-highwater'
-);
-
-%procDefaults = (
-'pid-file', 'innfeed.pid',
-'debug-level', '0',
-'use-mmap', 'false',
-'log-file', 'innfeed.log',
-'stdio-fdmax', '0',
-'backlog-directory', 'innfeed',
-'backlog-rotate-period', '60',
-'backlog-ckpt-period', '30',
-'backlog-newfile-period', '600',
-'dns-retry', '900',
-'dns-expire', '86400',
-'close-period', '3600',
-'gen-html', 'false',
-'status-file', 'innfeed.status',
-'connection-stats', 'false',
-'host-queue-highwater', '10',
-'stats-period', '600',
-'stats-reset', '43200',
-'max-reconnect-time', '3600',
-'initial-reconnect-time', '30',
-'article-timeout', '600',
-'response-timeout', '300',
-'initial-connections', '1',
-'max-connections', '5',
-'max-queue-size', '25',
-'streaming', 'true',
-'no-check-high', '195.0',
-'no-check-low', '90.0',
-'port-number', '119',
-'backlog-limit', '0',
-'backlog-factor', '1.10',
-'backlog-limit-highwater', '0',
- );
-
-%defaultKeys = ('article-timeout', 1,
- 'response-timeout', 1,
- 'initial-connections', 1,
- 'max-connections', 1,
- 'max-queue-size', 1,
- 'streaming', 1,
- 'no-check-high', 1,
- 'no-check-low', 1,
- 'port-number', 1,
- 'backlog-limit', 1) ;
-
-@defaultOrder = ('article-timeout',
- 'response-timeout',
- 'initial-connections',
- 'max-connections',
- 'max-queue-size',
- 'streaming',
- 'no-check-high',
- 'no-check-low',
- 'port-number',
- 'backlog-limit') ;
-
-%formats = () ;
-
-foreach $key (keys %procDefaults) {
- $max = length ($key) if length ($key) > $max ;
- if ($procDefaults{$key} =~ /^true$/i || $procDefaults{$key} =~ /^false$/i){
- $formats{$key} = "%s" ;
- } elsif ($procDefaults{$key} =~ /^\d+$/) {
- $formats{$key} = "%d" ;
- } elsif ($procDefaults{$key} =~ /^\d+\.\d*$/) {
- $formats{$key} = "%.4f" ;
- } else {
- $formats{$key} = "%s" ;
- }
-}
-
-
-while (<>) {
- next if /^\s*$/ ;
- next if /^#/ ;
-
- chop ;
- @F = split (':') ;
-
- if ($F[0] eq "default") {
- $procDefaults{'article-timeout'} = $F[2] ;
- $procDefaults{'response-timeout'} = $F[3] ;
- $procDefaults{'initial-connections'} = $F[4] ;
- $procDefaults{'max-connections'} = $F[5] ;
- $procDefaults{'max-queue-size'} = $F[6] ;
- $procDefaults{'streaming'} = $F[7] ;
- $procDefaults{'no-check-low'} = $F[8] * 10.0 ;
- $procDefaults{'no-check-high'} = $F[9] * 10.0 ;
- $procDefaults{'port-number'} = $F[10] ;
-
- printf "## This file was automatically generated created by $0\n" ;
- printf "## On %s##\n\n", &ctime(time) ;
-
- foreach $key (@keyorder) {
- next if $defaultKeys{$key} ;
-
- die "No format for $key\n" unless $formats{$key} ;
- $format = "%${max}s:\t" . $formats{$key} . "\n" ;
- printf $format, $key, $procDefaults{$key} ;
- }
-
- printf "\n\n## Defaults merged from:\n##\t$_\n\n" ;
- foreach $key (@defaultOrder) {
- die "No format for $key\n" unless $formats{$key} ;
- $format ="%${max}s:\t" . $formats{$key} . "\n" ;
- printf $format, $key, $procDefaults{$key} ;
- }
- print "\n\n\n" ;
- $gotDefault = 1 ;
- } elsif (@F == 0) {
- die "Badly formed line: $0\n" ;
- } else {
- if (!$gotDefault) {
- $gotDefault = 1 ; # warn only one time.
- warn "No default line was present.\n" ;
- }
-
- print "## Peer created from:\n" ;
- print "##\t$_\n\n" ;
- printf "peer %s {\n", $F[0] ;
-
- printf "\tip-name: $F[1]\n" if $F[1] && $F[0] ne $F[1] ;
- printf "\tarticle-timeout: %d\n", $F[2] if $F[2] ;
- printf "\tresponse-timeout: %d\n", $F[3] if $F[3] ;
- printf "\tinitial-connections: %d\n", $F[4] if ($F[4] ne "") ;
- printf "\tmax-connections: %d\n", $F[5] if ($F[5] ne "") ;
- printf "\tmax-queue-size: %d\n", $F[6] if ($F[6] ne "") ;
- printf "\tstreaming: %s\n", $F[7] if ($F[7] ne "") ;
- printf "\tno-check-high: %0.2f\n", $F[9] * 10.0 if ($F[9] ne "") ;
- printf "\tno-check-low: %0.2f\n", $F[8] * 10.0 if ($F[8] ne "") ;
- printf "\tport-number: %d\n", $F[10] if ($F[10] ne "") ;
-
- print "}\n\n\n" ;
- }
-}
-
-
+++ /dev/null
-/* $Id: innfeed.h 7559 2006-08-28 02:10:39Z eagle $
-**
-** innfeed's configuration values.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The application configuration values. This file is #include'd before any
-** system header files, so it can't rely on any CPP symbols other that what
-** the compiler defines.
-*/
-
-#if ! defined ( innfeed_h__ )
-#define innfeed_h__
-
-#include "inn/timer.h"
-
-/**********************************************************************/
-/* Application specific defines */
-/**********************************************************************/
-
-/* the path to the run-time config file. If relative, then relative to
- @ETCDIR@. Overridden by ``-c'' option. */
-#define CONFIG_FILE "innfeed.conf"
-
-
-/*
- * This next section contains things than can be overriden in the config
- * file. The strings inside each comment is the key used in the
- * innfeed.conf file to override the value here. See innfeed.conf for a
- * description of each./
- */
-
-/* in tape.c */
-#define TAPE_DIRECTORY "innfeed" /* [pathspool]/backlog-directory */
-#define TAPE_HIGHWATER 5 /* backlog-highwater */
-#define TAPE_ROTATE_PERIOD 60 /* backlog-rotate-period */
-#define TAPE_CHECKPOINT_PERIOD 30 /* backlog-ckpt-period */
-#define TAPE_NEWFILE_PERIOD 600 /* backlog-newfile-period */
-#define TAPE_DISABLE false /* no-backlog */
-
-/* in main.c */
-#define PID_FILE "innfeed.pid" /* [pathrun]/pid-file */
-#define LOG_FILE "innfeed.log" /* [pathlog]/log-file */
-
-/* in host.c */
-#define DNS_RETRY_PERIOD 900 /* dns-retry */
-#define DNS_EXPIRE_PERIOD 86400 /* dns-expire */
-#define CLOSE_PERIOD (60 * 60 * 24) /* close-period */
-#define GEN_HTML false /* gen-html */
-#define INNFEED_STATUS "innfeed.status" /* status-file */
-#define LOG_CONNECTION_STATS 0 /* connection-stats */
-#define HOST_HIGHWATER 10 /* host-highwater */
-#define STATS_PERIOD (60 * 10) /* stats-period */
-#define STATS_RESET_PERIOD (60 * 60 * 12) /* stats-reset-period */
-
-#define ARTTOUT 600 /* article-timeout */
-#define RESPTOUT 300 /* response-timeout */
-#define INIT_CXNS 1 /* initial-connections */
-#define MAX_CXNS 2 /* max-connections */
-#define MAX_Q_SIZE 5 /* max-queue-size */
-#define STREAM true /* streaming */
-#define NOCHECKHIGH 95.0 /* no-check-high */
-#define NOCHECKLOW 90.0 /* no-check-low */
-#define PORTNUM 119 /* port-number */
-#define FORCE_IPv4 false /* force using IPv4 */
-#define BLOGLIMIT 0 /* backlog-limit */
-#define LIMIT_FUDGE 1.10 /* backlog-factor */
-#define BLOGLIMIT_HIGH 0 /* backlog-limit-high */
-
-#define INIT_RECON_PER 30 /* initial-reconnect-time */
-#define MAX_RECON_PER (60 * 60 * 1)/* max-reconnect-time */
-
-
-
-
-
-
-
-/****************************************************************************/
-/*
- * The rest below are not run-time configurable.
- */
-
-/* If this file exists at startup then it's the same as having done
- '-d 1' on the command line. This is a cheap way of avoiding continual
- reloading of the newsfeeds file when debugging. */
-#define DEBUG_FILE "innfeed.debug" /* Relative to pathlog */
-
-/* if defined to a non-zero number, then a snapshot will be printed
- whenever die() is called (e.g. on assert failure). This can use up a
- lot of disk space. */
-#define SNAPSHOT_ON_DIE 0
-
-/* the full pathname of the file to get a printed dump of the system when
- a SIGINT is delivered (or SNAPSHOT_ON_DIE is non-zero--see below). */
-#define SNAPSHOT_FILE "innfeed.snapshot" /* Relative to pathlog */
-
-/* Define this be an existing directory (or NULL). If innfeed deliberatly
- dumps core it will chdir() to this directory first (if non-NULL). If
- NULL then it will chdir to TAPE_DIRECTORY (as possibly modified by
- the '-b' option). */
-#define CORE_DIRECTORY NULL
-
-/* strings that get added to the end of a peer name for generating
- backlog file names. A peername cannot end in any of these string
- (e.g. having a peer called 'mypeer.input' will not work) */
-#define OUTPUT_TAIL ".output"
-#define INPUT_TAIL ".input"
-#define LOCK_TAIL ".lock"
-
-/* rough estimate of average article line length (including
- headers). Smaller number means more efficient article preparation (for
- transfer), but, if much smaller than reality, then more memory
- wastage. */
-#define CHARS_PER_LINE 60
-
-/* How many seconds between logging statistics on article allocation.
- For no logging set to 0 */
-#define ARTICLE_STATS_PERIOD (10 * 60) /* 10 minutes */
-
-/* max number of parallel connections to a single remote. This is just a
- sanity check for the runtime config file. */
-#define MAX_CONNECTION_COUNT 50
-
-/* default size in bytes for buffers */
-#define BUFFER_SIZE 256
-
-/* amount we expand buffers on partial reads */
-#define BUFFER_EXPAND_AMOUNT 128
-
-/* minimum number of seconds between log messages for starting
- spooling. i.e. if the connection bounces up and down this will prevent
- frequent logging of the spooling message. 0 turns off this logging. */
-#define SPOOL_LOG_PERIOD 600
-
-/* some big numbers just for sanity checking */
-#define MAX_MAXCHECKS 10000 /* no more than 10000 articles at a time */
-#define MAX_MAXART_TOUT 86400 /* one day max between articles from inn */
-#define MAX_RESP_TOUT 3600 /* one hour max to wait for response */
-
-/* the check / no-check filter value, i.e. roughly how many past
- articles we take into account whilst doing the average for
- check / no-check mode.
- Ensure it's a float. */
-#define FILTERVALUE 50.0
-
-/* the maximum number of peers we'll handle (not connections) */
-#define MAX_HOSTS 100
-
-/* We try to keep article memory allocation below this limit. Doesn't work
- very well, though. */
-#define SOFT_ARTICLE_BYTE_LIMIT (1024 * 1024 * 10) /* 10MB */
-
-/* define SELECT_RATIO to the number of times through the main loop before
- checking on the fd from inn again.... */
-#define SELECT_RATIO 3
-
-
-#if defined (DBTIMES)
-
- /* some small values for testing things. */
-
-#undef STATS_PERIOD
-#define STATS_PERIOD 30 /* 30 seconds */
-
-#undef STATS_RESET_PERIOD
-#define STATS_RESET_PERIOD (6 * 60) /* 6 minutes */
-
-#undef ARTICLE_STATS_PERIOD
-#define ARTICLE_STATS_PERIOD (6 * 60) /* 7 minutes */
-
-#undef CLOSE_PERIOD
-#define CLOSE_PERIOD (3 * 60) /* 5 minutes */
-
-#endif /* DBTIMES */
-
-
-/* Additional OS-specific defines. These should really be moved into
- configure at some point. */
-
-/* Some broken system (all SunOS versions) have a lower limit for the
- maximum number of stdio files that can be open, than the limit of open
- file the OS will let you have. If this value is > 0 (and ``stdio-fdmax''
- is *not* used in the config file), then all non-stdio file descriptors
- will be kept above this value (by dup'ing them). */
-#if defined (sun)
-# if defined (__SVR4)
-# define MAX_STDIO_FD 256
-# else
-# define MAX_STDIO_FD 128
-# endif
-#else
-# define MAX_STDIO_FD 0
-#endif
-
-/* some timer constants */
-
-typedef enum { TMR_IDLE = TMR_APPLICATION, TMR_BACKLOGSTATS,
- TMR_STATUSFILE, TMR_NEWARTICLE, TMR_READART, TMR_PREPART, TMR_READ,
- TMR_WRITE, TMR_CALLBACK, TMR_MAX
-} TMRTYPE;
-
-#endif /* innfeed_h__ */
+++ /dev/null
-/* $Id: innlistener.c 6716 2004-05-16 20:26:56Z rra $
-**
-** The implementation of the innfeed InnListener class.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "configfile.h"
-#include "endpoint.h"
-#include "host.h"
-#include "innlistener.h"
-#include "nntp.h"
-#include "tape.h"
-
-#define LISTENER_INPUT_BUFFER (1024 * 8) /* byte size of the input buffer */
-#define EOF_SLEEP_TIME 1 /* seconds to sleep when EOF on InputFile */
-
-struct innlistener_s
-{
- EndPoint myep ;
-
- Host *myHosts ;
- size_t hostLen ;
- Buffer inputBuffer ;
- bool dummyListener ;
- bool dynamicPeers ;
- TimeoutId inputEOFSleepId ;
-
- InnListener next ;
-};
-
-static unsigned int listenerCount = 0 ;
-static InnListener listenerList = NULL ;
-
-InnListener mainListener ;
-
-static FILE *droppedFp = NULL ;
-static long droppedCount = 0 ;
-static int droppedFileCount = 0 ;
-static char *dropArtFile = NULL ;
-static bool fastExit = false ;
-
-extern const char *pidFile ;
-extern const char *InputFile ;
-extern bool RollInputFile ;
-extern bool genHtml ;
-
-
-static void giveArticleToPeer (InnListener lis,
- Article article, const char *peerName) ;
-static void newArticleCommand (EndPoint ep, IoStatus i,
- Buffer *buffs, void *data) ;
-static void wakeUp (TimeoutId id, void *data) ;
-static void writeCheckPoint (int offsetAdjust) ;
-static void dropArticle (const char *peer, Article article) ;
-static void listenerCleanup (void) ;
-
-static bool inited = false ;
-
-
-void listenerLogStatus (FILE *fp)
-{
- fprintf (fp,"%sListener Status:%s\n",
- genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
- fprintf (fp," Dropped article file: %s\n",dropArtFile) ;
- fprintf (fp," Dropped article count: %ld\n",(long) droppedCount) ;
- fprintf (fp,"\n") ;
-}
-
-InnListener newListener (EndPoint endp, bool isDummy, bool dynamicPeers)
-{
- InnListener l = xcalloc (1, sizeof(struct innlistener_s)) ;
- Buffer *readArray ;
-
- if (!inited)
- {
- inited = true ;
- atexit (listenerCleanup) ;
- }
-
- l->myep = endp ;
-
- l->hostLen = MAX_HOSTS ;
- l->myHosts = xcalloc (l->hostLen, sizeof(Host)) ;
-
- l->inputBuffer = newBuffer (LISTENER_INPUT_BUFFER) ;
- l->dummyListener = isDummy ;
- l->dynamicPeers = dynamicPeers ;
-
- addPointerFreedOnExit ((char *)bufferBase(l->inputBuffer)) ;
- addPointerFreedOnExit ((char *)l->myHosts) ;
- addPointerFreedOnExit ((char *)l) ;
-
- readArray = makeBufferArray (bufferTakeRef (l->inputBuffer), NULL) ;
- prepareRead (endp,readArray,newArticleCommand,l,1) ;
-
- l->next = listenerList ;
- listenerList = l ;
-
- listenerCount++ ;
-
- return l ;
-}
-
-void gPrintListenerInfo (FILE *fp, unsigned int indentAmt)
-{
- InnListener p ;
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal InnListener list : %p (count %d) {\n",
- indent,(void *) listenerList,listenerCount) ;
- for (p = listenerList ; p != NULL ; p = p->next)
- printListenerInfo (p,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-void printListenerInfo (InnListener listener, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sInnListener : %p {\n",indent,(void *) listener) ;
- fprintf (fp,"%s endpoint : %p\n", indent,(void *) listener->myep) ;
- fprintf (fp,"%s dummy-listener : %s\n",indent,
- boolToString (listener->dummyListener)) ;
- fprintf (fp,"%s dynamicPeers : %s\n",indent,
- boolToString (listener->dynamicPeers)) ;
-
- fprintf (fp,"%s input-buffer {\n",indent) ;
- printBufferInfo (listener->inputBuffer,fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s hosts {\n",indent) ;
- for (i = 0 ; i < listener->hostLen ; i++)
- {
-#if 0
- if (listener->myHosts [i] != NULL)
- printHostInfo (listener->myHosts [i],fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,(void *) listener->myHosts[i]) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
- /* Unlink the pidFile if and only if it is our pidFile.
- There is still a racecondition here but very small. */
-static void unlinkPidFile (void)
-{
- FILE *fp;
- char buf[32];
-
- if ((fp = fopen(pidFile, "r")) == NULL)
- return;
-
- if (fgets(buf, 32, fp) != NULL && atoi(buf) == getpid())
- unlink(pidFile);
- fclose(fp);
-}
-
- /* Close down all hosts on this listener. When they're all gone the
- Listener will be deleted. */
-void shutDown (InnListener l)
-{
- unsigned int i ;
- unsigned int count ;
-
- d_printf (1,"Shutting down the listener\n") ;
-
- /* When shutting down the mainListener, stop writing to the
- StatusFile and remove our pidFile. */
- if (l == mainListener)
- {
- /*hostCleanup (); should do this but .. */
- hostSetStatusFile ("/dev/null");
- unlinkPidFile();
- }
-
- closeDroppedArticleFile () ;
-
- if (l->myep != NULL)
- {
- if (l->inputEOFSleepId != 0)
- removeTimeout (l->inputEOFSleepId) ;
- l->inputEOFSleepId = 0 ;
- delEndPoint (l->myep) ;
- }
- l->myep = NULL ;
-
- for (i = 0, count = 0 ; i < l->hostLen ; i++)
- if (l->myHosts [i] != NULL)
- {
- hostClose (l->myHosts[i]) ;
- count++ ;
- }
-
- if (count == 0 || fastExit)
- {
- time_t now = theTime () ;
- char dateString [30] ;
-
- gHostStats();
- strlcpy (dateString,ctime (&now),sizeof (dateString)) ;
- dateString [24] = '\0' ;
-
- if (fastExit)
- notice ("ME finishing (quickly) at %s", dateString) ;
- else
- notice ("ME finishing at %s", dateString) ;
-
- unlinkPidFile();
- exit (0) ;
- }
-}
-
-
-bool listenerAddPeer (InnListener listener, Host hostObj)
-{
- unsigned int i ;
-
- d_printf (1,"Adding peer: %s\n", hostPeerName (hostObj)) ;
-
- for (i = 0 ; i < listener->hostLen ; i++)
- {
- if (listener->myHosts [i] == NULL)
- {
- listener->myHosts [i] = hostObj ;
-
- return true ;
- }
- }
-
- return false ;
-}
-
-
-/* return true if this listener doesn't ever generate articles. */
-bool listenerIsDummy (InnListener listener)
-{
- return listener->dummyListener ;
-}
-
-/* Called by the Host when it (the Host) is about to delete itself. */
-unsigned int listenerHostGone (InnListener listener, Host host)
-{
- unsigned int i ;
- unsigned int someThere = 0 ;
-
- d_printf (1,"Host is gone: %s\n", hostPeerName (host)) ;
-
- for (i = 0 ; i < listener->hostLen ; i++)
- if (listener->myHosts [i] == host)
- listener->myHosts [i] = NULL ;
- else if (listener->myHosts [i] != NULL)
- someThere++ ;
-
- return someThere ;
-}
-
-
-/* called by the Host when it has nothing to do. */
-void listenerHostIsIdle (InnListener listener, Host host)
-{
- ASSERT (listener != NULL) ;
- ASSERT (host != NULL) ;
-
- d_printf (1,"Host is idle: %s\n", hostPeerName (host)) ;
-
- if (!listener->dummyListener)
- return ;
-
- /* if this listener is a dummy (i.e. not generating articles cause we're
- just dealing with backlog files) then forget about the host and when
- last one is gone we exit. */
-
- hostClose (host) ;
-}
-
-
-void openInputFile (void)
-{
- int fd, i, mainFd ;
- off_t offset ;
- char buf [32], *p ;
-
- ASSERT (InputFile && *InputFile) ;
-
- fd = open(InputFile, O_RDWR) ;
- if (fd < 0)
- die ("open %s: %s\n", InputFile, strerror(errno)) ;
-
- mainFd = getMainEndPointFd() ;
- if (fd != mainFd)
- {
- if (dup2(fd, mainFd) < 0)
- die ("dup2 %d %d: %s\n", fd, mainFd, strerror(errno)) ;
- close (fd);
- }
-
- i = read(mainFd, buf, sizeof (buf)) ;
- if (i < 0)
- die ("read %s: %s\n", InputFile, strerror(errno)) ;
- else if (i > 0)
- {
- p = buf;
- buf [ sizeof(buf) - 1 ] = '\0';
- offset = (off_t) strtol (p, &p, 10) ;
- if (offset > 0 && *p == '\n')
- lseek (mainFd, offset, SEEK_SET) ;
- else
- lseek (mainFd, 0, SEEK_SET) ;
- }
- syslog(LOG_NOTICE, "ME opened %s", InputFile);
-}
-
-
-int listenerConfigLoadCbk (void *data UNUSED)
-{
- int bval ;
-
- if (getBool (topScope,"fast-exit",&bval,NO_INHERIT))
- fastExit = (bval ? true : false) ;
-
- return 1 ;
-}
-
-/**********************************************************************/
-/** STATIC PRIVATE FUNCTIONS **/
-/**********************************************************************/
-
-
-/* EndPoint callback function for when the InnListener's fd is ready for
- reading. */
-static void newArticleCommand (EndPoint ep, IoStatus i,
- Buffer *buffs, void *data)
-{
- InnListener lis = (InnListener) data ;
- char *msgid, *msgidEnd ;
- char *fileName, *fileNameEnd ;
- char *peer, *peerEnd ;
- char *cmd, *endc ;
- char *bbase = bufferBase (buffs [0]) ;
- size_t blen = bufferDataSize (buffs [0]) ;
- Buffer *readArray ;
- static int checkPointCounter ;
- char *s;
-
- ASSERT (ep == lis->myep) ;
-
- bufferAddNullByte (buffs [0]) ;
-
- if (i == IoEOF)
- {
- if ( lis == mainListener && InputFile != NULL )
- {
- if ( RollInputFile )
- {
- syslog(LOG_NOTICE, "ME reached EOF in %s", InputFile);
- openInputFile () ;
- RollInputFile = false ;
- readArray = makeBufferArray (bufferTakeRef (buffs [0]),NULL) ;
- prepareRead (ep, readArray, newArticleCommand, data, 1) ;
- }
- else
- {
- lis->inputEOFSleepId =
- prepareSleep (wakeUp, EOF_SLEEP_TIME, data) ;
-
- }
- }
- else
- {
- d_printf (1,"Got EOF on listener\n") ;
- notice ("ME source lost . Exiting");
- shutDown (lis) ;
- }
- }
- else if (i == IoFailed)
- {
- errno = endPointErrno (ep) ;
-#if HAVE_SOCKETPAIR
- if (errno != ECONNABORTED)
-#endif
- syswarn ("ME source read error, exiting") ;
- d_printf (1,"Got IO Error on listener\n") ;
- shutDown (lis) ;
- }
- else if (strchr (bbase, '\n') == NULL) /* partial read */
- {
- /* check for input corrupted by NULs - if they
- precede the newline, we never get out of here */
- if (strlen(bbase) < blen)
- {
- warn ("ME source format bad, exiting: %s", bbase) ;
- shutDown (lis) ;
-
- return ;
- }
- if (blen == bufferSize(buffs [0])) {
- if (!expandBuffer (buffs [0], BUFFER_EXPAND_AMOUNT)) {
- warn ("ME error expanding input buffer") ;
- shutDown (lis) ;
- return ;
- }
- }
- readArray = makeBufferArray (bufferTakeRef (buffs [0]),NULL) ;
- if (!prepareRead (ep, readArray, newArticleCommand, data, 1)) {
- warn ("ME error prepare read failed") ;
- freeBufferArray (readArray) ;
- shutDown (lis) ;
- return ;
- }
- }
- else
- {
- /* now iterate over each full command we got on the input. */
- cmd = bbase ;
- while ((cmd < (bbase + blen)) && ((endc = strchr (cmd,'\n')) != NULL))
- {
- Article article ;
- char *next = endc + 1;
-
- if (*next == '\r')
- next++ ;
-
- endc-- ;
- if (*endc != '\r')
- endc++ ;
-
- *endc = '\0' ;
-
- /* check for input corrupted by NULs - if they are preceded
- by newline, we may skip a large chunk without noticing */
- if (*next == '\0' && next < bbase + blen)
- {
- warn ("ME source format bad, exiting: %s", cmd) ;
- shutDown (lis) ;
-
- return ;
- }
-
- d_printf (2,"INN Command: %s\n", cmd) ;
-
- /* pick out the leading string (the filename) */
- if ((fileName = findNonBlankString (cmd,&fileNameEnd)) == NULL)
- {
- warn ("ME source format bad, exiting: %s", cmd) ;
- shutDown (lis) ;
-
- return ;
- }
-
- *fileNameEnd = '\0' ; /* for the benefit of newArticle() */
-
- /* now pick out the next string (the message id) */
- if ((msgid = findNonBlankString (fileNameEnd + 1,&msgidEnd)) == NULL)
- {
- *fileNameEnd = ' ' ; /* to make syslog work properly */
- warn ("ME source format bad, exiting: %s", cmd) ;
- shutDown (lis) ;
-
- return ;
- }
-
- *msgidEnd = '\0' ; /* for the benefit of newArticle() */
-
- /* now create an article object and give it all the peers on the
- rest of the command line. Will return null if file is missing. */
- article = newArticle (fileName, msgid) ;
- *fileNameEnd = ' ' ;
-
- /* Check the message ID length */
- if (strlen(msgid) > NNTP_MSGID_MAXLEN) {
- warn ("ME message id exceeds limit of %d octets: %s",
- NNTP_MSGID_MAXLEN, msgid) ;
- *(msgidEnd+1) = '\0' ;
- }
- *msgidEnd = ' ' ;
-
- /* Check if message ID starts with < and ends with > */
- if (*msgid != '<' || *(msgidEnd-1) != '>') {
- warn ("ME source format bad, exiting: %s", cmd) ;
- *(msgidEnd+1) = '\0';
- }
-
- /* now get all the peernames off the rest of the command lines */
- peerEnd = msgidEnd ;
- do
- {
- *peerEnd = ' ' ;
-
- /* pick out the next peer name */
- if ((peer = findNonBlankString (peerEnd + 1,&peerEnd))==NULL)
- break ; /* even no peer names is OK. */ /* XXX REALLY? */
-
- *peerEnd = '\0' ;
-
- /* See if this is a valid peername */
- for(s = peer; *s; s++)
- if (!CTYPE(isalnum, *s) && *s != '.' && *s != '-' && *s != '_')
- break;
- if (*s != 0) {
- warn ("ME invalid peername %s", peer) ;
- continue;
- }
- if (article != NULL)
- giveArticleToPeer (lis,article,peer) ;
- }
- while (peerEnd < endc) ;
-
- delArticle (article) ;
-
- cmd = next ;
-
- /* write a checkpoint marker if we've done another large chunk */
- if (InputFile && *InputFile && ++checkPointCounter == 1000)
- {
- /* adjust the seek pointer value by the current location
- within the input buffer */
- writeCheckPoint (blen - (cmd - bbase)) ;
- checkPointCounter = 0 ;
- }
-
- }
-
- if (*cmd != '\0') /* partial command left in buffer */
- {
- Buffer *bArr ;
- unsigned int leftAmt = blen - (cmd - bbase) ;
-
- ASSERT (cmd != bbase) ;
- /* first we shift whats left in the buffer down to the bottom */
- memmove (bbase,cmd,leftAmt) ;
- bufferSetDataSize (buffs [0],leftAmt) ;
-
- bArr = makeBufferArray (bufferTakeRef (buffs [0]),NULL) ;
-
- if ( !prepareRead (lis->myep, bArr, newArticleCommand, lis, 1) )
- {
- warn ("ME error prepare read failed") ;
-
- freeBufferArray (bArr) ;
-
- shutDown (lis) ;
-
- return ;
- }
- }
- else if ( !readIsPending (lis->myep) )
- { /* XXX read should never be pending here */
- Buffer *bArr = makeBufferArray (bufferTakeRef (buffs [0]),NULL) ;
-
- bufferSetDataSize (buffs [0],0) ;
-
- if ( !prepareRead (lis->myep, bArr, newArticleCommand, lis, 1) )
- {
- warn ("ME error prepare read failed") ;
-
- shutDown (lis) ;
-
- return ;
- }
- }
- }
-
- freeBufferArray (buffs) ;
-}
-
-/* EndPoint callback function for when the sleep due to
- having reached EOF on InputFile is done. */
-static void wakeUp (TimeoutId id, void *data)
-{
- InnListener lis = (InnListener) data ;
- Buffer *readArray ;
-
- ASSERT (id == lis->inputEOFSleepId) ;
-
- lis->inputEOFSleepId = 0 ;
- readArray = makeBufferArray (bufferTakeRef (lis->inputBuffer), NULL) ;
- prepareRead (lis->myep,readArray,newArticleCommand,lis,1) ;
-}
-
-
-/* Find the Host object for the peer and hand off a reference to the
- article for it to transmit. */
-static void giveArticleToPeer (InnListener lis,
- Article article, const char *peerName)
-{
- unsigned int i ;
-
- for (i = 0 ; i < lis->hostLen ; i++)
- if (lis->myHosts[i] != NULL)
- if (strcmp (peerName,hostPeerName (lis->myHosts [i])) == 0)
- {
- d_printf (1,"Giving article to peer: %s\n", peerName) ;
- hostSendArticle (lis->myHosts [i],artTakeRef (article)) ;
- break ;
- }
-
- if (i == lis->hostLen)
- {
- d_printf (1,"Failed to give article to peer: -%s-\n", peerName) ;
-
- if (lis->dynamicPeers)
- {
- Host newHostObj;
-
- d_printf (1, "Adding peer dynamically\n") ;
-
- newHostObj = newDefaultHost (lis, peerName);
-
- if (newHostObj == NULL)
- {
- /* Most likely we couldn't get the lock, i.e. the
- peer is blocked.
- */
- dropArticle (peerName,article) ;
- }
- else if ( !listenerAddPeer (lis, newHostObj) )
- {
- /* XXX need to remember we've gone over the limit and not try
- to add any more. */
- warn ("ME internal too many hosts. (max is %lu)",
- (unsigned long) lis->hostLen) ;
- dropArticle (peerName,article) ;
- }
- else
- {
- d_printf (1,"Giving article to peer: %s\n", peerName) ;
- hostSendArticle (newHostObj,artTakeRef (article)) ;
- }
- }
- else
- {
- dropArticle (peerName,article) ;
- }
- }
-}
-
-
-static void writeCheckPoint (int offsetAdjust)
-{
- char offsetString[16], *writePointer ;
- off_t offset ;
- int writeBytes, writeReturn, mainFd ;
-
- mainFd = getMainEndPointFd() ;
- offset = lseek (mainFd, 0, SEEK_CUR) ;
- if (offset < 0)
- syslog (LOG_ERR, "ME tell(mainFd): %m") ;
- else
- {
- snprintf (offsetString, sizeof(offsetString), "%ld\n",
- (long)(offset - offsetAdjust) ) ;
- if ( lseek (mainFd, 0, SEEK_SET) != 0 )
- syslog (LOG_ERR, "ME seek(mainFd, 0, 0): %m") ;
- else
- {
- writeBytes = strlen (offsetString) ;
- writePointer = offsetString ;
- do
- {
- writeReturn = write (mainFd, writePointer, writeBytes) ;
- if (writeReturn < 0)
- {
- syslog (LOG_ERR,"ME write input checkpoint: %m") ;
- break ;
- }
- writePointer += writeReturn ;
- writeBytes -= writeReturn ;
- } while (writeBytes) ;
- if ( lseek (mainFd, offset, SEEK_SET) != offset )
- die ("ME seek(mainFd, %ld, SEEK_SET): %s\n", (long)offset,
- strerror(errno) ) ;
- }
- }
-}
-
-
-void openDroppedArticleFile (void)
-{
- pid_t myPid = getpid () ;
- const char *tapeDir = getTapeDirectory() ;
- size_t len;
-
- if (dropArtFile != NULL)
- free (dropArtFile) ;
-
- len = pathMax(tapeDir) + 1;
- dropArtFile = xmalloc(len);
- snprintf (dropArtFile,len,"%s/innfeed-dropped.%c%06d",
- tapeDir, droppedFileCount + 'A', (int) myPid) ;
-
- if ((droppedFp = fopen (dropArtFile,"w")) == NULL)
- {
- syswarn ("ME cant open %s: loosing articles", dropArtFile) ;
-
- free (dropArtFile) ;
- dropArtFile = NULL ;
-
- if ((droppedFp = fopen ("/dev/null","w")) == NULL)
- {
- die ("ME error opening /dev/null") ;
- }
- }
-
-
-}
-
-void closeDroppedArticleFile (void)
-{
- off_t pos ;
-
- if (droppedFp == NULL)
- return ;
-
- fflush (droppedFp) ;
- pos = ftello (droppedFp) ;
-
- fclose (droppedFp) ;
- droppedFp = NULL ;
-
- if (pos == 0 && dropArtFile != NULL)
- unlink (dropArtFile) ;
- else if (pos != 0 && dropArtFile == NULL)
- warn ("ME lost %ld articles", droppedCount) ;
- else if (pos != 0)
- notice ("ME dropped %ld articles", droppedCount) ;
-
- droppedFileCount = (droppedFileCount + 1) % 26 ;
- droppedCount = 0 ;
-}
-
-static void dropArticle (const char *peerName, Article article)
-{
- static bool logged = false ;
-
- if (!logged)
- {
- warn ("ME dropping articles into %s", dropArtFile) ;
- logged = true ;
- }
-
- droppedCount++ ;
- fprintf (droppedFp,"%s %s %s\n",artFileName (article),
- artMsgId (article), peerName) ;
-}
-
-
-static void listenerCleanup (void)
-{
- free (dropArtFile) ;
- dropArtFile = NULL ;
-}
+++ /dev/null
-/* $Id: innlistener.h 6648 2004-01-25 20:07:11Z rra $
-**
-** The public interface to the InnListener class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The public interface of the things that listens to commands from INN. It
-** receives lines of the form:
-**
-** filename msgid peer1 peer2 peer3
-**
-** and turns them into Article objects and hands those Articles off to the
-** Host objects.
-*/
-
-#if ! defined ( innlistener_h__ )
-#define innlistener_h__
-
-#include <stdio.h>
-
-#include "misc.h"
-
-
-extern InnListener mainListener ;
-
-/* Initialization of the InnListener object. If it fails then returns
- NULL. ENDPOINT is the endpoint where the article info will come
- from. A dummy listener exists when processing backlog files and is
- there just to help drive the process. */
-InnListener newListener (EndPoint endp, bool isDummy, bool dynamicPeers) ;
-
-/* print some useful debugging information about the Listener and all its
- * Hosts and all their Connecitons/Article/Buffers etc. to the given FILE.
- */
-void gPrintListenerInfo (FILE *fp, unsigned int indentAmt) ;
-void printListenerInfo (InnListener listener, FILE *fp, unsigned int indentAmt) ;
-
-/* Called by the Host when it is about to delete itself */
-unsigned int listenerHostGone (InnListener listener, Host host) ;
-
-/* Called to hook up the given Host to the Listener. */
-bool listenerAddPeer (InnListener listener, Host hostObj) ;
-
-/* true if the listener is a dummy. */
-bool listenerIsDummy (InnListener listener) ;
-
-/*
- * This gets called to stop accepting new articles from innd. Typically
- * called by the signal handler, or when the listener gets EOF on its input
- * (in channel mode)
- */
-void shutDown (InnListener cxn) ;
-
-/* Callback fired after config file is loaded */
-int listenerConfigLoadCbk (void *data) ;
-
- /* stop a specific host. */
-void shutDownHost (InnListener cxn, const char *peerName) ;
-
- /* Called by the Host when it has nothing to do (so it can be shut down
- if necessary). */
-void listenerHostIsIdle (InnListener listener, Host host) ;
-
-void openInputFile (void) ;
-
-void openDroppedArticleFile (void) ;
-void closeDroppedArticleFile (void) ;
-
-void listenerLogStatus (FILE *fp) ;
-
-#endif /* innlistener_h__ */
+++ /dev/null
-/* $Id: main.c 6956 2004-06-29 22:41:35Z rra $
-**
-** Main routines for the innfeed program.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <netdb.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
-# include <sys/un.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "storage.h"
-
-#include "article.h"
-#include "buffer.h"
-#include "configfile.h"
-#include "connection.h"
-#include "endpoint.h"
-#include "host.h"
-#include "innlistener.h"
-#include "misc.h"
-#include "tape.h"
-
-#define INHERIT 1
-#define NO_INHERIT 0
-
-/* exports */
-bool talkToSelf ;
-extern int debugWrites ;
-bool sigFlag = false ;
-const char *InputFile ;
-char *configFile = NULL ;
-bool RollInputFile = false ;
-char *pidFile = NULL ;
-bool useMMap = false ;
-void (*gPrintInfo) (void) ;
-char *dflTapeDir;
-/* these are used by imapfeed */
-char *deliver_username = NULL;
-char *deliver_authname = NULL;
-char *deliver_password = NULL;
-char *deliver_realm = NULL;
-const char *deliver_rcpt_to = "+%s";
-char *deliver_to_header = NULL;
-
-/* imports */
-extern char *versionInfo ;
-#if defined (sun)
-extern char *optarg ; /* needed for Solaris */
-extern int optind;
-#endif
-extern bool genHtml ;
-
-extern void openInputFile (void);
-
-/* privates */
-static char *logFile ;
-static char *newsspool ;
-
-static void sigemt (int sig) ;
-static void sigalrm (int sig) ;
-static void sigchld (int sig) ;
-static void sigint (int sig) ;
-static void sigquit (int sig) ;
-static void sighup (int sig) ;
-static void sigterm (int sig) ;
-static void sigusr (int sig) ;
-static void usage (int) ;
-static void gprintinfo (void) ;
-static void openLogFile (void) ;
-static void writePidFile (void) ;
-static int mainOptionsProcess (void *data) ;
-static int mainConfigLoadCbk (void *data) ;
-static void mainCleanup (void) ;
-
-static char *bopt = NULL ;
-static char *aopt = NULL ;
-static char *popt = NULL ;
-static bool Mopt = false ;
-static bool Zopt = false ;
-static bool Dopt = false ;
-static int debugLevel = 0 ;
-static unsigned int initialSleep = 2 ;
-static char *sopt = NULL ;
-static char *lopt = NULL ;
-static bool eopt = false ;
-static int elimit = 0 ;
-
-int main (int argc, char **argv)
-{
- EndPoint ep ;
- InnListener listener ;
- int optVal, fd, rval ;
- const char *subProgram = NULL ;
- bool seenV = false ;
- bool dynamicPeers = false ;
- time_t now = theTime() ;
- char dateString [30] ;
- char *copt = NULL ;
- char *debugFile;
- bool checkConfig = false ;
- bool val;
-
- strlcpy (dateString,ctime(&now),sizeof (dateString)) ;
-
- message_program_name = strrchr (argv [0],'/');
- if (message_program_name == NULL)
- message_program_name = argv [0] ;
- else
- message_program_name++;
-
- gPrintInfo = gprintinfo ;
-
- openlog (message_program_name,(int)(L_OPENLOG_FLAGS|LOG_PID),LOG_INN_PROG) ;
- if (!innconf_read(NULL)) {
- syslog(LOG_ERR, "cant read inn.conf\n");
- exit(1);
- }
-
-#if defined (HAVE_MMAP)
- useMMap = true ;
-#else
- useMMap = false ;
-#endif
-
- message_handlers_die (2, error_log_stderr_date, message_log_syslog_err) ;
- message_handlers_warn (1, message_log_syslog_warning);
- message_handlers_notice (1, message_log_syslog_notice) ;
-
-#define OPT_STRING "a:b:c:Cd:e:hl:mMo:p:S:s:vxyz"
-
- while ((optVal = getopt (argc,argv,OPT_STRING)) != EOF)
- {
- switch (optVal)
- {
- case 'a':
- aopt = optarg ;
- break ;
-
- case 'b':
- if ( !isDirectory (optarg) )
- logAndExit (1,"Not a directory: %s\n",optarg) ;
- bopt = optarg ;
- break ;
-
- case 'C':
- checkConfig = true ;
- break ;
-
- case 'c':
- copt = optarg ;
- break ;
-
- case 'd':
- loggingLevel = atoi (optarg) ;
- debugLevel = loggingLevel ;
- Dopt = true ;
- break ;
-
- case 'e':
- eopt = true ;
- elimit = atoi (optarg) ;
- if (elimit <= 0)
- {
- fprintf (stderr,"Illegal value for -e option\n") ;
- usage (1) ;
- }
- break ;
-
- case 'h':
- usage (0) ;
-
- case 'l':
- lopt = optarg ;
- break ;
-
- case 'M':
- Mopt = true ;
- useMMap = false ;
- break ;
-
- case 'm':
- artLogMissingArticles (true) ;
- break ;
-
- case 'o':
- artSetMaxBytesInUse (atoi (optarg)) ;
- break ;
-
- case 'p':
- popt = optarg ;
- break ;
-
- case 's':
- subProgram = optarg ;
- break ;
-
- case 'S':
- sopt = optarg ;
- break ;
-
- case 'v':
- seenV = true ;
- break ;
-
- case 'x':
- talkToSelf = true ;
- break ;
-
- case 'y':
- dynamicPeers = true ;
- break ;
-
- case 'z':
- Zopt = true ;
- break ;
-
- default:
- usage (1) ;
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc > 1)
- usage (1) ;
- else if (argc == 1)
- InputFile = *argv;
-
- if (seenV)
- {
- warn ("%s version: %s\n",message_program_name, versionInfo) ;
- exit (0) ;
- }
-
- /* make sure we have valid fds 0, 1 & 2 so it is not taken by
- something else, probably openlog(). fd 0 will be freopen()ed on the
- inputFile, the subProgram, or ourself. fd 1 and fd 2 will
- be freopen()ed on the log file (or will stay pointed at /dev/null).
-
- without doing this, if the descriptors were closed then the
- freopen calls on some systems (like BSDI 2.1) will really close
- whatever has aquired the stdio descriptors, such as the socket
- to syslogd.
-
- XXX possible problems: what if fd 0 is closed but no inputFile,
- XXX subProgram or talkToSelf is true? it will not be freopen()ed, so
- XXX innfeed won't have any fresh data (besides, fd 0 is only writable
- XXX here). perhaps a warning should be issued.
- */
- do
- {
- fd = open("/dev/null", O_WRONLY);
- switch (fd)
- {
- case -1:
- logAndExit (1,"open(\"/dev/null\", O_WRONLY): %s",
- strerror (errno));
- break;
- case 0:
- case 1:
- case 2:
- /* good, we saved an fd from being trounced */
- break;
- default:
- close(fd);
- }
- } while (fd < 2);
-
- if ( !checkConfig )
- {
- notice ("ME starting %s at %s", versionInfo, dateString) ;
- }
-
- val = true;
- if (!SMsetup(SM_PREOPEN, (void *)&val)) {
- syslog(LOG_ERR, "cant setup the storage subsystem\n");
- exit(1);
- }
- if (!SMinit()) {
- d_printf(0, "Storage manager initialization failed\n");
- syslog(LOG_ERR, "Storage manager initialization failed\n");
- exit(1);
- }
-
- if (subProgram == NULL && talkToSelf == false)
- {
- struct stat buf ;
-
- if (fstat (0,&buf) < 0)
- logAndExit (1,"ME oserr fstat stdin: %s", strerror (errno)) ;
- else if (S_ISREG (buf.st_mode))
- InputFile = "";
- }
-
- /*
- * set up the config file name and then read the file in. Order is important.
- */
- configAddLoadCallback (mainOptionsProcess,(checkConfig ? stderr : NULL)) ;
- configAddLoadCallback (tapeConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
-
- configAddLoadCallback (endpointConfigLoadCbk,(checkConfig ? stderr : NULL));
- configAddLoadCallback (hostConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
- configAddLoadCallback (cxnConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
- configAddLoadCallback (mainConfigLoadCbk,(checkConfig ? stderr : NULL)) ;
- configAddLoadCallback (listenerConfigLoadCbk,(checkConfig ? stderr : NULL));
-
- if (copt != NULL && *copt == '\0')
- {
- logOrPrint (LOG_CRIT,(checkConfig ? stderr : NULL),
- "Empty pathname for ``-c'' option") ;
- exit (1) ;
- }
- configFile = buildFilename(innconf->pathetc, copt ? copt : CONFIG_FILE);
- dflTapeDir = buildFilename(innconf->pathspool, TAPE_DIRECTORY);
-
- rval = readConfig (configFile,(checkConfig ? stderr : NULL),
- checkConfig,loggingLevel > 0);
-
- if (subProgram != NULL && (talkToSelf == true || InputFile))
- {
- d_printf (0,"Cannot specify '-s' with '-x' or an input file\n") ;
- syslog (LOG_ERR,"Incorrect arguments: '-s' with '-x' or an input file\n");
- usage (1) ;
- }
-
- if (checkConfig)
- {
- if (!rval)
- {
- fprintf (stderr,"config loading failed.\n") ;
- exit (1) ;
- }
- else
- {
- fprintf (stderr,"config loading succeeded.\n") ;
- exit (0) ;
- }
- }
- else if (!rval)
- exit (1) ;
-
- debugFile = buildFilename (innconf->pathlog, DEBUG_FILE);
- if (loggingLevel == 0 && fileExistsP (debugFile))
- loggingLevel = 1 ;
-
- if (logFile == NULL && ! isatty (fileno (stderr)))
- logFile = buildFilename (innconf->pathlog, LOG_FILE) ;
-
- if (logFile)
- openLogFile () ;
-
- openfds = 4 ; /* stdin, stdout, stderr and syslog */
-
- writePidFile ();
-
- if (subProgram != NULL)
- {
- int fds [2] ;
- int pid ;
-
- if (pipe (fds) < 0)
- sysdie ("ME fatal pipe") ;
-
- if ((pid = fork ()) < 0)
- {
- sysdie ("ME fatal fork") ;
- }
- else if (pid == 0)
- { /* child */
- close (fds[0]) ;
- close (0) ;
- close (1) ;
- close (2) ;
- dup2 (fds[1],1) ;
- dup2 (fds[1],2) ;
- execlp ("sh", "sh", "-c", subProgram, (char *) 0) ;
- perror ("execlp") ;
- exit (1) ;
- }
- else
- { /* parent */
- close (0) ;
- dup2 (fds[0],0) ;
- close (fds[1]) ;
- xsignal(SIGCHLD,sigchld) ;
- openfds++ ;
- }
- }
- else if (talkToSelf)
- {
- /* We're not really getting information from innd or a subprogram,
- but are just processing backlog files. We set up a pipe to ourself
- that we never write to, to simulate an idle innd. */
- int pipefds [2] ;
-
- if (pipe (pipefds) != 0)
- sysdie ("ME fatal pipe") ;
-
- close (0) ;
- dup2 (pipefds [0], 0) ;
-
- openfds++ ;
- openfds++ ;
- }
-
- if (chdir (newsspool) != 0)
- sysdie ("ME fatal chdir %s", newsspool) ;
-
- /* hook up the endpoint to the source of new article information (usually
- innd). */
- ep = newEndPoint (0) ; /* fd 0, i.e. stdin */
-
- /* now arrange for this endpoint to always be the first one checked for
- possible activity. */
- setMainEndPoint (ep) ;
-
- listener = newListener (ep, talkToSelf,dynamicPeers) ;
- mainListener = listener ;
-
- sleep (initialSleep) ;
-
- if (innconf->rlimitnofile >= 0)
- if (setfdlimit (innconf->rlimitnofile) < 0)
- syswarn ("ME oserr setrlimit(RLIM_NOFILE,%ld)", innconf->rlimitnofile) ;
-
- if (innconf->timer > 0)
- TMRinit (TMR_MAX) ;
-
- configHosts (talkToSelf) ;
-
- if (InputFile && *InputFile) {
- openInputFile () ;
- }
-
- /* handle signal to shutdown */
- setSigHandler (SIGTERM,sigterm) ;
- setSigHandler (SIGQUIT,sigquit) ;
-
- /* handle signal to reload config */
- setSigHandler (SIGHUP,sighup) ;
-
- /* handle signal to print snapshot. */
- setSigHandler (SIGINT,sigint) ;
-
- /* handle signal to roll input file */
- setSigHandler (SIGALRM,sigalrm) ;
-
- /* handle signal to flush all the backlog files */
- setSigHandler (SIGCHLD,sigemt) ;
-
- /* we can increment and decrement logging levels by sending SIGUSR{1,2} */
- setSigHandler (SIGUSR1,sigusr) ;
- setSigHandler (SIGUSR2,sigusr) ;
-
- atexit (mainCleanup) ;
-
- Run () ;
-
- exit (0) ;
-}
-
-static void usage (int val)
-{
- fprintf (stderr,"usage: %s [ options ] [ file ]\n\n",
- message_program_name) ;
- fprintf (stderr,"Version: %s\n\n",versionInfo) ;
- fprintf (stderr,"Config file: %s\n",CONFIG_FILE) ;
- fprintf (stderr,"Backlog directory: %s/%s\n", innconf->pathspool, TAPE_DIRECTORY) ;
- fprintf (stderr,"\nLegal options are:\n") ;
- fprintf (stderr,"\t-a dir Use the given directory as the top of the article spool\n") ;
-
- fprintf (stderr,"\t-b dir Use the given directory as the the storage\n");
- fprintf (stderr,"\t place for backlog files and lock files.\n");
-
- fprintf (stderr,"\t-c file Use the given file as the config file instead of the\n");
- fprintf (stderr,"\t default of %s\n",CONFIG_FILE);
-
- fprintf (stderr,"\t-C Check the config file and then exit.\n") ;
- fprintf (stderr,"\t-d num set the logging level to num (an integer).\n");
- fprintf (stderr,"\t Larger value means more logging. 0 means no\n");
- fprintf (stderr,"\t logging. The default is 0\n");
-
- fprintf (stderr,"\t-e bytes Keep the output backlog files to no bigger\n");
- fprintf (stderr,"\t than %.2f times this number\n",LIMIT_FUDGE);
-
- fprintf (stderr,"\t-h print this message\n");
-
- fprintf (stderr,"\t-l file redirect stderr and stdout to the given file.\n");
- fprintf (stderr,"\t When run under INN they normally are redirected to\n");
- fprintf (stderr,"\t /dev/null. This is needed if using '-d'.\n");
-
- fprintf (stderr,"\t-m Log information on all missing articles\n");
-
- fprintf (stderr,"\t-M Turn *off* use of mmap\n") ;
-#if ! defined (HAVE_MMAP)
- fprintf (stderr,"\t (a no-op as this excutable has been built without mmap support\n") ;
-#endif
-
- fprintf (stderr,"\t-p file Write the process id to the given file\n") ;
- fprintf (stderr,"\t instead of the default of %s\n",PID_FILE);
- fprintf (stderr,"\t A relative path is relative to %s\n", innconf->pathrun) ;
-
- fprintf (stderr,"\t-s command run the given command in a subprocess and use\n");
- fprintf (stderr,"\t its output as article information instead of\n");
- fprintf (stderr,"\t running under innd\n");
-
- fprintf (stderr,"\t-S file Use the give filename instead of innfeed.status\n") ;
- fprintf (stderr,"\t relative pathnames start from %s\n", innconf->pathlog) ;
-
- fprintf (stderr,"\t-v print version information\n");
-
- fprintf (stderr,"\t-x Do not read any article information off stdin,\n");
- fprintf (stderr,"\t but simply process backlog files and then exit\n");
- fprintf (stderr,"\t when done\n");
-
- fprintf (stderr,"\t-y Add peers dynamically. If an unrecognized peername\n");
- fprintf (stderr,"\t is received from innd, then it is presumed to also\n");
- fprintf (stderr,"\t be the ip name and a new peer binding is set up\n");
-
- fprintf (stderr,"\t-z have each of the connections issue their own stats\n");
- fprintf (stderr,"\t whenever they close, or whenever their controller\n");
- fprintf (stderr,"\t issues its own stats\n");
-
- exit (val) ;
-}
-
-static void sigterm (int sig UNUSED)
-{
- notice ("ME received shutdown signal") ;
- shutDown (mainListener) ;
-}
-
-static void sigquit (int sig UNUSED)
-{
- sigterm (0) ;
-}
-
-static void sigint (int sig UNUSED)
-{
- gprintinfo () ;
-}
-
-static void sighup (int sig UNUSED)
-{
- notice ("ME reloading config file %s", configFile) ;
-
- if (!readConfig (configFile,NULL,false,loggingLevel > 0))
- {
- die ("ME config aborting, error parsing config file") ;
- }
-
- configHosts (talkToSelf) ;
-}
-
-static void sigemt (int sig UNUSED)
-{
- gFlushTapes () ;
-}
-
-static void sigalrm (int sig UNUSED)
-{
- if (InputFile == NULL)
- warn ("ME signal SIGALRM in non-funnel-file mode ignored") ;
- else
- {
- RollInputFile = true;
- syslog(LOG_NOTICE, "ME preparing to roll %s", InputFile);
- }
-}
-
-static void sigchld (int sig UNUSED)
-{
-#if 0
- wait (&status) ; /* we don't care */
-#endif
-
- xsignal (sig,sigchld) ;
-}
-
- /* SIGUSR1 increments logging level. SIGUSR2 decrements. */
-static void sigusr (int sig)
-{
- if (sig == SIGUSR1) {
- loggingLevel++ ;
- notice ("ME increasing logging level to %d", loggingLevel) ;
- } else if (sig == SIGUSR2 && loggingLevel > 0) {
- loggingLevel-- ;
- notice ("ME decreasing logging level to %d", loggingLevel) ;
- }
-}
-
-static void openLogFile (void)
-{
- FILE *fpr ;
-
- if (logFile)
- {
- fpr = freopen (logFile,"a",stdout) ;
- if (fpr != stdout)
- logAndExit (1,"freopen (%s, \"a\", stdout): %s",
- logFile, strerror (errno)) ;
-
- fpr = freopen (logFile,"a",stderr) ;
- if (fpr != stderr)
- logAndExit (1,"freopen (%s, \"a\", stderr): %s",
- logFile, strerror (errno)) ;
-
-#if defined (HAVE_SETBUFFER)
- setbuffer (stdout, NULL, 0) ;
- setbuffer (stderr, NULL, 0) ;
-#else
- setbuf (stdout, NULL) ;
- setbuf (stderr, NULL) ;
-#endif
- }
-}
-
-static void writePidFile (void)
-{
- FILE *F;
- int pid;
-
- if (pidFile == NULL)
- logAndExit (1,"NULL pidFile\n") ;
-
- /* Record our PID. */
- pid = getpid();
- if ((F = fopen(pidFile, "w")) == NULL)
- {
- syslog(LOG_ERR, "ME cant fopen %s %m", pidFile);
- }
- else
- {
- if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F))
- {
- syslog(LOG_ERR, "ME cant fprintf %s %m", pidFile);
- }
- if (fclose(F) == EOF)
- {
- syslog(LOG_ERR, "ME cant fclose %s %m", pidFile);
- }
- if (chmod(pidFile, 0664) < 0)
- {
- syslog(LOG_ERR, "ME cant chmod %s %m", pidFile);
- }
- }
-}
-
-static void gprintinfo (void)
-{
- char *snapshotFile;
- FILE *fp;
- time_t now = theTime() ;
-
- snapshotFile = buildFilename(innconf->pathlog, SNAPSHOT_FILE);
- fp = fopen (snapshotFile,"a") ;
- if (fp == NULL)
- {
- syswarn ("ME fopen %s", snapshotFile) ;
- free(snapshotFile);
- return ;
- }
- free(snapshotFile);
-
-#if defined (HAVE_SETBUFFER)
- setbuffer (fp, NULL, 0) ;
-#else
- setbuf (fp, NULL) ;
-#endif
-
- fprintf (fp,"----------------------------System snaphot taken at: %s\n",
- ctime (&now)) ;
- gPrintListenerInfo (fp,0) ;
- fprintf (fp,"\n\n\n\n") ;
- gPrintHostInfo (fp,0) ;
- fprintf (fp,"\n\n\n\n") ;
- gPrintCxnInfo (fp,0) ;
- fprintf (fp,"\n\n\n\n") ;
- gPrintArticleInfo (fp,0) ;
- fprintf (fp,"\n\n\n\n") ;
- gPrintBufferInfo (fp,0) ;
- fprintf (fp,"\n\n\n\n") ;
- fclose (fp) ;
-}
-
-/* called after the config file is loaded and after the config data has
- been updated with command line options. */
-static int mainConfigLoadCbk (void *data)
-{
- FILE *fp = (FILE *) data ;
- char *p ;
- long ival ;
- int bval ;
-
- if (getString (topScope,"news-spool", &p,NO_INHERIT))
- {
- if ( !isDirectory (p) && isDirectory (innconf->patharticles) )
- {
- logOrPrint (LOG_WARNING,fp,
- "ME config: definition of news-spool (%s) is a"
- " non-existant directory. Using %s",p,
- innconf->patharticles) ;
- p = xstrdup (innconf->patharticles) ;
- }
- else if (!isDirectory (p))
- logAndExit (1,"Bad spool directories: %s, %s\n",p,innconf->patharticles) ;
- }
- else if (!isDirectory (innconf->patharticles))
- logAndExit (1,"ME config: no definition of news-spool, and %s is no good",
- innconf->patharticles);
- else
- p = xstrdup (innconf->patharticles) ;
- newsspool = p ;
-
- /***************************************************/
-
- if (getString (topScope,"input-file",&p,NO_INHERIT))
- {
- if (*p != '\0')
- InputFile = buildFilename (getTapeDirectory(),p) ;
- else
- InputFile = "" ;
- free (p) ;
- }
-
- if (getString (topScope,"pid-file",&p,NO_INHERIT))
- {
- pidFile = buildFilename (innconf->pathrun,p) ;
- free (p) ;
- }
- else
- pidFile = buildFilename (innconf->pathrun,PID_FILE) ;
-
- if (getInteger (topScope,"debug-level",&ival,NO_INHERIT))
- loggingLevel = (unsigned int) ival ;
-
-
- if (getInteger (topScope,"initial-sleep",&ival,NO_INHERIT))
- initialSleep = (unsigned int) ival ;
-
-
- if (getBool (topScope,"use-mmap",&bval,NO_INHERIT))
- useMMap = (bval ? true : false) ;
-
-
- if (getString (topScope,"log-file",&p,NO_INHERIT))
- {
- logFile = buildFilename (innconf->pathlog,p) ;
- free (p) ;
- }
-
- /* For imap/lmtp delivering */
- if (getString (topScope,"deliver-username",&p, NO_INHERIT))
- {
- deliver_username = p;
- /* don't need to free */
- }
-
- if (getString (topScope,"deliver-authname",&p, NO_INHERIT))
- {
- deliver_authname = p;
- /* don't need to free */
- }
-
- if (getString (topScope,"deliver-password",&p, NO_INHERIT))
- {
- deliver_password = p;
- /* don't need to free */
- }
-
- if (getString (topScope,"deliver-realm",&p, NO_INHERIT))
- {
- deliver_realm = p;
- /* don't need to free */
- }
-
- if (getString (topScope,"deliver-rcpt-to",&p, NO_INHERIT))
- {
- deliver_rcpt_to = p;
- /* don't need to free */
- }
-
- if (getString (topScope,"deliver-to-header",&p, NO_INHERIT))
- {
- deliver_to_header = p;
- /* don't need to free */
- }
-
-
-
- return 1 ;
-}
-
-/*
- * called after config file is loaded but before other callbacks, so we
- * can adjust config file values from options. They will be validated in the
- * second callback.
- */
-static int mainOptionsProcess (void *data UNUSED)
-{
- value *v ;
-
- if (bopt != NULL)
- {
- if ((v = findValue (topScope,"backlog-directory",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (bopt) ;
- }
- else
- addString (topScope,"backlog-directory",xstrdup (bopt)) ;
- }
-
- if (aopt != NULL)
- {
- if ((v = findValue (topScope,"news-spool",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (aopt) ;
- }
- else
- addString (topScope,"news-spool",xstrdup (aopt)) ;
- }
-
- if (sopt != NULL)
- {
- if ((v = findValue (topScope,"status-file",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (sopt) ;
- }
- else
- addString (topScope,"status-file",xstrdup (sopt)) ;
- }
-
-
- if (Dopt)
- {
- if ((v = findValue (topScope,"debug-level",NO_INHERIT)) != NULL)
- v->v.int_val = debugLevel ;
- else
- addInteger (topScope,"debug-level",debugLevel) ;
- }
-
-
- if (eopt || talkToSelf)
- {
- if (talkToSelf)
- elimit = 0 ;
-
- if ((v = findValue (topScope,"backlog-limit",NO_INHERIT)) != NULL)
- v->v.int_val = elimit ;
- else
- addInteger (topScope,"backlog-limit",elimit) ;
- }
-
-
- if (Mopt)
- {
- if ((v = findValue (topScope,"use-mmap",NO_INHERIT)) != NULL)
- v->v.bool_val = 0 ;
- else
- addBoolean (topScope,"use-mmap",0) ;
- }
-
-
- if (popt != NULL)
- {
- if ((v = findValue (topScope,"pid-file",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (popt) ;
- }
- else
- addString (topScope,"pid-file",xstrdup (popt)) ;
- }
-
- if (Zopt)
- {
- if ((v = findValue (topScope,"connection-stats",NO_INHERIT)) != NULL)
- v->v.bool_val = 1 ;
- else
- addBoolean (topScope,"connection-stats",1) ;
- }
-
- if (lopt != NULL)
- {
- if ((v = findValue (topScope,"log-file",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (lopt) ;
- }
- else
- addString (topScope,"log-file",xstrdup (lopt)) ;
- }
-
- if (InputFile != NULL)
- {
- if ((v = findValue (topScope,"input-file",NO_INHERIT)) != NULL)
- {
- free (v->v.charp_val) ;
- v->v.charp_val = xstrdup (InputFile) ;
- }
- else
- addString (topScope,"input-file",xstrdup (InputFile)) ;
- }
-
- return 1 ;
-}
-
-
-
-static void mainCleanup (void)
-{
- free ((void *)configFile) ;
- free ((void *)pidFile) ;
- free (logFile) ;
- free (newsspool) ;
- configFile = NULL ;
- pidFile = NULL ;
- logFile = NULL ;
- newsspool = NULL ;
-}
-
-
-void mainLogStatus (FILE *fp)
-{
- fprintf (fp,"%sGlobal configuration parameters:%s\n",
- genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
- fprintf (fp," Mode: ") ;
- if (InputFile != NULL)
- fprintf (fp,"Funnel file") ;
- else if (talkToSelf)
- fprintf (fp,"Batch") ;
- else
- fprintf (fp,"Channel") ;
- if (InputFile != NULL)
- fprintf (fp," (%s)",(*InputFile == '\0' ? "stdin" : InputFile)) ;
- fprintf (fp,"\n") ;
- fprintf (fp," News spool: %s\n",newsspool) ;
- fprintf (fp," Pid file: %s\n",pidFile) ;
- fprintf (fp," Log file: %s\n",(logFile == NULL ? "(none)" : logFile));
- fprintf (fp," Debug level: %2ld Mmap: %s\n",
- (long)loggingLevel,boolToString(useMMap)) ;
- fprintf (fp,"\n") ;
-}
+++ /dev/null
-/* $Id: misc.c 7420 2005-10-09 04:40:13Z eagle $
-**
-** Helper routines for the innfeed program.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <syslog.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <time.h>
-
-/* FIXME: Default to a max length of 256 characters for path names if the
- host headers doesn't give better information. Should be replaced by the
- code from Stevens. */
-#ifndef PATH_MAX
-# define PATH_MAX 256
-#endif
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "endpoint.h"
-#include "misc.h"
-#include "tape.h"
-
-unsigned int openfds ;
-int debuggingOutput ;
-unsigned int loggingLevel ;
-char **PointersFreedOnExit ;
-
-bool debuggingDump = true ;
-extern void (*gPrintInfo) (void) ;
-void (*gCleanUp) (void) = 0 ;
-
-
-/* Log a message to stderr, called from warn or die. Mostly the same as the
- standard message_log_stderr, but prepends the date to each line. */
-void
-error_log_stderr_date(int len UNUSED, const char *fmt, va_list args, int err)
-{
- char timebuff[30];
- time_t now;
- struct tm *tm;
-
- now = time(NULL);
- tm = localtime(&now);
- strftime(timebuff, sizeof(timebuff), "%Y-%m-%d %H:%M:%S", tm);
- fprintf(stderr, "%s %s: ", timebuff,
- (message_program_name ? message_program_name : "UNKNOWN"));
- vfprintf(stderr, fmt, args);
- if (err) fprintf(stderr, ": %s", strerror(err));
- fprintf(stderr, "\n");
-}
-
-/* If desired, print out the state of innfeed, call a cleanup function, and
- then dump core. Used as an exit handler for die. */
-int
-dump_core(void)
-{
-#if SNAPSHOT_ON_DIE
- if (debuggingDump && gPrintInfo != NULL)
- (*gPrintInfo)();
-#endif
-
- if (gCleanUp != NULL)
- (*gCleanUp)();
-
- if (CORE_DIRECTORY != NULL)
- chdir(CORE_DIRECTORY);
- else
- chdir(getTapeDirectory());
-
- sleep(5);
- abort();
-
- /* Not reached. */
- return 1;
-}
-
-/* An alternate version of die, used when we don't want to dump core. This
- should somehow eventually be phased out to simplify things; it's
- basically a copy of die() from lib/error.c that ignores the cleanup
- handler and has innfeed's handlers hard-coded (ugh). */
-void
-logAndExit(int status, const char *format, ...)
-{
- va_list args;
- int length;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- va_start(args, format);
- error_log_stderr_date(length, format, args, 0);
- va_end(args);
- va_start(args, format);
- message_log_syslog_err(length, format, args, 0);
- va_end(args);
- exit(status);
-}
-
-
-
-void d_printf (unsigned int level, const char *fmt, ...)
-{
- static pid_t myPid ;
- char timeString [30] ;
- time_t now ;
- va_list ap ;
-
- if (myPid == 0)
- myPid = getpid () ;
-
- if (loggingLevel < level)
- return ;
-
- now = theTime() ;
- /* strip off leading day name */
- strlcpy (timeString, ctime (&now) + 4, sizeof (timeString)) ;
- timeString [15] = '\0' ; /* strip off trailing year and newline */
-
- va_start (ap, fmt) ;
- fprintf (stderr, "%s %s[%ld]: ",timeString,
- (message_program_name ? message_program_name : "UNKNOWN"),
- (long) myPid) ;
- vfprintf (stderr, fmt, ap) ;
- va_end (ap) ;
-}
-
-void logOrPrint (int level, FILE *fp, const char *fmt, ...)
-{
- va_list ap ;
-
- va_start (ap,fmt) ;
- if (fp != NULL)
- {
- vfprintf (fp,fmt,ap) ;
- fputc ('\n',fp) ;
- }
- else
- {
- char buffer [512] ; /* gag me */
-
- vsnprintf (buffer,sizeof (buffer),fmt,ap) ;
- syslog (level,"%s",buffer) ;
- }
- va_end (ap) ;
-}
-
-
-
-/* return true if the file exists and is a regular file. */
-bool fileExistsP (const char *filename)
-{
- struct stat buf ;
-
- if (stat (filename,&buf) < 0)
- return false ;
-
- return (S_ISREG (buf.st_mode) ? true : false) ;
-}
-
-
-bool isDirectory (const char *filename)
-{
- struct stat buf ;
-
- if (stat (filename,&buf) < 0)
- return false ;
-
- return (S_ISDIR (buf.st_mode) ? true : false) ;
-}
-
-
-
-bool getNntpResponse (char *p, int *code, char **rest)
-{
- bool rval = true ;
- int cd = 0 ;
- int digits = 0 ;
-
- if (rest)
- *rest = 0 ;
- *code = 0 ;
-
- if (p == NULL)
- return false ;
-
- while (*p && CTYPE (isspace, *p))
- p++ ;
-
- while (*p && CTYPE (isdigit, *p))
- {
- digits++ ;
- cd = (cd * 10) + (*p - '0') ;
- p++ ;
- }
-
- if (digits != 3)
- return false ;
-
- if (*p == '-')
- p++ ;
-
- while (*p && CTYPE (isspace, *p))
- p++ ;
-
- if (rest)
- *rest = p ;
-
- *code = cd ;
-
- return rval ;
-}
-
-
-
-/* Pull out a message id from a response on to a streaming command */
-char *getMsgId (const char *p)
-{
- const char *q ;
- char *rval ;
-
- while (*p && CTYPE (isspace, *p)) p++ ;
- while (*p && !CTYPE (isspace, *p)) p++ ; /* skip response code */
- while (*p && CTYPE (isspace, *p)) p++ ;
-
- if ( *p == '\0' )
- return NULL ;
-
- q = p ;
- while ( *q && !CTYPE (isspace, *q) )
- q++ ;
-
- rval = xstrndup (p, q - p) ;
-
- return rval ;
-}
-
-
-
-
-char *findNonBlankString (char *ptr, char **tail)
-{
- char *p, *q ;
-
- for (p = ptr ; *p && CTYPE (isspace, *p) ; p++)
- /* nada */ ;
- if ( ! *p )
- return NULL ;
-
- for (q = p ; *q && !CTYPE (isspace, *q) ; q++)
- /* nada */ ;
-
- *tail = q ;
-
- return p ;
-}
-
-
-/* strtok can't handle zero length tokens. */
-char *mystrtok (char *line, const char *sep)
-{
- static char *newPoint ;
- char *oldline ;
-
- if (line == NULL && newPoint == NULL)
- return NULL ;
-
- if (line != NULL)
- {
- oldline = line ;
- while (*line != '\0' && strchr (sep,*line) == NULL)
- line++ ;
-
- if (*line == '\0')
- newPoint = NULL ;
- else
- {
- newPoint = line + 1 ;
- *line = '\0' ;
- }
- }
- else
- {
- if (newPoint == NULL)
- return NULL ;
-
- oldline = newPoint ;
- line = oldline ;
-
- while (*line != '\0' && strchr (sep,*line) == NULL)
- line++ ;
-
- if (*line == '\0')
- newPoint = NULL ;
- else
- {
- newPoint = line + 1 ;
- *line = '\0' ;
- }
- }
-
- return oldline ;
-}
-
-
-
-void trim_ws (char *string)
-{
- char *p ;
- unsigned int len ;
-
- assert (string != NULL) ;
-
- len = strlen (string) ;
- if (len == 0)
- return ;
-
- for (p = string + len - 1 ; p >= string && CTYPE (isspace, *p) ; p--)
- /* nada */ ;
- *++p = '\0' ;
-}
-
-
-#if 0
-/* Scribble on top of memory we're about to free. */
-void deadBeef (void *base, size_t byteCount)
-{
- unsigned char *b = (unsigned char *) base ;
- int i ;
-
-#if 0
-
- memset (base, 0, byteCount) ;
-
-#else
-
- assert (b != NULL) ;
-
- for (i = 0 ; i < ((int) byteCount) - 4 ; i += 4)
- {
-#if 0
- *((int *) (b + i)) = 0xdeadbeef ;
-#else
- b [i + 0] = (unsigned char) 0xde ;
- b [i + 1] = (unsigned char) 0xad ;
- b [i + 2] = (unsigned char) 0xbe ;
- b [i + 3] = (unsigned char) 0xef ;
-#endif
- }
-
- switch (byteCount % 4)
- {
- case 0:
- *(b + i + 3) = (unsigned char) 0xef ;
-
- case 3:
- *(b + i + 2) = (unsigned char) 0xbe ;
-
- case 2:
- *(b + i + 1) = (unsigned char) 0xad ;
-
- case 1:
- *b = (unsigned char) 0xde ;
- }
-
-#endif
-}
-#endif
-
-/* Not using plain flock or lockf 'cause I don't want to waste file
- descriptors. This routine is based on the file shlock.c from INN. */
-bool lockFile (const char *fileName)
-{
- char buff [20] ;
- char tmpName [PATH_MAX], realName [PATH_MAX] ;
- char *p ;
- int fd, i ;
- pid_t pid = getpid () ;
-
- strlcpy (realName,fileName,sizeof (realName)) ;
- if ((p = strrchr (realName, '/')) != NULL)
- {
- *p = '\0' ;
- snprintf (tmpName, sizeof(tmpName), "%s/lockf%ld", realName,
- (long) pid) ;
- *p = '/' ;
- }
- else
- snprintf (tmpName, sizeof(tmpName), "lockf%ld", (long) pid) ;
-
- /* Create the temporary name for the lock file. */
- while ((fd = open (tmpName, O_RDWR | O_CREAT | O_EXCL, 0644)) < 0)
- {
- switch (errno)
- {
- default:
- unlink (tmpName) ;
- syswarn ("ME lock file open: %s", tmpName) ;
- return false ;
-
- case EEXIST:
- if (unlink (tmpName) < 0)
- {
- syswarn ("ME lock file unlink: %s", tmpName) ;
- return false ;
- }
- break;
- }
- }
-
- /* stick our pid in the temp file. */
- snprintf (buff,sizeof(buff),"%ld\n",(long) pid) ;
- if (write (fd,buff,(size_t) strlen (buff)) != (int) strlen (buff))
- {
- syswarn ("ME lock file pid-write") ;
- close (fd) ;
- unlink (tmpName) ;
- return false ;
- }
- close (fd) ;
-
- /* now link the real name to the temp file. */
- while (link (tmpName,realName) < 0)
- {
- switch (errno)
- {
- default: /* opps. bailing out. */
- syswarn ("ME lock file link: %s", realName) ;
- unlink (tmpName) ;
- return false ;
-
- case EEXIST:
- /* the real lock file exists. So pull out the pid in there and
- see if that process is still alive. */
- if ((fd = open (realName,O_RDONLY)) < 0)
- {
- syswarn ("ME lock file open: %s", realName) ;
- unlink (tmpName) ;
- return false ;
- }
-
- if ((i = read (fd,buff,sizeof (buff) - 1)) <= 0)
- {
- close (fd) ;
- unlink (tmpName) ;
- return false ;
- }
- close (fd) ;
-
- buff [i] = '\0' ;
- pid = (pid_t) atol (buff) ;
- if (pid <= 0)
- {
- warn ("ME lock bad-pid info in %s: %s", realName, buff) ;
- unlink (tmpName) ;
- return false ;
- }
-
- /* now send a null signal to the process named inside to see if
- it's still alive. */
- if (kill (pid,0) == 0)
- {
- warn ("ME lock in-use already: %s by pid %ld", realName,
- (unsigned long) pid);
- unlink (tmpName) ;
- return false ; /* process is still alive */
- }
-
- /* process that took out the lock is gone */
- if (unlink (realName) < 0)
- {
- syswarn ("ME lock file unlink: %s", realName) ;
- unlink (tmpName) ;
- return false ;
- }
- }
- }
-
- unlink (tmpName) ;
-
- return true ;
-}
-
-
-void unlockFile (const char *lockfile)
-{
- unlink (lockfile) ;
-}
-
-
-bool endsIn (const char *string, const char *tail)
-{
- size_t len = strlen (tail) ;
- size_t slen = strlen (string) ;
-
- if (slen < len)
- return false ;
- else if (strcmp (string + slen - len, tail) == 0)
- return true ;
- else
- return false ;
-}
-
-
-/* append the contents of src to dest. src is removed if append if
- successful */
-bool appendFile (const char *dest, const char *src)
-{
- FILE *inTmp, *outTmp ;
- char buff [BUFSIZ] ;
- size_t rval ;
-
- /* append the outputFilename file to the inputFilename file */
- if ((outTmp = fopen (dest, "a")) == NULL)
- die ("fopen (%s): %s",dest, strerror (errno)) ;
- if ((inTmp = fopen (src, "r")) == NULL)
- die ("fopen (%s): %s",src, strerror (errno)) ;
-
- while ((rval = fread (buff,sizeof (char),BUFSIZ,inTmp)) > 0)
- {
- if (fwrite (buff,sizeof (char), rval, outTmp) != rval)
- die ("fwrite: %s", strerror (errno)) ;
- }
-
- if (ferror (inTmp))
- die ("Error on inTmp in newTape") ;
- if (ferror (outTmp))
- die ("Error on outTmp in newTape") ;
-
- if (fclose (inTmp) != 0)
- die ("fclose (inTmp): appendFile (%s,%s): %s",dest,src,strerror (errno)) ;
-
- if (fclose (outTmp) != 0)
- die ("fclose (outTmp): appendFile (%s,%s): %s",dest,src,strerror (errno)) ;
-
- if (unlink (src) != 0)
- die ("unlink (%s): %s", src, strerror (errno)) ;
-
- return true ;
-}
-
-
-/* return true if file1 is older than file2 */
-bool isOlder (const char *file1, const char *file2)
-{
- struct stat buf1 ;
- struct stat buf2 ;
-
- if (stat (file1,&buf1) < 0)
- return false ;
-
- if (stat (file2,&buf2) < 0)
- return false ;
-
- return ((buf1.st_mtime < buf2.st_mtime) ? true : false) ;
-}
-
-
-void freeCharP (char *charp)
-{
- free (charp) ;
-}
-
-
-/* return the length of the file reference by the given file descriptor */
-long fileLength (int fd)
-{
- struct stat buf ;
-
- if (fstat (fd,&buf) < 0)
- return false ;
-
- return ((long) buf.st_size) ;
-}
-
-
-
-const char *boolToString (bool val)
-{
- return val ? "true" : "false" ;
-}
-
-void addPointerFreedOnExit (char *pointerToFree)
-{
- static int totalPointers = 0 ;
- static int nextPointer = 0 ;
-
- if (nextPointer == 0 || nextPointer == totalPointers - 1)
- {
- int i;
-
- totalPointers += 16 ;
- if (PointersFreedOnExit == NULL)
- PointersFreedOnExit = xmalloc (sizeof(char *) * totalPointers) ;
- else
- PointersFreedOnExit =
- xrealloc (PointersFreedOnExit, sizeof(char *) * totalPointers) ;
-
- for (i = nextPointer; i < totalPointers; i++)
- PointersFreedOnExit [i] = NULL;
- }
- PointersFreedOnExit [nextPointer++] = pointerToFree ;
-}
-
-/* malloc a buffer and build the filename in it. */
-char *buildFilename (const char *directory, const char *fname)
-{
- int len = 0 ;
- char *p = NULL ;
-
- if (fname == NULL)
- return NULL ;
-
- if (directory == NULL)
- directory = "." ;
-
- len = strlen (directory) + strlen (fname) + 2 + 1 ;
-
- if (len < pathMax(directory) - 2)
- {
- p = xmalloc (len) ;
- p [0] = '\0' ;
- if (fname [0] != '/')
- {
- strlcat (p,directory,len) ;
- if (p [strlen(p) - 1] != '/')
- strlcat (p,"/",len) ;
- }
- strlcat (p,fname,len) ;
- }
-
- return p ;
-}
-
-
-
-/* borrows heavily from the shrinkfile program by chongo. */
-bool shrinkfile (FILE *fp, long size, char *name, const char *mode)
-{
- long currlen = ftello (fp) ;
- char *tmpname ;
- char buffer [BUFSIZ] ;
- FILE *tmpFp ;
- int c ;
- int i ;
- int fd ;
-
- if (currlen <= size)
- {
- d_printf (1,"No need to shrink file (%s %ld vs %ld\n",
- name,size,currlen) ;
- return true ;
- }
-
- /* create a temp file. */
- tmpname = concat (name,".XXXXXX",(char *)0) ;
- fd = mkstemp (tmpname) ;
-
- if (fd < 0)
- {
- syswarn ("ME error creating temp shrink file for %s", name) ;
- free (tmpname) ;
- return false ;
- }
-
- if ((tmpFp = fdopen (fd,"w")) == NULL)
- {
- syswarn ("ME error opening temp shrink file %s", tmpname) ;
- free (tmpname) ;
- return false ;
- }
-
- if (fseeko (fp,currlen - size,SEEK_SET) != 0)
- {
- fclose (tmpFp) ;
- warn ("ME error seeking to point %ld in %s", currlen - size, name) ;
- free (tmpname) ;
- return false ;
- }
-
- /* find the end of the next line in the shrinking file. */
- while ((c = fgetc (fp)) != '\n')
- if (c == EOF)
- {
- warn ("ME no newline in shrinking file %s", name) ;
- fclose (tmpFp) ;
- fseeko (fp,currlen,SEEK_SET) ;
- free (tmpname) ;
- return false ;
- }
-
- /* copy the tail of the shrinking file to the temp file. */
- while ((i = fread (buffer,1,sizeof (buffer),fp)) > 0)
- {
- if (fwrite (buffer,1,i,tmpFp) != (size_t) i)
- {
- fclose (tmpFp) ;
- syswarn ("ME fwrite failed to temp shrink file %s", tmpname) ;
- fseeko (fp,currlen, SEEK_SET) ;
- free (tmpname) ;
- return false ;
- }
- }
-
- if (i < 0)
- logAndExit (1,"ME fread failed on file %s: %s",name, strerror (errno)) ;
-
- fclose (tmpFp) ;
-
- if (unlink (name) != 0)
- logAndExit (1,"ME oserr unlink %s: %s",name, strerror (errno)) ;
-
- /* we're in the same directory so this is ok. */
- if (rename (tmpname,name) != 0)
- logAndExit (1,"ME oserr rename %s, %s: %s", tmpname, name,
- strerror (errno)) ;
-
- if (freopen (name,mode,fp) != fp)
- logAndExit (1,"ME freopen on shrink file failed %s: %s", name,
- strerror (errno)) ;
-
- fseeko (fp,0,SEEK_END) ;
- size = ftello (fp) ;
-
- notice ("ME file %s shrunk from %ld to %ld", name, currlen, size) ;
-
- free (tmpname) ;
-
- return true ;
-}
-
-
-
-long pathMax (const char *pathname UNUSED)
-{
- static long rval = 0 ;
-
- if (rval > 0)
- return rval ;
-
-#if defined (PATH_MAX)
-
- rval = PATH_MAX ;
-
-#elif defined (_POSIX_PATH_MAX)
-
- rval = _POSIX_PATH_MAX ;
-
-#elif defined (DO_HAVE_PATHCONF) && defined (_PC_PATH_MAX)
-
- if (pathname == NULL)
- pathname = "/tmp" ;
-
- rval = pathconf (pathname,_PC_PATH_MAX) ;
-
-#else
-
- rval = 255 ;
- if (!logged)
- {
- syslog (LOG_ERR,NO_PATH_MAX,rval) ;
- logged = true ;
- }
-
-#endif
-
- return rval ;
-}
+++ /dev/null
-/* $Id: misc.h 6648 2004-01-25 20:07:11Z rra $
-**
-** Miscellaneous utility functions for innfeed.
-**
-** Written by James Brister <brister@vix.com>
-*/
-
-#if ! defined ( misc_h__ )
-#define misc_h__
-
-#include "config.h"
-
-#include <stdarg.h>
-#include <sys/types.h>
-
-/* These typedefs are all here because C is too stupid to let me multiply
- define typedefs to the same things (as C++ will). Hence I can't redeclare
- the typedefs to get around recursive header file includes (like host.h and
- connection.h would need if they contained their own typedefs). */
-
-typedef struct article_s *Article ; /* see article.h */
-typedef struct buffer_s *Buffer ; /* see buffer.h */
-typedef struct commander_s *Commander ; /* see commander.h */
-typedef struct config_s *Config ; /* see config.h */
-typedef struct connection_s *Connection ; /* see connection.h */
-typedef struct endpoint_s *EndPoint ; /* see endpoint.h */
-typedef struct host_s *Host ; /* see host.h */
-typedef struct innlistener_s *InnListener ; /* see innlistener.h */
-typedef struct tape_s *Tape ; /* see tape.h */
-
-typedef int TimeoutId ; /* see endpoint.h */
-typedef enum { /* see endpoint.h */
- IoDone, IoIncomplete, IoFailed, IoEOF, IoProgress
-} IoStatus ;
-
-typedef void (*EndpRWCB) (EndPoint e, /* see endpoint.h */
- IoStatus i, Buffer *b, void *d) ;
-typedef void (*EndpTCB) (TimeoutId tid, void *d) ; /* see endpoint.h */
-typedef void (*EndpWorkCbk) (EndPoint ep, void *data) ;
-
-
-/* debugging information */
-extern unsigned int loggingLevel ; /* if 0 then d_printf is a no-op */
-
-/* the current count of file desccriptors */
-extern unsigned int openfds ;
-
-/* if level <= loggingLevel then print */
-void d_printf (unsigned int level, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3)));
-
-/* for the gethostbyname() error code */
-const char *host_err_str (void) ;
-
-/* parse a reponse line into it's code and body. *rest will end up pointing
- into the middle of p */
-bool getNntpResponse (char *p, int *code, char **rest) ;
-
-/* parse out the first field of a nntp response code as a message-id. Caller
- must free the return value when done. */
-char *getMsgId (const char *p) ;
-
-/* pick out the next non-blank string inside PTR. TAIL is set to point at
- the first blank (or NULL) after the string. Returns a pointer into PTR */
-char *findNonBlankString (char *ptr, char **tail) ;
-
-/* if fp is not NULL then print to it, otherwise syslog at the level. */
-void logOrPrint (int level, FILE *fp, const char *fmt, ...)
- __attribute__ ((__format__ (printf, 3, 4)));
-
-/* Error handling functions for use with warn and die. */
-void error_log_stderr_date(int len, const char *fmt, va_list args, int err);
-
-/* Do cleanup and then abort, for use with die. */
-int dump_core(void);
-
-/* Alternate die that doesn't invoke an error handler. */
-void logAndExit (int exitVal, const char *fmt, ...)
- __attribute__ ((__format__ (printf, 2, 3)));
-
-/* return true of the file exists and is a regular file */
-bool fileExistsP (const char *filename) ;
-
-/* return true if file exists and is a directory */
-bool isDirectory (const char *filename) ;
-
-char *mystrtok (char *string, const char *sep) ;
-
-/* remove trailing whitespace */
-void trim_ws (char *string) ;
-
-/* locks the peer and returns true or returns false */
-bool lockPeer (const char *peerName) ;
-
-/* return true if the end of string matches tail. */
-bool endsIn (const char *string, const char *tail) ;
-
-/* scribble over then free up the null-terminated string */
-void freeCharP (char *charp) ;
-
-/* append the contents of src to dest. src is removed if append if
- successful */
-bool appendFile (const char *dest, const char *src) ;
-
-/* return the length of the file reference by the given file descriptor */
-long fileLength (int fd) ;
-
-bool lockFile (const char *fileName) ;
-void unlockFile (const char *lockfile) ;
-
-
-/* return true if file1 is older than file2 */
-bool isOlder (const char *file1, const char *file2) ;
-
-/* converts val into a printable string */
-const char *boolToString (bool val) ;
-
-/* memory leak checker helper. */
-void addPointerFreedOnExit (char *pointerToFree) ;
-
-/* splice direcotory and fname together and return free'able string */
-char *buildFilename (const char *directory, const char *fname) ;
-
-/* string the file opened by FP to the give SIZE. The NEWNAME is the name
- of the file to have after truncation. FP will be reopened for writing on
- the new file and will be positioned at the end */
-bool shrinkfile (FILE *fp, long size, char *name, const char *mode) ;
-
-/* max length of pathname */
-long pathMax (const char *pathname) ;
-
-#define ASSERT(x) do{if (!(x))die("assertion -- %s -- failed in file %s line %d",#x,__FILE__,__LINE__);}while(0)
-
-#define INDENT_INCR 5
-#define INDENT_BUFFER_SIZE 80
-#if ! defined (MIN)
-#define MIN(A,B) ((A) < (B) ? (A) : (B))
-#endif
-
-#endif /* misc_h__ */
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Thu May 16 10:32:02 1996 +0200
-# Project: INN -- innfeed
-# File: procbatch.pl
-# RCSId: $Id: procbatch.in 6648 2004-01-25 20:07:11Z rra $
-#
-# Description: Take a file of the form generated by innd in the out.going
-# directory ("Wnm*") and separate it into tape files for inn.
-#
-# Thanks to Clayton O'Neill <coneill@premier.net> for serious speed
-# improvments.
-#
-
-#
-# Hmm, perhaps we should try to read "backlog-directory"
-# from innfeed.conf. Oh well.
-#
-$tapeDir = $inn'pathspool . "/innfeed"; #'
-$destDir = $inn'spooltemp ; #'
-$spoolArts = $inn'patharticles ; #'
-$outGoing = $inn'pathoutgoing; #'
-
-##
-## Everything below here should probably be left alone.
-##
-
-$0 =~ s!.*/!! ;
-
-require 'getopts.pl' ;
-
-$usage = "$0 [ -q ][ -v ][ -u ][ -e host ][ -d dir ][ -c [ -s dir ]][ -m [-t dir ]] inn-batchfile\n
- -e host to process on entries for only that host
- -d dir to put the output file(s) in that directory ($destDir)
- -c to check pathnames of articles before storing them
- -s dir to specify where the news articles are
- ($spoolArts)
- -m to have $0 move the new files to the backlog directory.
- -t dir to specify the backlog directory ($tapeDir)
- -u to unlink the input files when finished
- -v for verbosity
- -q quiet mode; only display error messages. Good for cron jobs.
-
-$0 will take an inn funnel file (normally a file in
-$outGoing), or an innfeed ``dropped'' file,
-which is presumed to be of the format:
-
- pathname message-id peer1 peer2 peer3 ...
-
-and will break it up into files peer1.tmp peer2.tmp peer3.tmp... Each of
-these files wil be of the format:
-
- pathname message-id
-
-that is the same as innfeed's backlog file format. Simply rename these files
-to peer1 peer2 peer3 in a running innfeed's backlog directory and they will be
-picked up automatically and processed by innfeed. Use the '-m' flag and
-they'll be moved automatically.
-" ;
-
-$opt_u = $opt_h = ""; # shut up, perl -w
-&Getopts ("he:t:s:d:cvumq") || die $usage ;
-
-die $usage if ( $opt_h ) ;
-die "Cannot specify both -q and -v\n\n" . $usage if ($opt_q && $opt_v);
-
-$spoolArts = $opt_s if $opt_s ;
-$destDir = $opt_d if $opt_d ;
-$tapeDir = $opt_t if $opt_t ;
-$inputFile = shift ;
-
-die $usage if !$inputFile ;
-unless (-f $inputFile) {
- exit if $opt_q;
- die "No such file: $inputFile\n\n" . $usage;
-}
-die "No such directory: $spoolArts\n\n" . $usage if ( ! -d $spoolArts && $opt_c ) ;
-die "No such directory: $destDir\n\n" . $usage if ( ! -d $destDir ) ;
-die "No such directory: $tapeDir\n\n" . $usage if ( ! -d $tapeDir && $opt_m ) ;
-
-print "Using $inputFile\n" if $opt_v ;
-open (INPUT,"<$inputFile") || die "$0: open ($inputFile): $!\n" ;
-
-while (<INPUT>) {
- chop ;
- @F = split ;
-
- # Check the format of the line vigorously
- next unless (m!^\S+/\d+ <.+@.+> \S+! || m!^@[0-9A-F]+@ <.+@.+> \S+!) ;
-
- if ( $opt_c ) {
- if ( ! -f "$spoolArts/$F[0]" ) {
- $missing++ ;
- print "Dropping file: $spoolArts/$F[0]\n" if $opt_v ;
- next ;
- }
- }
-
- for ($i = 2 ; $i <= $#F ; $i++) {
- $host = $F[$i] ;
- next if ($opt_e && $opt_e ne $host) ;
-
- # Keep out host names with any funny characters (from
- # corrupted files)
- if ($host !~ /^[-\._0-9A-Za-z]+$/) {
- warn "$0: bad site name ignored: \"$host\"\n";
- next;
- }
-
- if ($hosts{$host}) {
- print {$hosts{$host}} "$F[0] $F[1]\n";
- } else {
- $outputFile = "$destDir/$host.tmp" ;
- print "Starting $host\n" if ($opt_v);
- $hosts{$host}=$host;
- open ($hosts{$host},">>$outputFile") ||
- die "open >>$outputFile: $!\n" ;
- print {$hosts{$host}} "$F[0] $F[1]\n";
- }
- }
-}
-close (INPUT) ;
-
-foreach $host (keys %hosts) {
- close($hosts{$host});
- $outputFile = "$destDir/$host.tmp" ;
- $tmpTape = "$tapeDir/$host.tmp" ;
- $tapeFile = "$tapeDir/$host" ;
- if ( $opt_m ) {
- if ($outputFile ne $tmpTape) {
- $cmd = "mv $outputFile $tmpTape" ;
- system ($cmd) ;
- die "$0: $cmd: failed\n" unless ($? == 0) ;
- }
-
- $cmd = "cat $tmpTape |sort -u >> $tapeFile && rm -f $tmpTape" ;
- system ($cmd) ;
- die "$0: $cmd: failed\n" unless ($? == 0) ;
- }
-}
-
-unlink($inputFile) if ($opt_u);
-
-print "$missing articles dropped\n" if ( $opt_v && $missing > 0 ) ;
+++ /dev/null
-/* $Id: startinnfeed.c 7065 2004-12-19 21:49:18Z rra $
-**
-** Raise system limits and exec innfeed.
-**
-** This is a setuid root wrapper around innfeed to increase system limits
-** (file descriptor limits and stack and data sizes). In order to prevent
-** abuse, it uses roughly the same security model as inndstart; only the
-** news user can run this program, and it attempts to drop privileges when
-** doing operations that don't require it.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <syslog.h>
-#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
-
-/* FreeBSD 3.4 RELEASE needs <sys/time.h> before <sys/resource.h>. */
-#if HAVE_SETRLIMIT
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# endif
-# include <sys/resource.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-/* Options for debugging malloc. */
-#ifdef USE_DMALLOC
-# define DMALLOC_OPTIONS \
- "DMALLOC_OPTIONS=debug=0x4e405c3,inter=100,log=innfeed-logfile"
-#endif
-
-
-int
-main(int argc, char *argv[])
-{
- struct passwd * pwd;
- struct group * grp;
- uid_t news_uid;
- gid_t news_gid;
- char ** innfeed_argv;
- char * spawn_path;
- int i;
-
-#if HAVE_SETRLIMIT
- struct rlimit rl;
-#endif
-
- openlog("innfeed", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_handlers_warn(1, message_log_syslog_warning);
- message_handlers_die(1, message_log_syslog_err);
-
- /* Convert NEWSUSER and NEWSGRP to a UID and GID. getpwnam() and
- getgrnam() don't set errno normally, so don't print strerror() on
- failure; it probably contains garbage.*/
- pwd = getpwnam(NEWSUSER);
- if (!pwd) die("can't getpwnam(%s)", NEWSUSER);
- news_uid = pwd->pw_uid;
- grp = getgrnam(NEWSGRP);
- if (!grp) die("can't getgrnam(%s)", NEWSGRP);
- news_gid = grp->gr_gid;
-
- /* Exit if run by another user. */
- if (getuid() != news_uid)
- die("ran by UID %lu, who isn't %s (%lu)", (unsigned long) getuid(),
- NEWSUSER, (unsigned long) news_uid);
-
- /* Drop privileges to read inn.conf. */
- if (seteuid(news_uid) < 0)
- sysdie("can't seteuid(%lu)", (unsigned long) news_uid);
- if (!innconf_read(NULL))
- exit(1);
-
- /* Regain privileges to increase system limits. */
- if (seteuid(0) < 0) sysdie("can't seteuid(0)");
- if (innconf->rlimitnofile >= 0)
- if (setfdlimit(innconf->rlimitnofile) < 0)
- syswarn("can't set file descriptor limit to %ld",
- innconf->rlimitnofile);
-
- /* These calls will fail on some systems, such as HP-UX 11.00. On those
- systems, we just blindly assume that the stack and data limits are
- high enough (they generally are). */
-#if HAVE_SETRLIMIT
- rl.rlim_cur = RLIM_INFINITY;
- rl.rlim_max = RLIM_INFINITY;
-# ifdef RLIMIT_DATA
- setrlimit(RLIMIT_DATA, &rl);
-# endif
-#endif /* HAVE_SETRLIMIT */
-
- /* Permanently drop privileges. */
- if (setuid(news_uid) < 0 || getuid() != news_uid)
- sysdie("can't setuid to %lu", (unsigned long) news_uid);
-
- /* Check for imapfeed -- continue to use "innfeed" in variable
- names for historical reasons regardless */
- if ((argc > 1) && (strcmp(argv[1],"imapfeed") == 0))
- {
- argc--;
- argv++;
- spawn_path = concat(innconf->pathbin, "/imapfeed", (char *) 0);
- }
- else
- spawn_path = concat(innconf->pathbin, "/innfeed", (char *) 0);
-
-
- /* Build the argument vector for innfeed. */
- innfeed_argv = xmalloc((argc + 1) * sizeof(char *));
- innfeed_argv[0] = spawn_path;
- for (i = 1; i <= argc; i++)
- innfeed_argv[i] = argv[i];
- innfeed_argv[argc] = NULL;
-
- /* Set debugging malloc options. */
-#ifdef USE_DMALLOC
- putenv(DMALLOC_OPTIONS);
-#endif
-
- /* Exec innfeed. */
- execv(innfeed_argv[0], innfeed_argv);
- sysdie("can't exec %s", innfeed_argv[0]);
-
- /* Not reached. */
- return 1;
-}
+++ /dev/null
-/* $Id: tape.c 6716 2004-05-16 20:26:56Z rra $
-**
-** The implementation of the innfeed Tape class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The implementation of the Tape class. Tapes are read-only or write-only
-** files that are accessed sequentially. Their basic unit of i/o is an
-** Article. Tapes work out of a single directory and manage all file names
-** themselves.
-**
-** Tapes will checkpoint themselves periodically so that when innfeed exits
-** or crashes things can restart close to where they were last. The period
-** checkpointing is handled entirely by the Tape class, but the checkpoint
-** period needs to be set by some external user before the first tape is
-** created.
-*/
-
-#include "innfeed.h"
-#include "config.h"
-#include "clibrary.h"
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#if defined (HAVE_DIRENT_H)
-#include <dirent.h>
-typedef struct dirent DIRENTRY ;
-#else
-#include <sys/dir.h>
-typedef struct direct DIRENTRY ;
-#endif
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-
-#include "article.h"
-#include "configfile.h"
-#include "endpoint.h"
-#include "tape.h"
-
-extern char *dflTapeDir;
-extern bool genHtml ;
-
-#if 0
-/* a structure for temporary storage of articles. */
-typedef struct q_e_s
-{
- Article article ;
- struct q_e_s *next ;
-} *QueueElem ;
-#endif
-
-/* The Tape class type. */
-struct tape_s
-{
- /* the pathname of the file the administrator can drop in by hand. */
- char *handFilename ;
-
- /* the pathname of the file the Tape will read from */
- char *inputFilename ;
-
- /* the pathname of the file the Tape will write to. */
- char *outputFilename ;
-
- /* the pathname of the file used in locking */
- char *lockFilename ;
-
- /* the peer we're doing this for. */
- char *peerName ;
-
- FILE *inFp ; /* input FILE */
- FILE *outFp ; /* output FILE */
-
- time_t lastRotated ; /* time files last got switched */
- bool checkNew ; /* set bool when we need to check for
- hand-crafted file. */
-
-#if 0
- /* the tape holds a small output queue in memory to avoid thrashing. */
- QueueElem head ;
- QueueElem tail ;
- unsigned int qLength ; /* amount on the queue */
-#endif
-
- long outputSize ; /* the current size of the output file. */
- long lossage ;
-
- /* the number of bytes we try to keep the output under. We actually
- wait for the outputSize to get 10% greater than this amount before
- shrinking the file down again. A value of zero means no limit. */
- long outputLowLimit ;
- long outputHighLimit ;
- double backlogFactor ;
-
- bool scribbled ; /* have we scribbled a checkpoint value in
- the file. */
- long tellpos ; /* for input file checkpointing. */
- bool changed ; /* true if tape was read since last
- checkpoint or start. */
-
- /* true if articles that are output are NOT later input. */
- bool noRotate ;
-
- /* true if no articles should ever be spooled */
- bool noBacklog ;
-};
-
-
-static void checkpointTape (Tape tape) ;
-static void removeTapeGlobally (Tape tape) ;
-static void addTapeGlobally (Tape tape) ;
-static void prepareFiles (Tape tape) ;
-static void tapeCkNewFileCbk (TimeoutId id, void *d) ;
-static void tapeCheckpointCallback (TimeoutId id, void *d) ;
-#if 0
-static void flushTape (Tape tape) ;
-#endif
-static void tapesSetCheckNew (void) ;
-static void initTape (Tape nt) ;
-static void tapeCleanup (void) ;
-
-
-
-/* pathname of directory we store tape files in. */
-static char *tapeDirectory ;
-
-/* the callback ID of the checkpoint timer callback. */
-static TimeoutId checkPtId ;
-static TimeoutId ckNewFileId ;
-
-/* number of seconds between tape checkpoints. */
-static unsigned int tapeCkPtPeriod ;
-static unsigned int tapeCkNewFilePeriod ;
-
-static time_t rotatePeriod = TAPE_ROTATE_PERIOD ;
-
-/* global list of tapes so we can checkpoint them periodically */
-static Tape *activeTapes ;
-
-/* Size of the activeTapes array */
-static size_t activeTapeSize ;
-
-/* index of last element in activeTapes that's being used. */
-static size_t activeTapeIdx ;
-
-#if 0
-/* default limit of the size of output tapes. */
-static long defaultSizeLimit ;
-#endif
-
-unsigned int tapeHighwater ;
-
-bool debugShrinking = false ;
-
-extern bool talkToSelf ; /* main.c */
-
-
-
-
-/* callback when config file is loaded */
-int tapeConfigLoadCbk (void *data)
-{
- int rval = 1 ;
- long iv ;
- int bv ;
- FILE *fp = (FILE *) data ;
- char *dir, *p ;
-
- if (getString (topScope,"backlog-directory",&p,NO_INHERIT))
- {
- dir = buildFilename(innconf->pathspool, p);
- free(p);
- if (tapeDirectory != NULL && strcmp (tapeDirectory,dir) != 0)
- {
- warn ("ME config: cannot change backlog-directory of a running"
- " process") ;
- free (dir) ;
- dir = xstrdup (tapeDirectory) ;
- }
-
- if (!isDirectory (dir) && isDirectory (dflTapeDir))
- {
- logOrPrint (LOG_ERR,fp,
- "ME config: definition of backlog-directory (%s) is a"
- " non-existant directory. Using %s",
- dir,dflTapeDir) ;
- free (dir) ;
- dir = xstrdup (dflTapeDir) ;
- }
- else if (!isDirectory (dir))
- logAndExit (1,"ME config: no usable value for backlog-directory") ;
- }
- else if (!isDirectory (dflTapeDir))
- {
- logAndExit (1,"ME config: no usable value for backlog-directory") ;
- return -1; /* not reached */
- }
- else
- dir = xstrdup (dflTapeDir) ;
-
- if (tapeDirectory != NULL)
- free (tapeDirectory) ;
- tapeDirectory = dir ;
-
-
-
- if (getInteger (topScope,"backlog-highwater",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld","backlog-highwater",
- iv,"global scope",(long)TAPE_HIGHWATER);
- iv = TAPE_HIGHWATER ;
- }
- }
- else
- iv = TAPE_HIGHWATER ;
- tapeHighwater = (unsigned int) iv ;
-
-
-
- if (getInteger (topScope,"backlog-rotate-period",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld",
- "backlog-rotate-period",
- iv,"global scope",(long)TAPE_ROTATE_PERIOD);
- iv = TAPE_ROTATE_PERIOD ;
- }
- }
- else
- iv = TAPE_ROTATE_PERIOD ;
- rotatePeriod = (unsigned int) iv ;
-
-
- if (getInteger (topScope,"backlog-ckpt-period",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld",
- "backlog-ckpt-period",iv,
- "global scope",(long)TAPE_CHECKPOINT_PERIOD);
- iv = TAPE_CHECKPOINT_PERIOD ;
- }
- }
- else
- iv = TAPE_CHECKPOINT_PERIOD ;
- tapeCkPtPeriod = (unsigned int) iv ;
-
-
- if (getInteger (topScope,"backlog-newfile-period",&iv,NO_INHERIT))
- {
- if (iv < 0)
- {
- rval = 0 ;
- logOrPrint (LOG_ERR,fp,
- "ME config: value of %s (%ld) in %s cannot be less"
- " than 0. Using %ld",
- "backlog-newfile-period",
- iv,"global scope",(long)TAPE_NEWFILE_PERIOD);
- iv = TAPE_NEWFILE_PERIOD ;
- }
- }
- else
- iv = TAPE_NEWFILE_PERIOD ;
- tapeCkNewFilePeriod = (unsigned int) iv ;
-
-
- if (getBool (topScope,"debug-shrinking",&bv,NO_INHERIT))
- debugShrinking = (bv ? true : false) ;
-
- return rval ;
-}
-
-
-/* Create a new Tape object. There are three potential files involved in
- I/O. 'peerName' is what the admin may have dropped in by
- hand. 'peerName.input' is the file that was being used as input the last
- time things were run. 'peerName.output' is the file that was being used
- as output. The file 'peerName' is appended to 'peerName.input' (or
- renamed if 'peerName.input' doesn't exist). Then 'peerName.output' is
- appeneded (or renamed) to 'peerName.input' */
-
-static bool inited = false ;
-Tape newTape (const char *peerName, bool dontRotate)
-{
- Tape nt = xmalloc (sizeof(struct tape_s)) ;
- size_t pLen = strlen (peerName) ;
- size_t dLen = strlen (tapeDirectory) ;
-
- if (!inited)
- {
- inited = true ;
- atexit (tapeCleanup) ;
- }
-
- ASSERT (nt != NULL) ;
-
- if (endsIn (peerName,INPUT_TAIL))
- die ("Sorry, can't have a peer name ending in \"%s\"",INPUT_TAIL) ;
-
- if (endsIn (peerName,OUTPUT_TAIL))
- die ("Sorry, can't have a peer name ending in \"%s\"",OUTPUT_TAIL) ;
-
- if (endsIn (peerName,LOCK_TAIL))
- die ("Sorry, can't have a peer name ending in \"%s\"",LOCK_TAIL) ;
-
- nt->peerName = xstrdup (peerName) ;
-
- nt->handFilename = xmalloc (pLen + dLen + 2) ;
- sprintf (nt->handFilename,"%s/%s",tapeDirectory,peerName) ;
-
- nt->lockFilename = xmalloc (pLen + dLen + strlen(LOCK_TAIL) + 2) ;
- sprintf (nt->lockFilename,"%s/%s%s",tapeDirectory,peerName,LOCK_TAIL) ;
-
- nt->inputFilename = xmalloc (pLen + dLen + strlen(INPUT_TAIL) + 2) ;
- sprintf (nt->inputFilename,"%s/%s%s",tapeDirectory,peerName,INPUT_TAIL) ;
-
- nt->outputFilename = xmalloc (pLen + dLen + strlen(OUTPUT_TAIL) + 2) ;
- sprintf (nt->outputFilename,"%s/%s%s",tapeDirectory,peerName,OUTPUT_TAIL) ;
-
- if ( !lockFile (nt->lockFilename) )
- {
- warn ("ME lock failed for host: %s", nt->lockFilename) ;
-
- free (nt->handFilename) ;
- free (nt->lockFilename) ;
- free (nt->inputFilename) ;
- free (nt->outputFilename) ;
- free (nt) ;
-
- return NULL ;
- }
-
- nt->noRotate = false ; /* for first time prepare */
- initTape (nt) ;
- nt->noRotate = dontRotate ;
-
- addTapeGlobally (nt) ;
-
- if (checkPtId == 0 && tapeCkPtPeriod > 0) /* only done once. */
- checkPtId = prepareSleep (tapeCheckpointCallback,tapeCkPtPeriod,NULL);
-
- if (ckNewFileId == 0 && tapeCkNewFilePeriod > 0)
- ckNewFileId = prepareSleep (tapeCkNewFileCbk,tapeCkNewFilePeriod,NULL) ;
-
- return nt ;
-}
-
-static void initTape (Tape nt)
-{
- value *peerVal = findPeer (nt->peerName) ;
- scope *s = (peerVal == NULL ? NULL : peerVal->v.scope_val) ;
-
- nt->inFp = NULL ;
- nt->outFp = NULL ;
-
- nt->lastRotated = 0 ;
- nt->checkNew = false ;
-
-#if 0
- nt->head = NULL ;
- nt->tail = NULL ;
- nt->qLength = 0 ;
-#endif
-
- nt->scribbled = false ;
- nt->tellpos = 0 ;
-
- nt->changed = false ;
-
- nt->outputSize = 0 ;
- nt->lossage = 0 ;
-
- nt->noBacklog = false ;
- nt->backlogFactor = 0.0 ;
- nt->outputLowLimit = 0 ;
- nt->outputHighLimit = 0 ;
-
- if (!talkToSelf)
- {
- int bval ;
-
- if (getBool (s, "no-backlog", &bval, INHERIT))
- nt->noBacklog = (bval ? true : false);
- else
- nt->noBacklog = TAPE_DISABLE;
-
- if (getInteger (s,"backlog-limit",&nt->outputLowLimit,INHERIT))
- {
- if (!getReal (s,"backlog-factor",&nt->backlogFactor,INHERIT))
- {
- if (!getInteger (s,"backlog-limit-highwater",
- &nt->outputHighLimit,INHERIT))
- {
- warn ("%s no backlog-factor or backlog-high-limit",
- nt->peerName) ;
- nt->outputLowLimit = 0 ;
- nt->outputHighLimit = 0 ;
- nt->backlogFactor = 0.0 ;
- }
- }
- else
- nt->outputHighLimit = (long)(nt->outputLowLimit * nt->backlogFactor);
- }
- else
- warn ("ME config: no definition for required key backlog-limit") ;
- }
-
- d_printf (1, "%s spooling: %s\n", nt->peerName,
- nt->noBacklog ? "disabled" : "enabled");
-
- d_printf (1,"%s tape backlog limit: [%ld %ld]\n",nt->peerName,
- nt->outputLowLimit,
- nt->outputHighLimit) ;
-
- prepareFiles (nt) ;
-}
-
-
-void gFlushTapes (void)
-{
- unsigned int i ;
-
- notice ("ME flushing tapes") ;
- for (i = 0 ; i < activeTapeIdx ; i++)
- tapeFlush (activeTapes [i]) ;
-}
-
-
-
-/* close the input and output tapes and reinitialize everything in the
- tape. */
-void tapeFlush (Tape tape)
-{
- if (tape->inFp != NULL)
- {
- checkpointTape (tape) ;
- fclose (tape->inFp) ;
- }
-
- if (tape->outFp != NULL)
- fclose (tape->outFp) ;
-
- initTape (tape) ;
-}
-
-
-
-void gPrintTapeInfo (FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sGlobal Tape List : (count %lu) {\n",
- indent,(unsigned long) activeTapeIdx) ;
-
- for (i = 0 ; i < activeTapeIdx ; i++)
- printTapeInfo (activeTapes [i],fp,indentAmt + INDENT_INCR) ;
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-void tapeLogGlobalStatus (FILE *fp)
-{
- fprintf (fp,"%sBacklog file global values:%s\n",
- genHtml ? "<B>" : "", genHtml ? "</B>" : "") ;
- fprintf (fp," directory: %s\n",tapeDirectory) ;
- fprintf (fp," rotate period: %-3ld seconds\n",(long) rotatePeriod) ;
- fprintf (fp,"checkpoint period: %-3ld seconds\n",(long) tapeCkPtPeriod) ;
- fprintf (fp," newfile period: %-3ld seconds\n",(long) tapeCkNewFilePeriod);
- fprintf (fp,"\n") ;
-}
-
-
-void tapeLogStatus (Tape tape, FILE *fp)
-{
- if (tape == NULL)
- fprintf (fp,"(no tape)\n") ;
- else if (tape->noBacklog)
- fprintf (fp," spooling: DISABLED\n");
- else if (tape->outputLowLimit == 0)
- fprintf (fp," spooling: UNLIMITED\n");
- else
- {
- fprintf (fp," backlog low limit: %ld\n",
- tape->outputLowLimit) ;
- fprintf (fp," backlog upper limit: %ld",
- tape->outputHighLimit) ;
- if (tape->backlogFactor > 0.0)
- fprintf (fp," (factor %1.2f)",tape->backlogFactor) ;
- fputc ('\n',fp) ;
- fprintf (fp," backlog shrinkage: ") ;
- fprintf (fp,"%ld bytes (from current file)\n",tape->lossage) ;
- }
-}
-
-void printTapeInfo (Tape tape, FILE *fp, unsigned int indentAmt)
-{
- char indent [INDENT_BUFFER_SIZE] ;
- unsigned int i ;
-#if 0
- QueueElem qe ;
-#endif
-
- for (i = 0 ; i < MIN(INDENT_BUFFER_SIZE - 1,indentAmt) ; i++)
- indent [i] = ' ' ;
- indent [i] = '\0' ;
-
- fprintf (fp,"%sTape : %p {\n",indent,(void *) tape) ;
-
- if (tape == NULL)
- {
- fprintf (fp,"%s}\n",indent) ;
- return ;
- }
-
- fprintf (fp,"%s master-file : %s\n", indent, tape->handFilename) ;
- fprintf (fp,"%s input-file : %s\n", indent, tape->inputFilename) ;
- fprintf (fp,"%s output-file : %s\n",indent, tape->outputFilename) ;
- fprintf (fp,"%s lock-file : %s\n",indent, tape->lockFilename) ;
- fprintf (fp,"%s peerName : %s\n",indent,tape->peerName) ;
- fprintf (fp,"%s input-FILE : %p\n",indent, (void *) tape->inFp) ;
- fprintf (fp,"%s output-FILE : %p\n",indent, (void *) tape->outFp) ;
- fprintf (fp,"%s output-limit : %ld\n",indent, tape->outputLowLimit) ;
-
-#if 0
- fprintf (fp,"%s in-memory article queue (length %d) {\n",indent,
- tape->qLength) ;
-
- for (qe = tape->head ; qe != NULL ; qe = qe->next)
- {
-#if 0
- printArticleInfo (qe->article,fp,indentAmt + INDENT_INCR) ;
-#else
- fprintf (fp,"%s %p\n",indent,qe->article) ;
-#endif
- }
-
- fprintf (fp,"%s }\n",indent) ;
-#endif
-
- fprintf (fp,"%s tell-position : %ld\n",indent,(long) tape->tellpos) ;
- fprintf (fp,"%s input-FILE-changed : %s\n",indent,
- boolToString (tape->changed)) ;
-
- fprintf (fp,"%s no-rotate : %s\n",indent, boolToString (tape->noRotate));
-
- fprintf (fp,"%s}\n",indent) ;
-}
-
-
-
-
-/* delete the tape. Spools the in-memory articles to disk. */
-void delTape (Tape tape)
-{
- struct stat st ;
-
- if (tape == NULL)
- return ;
-
-#if 1
-
- if (tape->outFp != NULL && fclose (tape->outFp) != 0)
- syswarn ("ME ioerr fclose %s", tape->outputFilename) ;
-
- if (stat(tape->outputFilename, &st) == 0 && st.st_size == 0)
- {
- d_printf (1,"removing empty output tape: %s\n",tape->outputFilename) ;
- unlink (tape->outputFilename) ;
- }
-
- tape->outFp = NULL ;
- tape->outputSize = 0 ;
-
-#else
-
- tapeClose (tape) ;
-
-#endif
-
- if (tape->inFp != NULL)
- {
- checkpointTape (tape) ;
- fclose (tape->inFp) ;
- }
-
- unlockFile (tape->lockFilename) ;
-
- freeCharP (tape->handFilename) ;
- freeCharP (tape->inputFilename) ;
- freeCharP (tape->outputFilename) ;
- freeCharP (tape->lockFilename) ;
- freeCharP (tape->peerName) ;
-
- removeTapeGlobally (tape) ;
-
- free (tape) ;
-}
-
-
-void tapeTakeArticle (Tape tape, Article article)
-{
-#if 0
- QueueElem elem ;
-#endif
- int amt ;
- const char *fname, *msgid ;
-
- ASSERT (tape != NULL) ;
-
- /* return immediately if spooling disabled - jgarzik */
- if (tape->noBacklog)
- {
- delArticle (article) ;
- return;
- }
-
- fname = artFileName (article) ;
- msgid = artMsgId (article) ;
- amt = fprintf (tape->outFp,"%s %s\n", fname, msgid) ;
-
- /* I'd rather know where I am each time, and I don't trust all
- fprintf's to give me character counts. */
-#if defined (TRUST_FPRINTF)
-
- tape->outputSize += amt ;
-
-#else
-#if defined (NO_TRUST_STRLEN)
-
- tape->outputSize = ftello (tape->outFp) ;
-
-#else
-
- tape->outputSize += strlen(fname) + strlen(msgid) + 2 ; /* " " + "\n" */
-
-#endif
-#endif
-
- delArticle (article) ;
-
- if (debugShrinking)
- {
- struct stat sb ;
-
- fflush (tape->outFp) ;
-
- if (fstat (fileno (tape->outFp),&sb) != 0)
- syswarn ("ME oserr fstat %s",tape->outputFilename) ;
- else if (sb.st_size != tape->outputSize)
- syslog (LOG_ERR,"fstat and ftello do not agree: %ld %ld for %s\n",
- (long)sb.st_size,tape->outputSize,tape->outputFilename) ;
- }
-
- if (tape->outputHighLimit > 0 && tape->outputSize >= tape->outputHighLimit)
- {
- long oldSize = tape->outputSize ;
- shrinkfile (tape->outFp,tape->outputLowLimit,tape->outputFilename,"a+");
- tape->outputSize = ftello (tape->outFp) ;
- tape->lossage += oldSize - tape->outputSize ;
- }
-}
-
-
-/* Pick an article off a tape and return it. NULL is returned if there
- are no more articles. */
-Article getArticle (Tape tape)
-{
- char line [2048] ; /* ick. 1024 for filename + 1024 for msgid */
- char *p, *q ;
- char *msgid, *filename ;
- Article art = NULL ;
- time_t now = theTime() ;
-
- ASSERT (tape != NULL) ;
-
- if (tape->inFp == NULL && (now - tape->lastRotated) > rotatePeriod)
- prepareFiles (tape) ; /* will flush queue too. */
-
- while (tape->inFp != NULL && art == NULL)
- {
- tape->changed = true ;
-
- if (fgets (line,sizeof (line), tape->inFp) == NULL)
- {
- if (ferror (tape->inFp))
- syswarn ("ME ioerr on tape file %s", tape->inputFilename) ;
- else if ( !feof (tape->inFp) )
- syswarn ("ME oserr fgets %s", tape->inputFilename) ;
-
- if (fclose (tape->inFp) != 0)
- syswarn ("ME ioerr fclose %s", tape->inputFilename) ;
-
- d_printf (1,"No more articles on tape %s\n",tape->inputFilename) ;
-
- tape->inFp = NULL ;
- tape->scribbled = false ;
-
- unlink (tape->inputFilename) ;
-
- if ((now - tape->lastRotated) > rotatePeriod)
- prepareFiles (tape) ; /* rotate files to try next. */
- }
- else
- {
- msgid = filename = NULL ;
-
- for (p = line ; *p && CTYPE(isspace, *p) ; p++) /* eat whitespace */
- /* nada */ ;
-
- if (*p != '\0')
- {
- q = strchr (p,' ') ;
-
- if (q != NULL)
- {
- filename = p ;
- *q = '\0' ;
-
- for (q++ ; *q && CTYPE(isspace, *q) ; q++)
- /* nada */ ;
-
- if (*q != '\0')
- {
- if (((p = strchr (q, ' ')) != NULL) ||
- ((p = strchr (q, '\n')) != NULL))
- *p = '\0' ;
-
- if (p != NULL)
- msgid = q ;
- else
- filename = NULL ; /* no trailing newline or blank */
- }
- else
- filename = NULL ; /* line had one field and some blanks */
- }
- else
- filename = NULL ; /* line only had one field */
- }
-
- /* See if message ID looks valid. */
- if (msgid) {
- for (p = msgid; *p; p++)
- ;
- if (p > msgid) p--;
- if (*msgid != '<' || *p != '>') {
- warn ("ME tape invalid messageID in %s: %s",
- tape->inputFilename,msgid);
- msgid = NULL;
- }
- }
-
- if (filename != NULL && msgid != NULL)
- art = newArticle (filename, msgid) ;
-
- /* art may be NULL here if the file is no longer valid. */
- }
- }
-
-#if 0
- /* now we either have an article or there is no more on disk */
- if (art == NULL)
- {
- if (tape->inFp != NULL && ((c = fgetc (tape->inFp)) != EOF))
- ungetc (c,tape->inFp) ; /* shouldn't happen */
- else if (tape->inFp != NULL)
- {
- /* last article read was the end of the tape. */
- if (fclose (tape->inFp) != 0)
- syswarn ("ME ioerr fclose %s", tape->inputFilename) ;
-
- tape->inFp = NULL ;
- tape->scribbled = false ;
-
- /* toss out the old input file and prepare the new one */
- unlink (tape->inputFilename) ;
-
- if (now - tape->lastRotated > rotatePeriod)
- prepareFiles (tape) ;
- }
- }
-#endif
-
- if (art == NULL)
- d_printf (2,"%s All out of articles in the backlog\n", tape->peerName) ;
- else
- d_printf (2,"%s Peeled article %s from backlog\n",tape->peerName,
- artMsgId (art)) ;
-
- return art ;
-}
-
-
-/****************************************************/
-/** CLASS FUNCTIONS **/
-/****************************************************/
-
-/* Cause all the Tapes to checkpoint themselves. */
-void checkPointTapes (void)
-{
- unsigned int i ;
-
- for (i = 0 ; i < activeTapeIdx ; i++)
- checkpointTape (activeTapes [i]) ;
-}
-
-
-/* make all the tapes set their checkNew flag. */
-static void tapesSetCheckNew (void)
-{
- unsigned int i ;
-
- for (i = 0 ; i < activeTapeIdx ; i++)
- activeTapes[i]->checkNew = true ;
-}
-
-
-#if 0
-/* Set the pathname of the directory for storing tapes in. */
-void setTapeDirectory (const char *newDir)
-{
- /* the activeTape variable gets set when the first Tape object
- is created */
- if (activeTapes != NULL)
- {
- syslog (LOG_CRIT,"Resetting backlog directory") ;
- abort() ;
- }
-
- if (tapeDirectory != NULL)
- freeCharP (tapeDirectory) ;
-
- tapeDirectory = xstrdup (newDir) ;
-
- addPointerFreedOnExit (tapeDirectory) ;
-}
-#endif
-
-/* Get the pathname of the directory tapes are stored in. */
-const char *getTapeDirectory (void)
-{
- ASSERT (tapeDirectory != NULL) ;
-
-#if 0
- if (tapeDirectory == NULL)
- {
- tapeDirectory = xstrdup (dflTapeDir) ;
- addPointerFreedOnExit (tapeDirectory) ;
- }
-#endif
-
- return tapeDirectory ;
-}
-
-
-#if 0
-void setOutputSizeLimit (long val)
-{
- defaultSizeLimit = val ;
-}
-#endif
-
-
-
-
-
-
-/**********************************************************************/
-/* PRIVATE FUNCTIONS */
-/**********************************************************************/
-
-
-/* Add a new tape to the class-level list of active tapes. */
-static void addTapeGlobally (Tape tape)
-{
- ASSERT (tape != NULL) ;
-
- if (activeTapeSize == activeTapeIdx)
- {
- unsigned int i ;
-
- activeTapeSize += 10 ;
- if (activeTapes != NULL)
- activeTapes = xrealloc (activeTapes, sizeof(Tape) * activeTapeSize) ;
- else
- activeTapes = xmalloc (sizeof(Tape) * activeTapeSize) ;
-
- for (i = activeTapeIdx ; i < activeTapeSize ; i++)
- activeTapes [i] = NULL ;
- }
- activeTapes [activeTapeIdx++] = tape ;
-}
-
-
-/* Remove a tape for the class-level list of active tapes. */
-static void removeTapeGlobally (Tape tape)
-{
- unsigned int i ;
-
- if (tape == NULL)
- return ;
-
- ASSERT (activeTapeIdx > 0) ;
-
- for (i = 0 ; i < activeTapeIdx ; i++)
- if (activeTapes [i] == tape)
- break ;
-
- ASSERT (i < activeTapeIdx) ;
-
- for ( ; i < (activeTapeIdx - 1) ; i++)
- activeTapes [i] = activeTapes [i + 1] ;
-
- activeTapes [--activeTapeIdx] = NULL ;
-
- if (activeTapeIdx == 0)
- {
- free (activeTapes) ;
- activeTapes = NULL ;
- }
-}
-
-
-/* Have a tape checkpoint itself so that next process can pick up where
- this one left off. */
-static void checkpointTape (Tape tape)
-{
- if (tape->inFp == NULL) /* no input file being read. */
- return ;
-
- if (!tape->changed) /* haven't read since last checkpoint */
- {
- d_printf (1,"Not checkpointing unchanged tape: %s\n", tape->peerName) ;
- return ;
- }
-
- if ((tape->tellpos = ftello (tape->inFp)) < 0)
- {
- syswarn ("ME oserr ftello %s", tape->inputFilename) ;
- return ;
- }
-
- /* strlen of "18446744073709551616\n" (2^64) */
-#define BITS64 21
-
- /* make sure we're not right at the beginning of the file so we can write. */
- if (tape->tellpos > BITS64)
- {
- rewind (tape->inFp) ;
-
- /* scribble blanks over the first lines characters */
- if (!tape->scribbled)
- {
- int currloc = 0 ;
- int c ;
-
- while ((c = fgetc (tape->inFp)) != '\n' || currloc <= BITS64)
- if (c == EOF)
- return ;
- else
- currloc++ ;
-
- rewind (tape->inFp) ;
-
- while (currloc-- > 0)
- fputc (' ',tape->inFp) ;
-
- rewind (tape->inFp) ;
-
- fflush (tape->inFp) ;
- tape->scribbled = true ;
- }
-
- fprintf (tape->inFp,"%ld",tape->tellpos) ;
-
- if (fseeko (tape->inFp,tape->tellpos,SEEK_SET) != 0)
- syswarn ("ME oserr fseeko(%s,%ld,SEEK_SET)",tape->inputFilename,
- tape->tellpos) ;
- }
-
- tape->changed = false ;
-}
-
-
-
-/* Prepare the tape file(s) for input and output */
-
-/* For a given Tape there are
- * three possible files: PEER.input PEER and
- * PEER.output. PEER.input and PEER.output are private to
- * innfeed. PEER is where a sysadmin can drop a file that (s)he
- * wants to inject into the process. If the first line of the input file
- * contains only an integer (possibly surrounded by spaces), then this is
- * taken to be the position to seek to before reading.
- *
- * prepareFiles will process them in a manner much like the following shell
- * commands:
- *
- * if [ ! -f PEER.input ]; then
- * if [ -f PEER ]; then mv PEER PEER.input
- * elif [ -f PEER.output ]; then mv PEER.output PEER; fi
- * fi
- *
- * At this point PEER.input is opened for reading if it exists.
- *
- * The checkpoint file is left as-is unless the PEER.input file
- * happens to be newer that the checkpoint file.
- */
-static void prepareFiles (Tape tape)
-{
- bool inpExists ;
- bool outExists ;
- bool newExists ;
-
-#if 0
- /* flush any in memory articles to disk */
- if (tape->head != NULL && tape->outFp != NULL)
- flushTape(tape) ;
-#endif
-
- tape->tellpos = 0 ;
-
- /* First time through, or something external has set checkNew */
- if (tape->lastRotated == 0 || tape->checkNew)
- {
- newExists = fileExistsP (tape->handFilename) ;
- if (newExists)
- notice ("%s new hand-prepared backlog file", tape->peerName) ;
- }
- else
- newExists = false ;
-
- if (tape->lastRotated == 0) /* first time here */
- {
- inpExists = fileExistsP (tape->inputFilename) ;
- outExists = fileExistsP (tape->outputFilename) ;
- }
- else
- {
- inpExists = (tape->inFp != NULL) ? true : false ; /* can this ever be true?? */
- outExists = (tape->outFp != NULL && tape->outputSize > 0) ? true : false ;
- }
-
-
- /* move the hand-dropped file to the input file if needed. */
- if (newExists && !inpExists)
- {
- if (rename (tape->handFilename,tape->inputFilename) != 0)
- syswarn ("ME oserr rename %s, %s", tape->handFilename,
- tape->inputFilename);
- else
- {
- notice ("%s grabbing external tape file", tape->peerName) ;
- inpExists = true ;
- }
- }
-
- /* now move the output file to the input file, if needed and only if in
- not in NOROTATE mode. */
- if (outExists && !inpExists && !tape->noRotate)
- {
- if (tape->outFp != NULL)
- {
- fclose (tape->outFp) ;
- tape->outFp = NULL ;
- }
-
- if (rename (tape->outputFilename,tape->inputFilename) != 0)
- syswarn ("ME oserr rename %s, %s", tape->outputFilename,
- tape->inputFilename) ;
- else
- inpExists = true ;
-
- outExists = false ;
- }
-
- /* now open up the input file and seek to the proper position. */
- if (inpExists)
- {
- int c ;
- long flength ;
-
- if ((tape->inFp = fopen (tape->inputFilename,"r+")) == NULL)
- syswarn ("ME fopen %s", tape->inputFilename) ;
- else
- {
- char buffer [64] ;
-
- if (fgets (buffer,sizeof (buffer) - 1, tape->inFp) == NULL)
- {
- if (feof (tape->inFp))
- {
- d_printf (1,"Empty input file: %s\n",tape->inputFilename) ;
- unlink (tape->inputFilename) ;
- }
- else
- syswarn ("ME oserr fgets %s", tape->inputFilename) ;
-
- fclose (tape->inFp) ;
- tape->inFp = NULL ;
- tape->scribbled = false ;
- }
- else
- {
- unsigned int len = strlen (buffer) ;
- long newPos = 0 ;
-
- if (len > 0 && buffer [len - 1] == '\n')
- buffer [--len] = '\0' ;
-
- if (len > 0 && strspn (buffer,"0123456789 \n") == len)
- {
- if (sscanf (buffer,"%ld",&newPos) == 1)
- {
- tape->scribbled = true ;
- tape->tellpos = newPos ;
- }
- }
-
- if ((flength = fileLength (fileno (tape->inFp))) < tape->tellpos)
- {
- warn ("ME tape short: %s %ld %ld", tape->inputFilename,
- flength, tape->tellpos) ;
- tape->tellpos = 0 ;
- }
- else if (tape->tellpos == 0)
- rewind (tape->inFp) ;
- else if (fseeko (tape->inFp,tape->tellpos - 1,SEEK_SET) != 0)
- syswarn ("ME oserr fseeko(%s,%ld,SEEK_SET)",
- tape->inputFilename,tape->tellpos) ;
- else if ((c = fgetc (tape->inFp)) != '\n')
- {
- while (c != EOF && c != '\n')
- c = fgetc (tape->inFp) ;
-
- if (c == EOF)
- {
- fclose (tape->inFp) ;
- unlink (tape->inputFilename) ;
- tape->inFp = NULL ;
- tape->scribbled = false ;
- prepareFiles (tape) ;
- }
- else
- {
- long oldPos = tape->tellpos ;
-
- tape->changed = true ;
- checkpointTape (tape) ;
-
- warn ("ME internal checkpoint line boundary missed:"
- " %s %ld vs. %ld",tape->inputFilename,
- tape->tellpos, oldPos) ;
- }
- }
- }
- }
- }
-
- tape->lastRotated = theTime() ;
- tape->checkNew = false ;
-
- /* now open up the output file. */
- if (tape->outFp == NULL)
- {
- if ((tape->outFp = fopen (tape->outputFilename,"a+")) == NULL)
- {
- syswarn ("ME tape open failed (a+) %s", tape->outputFilename) ;
- return ;
- }
- fseeko (tape->outFp,0,SEEK_END) ;
- tape->outputSize = ftello (tape->outFp) ;
- tape->lossage = 0 ;
- }
-}
-
-
-static void tapeCkNewFileCbk (TimeoutId id, void *d UNUSED)
-{
- ASSERT (id == ckNewFileId) ;
- ASSERT (tapeCkNewFilePeriod > 0) ;
-
- tapesSetCheckNew () ;
-
- ckNewFileId = prepareSleep (tapeCkNewFileCbk,tapeCkNewFilePeriod,NULL) ;
-}
-
-
-/* The timer callback function that will checkpoint all the active tapes. */
-static void tapeCheckpointCallback (TimeoutId id, void *d UNUSED)
-{
- ASSERT (id == checkPtId) ;
- ASSERT (tapeCkPtPeriod > 0) ;
-
- d_printf (1,"Checkpointing tapes\n") ;
-
- checkPointTapes () ;
-
- checkPtId = prepareSleep (tapeCheckpointCallback,tapeCkPtPeriod,NULL) ;
-}
-
-
-
-#if 0
-static void flushTape (Tape tape)
-{
- QueueElem elem ;
-
- /* flush out queue to disk. */
- elem = tape->head ;
- while (elem != NULL)
- {
- tape->head = tape->head->next ;
- fprintf (tape->outFp,"%s %s\n", artFileName (elem->article),
- artMsgId (elem->article)) ;
-
- delArticle (elem->article) ;
-
- free (elem) ;
- elem = tape->head ;
- }
- tape->tail = NULL ;
- tape->qLength = 0;
-
-
- /* I'd rather know where I am each time, and I don't trust all
- fprintf's to give me character counts. */
- tape->outputSize = ftello (tape->outFp) ;
- if (debugShrinking)
- {
- struct stat buf ;
- static bool logged = false ;
-
- fflush (tape->outFp) ;
- if (fstat (fileno (tape->outFp),&buf) != 0 && !logged)
- {
- syslog (LOG_ERR,FSTAT_FAILURE,tape->outputFilename) ;
- logged = true ;
- }
- else if (buf.st_size != tape->outputSize)
- {
- warn ("ME fstat and ftello do not agree for %s",
- tape->outputFilename) ;
- logged = true ;
- }
- }
-
- if (tape->outputHighLimit > 0 && tape->outputSize > tape->outputHighLimit)
- {
- shrinkfile (tape->outFp,tape->outputLowLimit,tape->outputFilename,"a+");
- tape->outputSize = ftello (tape->outFp) ;
- }
-}
-#endif
-
-
-static void tapeCleanup (void)
-{
- free (tapeDirectory) ;
- tapeDirectory = NULL ;
-}
+++ /dev/null
-/* $Id: tape.h 6648 2004-01-25 20:07:11Z rra $
-**
-** The public interface to the Tape class.
-**
-** Written by James Brister <brister@vix.com>
-**
-** The Tape class simulates a mag tape. It only reads or writes Articles. A
-** tape is either in an Input or Output state. When an Article is given to a
-** Tape it will store the Article in memory until it reaches a highwater mark
-** at which point it dumps all it's articles to disk.
-**
-** Input tapes generate article objects on request if the underlying tape
-** file has info in it. The Tapes take care of cleaning up used-up files as
-** needed.
-*/
-
-#if ! defined ( tape_h__ )
-#define tape_h__
-
-#include <stdio.h>
-
-#include "misc.h"
-
-
-/* If dontRotate is true, then any articles that get written to the tape
- will never be read back in again. This is for the batch-mode-only case
- where articles written to tape were done so 'cause the remote
- temporarily rejected them. */
-Tape newTape (const char *peerName, bool dontRotate) ;
-
-void gPrintTapeInfo (FILE *fp, unsigned int inedntAmt) ;
-void printTapeInfo (Tape tape, FILE *fp, unsigned int indentAmt) ;
-
-/* deletes the tape objects. If it has any articles cached then it dumps
- them to the disk. */
-void delTape (Tape tape) ;
-
-/* give an article to the Tape for storage */
-void tapeTakeArticle (Tape tape, Article article) ;
-
-/* get a new article from an Input tape. */
-Article getArticle (Tape tape) ;
-
-/* close the input and output files and reopen them. */
-void gFlushTapes (void) ;
-void tapeFlush (Tape tape) ;
-
-
-/**************************************************/
-/* CLASS LEVEL FUNCTIONS */
-/**************************************************/
-
-/* get all the active input tapes to checkpoint their current positions */
-void checkPointTapes (void) ;
-
-/* get the name of the directory tapes are being stored in. */
-const char *getTapeDirectory (void) ;
-
-/* set the size limit of the output tapes. Default is zero which is no
- limit. */
-void setOutputSizeLimit (long limit) ;
-
-int tapeConfigLoadCbk (void *data) ;
-
-void tapeLogGlobalStatus (FILE *fp) ;
-void tapeLogStatus (Tape tape, FILE *fp) ;
-
-#endif /* tape_h__ */
+++ /dev/null
-#!/usr/bin/perl
-#
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Wed Jan 3 00:09:01 1996
-# Project: INN -- innfeed
-# File: testListener.pl
-# RCSId: $Id: testListener.pl 6312 2003-05-04 21:40:11Z rra $
-# Description: Generate news files for testing the innfeed feeder.
-#
-# Run like this:
-#
-# testListener.pl -t 30 -d tmp | innfeed
-#
-# or like this:
-#
-# innfeed -s 'perl testListener.pl -t 30 -d tmp'
-#
-
-$0 =~ s!.*/!! ;
-
-require 'getopts.pl' ;
-
-$usage = "$0 [ -a -b name -d directory -c count -t sleep-amt -r -u ] peers\n" .
- " -a is for duplicate article id's periodically\n" .
- " -u is for random unlinking of article\n" .
- " -b add bogus peername periodically\n" .
- " -d is the directory where articles show be written.\n" .
- " -c is how many articles to create (0 the default meamns no limit)\n" .
- " -t is the number of seconds to sleep between each article.\n" .
- " -r is to have articles be created in NNTP ready format\n" ;
-
-&Getopts ("a:b:c:d:t:rl:h:") || die $usage ;
-
-die $usage if $opt_h ;
-$total = $opt_c ;
-
-$sleepAmt = 1 ;
-$sleepAmt = $opt_t if ($opt_t =~ /^[\d\.]+/) ;
-
-$lineCount = 50 ;
-$lineCount = $opt_l if ($opt_l =~ /^\d+$/) ;
-
-$directory = "." ;
-$directory = $opt_d if $opt_d ;
-
-$bogus = $opt_b ;
-if ( $bogus && $bogus !~ /^[a-zA-Z]+$/ ) {
- print "The bogus peername must contain only letters\n" ;
-}
-
-$cr = ($opt_r ? "\r" : "") ;
-
-$SIG{'INT'} = 'IGNORE' ;
-$SIG{'TERM'} = 'sigHup' ;
-$SIG{'QUIT'} = 'sigHup' ;
-$SIG{'HUP'} = 'sigHup' ;
-
-sub sigHup {
- exit (1) ;
-}
-
-
-$monstr = "JanFebMarAprMayJunJulAugSepOctNovDec" ;
-$letstr = "abcdefghijklmnopqrstuvwxyz" ;
-
-sub createArticle {
- local ($counter) = @_ ;
- local ($filename,$msgid,$i) ;
- local ($time) = $^T ;
- local ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)
- = gmtime($time);
- local ($index) = $counter ;
-
-
- if ($opt_a && ((int (rand (4)) % 2) == 0)) {
- $index = int ($index / 2) ;
- }
-
- $msgid = "<$index.$$.$time\@home.octet.com.au>" ;
-
- $filename = sprintf ("%s/SampleArticle.%06d",$directory,$index) ;
-
- open (ARTICLE,">$filename") ||
- die "open ($filename): $!\n" ;
- print ARTICLE "Path: home.octet.com.au!not-for-mail$cr\n" ;
- print ARTICLE "From: brister\@home.octet.com.au$cr\n" ;
- print ARTICLE "Newsgroups: junk,local.test$cr\n" ;
- print ARTICLE "Subject: Test$cr\n" ;
- print ARTICLE "Date: " ;
-
- printf ARTICLE "%d %s %d %02d:%02d:%02d UTC$cr\n",
- $mday, substr($monstr,$mon * 3, 3), $year + 1900,
- $hour, $min, $sec ;
-
- print ARTICLE "Organization: None that I can think of$cr\n" ;
- print ARTICLE "Lines: 5$cr\n" ;
- print ARTICLE "Distribution: world$cr\n" ;
- print ARTICLE "Message-ID: $msgid$cr\n" ;
- print ARTICLE "NNTP-Posting-Host: localhost$cr\n" ;
- print ARTICLE "$cr\n" ;
-
- for ($i = 0 ; $i < $lineCount ; $i++) {
- print ARTICLE "x" x ($lineCount + 1), "$cr\n";
- }
- print ARTICLE ".This line has a leading dot.$cr\n" ;
- print ARTICLE "And the next line only has a dot.$cr\n" ;
- if ($opt_r) {
- print ARTICLE "..$cr\n" ;
- } else {
- print ARTICLE ".$cr\n" ;
- }
- print ARTICLE "And the next line has just two dots...$cr\n" ;
- print ARTICLE "...$cr\n" ;
- print ARTICLE "foo$cr\n" ;
- print ARTICLE "And the next line is the last line of the article$cr\n" ;
- print ARTICLE "and it only has a single dot on it.$cr\n" ;
- if ($opt_r) {
- print ARTICLE "..$cr\n" ;
- } else {
- print ARTICLE ".$cr\n" ;
- }
-
-
- close (ARTICLE) ;
-
- return ($msgid, $filename) ;
-}
-
-srand ;
-
-
-$| = 1 ;
-
-if ( ! -t STDERR ) {
- open (STDERR,">>/tmp/TESTLISTENER.LOG") || die ;
-}
-
-srand ;
-$sleepAmt = 1 if ($sleepAmt < 0) ;
-
-foreach $peer ( @ARGV ) {
- $PEERS{$peer} = 1 ;
-}
-
-die "Must give peernames on command line:\n$usage" if ( ! @ARGV ) ;
-
-for ( $i = 0 ; $total == 0 || $i < $total ; $i++ ) {
- ($msgid,$filename) = &createArticle ($i) ;
- if ($opt_a && ((rand (3) % 3) == 0)) {
- print TTY "Removing file $filename\n" ;
- unlink ($filename) if $opt_u ;
- }
- print "$filename $msgid @ARGV" ;
- print " $bogus" if ($bogus && (rand (5) % 5) == 0) ;
- print "\n" ;
-
- select (undef,undef,undef,(rand ($sleepAmt-1) + 1)) if $sleepAmt ;
-}
-
-sleep 11500 unless -f STDOUT ;
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS)
-
-# The base library files that are always compiled and included.
-SOURCES = buffer.c cleanfrom.c clientactive.c clientlib.c concat.c \
- conffile.c confparse.c daemonize.c date.c dbz.c defdist.c \
- fdflags.c fdlimit.c genid.c getfqdn.c getmodaddr.c gettime.c \
- hash.c hashtab.c innconf.c inndcomm.c list.c localopen.c \
- lockfile.c makedir.c md5.c messages.c mmap.c parsedate.c \
- qio.c radix32.c readin.c remopen.c reservedfd.c resource.c \
- sendarticle.c sendpass.c sequence.c sockaddr.c timer.c tst.c \
- uwildmat.c vector.c version.c wire.c xfopena.c xmalloc.c \
- xsignal.c xwrite.c
-
-# Sources for additional functions only built to replace missing system ones.
-EXTRA_SOURCES = fseeko.c ftello.c getpagesize.c hstrerror.c inet_aton.c \
- inet_ntoa.c memcmp.c mkstemp.c pread.c pwrite.c setenv.c \
- setproctitle.c strcasecmp.c strerror.c strlcat.c strlcpy.c \
- strspn.c strtok.c
-
-OBJECTS = $(LIBOBJS) $(SOURCES:.c=.o)
-LOBJECTS = $(OBJECTS:.o=.lo)
-
-.SUFFIXES: .lo
-
-all: libinn.$(EXTLIB) perl.o
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPUB) libinn.$(EXTLIB) $D$(PATHLIB)/libinn.$(EXTLIB)
-
-clobber clean distclean:
- rm -f *.o *.lo libinn.la libinn.a parsedate.c parsedate
- rm -f profiled perl$(PROFSUFFIX).o libinn$(PROFSUFFIX).a
- rm -f libinn_pure_*.a .pure
- rm -rf .libs
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES) ../include/*.h
-
-libinn.la: $(OBJECTS) $(LOBJECTS)
- $(LIBLD) $(LDFLAGS) -o $@ $(LOBJECTS) $(LIBS) \
- -rpath $(PATHLIB) -version-info 2:0:0
-
-libinn.a: $(OBJECTS)
- ar r $@ $(OBJECTS)
- $(RANLIB) libinn.a
-
-.c.o .c.lo:
- $(LIBCC) $(CFLAGS) -c $*.c
-
-perl.o: perl.c
- $(CC) $(CFLAGS) $(PERLINC) $(LDFLAGS) -c perl.c
-
-../include/inn/system.h:
- (cd ../include && $(MAKE))
-
-parsedate.c: parsedate.y
- @echo Expect 6 shift/reduce conflicts
- $(YACC) parsedate.y
- @mv y.tab.c parsedate.c
-
-parsedate: parsedate.c gettime.o
- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ -DTEST -DYYDEBUG parsedate.c gettime.o
-
-## Profiling. The rules are a bit brute-force, but good enough.
-profiled: libinn$(PROFSUFFIX).a perl$(PROFSUFFIX).o
- date >$@
-
-libinn$(PROFSUFFIX).a perl$(PROFSUFFIX).o: $(OBJECTS) perl.o
- rm -f $(OBJECTS)
- $(MAKEPROFILING) libinn.a
- $(MAKEPROFILING) perl.o
- mv libinn.a libinn$(PROFSUFFIX).a
- mv perl.o perl$(PROFSUFFIX).o
- $(RANLIB) libinn$(PROFSUFFIX).a
- rm -f $(OBJECTS)
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES) $(EXTRA_SOURCES) perl.c ../include/inn/system.h
- $(MAKEDEPEND) '$(CFLAGS) $(PERLINC)' $(SOURCES) $(EXTRA_SOURCES) perl.c
-
-# Special dependency to teach make to build the include directory properly.
-../include/inn/defines.h: ../include/inn/system.h
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-buffer.o: buffer.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/buffer.h ../include/inn/defines.h ../include/libinn.h
-cleanfrom.o: cleanfrom.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-clientactive.o: clientactive.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/libinn.h ../include/nntp.h ../include/paths.h
-clientlib.o: clientlib.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h
-concat.o: concat.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/libinn.h ../include/config.h
-conffile.o: conffile.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/conffile.h ../include/libinn.h
-confparse.o: confparse.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/confparse.h ../include/inn/defines.h \
- ../include/inn/hashtab.h ../include/inn/messages.h \
- ../include/inn/vector.h ../include/libinn.h
-daemonize.o: daemonize.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h
-date.o: date.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-dbz.o: dbz.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/dbz.h ../include/libinn.h ../include/inn/messages.h \
- ../include/inn/defines.h ../include/inn/innconf.h ../include/inn/mmap.h \
- ../include/libinn.h
-defdist.o: defdist.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/paths.h
-fdflags.o: fdflags.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-fdlimit.o: fdlimit.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-genid.o: genid.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h
-getfqdn.o: getfqdn.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h ../include/paths.h
-getmodaddr.o: getmodaddr.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h
-gettime.o: gettime.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/libinn.h ../include/config.h
-hash.o: hash.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/md5.h ../include/inn/defines.h ../include/libinn.h
-hashtab.o: hashtab.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/hashtab.h ../include/inn/defines.h ../include/libinn.h
-innconf.o: innconf.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/confparse.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h \
- ../include/inn/vector.h ../include/libinn.h ../include/paths.h
-inndcomm.o: inndcomm.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h \
- ../include/portable/socket.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inndcomm.h ../include/libinn.h \
- ../include/paths.h
-list.o: list.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/list.h ../include/inn/defines.h
-localopen.o: localopen.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h
-lockfile.o: lockfile.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-makedir.o: makedir.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-md5.o: md5.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/md5.h ../include/inn/defines.h
-messages.o: messages.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h
-mmap.o: mmap.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h \
- ../include/inn/mmap.h
-parsedate.o: parsedate.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-qio.o: qio.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/qio.h ../include/inn/defines.h ../include/libinn.h
-radix32.o: radix32.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-readin.o: readin.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-remopen.o: remopen.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h
-reservedfd.o: reservedfd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-resource.o: resource.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-sendarticle.o: sendarticle.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h ../include/nntp.h
-sendpass.o: sendpass.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h
-sequence.o: sequence.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/sequence.h ../include/inn/defines.h
-sockaddr.o: sockaddr.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h ../include/libinn.h
-timer.o: timer.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h \
- ../include/inn/timer.h ../include/libinn.h
-tst.o: tst.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/tst.h ../include/inn/defines.h ../include/libinn.h
-uwildmat.o: uwildmat.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-vector.o: vector.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/vector.h ../include/inn/defines.h ../include/libinn.h
-version.o: version.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/inn/version.h
-wire.o: wire.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/wire.h ../include/inn/defines.h ../include/libinn.h
-xfopena.o: xfopena.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-xmalloc.o: xmalloc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h ../include/libinn.h
-xsignal.o: xsignal.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/libinn.h ../include/config.h
-xwrite.o: xwrite.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h
-fseeko.o: fseeko.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-ftello.o: ftello.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-getpagesize.o: getpagesize.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h
-hstrerror.o: hstrerror.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-inet_aton.o: inet_aton.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-inet_ntoa.o: inet_ntoa.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-memcmp.o: memcmp.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h
-mkstemp.o: mkstemp.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/time.h ../include/config.h
-pread.o: pread.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-pwrite.o: pwrite.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-setenv.o: setenv.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-setproctitle.o: setproctitle.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/setproctitle.h \
- ../include/config.h ../include/inn/messages.h ../include/inn/defines.h
-strcasecmp.o: strcasecmp.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-strerror.o: strerror.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h
-strlcat.o: strlcat.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-strlcpy.o: strlcpy.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-strspn.o: strspn.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-strtok.o: strtok.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h
-perl.o: perl.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h
+++ /dev/null
-/* $Id: buffer.c 5463 2002-05-06 05:40:46Z rra $
-**
-** Counted, reusable memory buffer.
-**
-** A buffer is an allocated bit of memory with a known size and a separate
-** data length. It's intended to store strings and can be reused repeatedly
-** to minimize the number of memory allocations. Buffers increase in
-** increments of 1K.
-**
-** A buffer contains a notion of the data that's been used and the data
-** that's been left, used when the buffer is an I/O buffer where lots of data
-** is buffered and then slowly processed out of the buffer. The total length
-** of the data is used + left. If a buffer is just used to store some data,
-** used can be set to 0 and left stores the length of the data.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/buffer.h"
-#include "libinn.h"
-
-/*
-** Allocate a new struct buffer and initialize it.
-*/
-struct buffer *
-buffer_new(void)
-{
- struct buffer *buffer;
-
- buffer = xmalloc(sizeof(struct buffer));
- buffer->size = 0;
- buffer->used = 0;
- buffer->left = 0;
- buffer->data = NULL;
- return buffer;
-}
-
-
-/*
-** Resize a buffer to be at least as large as the provided second argument.
-** Resize buffers to multiples of 1KB to keep the number of reallocations to
-** a minimum. Refuse to resize a buffer to make it smaller.
-*/
-void
-buffer_resize(struct buffer *buffer, size_t size)
-{
- if (size < buffer->size)
- return;
- buffer->size = (size + 1023) & ~1023UL;
- buffer->data = xrealloc(buffer->data, buffer->size);
-}
-
-
-/*
-** Replace whatever data is currently in the buffer with the provided data.
-*/
-void
-buffer_set(struct buffer *buffer, const char *data, size_t length)
-{
- if (length > 0) {
- buffer_resize(buffer, length);
- memmove(buffer->data, data, length);
- }
- buffer->left = length;
- buffer->used = 0;
-}
-
-
-/*
-** Append data to a buffer. The new data shows up as additional unused data
-** at the end of the buffer. Resize the buffer to multiples of 1KB.
-*/
-void
-buffer_append(struct buffer *buffer, const char *data, size_t length)
-{
- size_t total;
-
- if (length == 0)
- return;
- total = buffer->used + buffer->left;
- buffer_resize(buffer, total + length);
- buffer->left += length;
- memcpy(buffer->data + total, data, length);
-}
-
-
-/*
-** Swap the contents of two buffers.
-*/
-void
-buffer_swap(struct buffer *one, struct buffer *two)
-{
- struct buffer tmp;
-
- tmp = *one;
- *one = *two;
- *two = tmp;
-}
+++ /dev/null
-/* $Id: cleanfrom.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-
-
-#define LPAREN '('
-#define RPAREN ')'
-
-
-/*
-** Clean up a from line, making the following transformations:
-** address address
-** address (stuff) address
-** stuff <address> address
-*/
-void HeaderCleanFrom(char *from)
-{
- char *p;
- char *end;
- int len;
-
- if ((len = strlen(from)) == 0)
- return;
- /* concatenate folded header */
- for (p = end = from ; p < from + len ;) {
- if (*p == '\n') {
- if ((p + 1 < from + len) && ISWHITE(p[1])) {
- if ((p - 1 >= from) && (p[-1] == '\r')) {
- end--;
- *end = p[1];
- p += 2;
- } else {
- *end = p[1];
- p++;
- }
- } else {
- *end = '\0';
- break;
- }
- } else
- *end++ = *p++;
- }
- if (end != from)
- *end = '\0';
-
- /* Do pretty much the equivalent of sed's "s/(.*)//g"; */
- while ((p = strchr(from, LPAREN)) && (end = strchr(p, RPAREN))) {
- while (*++end)
- *p++ = *end;
- *p = '\0';
- }
-
- /* Do pretty much the equivalent of sed's "s/\".*\"//g"; */
- while ((p = strchr(from, '"')) && (end = strchr(p, '"'))) {
- while (*++end)
- *p++ = *end;
- *p = '\0';
- }
-
- /* Do the equivalent of sed's "s/.*<\(.*\)>/\1/" */
- if ((p = strrchr(from, '<')) && (end = strrchr(p, '>'))) {
- while (++p < end)
- *from++ = *p;
- *from = '\0';
- }
-
- /* drop white spaces */
- if ((len = strlen(from)) == 0)
- return;
- for (p = end = from ; p < from + len ;) {
- if (ISWHITE(*p)) {
- p++;
- continue;
- }
- *end++ = *p++;
- }
- if (end != from)
- *end = '\0';
-}
+++ /dev/null
-/* $Id: clientactive.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-
-static char *CApathname;
-static FILE *CAfp;
-
-
-/*
-** Get a copy of the active file for a client host to use, locally or
-** remotely.
-*/
-FILE *
-CAopen(FILE *FromServer, FILE *ToServer)
-{
- char *path;
-
- /* Use a local (or NFS-mounted) copy if available. Make sure we don't
- * try to delete it when we close it. */
- path = concatpath(innconf->pathdb, _PATH_CLIENTACTIVE);
- CAfp = fopen(path, "r");
- free(path);
- if (CAfp != NULL) {
- CApathname = NULL;
- return CAfp;
- }
-
- /* Use the active file from the server */
- return CAlistopen(FromServer, ToServer, (char *)NULL);
-}
-
-
-/*
-** Internal library routine.
-*/
-FILE *
-CA_listopen(char *pathname, FILE *FromServer, FILE *ToServer,
- const char *request)
-{
- char buff[BUFSIZ];
- char *p;
- int oerrno;
- FILE *F;
-
- F = fopen(pathname, "w");
- if (F == NULL)
- return NULL;
-
- /* Send a LIST command to and capture the output. */
- if (request == NULL)
- fprintf(ToServer, "list\r\n");
- else
- fprintf(ToServer, "list %s\r\n", request);
- fflush(ToServer);
-
- /* Get the server's reply to our command. */
- if (fgets(buff, sizeof buff, FromServer) == NULL
- || strncmp(buff, NNTP_LIST_FOLLOWS, strlen(NNTP_LIST_FOLLOWS)) != 0) {
- oerrno = errno;
- /* Only call CAclose() if opened through CAopen() */
- if (strcmp(CApathname, pathname) == 0)
- CAclose();
- errno = oerrno;
- return NULL;
- }
-
- /* Slurp up the rest of the response. */
- while (fgets(buff, sizeof buff, FromServer) != NULL) {
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '.' && buff[1] == '\0') {
- if (ferror(F) || fflush(F) == EOF || fclose(F) == EOF)
- break;
- return fopen(pathname, "r");
- }
- fprintf(F, "%s\n", buff);
- }
-
- /* Ran out of input before finding the terminator; quit. */
- oerrno = errno;
- fclose(F);
- CAclose();
- errno = oerrno;
- return NULL;
-}
-
-
-/*
-** Use the NNTP list command to get a file from a server. Default is
-** the active file, otherwise ask for whatever is in the request param.
-*/
-FILE *
-CAlistopen(FILE *FromServer, FILE *ToServer, const char *request)
-{
- int fd, oerrno;
-
- /* Gotta talk to the server -- see if we can. */
- if (FromServer == NULL || ToServer == NULL) {
- errno = EBADF;
- return NULL;
- }
-
- CApathname = concatpath(innconf->pathtmp, _PATH_TEMPACTIVE);
- fd = mkstemp(CApathname);
- if (fd < 0) {
- oerrno = errno;
- free(CApathname);
- CApathname = 0;
- errno = oerrno;
- return NULL;
- }
- close(fd);
- return CAfp = CA_listopen(CApathname, FromServer, ToServer, request);
-}
-
-
-
-/*
-** Close the file opened by CAopen or CAlistopen.
-*/
-void
-CAclose(void)
-{
- if (CAfp) {
- fclose(CAfp);
- CAfp = NULL;
- }
- if (CApathname != NULL) {
- unlink(CApathname);
- CApathname = NULL;
- }
-}
+++ /dev/null
-/* $Id: clientlib.c 6155 2003-01-19 19:58:25Z rra $
-**
-** Routines compatible with the NNTP "clientlib" routines.
-*/
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-
-
-FILE *ser_rd_fp = NULL;
-FILE *ser_wr_fp = NULL;
-char ser_line[NNTP_STRLEN + 2];
-
-
-/*
-** Get the name of the NNTP server. Ignore the filename; we use
-** our own configuration stuff. Return pointer to static data.
-*/
-char *
-getserverbyfile(char *file UNUSED)
-{
- static char buff[256];
-
- strlcpy(buff, innconf->server, sizeof(buff));
- return buff;
-}
-
-
-/*
-** Get a connection to the remote news server. Return server's reply
-** code or -1 on error.
-*/
-int
-server_init(char *host, int port)
-{
- char line2[NNTP_STRLEN];
-
- /* This interface may be used by clients that assume C News behavior and
- won't read inn.conf themselves. */
- if (innconf == NULL)
- if (!innconf_read(NULL))
- return -1;
-
- if (NNTPconnect(host, port, &ser_rd_fp, &ser_wr_fp, ser_line) < 0) {
- if (ser_line[0] == '\0')
- /* I/O problem. */
- return -1;
-
- /* Server rejected connection; return it's reply code. */
- return atoi(ser_line);
- }
-
- /* Send the INN command; if understood, use that reply. */
- put_server("mode reader");
- if (get_server(line2, (int)sizeof line2) < 0)
- return -1;
- if (atoi(line2) != NNTP_BAD_COMMAND_VAL)
- strlcpy(ser_line, line2, sizeof(ser_line));
-
- /* Connected; return server's reply code. */
- return atoi(ser_line);
-}
-
-
-#define CANTPOST \
- "NOTE: This machine does not have permission to post articles"
-#define CANTUSE \
- "This machine does not have permission to use the %s news server.\n"
-/*
-** Print a message based on the the server's initial response.
-** Return -1 if server wants us to go away.
-*/
-int
-handle_server_response(int response, char *host)
-{
- char *p;
-
- switch (response) {
- default:
- printf("Unknown response code %d from %s.\n", response, host);
- return -1;
- case NNTP_GOODBYE_VAL:
- if (atoi(ser_line) == response) {
- p = &ser_line[strlen(ser_line) - 1];
- if (*p == '\n' && *--p == '\r')
- *p = '\0';
- if (p > &ser_line[3]) {
- printf("News server %s unavailable: %s\n", host,
- &ser_line[4]);
- return -1;
- }
- }
- printf("News server %s unavailable, try later.\n", host);
- return -1;
- case NNTP_ACCESS_VAL:
- printf(CANTUSE, host);
- return -1;
- case NNTP_NOPOSTOK_VAL:
- printf("%s.\n", CANTPOST);
- /* FALLTHROUGH */
- case NNTP_POSTOK_VAL:
- break;
- }
- return 0;
-}
-
-
-/*
-** Send a line of text to the server.
-*/
-void
-put_server(const char *buff)
-{
- fprintf(ser_wr_fp, "%s\r\n", buff);
- fflush(ser_wr_fp);
-}
-
-
-/*
-** Get a line of text from the server, strip trailing \r\n.
-** Return -1 on error.
-*/
-int
-get_server(char *buff, int buffsize)
-{
- char *p;
-
- if (fgets(buff, buffsize, ser_rd_fp) == NULL)
- return -1;
- p = &buff[strlen(buff)];
- if (p >= &buff[2] && p[-2] == '\r' && p[-1] == '\n')
- p[-2] = '\0';
- return 0;
-}
-
-
-/*
-** Send QUIT and close the server.
-*/
-void
-close_server(void)
-{
- char buff[NNTP_STRLEN];
-
- if (ser_wr_fp != NULL && ser_rd_fp != NULL) {
- put_server("QUIT");
- fclose(ser_wr_fp);
- ser_wr_fp = NULL;
-
- get_server(buff, (int)sizeof buff);
- fclose(ser_rd_fp);
- ser_rd_fp = NULL;
- }
-}
+++ /dev/null
-/* $Id: concat.c 4234 2000-12-21 03:43:02Z rra $
-**
-** Concatenate strings with dynamic memory allocation.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Usage:
-**
-** string = concat(string1, string2, ..., (char *) 0);
-** path = concatpath(base, name);
-**
-** Dynamically allocates (using xmalloc) sufficient memory to hold all of
-** the strings given and then concatenates them together into that
-** allocated memory, returning a pointer to it. Caller is responsible for
-** freeing. Assumes xmalloc is available. The last argument must be a
-** null pointer (to a char *, if you actually find a platform where it
-** matters).
-**
-** concatpath is similar, except that it only takes two arguments. If the
-** second argument begins with / or ./, a copy of it is returned;
-** otherwise, the first argument, a slash, and the second argument are
-** concatenated together and returned. This is useful for building file
-** names where names that aren't fully qualified are qualified with some
-** particular directory.
-*/
-
-#include "config.h"
-#include "libinn.h"
-
-#include <stdarg.h>
-#if STDC_HEADERS
-# include <string.h>
-#endif
-
-/* Abbreviation for cleaner code. */
-#define VA_NEXT(var, type) ((var) = (type) va_arg(args, type))
-
-/* ANSI C requires at least one named parameter. */
-char *
-concat(const char *first, ...)
-{
- va_list args;
- char *result, *p;
- const char *string;
- size_t length = 0;
-
- /* Find the total memory required. */
- va_start(args, first);
- for (string = first; string != NULL; VA_NEXT(string, const char *))
- length += strlen(string);
- va_end(args);
- length++;
-
- /* Create the string. Doing the copy ourselves avoids useless string
- traversals of result, if using strcat, or string, if using strlen to
- increment a pointer into result, at the cost of losing the native
- optimization of strcat if any. */
- result = xmalloc(length);
- p = result;
- va_start(args, first);
- for (string = first; string != NULL; VA_NEXT(string, const char *))
- while (*string != '\0')
- *p++ = *string++;
- va_end(args);
- *p = '\0';
-
- return result;
-}
-
-
-char *
-concatpath(const char *base, const char *name)
-{
- if (name[0] == '/' || (name[0] == '.' && name[1] == '/'))
- return xstrdup(name);
- else
- return concat(base, "/", name, (char *) 0);
-}
+++ /dev/null
-/* $Id: conffile.c 6733 2004-05-16 23:01:23Z rra $
-**
-** Routines for reading in incoming.conf-style config files.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "conffile.h"
-#include "libinn.h"
-
-static int getconfline(CONFFILE *F, char *buffer, int length) {
- if (F->f) {
- fgets(buffer, length, F->f);
- if (ferror(F->f)) {
- return 1;
- }
- } else if (F->array) {
- strlcpy(buffer, F->array[F->lineno], F->sbuf);
- }
- F->lineno++;
- if (strlen (F->buf) >= F->sbuf - 1) {
- return 1; /* Line too long */
- } else {
- return 0;
- }
-}
-
-static int cfeof(CONFFILE *F) {
- if (F->f) {
- return feof(F->f);
- } else if (F->array) {
- return (F->lineno == F->array_len);
- } else {
- return 1;
- }
-}
-
-static char *CONFgetword(CONFFILE *F)
-{
- char *p;
- char *s;
- char *t;
- char *word;
- bool flag, comment;
-
- if (!F) return (NULL); /* No conf file */
- if (!F->buf || !F->buf[0]) {
- if (cfeof (F)) return (NULL);
- if (!F->buf) {
- F->sbuf = BIG_BUFFER;
- F->buf = xmalloc(F->sbuf);
- }
- if (getconfline(F, F->buf, F->sbuf) != 0)
- return (NULL); /* Line too long */
- }
- do {
- /* Ignore blank and comment lines. */
- if ((p = strchr(F->buf, '\n')) != NULL)
- *p = '\0';
- for (p = F->buf; *p == ' ' || *p == '\t' ; p++);
- flag = true;
- if ((*p == '\0' || *p == '#') && !cfeof(F)) {
- flag = false;
- if (getconfline(F, F->buf, F->sbuf))
- return (NULL); /* Line too long */
- continue;
- }
- break;
- } while (!cfeof(F) || !flag);
-
- comment = false;
- if (*p == '"') { /* double quoted string ? */
- p++;
- do {
- for (t = p; (*t != '"' || (*t == '"' && *(t - 1) == '\\')) &&
- *t != '\0'; t++);
- if (*t == '\0') {
- if (strlen(F->buf) >= F->sbuf - 2)
- return (NULL); /* Line too long */
- *t++ = '\n';
- *t = '\0';
- if (getconfline(F, t, F->sbuf - strlen(F->buf)))
- return (NULL); /* Line too long */
- if ((s = strchr(t, '\n')) != NULL)
- *s = '\0';
- }
- else
- break;
- } while (!cfeof(F));
- if (*t != '"')
- return (NULL);
- *t++ = '\0';
- }
- else {
- for (t = p; *t != ' ' && *t != '\t' && *t != '\0'; t++)
- if (*t == '#' && (t == p || *(t - 1) != '\\')) {
- comment = true;
- break;
- }
- if (*t != '\0')
- *t++ = '\0';
- }
- if (*p == '\0' && cfeof(F)) return (NULL);
- word = xstrdup (p);
- p = F->buf;
- if (!comment)
- for (; *t != '\0'; t++)
- *p++ = *t;
- *p = '\0';
-
- return (word);
-}
-
-CONFFILE *CONFfopen(char *filename)
-{
- FILE *f;
- CONFFILE *ret;
-
- f = fopen(filename, "r");
- if (!f)
- return(0);
- ret = xmalloc(sizeof(CONFFILE));
- if (!ret) {
- fclose(f);
- return(0);
- }
- ret->filename = xstrdup(filename);
- ret->buf = 0;
- ret->sbuf = 0;
- ret->lineno = 0;
- ret->f = f;
- ret->array = NULL;
- return(ret);
-}
-
-void CONFfclose(CONFFILE *f)
-{
- if (!f) return; /* No conf file */
- fclose(f->f);
- if (f->buf)
- free(f->buf);
- if (f->filename)
- free(f->filename);
- free(f);
-}
-
-CONFTOKEN *CONFgettoken(CONFTOKEN *toklist, CONFFILE *file)
-{
- char *word;
- static CONFTOKEN ret = {CONFstring, 0};
- int i;
-
- if (ret.name) {
- free(ret.name);
- ret.name = 0;
- }
- word = CONFgetword(file);
- if (!word)
- return(0);
- if (toklist) {
- for (i = 0; toklist[i].type; i++) {
- if (strcmp(word, toklist[i].name) == 0) {
- free(word);
- return(&toklist[i]);
- }
- }
- }
- ret.name = word;
- return(&ret);
-}
+++ /dev/null
-/* $Id: confparse.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Parse a standard block-structured configuration file syntax.
-**
-** Herein are all the parsing and access functions for the configuration
-** syntax used by INN. See doc/config-* for additional documentation.
-**
-** All entry point functions begin with config_*. config_parse_file is
-** the entry point for most of the work done in this file; all other
-** functions access the parse tree that config_parse_file generates.
-**
-** Functions are named by the structure or basic task they work on:
-**
-** parameter_* config_parameter structs.
-** group_* config_group structs.
-** file_* config_file structs (including all I/O).
-** token_* The guts of the lexer.
-** parse_* The guts of the parser.
-** error_* Error reporting functions.
-** convert_* Converting raw parameter values.
-**
-** Each currently open file is represented by a config_file struct, which
-** contains the current parse state for that file, including the internal
-** buffer, a pointer to where in the buffer the next token starts, and the
-** current token. Inclusion of additional files is handled by maintaining a
-** stack of config_file structs, so when one file is finished, the top struct
-** popped off the stack and parsing continues where it left off.
-**
-** Since config_file structs contain the parse state, they're passed as an
-** argument to most functions.
-**
-** A config_file struct contains a token struct, representing the current
-** token. The configuration file syntax is specifically designed to never
-** require lookahead to parse; all parse decisions can be made on the basis
-** of the current state and a single token. A token consists of a type and
-** an optional attached string. Note that strings are allocated by the lexer
-** but are never freed by the lexer! Any token with an associated string
-** should have that string copied into permanent storage (like the params
-** hash of a config_group) or freed. error_unexpected_token will do the
-** latter.
-**
-** Errors in the lexer are indicated by setting the token to TOKEN_ERROR.
-** All parsing errors are indicated by setting the error flag in the current
-** config_file struct. Error recovery is *not* implemented by the current
-** algorithm; it would add a lot of complexity to the parsing algorithm and
-** the results still probably shouldn't be used by the calling program, so it
-** would only be useful to catch more than one syntax error per invocation
-** and it isn't expected that syntax errors will be that common. Instead, if
-** something fails to parse, the whole parser unwinds and returns failure.
-**
-** The config_param_* functions are used to retrieve the values of
-** parameters; each use a convert_* function to convert the raw parameter
-** value to the type specified by the user. group_parameter_get can
-** therefore be the same for all parameter types, with all of the variations
-** encapsulated in the convert_* functions.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-
-#include "inn/confparse.h"
-#include "inn/hashtab.h"
-#include "inn/messages.h"
-#include "inn/vector.h"
-#include "libinn.h"
-
-
-/* The types of tokens seen in configuration files. */
-enum token_type {
- TOKEN_CRLF,
- TOKEN_STRING,
- TOKEN_QSTRING,
- TOKEN_PARAM,
- TOKEN_LBRACE,
- TOKEN_RBRACE,
- TOKEN_LANGLE,
- TOKEN_RANGLE,
- TOKEN_LBRACKET,
- TOKEN_RBRACKET,
- TOKEN_SEMICOLON,
- TOKEN_EOF,
- TOKEN_ERROR
-};
-
-/* The parse status of a file. Variables marked internal are only used by
- file_* functions; other functions don't need to look at them. Other
- variables are marked by what functions are responsible for maintaining
- them. */
-struct config_file {
- int fd; /* Internal */
- char *buffer; /* Internal */
- size_t bufsize; /* Internal */
- const char *filename; /* file_open */
- unsigned int line; /* token_newline and token_quoted_string */
- bool error; /* Everyone */
-
- /* Set by file_* and token_*. current == NULL indicates we've not yet
- read from the file. */
- char *current;
-
- /* Normally set by token_*, but file_read and file_read_more may set token
- to TOKEN_ERROR or TOKEN_EOF when those conditions are encountered. In
- that situation, they also return false. */
- struct {
- enum token_type type;
- char *string;
- } token;
-};
-
-/* The types of parameters, used to distinguish the values of the union in the
- config_parameter_s struct. */
-enum value_type {
- VALUE_UNKNOWN,
- VALUE_BOOL,
- VALUE_INTEGER,
- VALUE_NUMBER,
- VALUE_STRING,
- VALUE_LIST,
- VALUE_INVALID
-};
-
-/* Each setting is represented by one of these structs, stored in the params
- hash of a config group. Since all of a config_group must be in the same
- file (either group->file for regular groups or group->included for groups
- whose definition is in an included file), we don't have to stash a file
- name here for error reporting but can instead get that from the enclosing
- group. */
-struct config_parameter {
- char *key;
- char *raw_value;
- unsigned int line; /* For error reporting. */
- enum value_type type;
- union {
- bool boolean;
- long integer;
- double number;
- char *string;
- struct vector *list;
- } value;
-};
-
-/* The type of a function that converts a raw parameter value to some other
- data type, storing the result in its second argument and returning true on
- success or false on failure. */
-typedef bool (*convert_func)(struct config_parameter *, const char *, void *);
-
-/* The basic element of configuration data, a group of parameters. This is
- the only struct that is exposed to callers, and then only as an opaque
- data structure. */
-struct config_group {
- char *type;
- char *tag;
- char *file; /* File in which the group starts. */
- unsigned int line; /* Line number where the group starts. */
- char *included; /* For group <file>, the included file. */
- struct hash *params;
-
- struct config_group *parent;
- struct config_group *child;
- struct config_group *next;
-};
-
-
-/* Parameter handling, used by the hash table stored in a config_group. */
-static const void *parameter_key(const void *p);
-static bool parameter_equal(const void *k, const void *p);
-static void parameter_free(void *p);
-
-/* Hash traversal function to collect parameters into a vector. */
-static void parameter_collect(void *, void *);
-
-/* Group handling. */
-static struct config_group *group_new(const char *file, unsigned int line,
- const char *type, const char *tag);
-static void group_free(struct config_group *);
-static bool group_parameter_get(struct config_group *group, const char *key,
- void *result, convert_func convert);
-
-/* Parameter type conversion functions. All take the parameter, the file, and
- a pointer to where the result can be placed. */
-static bool convert_boolean(struct config_parameter *, const char *, void *);
-static bool convert_integer(struct config_parameter *, const char *, void *);
-static bool convert_string(struct config_parameter *, const char *, void *);
-
-/* File I/O. Many other functions also manipulate config_file structs; see
- the struct definition for notes on who's responsible for what. */
-static struct config_file *file_open(const char *filename);
-static bool file_read(struct config_file *);
-static bool file_read_more(struct config_file *, ptrdiff_t offset);
-static void file_close(struct config_file *);
-
-/* The basic lexer function. The token is stashed in file; the return value
- is just for convenience and duplicates that information. */
-static enum token_type token_next(struct config_file *);
-
-/* Handler functions for specific types of tokens. These should only be
- called by token_next. */
-static void token_simple(struct config_file *, enum token_type type);
-static void token_newline(struct config_file *);
-static void token_string(struct config_file *);
-static void token_quoted_string(struct config_file *);
-
-/* Handles whitespace for the rest of the lexer. */
-static bool token_skip_whitespace(struct config_file *);
-
-/* Handles comments for the rest of the lexer. */
-static bool token_skip_comment(struct config_file *);
-
-/* Parser functions to parse the named syntactic element. */
-static bool parse_group_contents(struct config_group *, struct config_file *);
-static enum token_type parse_parameter(struct config_group *,
- struct config_file *, char *key);
-
-/* Error reporting functions. */
-static void error_bad_unquoted_char(struct config_file *, char bad);
-static void error_unexpected_token(struct config_file *,
- const char *expecting);
-
-
-/*
-** Return the key from a parameter struct, used by the hash table.
-*/
-static const void *
-parameter_key(const void *p)
-{
- const struct config_parameter *param = p;
-
- return param->key;
-}
-
-
-/*
-** Check to see if a provided key matches the key of a parameter struct,
-** used by the hash table.
-*/
-static bool
-parameter_equal(const void *k, const void *p)
-{
- const char *key = k;
- const struct config_parameter *param = p;
-
- return strcmp(key, param->key) == 0;
-}
-
-
-/*
-** Free a parameter, used by the hash table.
-*/
-static void
-parameter_free(void *p)
-{
- struct config_parameter *param = p;
-
- free(param->key);
- free(param->raw_value);
- if (param->type == VALUE_STRING) {
- free(param->value.string);
- } else if (param->type == VALUE_LIST) {
- vector_free(param->value.list);
- }
- free(param);
-}
-
-
-/*
-** Report an unexpected character while parsing a regular string and set the
-** current token type to TOKEN_ERROR.
-*/
-static void
-error_bad_unquoted_char(struct config_file *file, char bad)
-{
- warn("%s:%u: invalid character '%c' in unquoted string", file->filename,
- file->line, bad);
- file->token.type = TOKEN_ERROR;
- file->error = true;
-}
-
-
-/*
-** Report an unexpected token. If the token is TOKEN_ERROR, don't print an
-** additional error message. Takes a string saying what token was expected.
-** Sets the token to TOKEN_ERROR and frees the associated string if the
-** current token type is TOKEN_STRING, TOKEN_QSTRING, or TOKEN_PARAM.
-*/
-static void
-error_unexpected_token(struct config_file *file, const char *expecting)
-{
- const char *name;
- bool string = false;
-
- /* If the bad token type is a string, param, or quoted string, free the
- string associated with the token to avoid a memory leak. */
- if (file->token.type != TOKEN_ERROR) {
- switch (file->token.type) {
- case TOKEN_STRING: name = "string"; string = true; break;
- case TOKEN_QSTRING: name = "quoted string"; string = true; break;
- case TOKEN_PARAM: name = "parameter"; string = true; break;
- case TOKEN_CRLF: name = "end of line"; break;
- case TOKEN_LBRACE: name = "'{'"; break;
- case TOKEN_RBRACE: name = "'}'"; break;
- case TOKEN_LANGLE: name = "'<'"; break;
- case TOKEN_RANGLE: name = "'>'"; break;
- case TOKEN_LBRACKET: name = "'['"; break;
- case TOKEN_RBRACKET: name = "']'"; break;
- case TOKEN_SEMICOLON: name = "';'"; break;
- case TOKEN_EOF: name = "end of file"; break;
- default: name = "unknown token"; break;
- }
- warn("%s:%u: parse error: saw %s, expecting %s", file->filename,
- file->line, name, expecting);
- }
- if (string) {
- free(file->token.string);
- file->token.string = NULL;
- }
- file->token.type = TOKEN_ERROR;
- file->error = true;
-}
-
-
-/*
-** Handle a simple token (a single character), advancing the file->current
-** pointer past it and setting file->token as appropriate.
-*/
-static void
-token_simple(struct config_file *file, enum token_type type)
-{
- file->current++;
- file->token.type = type;
- file->token.string = NULL;
-}
-
-
-/*
-** Handle a newline. Skip any number of comments after the newline,
-** including reading more data from the file if necessary, and update
-** file->line as needed.
-*/
-static void
-token_newline(struct config_file *file)
-{
- /* If we're actually positioned on a newline, update file->line and skip
- over it. Try to handle CRLF correctly, as a single line terminator
- that only increments the line count once, while still treating either
- CR or LF alone as line terminators in their own regard. */
- if (*file->current == '\n') {
- file->current++;
- file->line++;
- } else if (*file->current == '\r') {
- if (file->current[1] == '\n')
- file->current += 2;
- else if (file->current[1] != '\0')
- file->current++;
- else {
- if (!file_read(file)) {
- file->current++;
- return;
- }
- if (*file->current == '\n')
- file->current++;
- }
- file->line++;
- }
-
- if (!token_skip_whitespace(file))
- return;
- while (*file->current == '#') {
- if (!token_skip_comment(file))
- return;
- if (!token_skip_whitespace(file))
- return;
- }
- file->token.type = TOKEN_CRLF;
- file->token.string = NULL;
-}
-
-
-/*
-** Handle a string. Only some characters are allowed in an unquoted string;
-** check that, since otherwise it could hide syntax errors. Any whitespace
-** ends the token. We have to distinguish between TOKEN_PARAM and
-** TOKEN_STRING; the former ends in a colon, unlike the latter.
-*/
-static void
-token_string(struct config_file *file)
-{
- int i;
- bool status;
- ptrdiff_t offset;
- bool done = false;
- bool colon = false;
-
- /* Use an offset from file->current rather than a pointer that moves
- through the buffer, since the base of file->current can change during a
- file_read_more() call and we don't want to have to readjust a
- pointer. If we have to read more, adjust our counter back one
- character, since the nul was replaced by a new, valid character. */
- i = 0;
- while (!done) {
- switch (file->current[i]) {
- case '\t': case '\r': case '\n': case ' ': case ';':
- done = true;
- break;
- case '"': case '<': case '>': case '[':
- case '\\': case ']': case '{': case '}':
- error_bad_unquoted_char(file, file->current[i]);
- return;
- case ':':
- if (colon) {
- error_bad_unquoted_char(file, file->current[i]);
- return;
- }
- colon = true;
- break;
- case '\0':
- offset = file->current - file->buffer;
- status = file_read_more(file, offset);
- if (status)
- i--;
- else
- done = true;
- break;
- default:
- if (colon) {
- error_bad_unquoted_char(file, ':');
- return;
- }
- }
- if (!done)
- i++;
- }
- file->token.type = colon ? TOKEN_PARAM : TOKEN_STRING;
- file->token.string = xstrndup(file->current, i - colon);
- file->current += i;
-}
-
-
-/*
-** Handle a quoted string. This token is unique as the only token that can
-** contain whitespace, even newlines if they're escaped, so we also have to
-** update file->line as we go. Note that the quotes *are* included in the
-** string we stash in file->token, since they should be part of the raw_value
-** of a parameter.
-*/
-static void
-token_quoted_string(struct config_file *file)
-{
- int i;
- ptrdiff_t offset;
- bool status;
- bool done = false;
-
- /* Use an offset from file->current rather than a pointer that moves
- through the buffer, since the base of file->current can change during a
- file_read_more() call and we don't want to have to readjust a pointer.
- If we have to read more, adjust our counter back one character, since
- the nul was replaced by a new, valid character. */
- for (i = 1; !done; i++) {
- switch (file->current[i]) {
- case '"':
- done = true;
- break;
- case '\r':
- case '\n':
- warn("%s:%u: no close quote seen for quoted string",
- file->filename, file->line);
- file->token.type = TOKEN_ERROR;
- file->error = true;
- return;
- case '\\':
- i++;
- if (file->current[i] == '\n')
- file->line++;
-
- /* CRLF should count as one line terminator. Handle most cases of
- that here, but the case where CR is at the end of one buffer
- and LF at the beginning of the next has to be handled in the \0
- case below. */
- if (file->current[i] == '\r') {
- file->line++;
- if (file->current[i + 1] == '\n')
- i++;
- }
- break;
- case '\0':
- offset = file->current - file->buffer;
- status = file_read_more(file, offset);
- if (status)
- i--;
- else {
- warn("%s:%u: end of file encountered while parsing quoted"
- " string", file->filename, file->line);
- file->token.type = TOKEN_ERROR;
- file->error = true;
- return;
- }
-
- /* If the last character of the previous buffer was CR and the
- first character that we just read was LF, the CR must have been
- escaped which means that the LF is part of it, forming a CRLF
- line terminator. Skip over the LF. */
- if (file->current[i] == '\r' && file->current[i + 1] == '\n')
- i++;
-
- break;
- default:
- break;
- }
- }
- file->token.type = TOKEN_QSTRING;
- file->token.string = xstrndup(file->current, i);
- file->current += i;
-}
-
-
-/*
-** Skip over a comment line at file->current, reading more data as necessary.
-** Stop when an end of line is encountered, positioning file->current
-** directly after the end of line. Returns false on end of file or a read
-** error, true otherwise.
-*/
-static bool
-token_skip_comment(struct config_file *file)
-{
- char *p = file->current;
-
- while (*p != '\0' && *p != '\n' && *p != '\r')
- p++;
- while (*p == '\0') {
- if (!file_read(file))
- return false;
- p = file->current;
- while (*p != '\0' && *p != '\n' && *p != '\r')
- p++;
- }
-
- /* CRLF should count as a single line terminator, but it may be split
- across a read boundary. Try to handle that case correctly. */
- if (*p == '\n')
- p++;
- else if (*p == '\r') {
- p++;
- if (*p == '\n')
- p++;
- else if (*p == '\0') {
- if (!file_read(file))
- return false;
- p = file->current;
- if (*p == '\n')
- p++;
- }
- }
- file->current = p;
- file->line++;
- return true;
-}
-
-/*
-** Skip over all whitespace at file->current, reading more data as
-** necessary. Stop when the first non-whitespace character is encountered or
-** at end of file, leaving file->current pointing appropriately. Returns
-** true if non-whitespace is found and false on end of file or a read error.
-*/
-static bool
-token_skip_whitespace(struct config_file *file)
-{
- char *p = file->current;
-
- while (*p == ' ' || *p == '\t')
- p++;
- while (*p == '\0') {
- if (!file_read(file))
- return false;
- p = file->current;
- while (*p == ' ' || *p == '\t')
- p++;
- }
- file->current = p;
- return true;
-}
-
-
-/*
-** The basic lexer function. Read the next token from a configuration file.
-** Returns the token, which is also stored in file. Lexer failures set the
-** token to TOKEN_ERROR.
-*/
-static enum token_type
-token_next(struct config_file *file)
-{
- /* If file->current is NULL, we've never read from the file. There is
- special handling for a comment at the very beginning of a file, since
- normally we only look for comments after newline tokens.
-
- If we do see a # at the beginning of the first line, let token_newline
- deal with it. That function can cope with file->current not pointing
- at a newline. We then return the newline token as the first token in
- the file. */
- if (file->current == NULL) {
- if (!file_read(file))
- return file->token.type;
- if (!token_skip_whitespace(file))
- return file->token.type;
- if (*file->current == '#') {
- token_newline(file);
- return file->token.type;
- }
- } else {
- if (!token_skip_whitespace(file))
- return file->token.type;
- }
-
- /* Almost all of our tokens can be recognized by the first character; the
- only exception is telling strings from parameters. token_string
- handles both of those and sets file->token.type appropriately.
- Comments are handled by token_newline. */
- switch (*file->current) {
- case '{': token_simple(file, TOKEN_LBRACE); break;
- case '}': token_simple(file, TOKEN_RBRACE); break;
- case '<': token_simple(file, TOKEN_LANGLE); break;
- case '>': token_simple(file, TOKEN_RANGLE); break;
- case '[': token_simple(file, TOKEN_LBRACKET); break;
- case ']': token_simple(file, TOKEN_RBRACKET); break;
- case ';': token_simple(file, TOKEN_SEMICOLON); break;
- case '\r': token_newline(file); break;
- case '\n': token_newline(file); break;
- case '"': token_quoted_string(file); break;
- default: token_string(file); break;
- }
-
- return file->token.type;
-}
-
-
-/*
-** Open a new configuration file and return config_file representing the
-** parse state of that file. We assume that we don't have to make a copy of
-** the filename argument. Default to stdio BUFSIZ for our buffer size, since
-** it's generally reasonably chosen with respect to disk block sizes, memory
-** consumption, and the like.
-*/
-static struct config_file *
-file_open(const char *filename)
-{
- struct config_file *file;
-
- file = xmalloc(sizeof(*file));
- file->filename = filename;
- file->fd = open(filename, O_RDONLY);
- if (file->fd < 0) {
- free(file);
- return NULL;
- }
- file->buffer = xmalloc(BUFSIZ);
- file->bufsize = BUFSIZ;
- file->current = NULL;
- file->line = 1;
- file->token.type = TOKEN_ERROR;
- file->error = false;
- return file;
-}
-
-
-/*
-** Read some data from a configuration file, handling errors (by reporting
-** them with warn) and returning true if there's data left and false on EOF
-** or a read error.
-*/
-static bool
-file_read(struct config_file *file)
-{
- ssize_t status;
-
- status = read(file->fd, file->buffer, file->bufsize - 1);
- if (status < 0) {
- syswarn("%s: read error", file->filename);
- file->token.type = TOKEN_ERROR;
- file->error = true;
- } else if (status == 0) {
- file->token.type = TOKEN_EOF;
- }
- if (status <= 0)
- return false;
- file->buffer[status] = '\0';
- file->current = file->buffer;
-
- /* Reject nuls, since otherwise they would cause strange problems. */
- if (strlen(file->buffer) != (size_t) status) {
- warn("%s: invalid NUL character found in file", file->filename);
- return false;
- }
- return true;
-}
-
-
-/*
-** Read additional data from a configuration file when there's some partial
-** data in the buffer already that we want to save. Takes the config_file
-** struct and an offset from file->buffer specifying the start of the data
-** that we want to preserve. Resizes the buffer if offset is 0. Returns
-** false on EOF or a read error, true otherwise.
-*/
-static bool
-file_read_more(struct config_file *file, ptrdiff_t offset)
-{
- char *start;
- size_t amount;
- ssize_t status;
-
- if (offset > 0) {
- size_t left;
-
- left = file->bufsize - offset - 1;
- memmove(file->buffer, file->buffer + offset, left);
- file->current -= offset;
- start = file->buffer + left;
- amount = offset;
- } else {
- file->buffer = xrealloc(file->buffer, file->bufsize + BUFSIZ);
- file->current = file->buffer;
- start = file->buffer + file->bufsize - 1;
- amount = BUFSIZ;
- file->bufsize += BUFSIZ;
- }
- status = read(file->fd, start, amount);
- if (status < 0)
- syswarn("%s: read error", file->filename);
- if (status <= 0)
- return false;
- start[status] = '\0';
-
- /* Reject nuls, since otherwise they would cause strange problems. */
- if (strlen(start) != (size_t) status) {
- warn("%s: invalid NUL character found in file", file->filename);
- return false;
- }
- return true;
-}
-
-
-/*
-** Close a file and free the resources associated with it.
-*/
-static void
-file_close(struct config_file *file)
-{
- close(file->fd);
- free(file->buffer);
- free(file);
-}
-
-
-/*
-** Given a config_group with the type and tag already filled in and a
-** config_file with the buffer positioned after the opening brace of the
-** group, read and add parameters to the group until encountering a close
-** brace. Returns true on a successful parse, false on an error that
-** indicates the group should be discarded.
-*/
-static bool
-parse_group_contents(struct config_group *group, struct config_file *file)
-{
- enum token_type token;
-
- token = token_next(file);
- while (!file->error) {
- switch (token) {
- case TOKEN_PARAM:
- token = parse_parameter(group, file, file->token.string);
- while (token == TOKEN_CRLF || token == TOKEN_SEMICOLON)
- token = token_next(file);
- break;
- case TOKEN_CRLF:
- token = token_next(file);
- break;
- case TOKEN_EOF:
- return true;
- default:
- error_unexpected_token(file, "parameter");
- break;
- }
- }
- return false;
-}
-
-
-/*
-** Parse a parameter. Takes the group we're currently inside, the
-** config_file parse state, and the key of the parameter. Returns the next
-** token after the parameter, and also checks to make sure that it's
-** something legal (end of line, end of file, or a semicolon).
-*/
-static enum token_type
-parse_parameter(struct config_group *group, struct config_file *file,
- char *key)
-{
- enum token_type token;
-
- token = token_next(file);
- if (token == TOKEN_STRING || token == TOKEN_QSTRING) {
- struct config_parameter *param;
- unsigned int line;
- char *value;
-
- /* Before storing the parameter, check to make sure that the next
- token is valid. If it isn't, chances are high that the user has
- tried to set a parameter to a value containing spaces without
- quoting the value. */
- value = file->token.string;
- line = file->line;
- token = token_next(file);
- switch (token) {
- default:
- error_unexpected_token(file, "semicolon or newline");
- free(value);
- break;
- case TOKEN_CRLF:
- case TOKEN_SEMICOLON:
- case TOKEN_EOF:
- param = xmalloc(sizeof(*param));
- param->key = key;
- param->raw_value = value;
- param->type = VALUE_UNKNOWN;
- param->line = line;
- if (!hash_insert(group->params, key, param)) {
- warn("%s:%u: duplicate parameter %s", file->filename, line,
- key);
- free(param->raw_value);
- free(param->key);
- free(param);
- }
- return token;
- }
- } else {
- error_unexpected_token(file, "parameter value");
- }
-
- /* If we fell through, we encountered some sort of error. Free allocated
- memory and return an error token. */
- free(key);
- return TOKEN_ERROR;
-}
-
-
-/*
-** Allocate a new config_group and set the initial values of all of the
-** struct members.
-*/
-static struct config_group *
-group_new(const char *file, unsigned int line, const char *type,
- const char *tag)
-{
- struct config_group *group;
-
- group = xmalloc(sizeof(*group));
- group->type = xstrdup(type);
- group->tag = (tag == NULL) ? NULL : xstrdup(tag);
- group->file = xstrdup(file);
- group->included = NULL;
- group->line = line;
- group->params = hash_create(4, hash_string, parameter_key,
- parameter_equal, parameter_free);
- group->parent = NULL;
- group->child = NULL;
- group->next = NULL;
- return group;
-}
-
-
-/*
-** Free a config_group and all associated storage.
-*/
-static void
-group_free(struct config_group *group)
-{
- free(group->type);
- if (group->tag != NULL)
- free(group->tag);
- free(group->file);
- if (group->included != NULL)
- free(group->included);
- hash_free(group->params);
- free(group);
-}
-
-
-/*
-** Accessor function for the group type.
-*/
-const char *
-config_group_type(struct config_group *group)
-{
- return group->type;
-}
-
-
-/*
-** Accessor function for the group tag.
-*/
-const char *
-config_group_tag(struct config_group *group)
-{
- return group->tag;
-}
-
-
-/*
-** Parse a configuration file, returning the config_group that's the root of
-** the tree represented by that file (and any other files that it includes).
-** Returns NULL on a parse failure.
-*/
-struct config_group *
-config_parse_file(const char *filename, ...)
-{
- struct config_group *group;
- struct config_file *file;
- bool success;
-
- file = file_open(filename);
- if (file == NULL) {
- syswarn("open of %s failed", filename);
- return NULL;
- }
- group = group_new(filename, 1, "GLOBAL", NULL);
- success = parse_group_contents(group, file);
- file_close(file);
- return success ? group : NULL;
-}
-
-
-/*
-** Given a config_group representing the root of a configuration structure,
-** recursively free the entire structure.
-*/
-void
-config_free(struct config_group *group)
-{
- group_free(group);
-}
-
-
-/*
-** Convert a given parameter value to a boolean, returning true if successful
-** and false otherwise.
-*/
-static bool
-convert_boolean(struct config_parameter *param, const char *file,
- void *result)
-{
- static const char *const truevals[] = { "yes", "on", "true", NULL };
- static const char *const falsevals[] = { "no", "off", "false", NULL };
- bool *value = result;
- int i;
-
- if (param->type == VALUE_BOOL) {
- *value = param->value.boolean;
- return true;
- } else if (param->type != VALUE_UNKNOWN) {
- warn("%s:%u: %s is not a boolean", file, param->line, param->key);
- return false;
- }
- param->type = VALUE_BOOL;
- for (i = 0; truevals[i] != NULL; i++)
- if (strcmp(param->raw_value, truevals[i]) == 0) {
- param->value.boolean = true;
- *value = true;
- return true;
- }
- for (i = 0; falsevals[i] != NULL; i++)
- if (strcmp(param->raw_value, falsevals[i]) == 0) {
- param->value.boolean = false;
- *value = false;
- return true;
- }
- param->type = VALUE_INVALID;
- warn("%s:%u: %s is not a boolean", file, param->line, param->key);
- return false;
-}
-
-
-/*
-** Convert a given parameter value to an integer, returning true if
-** successful and false otherwise.
-*/
-static bool
-convert_integer(struct config_parameter *param, const char *file,
- void *result)
-{
- long *value = result;
- char *p;
-
- if (param->type == VALUE_INTEGER) {
- *value = param->value.integer;
- return true;
- } else if (param->type != VALUE_UNKNOWN) {
- warn("%s:%u: %s is not an integer", file, param->line, param->key);
- return false;
- }
-
- /* Do a syntax check even though strtol would do some of this for us,
- since otherwise some syntax errors may go silently undetected. */
- p = param->raw_value;
- if (*p == '-')
- p++;
- for (; *p != '\0'; p++)
- if (*p < '0' || *p > '9')
- break;
- if (*p != '\0') {
- warn("%s:%u: %s is not an integer", file, param->line, param->key);
- return false;
- }
-
- /* Do the actual conversion with strtol. */
- errno = 0;
- param->value.integer = strtol(param->raw_value, NULL, 10);
- if (errno != 0) {
- warn("%s:%u: %s doesn't convert to an integer", file, param->line,
- param->key);
- return false;
- }
- *value = param->value.integer;
- param->type = VALUE_INTEGER;
- return true;
-}
-
-
-/*
-** Convert a parameter value to a string, interpreting it as a quoted string,
-** and returning true if successful and false otherwise. Does none of the
-** initial type checking, since convert_string should have already done that.
-*/
-static bool
-convert_string_quoted(struct config_parameter *param, const char *file,
- void *result)
-{
- const char **value = result;
- size_t length;
- char *src, *dest;
-
- length = strlen(param->raw_value) - 2;
- param->value.string = xmalloc(length + 1);
- src = param->raw_value + 1;
- dest = param->value.string;
- for (; *src != '"' && *src != '\0'; src++) {
- if (*src != '\\') {
- *dest++ = *src;
- } else {
- src++;
-
- /* This should implement precisely the semantics of backslash
- escapes in quoted strings in C. */
- switch (*src) {
- case 'a': *dest++ = '\a'; break;
- case 'b': *dest++ = '\b'; break;
- case 'f': *dest++ = '\f'; break;
- case 'n': *dest++ = '\n'; break;
- case 'r': *dest++ = '\r'; break;
- case 't': *dest++ = '\t'; break;
- case 'v': *dest++ = '\v'; break;
-
- case '\n': break; /* Escaped newlines disappear. */
-
- case '\\':
- case '\'':
- case '"':
- case '?':
- *dest++ = *src;
- break;
-
- case '\0':
- /* Should never happen; the tokenizer should catch this. */
- warn("%s:%u: unterminated string", file, param->line);
- goto fail;
-
- default:
- /* FIXME: \<octal>, \x, \u, and \U not yet implemented; the
- last three could use the same basic code. Think about
- whether the escape should generate a single 8-bit character
- or a UTF-8 encoded character; maybe the first two generate
- the former and \u and \U generate the latter? */
- warn("%s:%u: unrecognized escape '\\%c'", file, param->line,
- *src);
- goto fail;
- }
- }
- }
- *dest = '\0';
-
- /* The tokenizer already checked this for most cases but could miss the
- case where the final quote mark is escaped with a backslash. */
- if (*src != '"') {
- warn("%s:%u: unterminated string (no closing quote)", file,
- param->line);
- goto fail;
- }
-
- param->type = VALUE_STRING;
- *value = param->value.string;
- return true;
-
- fail:
- free(param->value.string);
- return false;
-}
-
-
-/*
-** Convert a given parameter value to a string, returning true if successful
-** and false otherwise.
-*/
-static bool
-convert_string(struct config_parameter *param, const char *file, void *result)
-{
- const char **value = result;
-
- if (param->type == VALUE_STRING) {
- *value = param->value.string;
- return true;
- } else if (param->type != VALUE_UNKNOWN) {
- warn("%s:%u: %s is not an string", file, param->line, param->key);
- return false;
- }
-
- if (*param->raw_value == '"') {
- return convert_string_quoted(param, file, result);
- } else {
- param->value.string = xstrdup(param->raw_value);
- param->type = VALUE_STRING;
- *value = param->value.string;
- return true;
- }
-}
-
-
-/*
-** Given a group, query it for the given parameter and then when the
-** parameter is found, check to see if it's already marked invalid. If so,
-** fail quietly; otherwise, hand it off to the conversion function to do
-** type-specific work, returning the result. Returns true if the parameter
-** is found in the group or one of its parents and convert can successfully
-** convert the raw value and put it in result, false otherwise (either for
-** the parameter not being found or for it being the wrong type).
-*/
-static bool
-group_parameter_get(struct config_group *group, const char *key, void *result,
- convert_func convert)
-{
- struct config_group *current = group;
-
- while (current != NULL) {
- struct config_parameter *param;
-
- param = hash_lookup(group->params, key);
- if (param != NULL) {
- if (param->type == VALUE_INVALID)
- return false;
- else
- return (*convert)(param, group->file, result);
- }
- current = group->parent;
- }
- return false;
-}
-
-
-/*
-** All of the config_param_* functions do the following:
-**
-** Given a group, query it for the given parameter, interpreting its value as
-** the appropriate type and returning it in the third argument. Returns true
-** on success, false on failure (such as the parameter not being set or an
-** error), and report errors via warn.
-*/
-bool
-config_param_boolean(struct config_group *group, const char *key,
- bool *result)
-{
- return group_parameter_get(group, key, result, convert_boolean);
-}
-
-bool
-config_param_integer(struct config_group *group, const char *key,
- long *result)
-{
- return group_parameter_get(group, key, result, convert_integer);
-}
-
-bool
-config_param_string(struct config_group *group, const char *key,
- const char **result)
-{
- return group_parameter_get(group, key, result, convert_string);
-}
-
-
-/*
-** A hash traversal function to add all parameter keys to the vector provided
-** as the second argument.
-*/
-static void
-parameter_collect(void *element, void *cookie)
-{
- struct config_parameter *param = element;
- struct vector *params = cookie;
-
- vector_add(params, param->key);
-}
-
-
-/*
-** Returns a newly allocated vector of all of the config parameters in a
-** group, including the inherited ones (not implemented yet).
-*/
-struct vector *
-config_params(struct config_group *group)
-{
- struct vector *params;
- size_t size;
-
- /* Size the vector, which we can do accurately for now. */
- params = vector_new();
- size = hash_count(group->params);
- vector_resize(params, size);
-
- /* Now, walk the hash to build the vector of params. */
- hash_traverse(group->params, parameter_collect, params);
- return params;
-}
-
-
-/*
-** Report an error in a given parameter. Used so that the file and line
-** number can be included in the error message.
-*/
-void
-config_error_param(struct config_group *group, const char *key,
- const char *fmt, ...)
-{
- va_list args;
- ssize_t length;
- char *message, *file;
- struct config_parameter *param;
-
- va_start(args, fmt);
- length = vsnprintf(NULL, 0, fmt, args);
- va_end(args);
- if (length < 0)
- return;
- message = xmalloc(length + 1);
- va_start(args, fmt);
- vsnprintf(message, length + 1, fmt, args);
- va_end(args);
-
- param = hash_lookup(group->params, key);
- if (param == NULL)
- warn("%s", message);
- else {
- file = (group->included != NULL ? group->included : group->file);
- warn("%s:%u: %s", file, param->line, message);
- }
-
- free(message);
-}
-
-
-/*
-** Stubs for functions not yet implemented.
-*/
-struct config_group *
-config_find_group(struct config_group *group UNUSED, const char *type UNUSED)
-{
- return NULL;
-}
-
-struct config_group *
-config_next_group(struct config_group *group UNUSED)
-{
- return NULL;
-}
-
-bool
-config_param_real(struct config_group *group UNUSED, const char *key UNUSED,
- double *result UNUSED)
-{
- return false;
-}
-
-bool
-config_param_list(struct config_group *group UNUSED, const char *key UNUSED,
- struct vector *result UNUSED)
-{
- return false;
-}
-
-void
-config_error_group(struct config_group *group UNUSED, const char *fmt UNUSED,
- ...)
-{
-}
+++ /dev/null
-/* $Id: daemonize.c 6395 2003-07-12 19:13:49Z rra $
-**
-** Become a long-running daemon.
-**
-** Usage:
-**
-** daemonize(path);
-**
-** Performs all of the various system-specific stuff required to become a
-** long-running daemon. Also chdir to the provided path (which is where
-** core dumps will go on most systems).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-void
-daemonize(const char *path)
-{
- int status;
- int fd;
-
- /* Fork and exit in the parent to disassociate from the current process
- group and become the leader of a new process group. */
- status = fork();
- if (status < 0)
- sysdie("cant fork");
- else if (status > 0)
- _exit(0);
-
- /* setsid() should take care of disassociating from the controlling
- terminal, and FreeBSD at least doesn't like TIOCNOTTY if you don't
- already have a controlling terminal. So only use the older TIOCNOTTY
- method if setsid() isn't available. */
-#if HAVE_SETSID
- if (setsid() < 0)
- syswarn("cant become session leader");
-#elif defined(TIOCNOTTY)
- fd = open("/dev/tty", O_RDWR);
- if (fd >= 0) {
- if (ioctl(fd, TIOCNOTTY, NULL) < 0)
- syswarn("cant disassociate from the terminal");
- close(fd);
- }
-#endif /* defined(TIOCNOTTY) */
-
- if (chdir(path) < 0)
- syswarn("cant chdir to %s", path);
-
- fd = open("/dev/null", O_RDWR, 0);
- if (fd != -1) {
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (fd > 2)
- close(fd);
- }
-}
+++ /dev/null
-/* $Id: date.c 7136 2005-03-11 19:18:27Z rra $
-**
-** Date parsing and conversion routines.
-**
-** Provides various date parsing and conversion routines, including
-** generating Date headers for posted articles. Note that the parsedate
-** parser is separate from this file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <time.h>
-
-#include "libinn.h"
-
-/*
-** Time constants.
-**
-** Do not translate these names. RFC 822 by way of RFC 1036 requires that
-** weekday and month names *not* be translated. This is why we use static
-** tables rather than strftime for building dates, to avoid locale
-** interference.
-*/
-
-static const char WEEKDAY[7][4] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
-};
-
-static const char MONTH[12][4] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
- "Nov", "Dec"
-};
-
-/* Number of days in a month. */
-static const int MONTHDAYS[] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/* Non-numeric time zones. Supporting these is required to support the
- obsolete date format of RFC 2822. The military time zones are handled
- separately. */
-static const struct {
- const char name[4];
- long offset;
-} ZONE_OFFSET[] = {
- { "UT", 0 }, { "GMT", 0 },
- { "EDT", -4 * 60 * 60 }, { "EST", -5 * 60 * 60 },
- { "CDT", -5 * 60 * 60 }, { "CST", -6 * 60 * 60 },
- { "MDT", -6 * 60 * 60 }, { "MST", -7 * 60 * 60 },
- { "PDT", -7 * 60 * 60 }, { "PST", -8 * 60 * 60 },
-};
-
-
-/*
-** Time parsing macros.
-*/
-
-/* Whether a given year is a leap year. */
-#define ISLEAP(year) \
- (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0))
-
-
-/*
-** RFC 2822 date parsing rules.
-*/
-
-/* The data structure to store a rule. The interpretation of the other fields
- is based on the value of type. For NUMBER, read between min and max
- characters and convert to a number. For LOOKUP, look for max characters
- and find that string in the provided table (with size elements). For
- DELIM, just make sure that we see the character stored in delimiter. */
-struct rule {
- enum {
- TYPE_NUMBER,
- TYPE_LOOKUP,
- TYPE_DELIM
- } type;
- char delimiter;
- const char (*table)[4];
- size_t size;
- int min;
- int max;
-};
-
-
-/*
-** Given a time as a time_t, return the offset in seconds of the local time
-** zone from UTC at that time (adding the offset to UTC time yields local
-** time). If the second argument is true, the time represents the current
-** time and in that circumstance we can assume that timezone/altzone are
-** correct. (We can't for arbitrary times in the past.)
-*/
-static long
-local_tz_offset(time_t date, bool current UNUSED)
-{
- struct tm *tm;
-#if !HAVE_TM_GMTOFF
- struct tm local, gmt;
- long offset;
-#endif
-
- tm = localtime(&date);
-
-#if !HAVE_TM_GMTOFF && HAVE_VAR_TIMEZONE
- if (current)
- return (tm->tm_isdst > 0) ? -altzone : -timezone;
-#endif
-
-#if HAVE_TM_GMTOFF
- return tm->tm_gmtoff;
-#else
- /* We don't have any easy returnable value, so we call both localtime
- and gmtime and calculate the difference. Assume that local time is
- never more than 24 hours away from UTC and ignore seconds. */
- local = *tm;
- tm = gmtime(&date);
- gmt = *tm;
- offset = local.tm_yday - gmt.tm_yday;
- if (offset < -1) {
- /* Local time is in the next year. */
- offset = 24;
- } else if (offset > 1) {
- /* Local time is in the previous year. */
- offset = -24;
- } else {
- offset *= 24;
- }
- offset += local.tm_hour - gmt.tm_hour;
- offset *= 60;
- offset += local.tm_min - gmt.tm_min;
- return offset * 60;
-#endif /* !HAVE_TM_GMTOFF */
-}
-
-
-/*
-** Given a time_t, a flag saying whether to use local time, a buffer, and
-** the length of the buffer, write the contents of a valid RFC 2822 / RFC
-** 1036 Date header into the buffer (provided it's long enough). Returns
-** true on success, false if the buffer is too long. Use snprintf rather
-** than strftime to be absolutely certain that locales don't result in the
-** wrong output. If the time is -1, obtain and use the current time.
-*/
-bool
-makedate(time_t date, bool local, char *buff, size_t buflen)
-{
- time_t realdate;
- struct tm *tmp_tm;
- struct tm tm;
- long tz_offset;
- int tz_hour_offset, tz_min_offset, tz_sign;
- size_t date_length;
- const char *tz_name;
-
- /* Make sure the buffer is large enough. A complete RFC 2822 date with
- spaces wherever FWS is required and the optional weekday takes:
-
- 1 2 3
- 1234567890123456789012345678901
- Sat, 31 Aug 2002 23:45:18 +0000
-
- 31 characters, plus another character for the trailing nul. The buffer
- will need to have another six characters of space to get the optional
- trailing time zone comment. */
- if (buflen < 32)
- return false;
-
- /* Get the current time if the provided time is -1. */
- realdate = (date == (time_t) -1) ? time(NULL) : date;
-
- /* RFC 2822 says the timezone offset is given as [+-]HHMM, so we have to
- separate the offset into a sign, hours, and minutes. Dividing the
- offset by 36 looks like it works, but will fail for any offset that
- isn't an even number of hours, and there are half-hour timezones. */
- if (local) {
- tmp_tm = localtime(&realdate);
- tm = *tmp_tm;
- tz_offset = local_tz_offset(realdate, date == (time_t) -1);
- tz_sign = (tz_offset < 0) ? -1 : 1;
- tz_offset *= tz_sign;
- tz_hour_offset = tz_offset / 3600;
- tz_min_offset = (tz_offset % 3600) / 60;
- } else {
- tmp_tm = gmtime(&realdate);
- tm = *tmp_tm;
- tz_sign = 1;
- tz_hour_offset = 0;
- tz_min_offset = 0;
- }
-
- /* tz_min_offset cannot be larger than 60 (by basic mathematics). If
- through some insane circumtances, tz_hour_offset would be larger,
- reject the time as invalid rather than generate an invalid date. */
- if (tz_hour_offset > 24)
- return false;
-
- /* Generate the actual date string, sans the trailing time zone comment
- but with the day of the week and the seconds (both of which are
- optional in the standard). */
- snprintf(buff, buflen, "%3.3s, %d %3.3s %d %02d:%02d:%02d %c%02d%02d",
- &WEEKDAY[tm.tm_wday][0], tm.tm_mday, &MONTH[tm.tm_mon][0],
- 1900 + tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec,
- (tz_sign > 0) ? '+' : '-', tz_hour_offset, tz_min_offset);
- date_length = strlen(buff);
-
- /* Now, get a pointer to the time zone abbreviation, and if there is
- enough room in the buffer, add it to the end of the date string as a
- comment. */
- if (!local) {
- tz_name = "UTC";
- } else {
-#if HAVE_TM_ZONE
- tz_name = tm.tm_zone;
-#elif HAVE_VAR_TZNAME
- tz_name = tzname[(tm.tm_isdst > 0) ? 1 : 0];
-#else
- tz_name = NULL;
-#endif
- }
- if (tz_name != NULL && date_length + 4 + strlen(tz_name) <= buflen) {
- snprintf(buff + date_length, buflen - date_length, " (%s)", tz_name);
- }
- return true;
-}
-
-
-/*
-** Given a struct tm representing a calendar time in UTC, convert it to
-** seconds since epoch. Returns (time_t) -1 if the time is not
-** convertable. Note that this function does not canonicalize the provided
-** struct tm, nor does it allow out of range values or years before 1970.
-*/
-static time_t
-mktime_utc(const struct tm *tm)
-{
- time_t result = 0;
- int i;
-
- /* We do allow some ill-formed dates, but we don't do anything special
- with them and our callers really shouldn't pass them to us. Do
- explicitly disallow the ones that would cause invalid array accesses
- or other algorithm problems. */
- if (tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70)
- return (time_t) -1;
-
- /* Convert to a time_t. */
- for (i = 1970; i < tm->tm_year + 1900; i++)
- result += 365 + ISLEAP(i);
- for (i = 0; i < tm->tm_mon; i++)
- result += MONTHDAYS[i];
- if (tm->tm_mon > 1 && ISLEAP(tm->tm_year + 1900))
- result++;
- result = 24 * (result + tm->tm_mday - 1) + tm->tm_hour;
- result = 60 * result + tm->tm_min;
- result = 60 * result + tm->tm_sec;
- return result;
-}
-
-
-/*
-** Check the ranges of values in a struct tm to make sure that the date was
-** well-formed. Assumes that the year has already been correctly set to
-** something (but may be before 1970).
-*/
-static bool
-valid_tm(const struct tm *tm)
-{
- if (tm->tm_sec > 60 || tm->tm_min > 59 || tm->tm_hour > 23)
- return false;
- if (tm->tm_mday < 1 || tm->tm_mon < 0 || tm->tm_mon > 11)
- return false;
-
- /* Make sure that the day isn't past the end of the month, allowing for
- leap years. */
- if (tm->tm_mday > MONTHDAYS[tm->tm_mon]
- && (tm->tm_mon != 1 || tm->tm_mday > 29
- || !ISLEAP(tm->tm_year + 1900)))
- return false;
-
- /* We can't handle years before 1970. */
- if (tm->tm_year < 70)
- return false;
-
- return true;
-}
-
-
-/*
-** Parse a date in the format used in NNTP commands such as NEWGROUPS and
-** NEWNEWS. The first argument is a string of the form YYYYMMDD and the
-** second a string of the form HHMMSS. The third argument is a boolean
-** flag saying whether the date is specified in local time; if false, the
-** date is assumed to be in UTC. Returns the time_t corresponding to the
-** given date and time or (time_t) -1 in the event of an error.
-*/
-time_t
-parsedate_nntp(const char *date, const char *hour, bool local)
-{
- const char *p;
- size_t datelen;
- time_t now, result;
- struct tm tm;
- struct tm *current;
- int century;
-
- /* Accept YYMMDD and YYYYMMDD. The first is what RFC 977 requires. The
- second is what the revision of RFC 977 will require. */
- datelen = strlen(date);
- if ((datelen != 6 && datelen != 8) || strlen(hour) != 6)
- return (time_t) -1;
- for (p = date; *p; p++)
- if (!CTYPE(isdigit, *p))
- return (time_t) -1;
- for (p = hour; *p; p++)
- if (!CTYPE(isdigit, *p))
- return (time_t) -1;
-
- /* Parse the date into a struct tm, skipping over the century part of
- the year, if any. We'll deal with it in a moment. */
- tm.tm_isdst = -1;
- p = date + datelen - 6;
- tm.tm_year = (p[0] - '0') * 10 + p[1] - '0';
- tm.tm_mon = (p[2] - '0') * 10 + p[3] - '0' - 1;
- tm.tm_mday = (p[4] - '0') * 10 + p[5] - '0';
- p = hour;
- tm.tm_hour = (p[0] - '0') * 10 + p[1] - '0';
- tm.tm_min = (p[2] - '0') * 10 + p[3] - '0';
- tm.tm_sec = (p[4] - '0') * 10 + p[5] - '0';
-
- /* Four-digit years are the easy case.
-
- For two-digit years, RFC 977 says "The closest century is assumed as
- part of the year (i.e., 86 specifies 1986, 30 specifies 2030, 99 is
- 1999, 00 is 2000)." draft-ietf-nntpext-base-10.txt simplifies this
- considerably and is what we implement:
-
- If the first two digits of the year are not specified, the year is
- to be taken from the current century if YY is smaller than or equal
- to the current year, otherwise the year is from the previous
- century.
-
- This implementation assumes "current year" means the last two digits
- of the current year. Note that this algorithm interacts poorly with
- clients with a slightly fast clock around the turn of a century, as
- it may send 00 for the year when the year on the server is still xx99
- and have it taken to be 99 years in the past. But 2000 has come and
- gone, and by 2100 news clients *really* should have started using UTC
- for everything like the new draft recommends. */
- if (datelen == 8) {
- tm.tm_year += (date[0] - '0') * 1000 + (date[1] - '0') * 100;
- tm.tm_year -= 1900;
- } else {
- now = time(NULL);
- current = local ? localtime(&now) : gmtime(&now);
- century = current->tm_year / 100;
- if (tm.tm_year > current->tm_year % 100)
- century--;
- tm.tm_year += century * 100;
- }
-
- /* Ensure that all of the date components are within valid ranges. */
- if (!valid_tm(&tm))
- return (time_t) -1;
-
- /* tm contains the broken-down date; convert it to a time_t. mktime
- assumes the supplied struct tm is in the local time zone; if given a
- time in UTC, use our own routine instead. */
- result = local ? mktime(&tm) : mktime_utc(&tm);
- return result;
-}
-
-
-/*
-** Skip any amount of CFWS (comments and folding whitespace), the RFC 2822
-** grammar term for whitespace, CRLF pairs, and possibly nested comments that
-** may contain escaped parens. We also allow simple newlines since we don't
-** always deal with wire-format messages. Note that we do not attempt to
-** ensure that CRLF or a newline is followed by whitespace. Returns the new
-** position of the pointer.
-*/
-static const char *
-skip_cfws(const char *p)
-{
- int nesting = 0;
-
- for (; *p != '\0'; p++) {
- switch (*p) {
- case ' ':
- case '\t':
- case '\n':
- break;
- case '\r':
- if (p[1] != '\n')
- return p;
- p++;
- break;
- case '(':
- nesting++;
- break;
- case ')':
- if (nesting == 0)
- return p;
- nesting--;
- break;
- case '\\':
- if (nesting == 0 || p[1] == '\0')
- return p;
- p++;
- break;
- default:
- if (nesting == 0)
- return p;
- break;
- }
- }
- return p;
-}
-
-
-/*
-** Parse a single number. Takes the parsing rule that we're applying and
-** returns a pointer to the new position of the parse stream. If there
-** aren't enough digits, return NULL.
-*/
-static const char *
-parse_number(const char *p, const struct rule *rule, int *value)
-{
- int count;
-
- *value = 0;
- for (count = 0; *p != '\0' && count < rule->max; p++, count++) {
- if (*p < '0' || *p > '9')
- break;
- *value = *value * 10 + (*p - '0');
- }
- if (count < rule->min || count > rule->max)
- return NULL;
- return p;
-}
-
-
-/*
-** Parse a single string value that has to be done via table lookup. Takes
-** the parsing rule that we're applying. Puts the index number of the string
-** if found into the value pointerand returns the new position of the string,
-** or NULL if the string could not be found in the table.
-*/
-static const char *
-parse_lookup(const char *p, const struct rule *rule, int *value)
-{
- size_t i;
-
- for (i = 0; i < rule->size; i++)
- if (strncasecmp(rule->table[i], p, rule->max) == 0) {
- p += rule->max;
- *value = i;
- return p;
- }
- return NULL;
-}
-
-
-/*
-** Apply a set of date parsing rules to a string. Returns the new position
-** in the parse string if this succeeds and NULL if it fails. As part of the
-** parse, stores values into the value pointer in the array of rules that was
-** passed in. Takes an array of rules and a count of rules in that array.
-*/
-static const char *
-parse_by_rule(const char *p, const struct rule rules[], size_t count,
- int *values)
-{
- size_t i;
- const struct rule *rule;
-
- for (i = 0; i < count; i++) {
- rule = &rules[i];
-
- switch (rule->type) {
- case TYPE_DELIM:
- if (*p != rule->delimiter)
- return NULL;
- p++;
- break;
- case TYPE_LOOKUP:
- p = parse_lookup(p, rule, &values[i]);
- if (p == NULL)
- return NULL;
- break;
- case TYPE_NUMBER:
- p = parse_number(p, rule, &values[i]);
- if (p == NULL)
- return NULL;
- break;
- }
-
- p = skip_cfws(p);
- }
- return p;
-}
-
-
-/*
-** Parse a legacy time zone. This uses the parsing rules in RFC 2822,
-** including assigning an offset of 0 to all single-character military time
-** zones due to their ambiguity in practice. Returns the new position in the
-** parse stream or NULL if we failed to parse the zone.
-*/
-static const char *
-parse_legacy_timezone(const char *p, long *offset)
-{
- const char *end;
- size_t max, i;
-
- for (end = p; *end != '\0' && !CTYPE(isspace, *end); end++)
- ;
- if (end == p)
- return NULL;
- max = end - p;
- for (i = 0; i < ARRAY_SIZE(ZONE_OFFSET); i++)
- if (strncasecmp(ZONE_OFFSET[i].name, p, max) == 0) {
- p += strlen(ZONE_OFFSET[i].name);
- *offset = ZONE_OFFSET[i].offset;
- return p;
- }
- if (max == 1 && CTYPE(isalpha, *p) && *p != 'J' && *p != 'j') {
- *offset = 0;
- return p + 1;
- }
- return NULL;
-}
-
-
-/*
-** Parse an RFC 2822 date, accepting the normal and obsolete syntax. Takes a
-** pointer to the beginning of the date and the length. Returns the
-** translated time in seconds since epoch, or (time_t) -1 on error.
-*/
-time_t
-parsedate_rfc2822(const char *date)
-{
- const char *p;
- int zone_sign;
- long zone_offset;
- struct tm tm;
- int values[8];
- time_t result;
-
- /* The basic rules. Note that we don't bother to check whether the day of
- the week is accurate or not. */
- static const struct rule base_rule[] = {
- { TYPE_LOOKUP, 0, WEEKDAY, 7, 3, 3 },
- { TYPE_DELIM, ',', NULL, 0, 1, 1 },
- { TYPE_NUMBER, 0, NULL, 0, 1, 2 },
- { TYPE_LOOKUP, 0, MONTH, 12, 3, 3 },
- { TYPE_NUMBER, 0, NULL, 0, 2, 4 },
- { TYPE_NUMBER, 0, NULL, 0, 2, 2 },
- { TYPE_DELIM, ':', NULL, 0, 1, 1 },
- { TYPE_NUMBER, 0, NULL, 0, 2, 2 }
- };
-
- /* Optional seconds at the end of the time. */
- static const struct rule seconds_rule[] = {
- { TYPE_DELIM, ':', NULL, 0, 1, 1 },
- { TYPE_NUMBER, 0, NULL, 0, 2, 2 }
- };
-
- /* Numeric time zone. */
- static const struct rule zone_rule[] = {
- { TYPE_NUMBER, 0, NULL, 0, 4, 4 }
- };
-
- /* Start with a clean slate. */
- memset(&tm, 0, sizeof(struct tm));
- memset(values, 0, sizeof(values));
-
- /* Parse the base part of the date. The initial day of the week is
- optional. */
- p = skip_cfws(date);
- if (CTYPE(isalpha, *p))
- p = parse_by_rule(p, base_rule, ARRAY_SIZE(base_rule), values);
- else
- p = parse_by_rule(p, base_rule + 2, ARRAY_SIZE(base_rule) - 2,
- values + 2);
- if (p == NULL)
- return (time_t) -1;
-
- /* Stash the results into a struct tm. Values are associated with the
- rule number of the same index. */
- tm.tm_mday = values[2];
- tm.tm_mon = values[3];
- tm.tm_year = values[4];
- tm.tm_hour = values[5];
- tm.tm_min = values[7];
-
- /* Parse seconds if they're present. */
- if (*p == ':') {
- p = parse_by_rule(p, seconds_rule, ARRAY_SIZE(seconds_rule), values);
- if (p == NULL)
- return (time_t) -1;
- tm.tm_sec = values[1];
- }
-
- /* Time zone. Unfortunately this is weird enough that we can't use nice
- parsing rules for it. */
- if (*p == '-' || *p == '+') {
- zone_sign = (*p == '+') ? 1 : -1;
- p = parse_by_rule(p + 1, zone_rule, ARRAY_SIZE(zone_rule), values);
- if (p == NULL)
- return (time_t) -1;
- zone_offset = ((values[0] / 100) * 60 + values[0] % 100) * 60;
- zone_offset *= zone_sign;
- } else {
- p = parse_legacy_timezone(p, &zone_offset);
- if (p == NULL)
- return (time_t) -1;
- }
-
- /* Fix up the year, using the RFC 2822 rules. Remember that tm_year
- stores the year - 1900. */
- if (tm.tm_year < 50)
- tm.tm_year += 100;
- else if (tm.tm_year >= 1000)
- tm.tm_year -= 1900;
-
- /* Done parsing. Make sure there's nothing left but CFWS and range-check
- our results and then convert the struct tm to seconds since epoch and
- then apply the time zone offset. */
- p = skip_cfws(p);
- if (*p != '\0')
- return (time_t) -1;
- if (!valid_tm(&tm))
- return (time_t) -1;
- result = mktime_utc(&tm);
- return (result == (time_t) -1) ? result : result - zone_offset;
-}
+++ /dev/null
-/*
- dbz.c V6.1.1
-
-Copyright 1988 Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
-You can use this code in any manner, as long as you leave my name on it
-and don't hold me responsible for any problems with it.
-
-Hacked on by gdb@ninja.UUCP (David Butler); Sun Jun 5 00:27:08 CDT 1988
-
-Various improvments + INCORE by moraes@ai.toronto.edu (Mark Moraes)
-
-Major reworking by Henry Spencer as part of the C News project.
-
-Minor lint and CodeCenter (Saber) fluff removal by Rich $alz (March, 1991).
-Non-portable CloseOnExec() calls added by Rich $alz (September, 1991).
-Added "writethrough" and tagmask calculation code from
-<rob@violet.berkeley.edu> and <leres@ee.lbl.gov> by Rich $alz (December, 1992).
-Merged in MMAP code by David Robinson, formerly <david@elroy.jpl.nasa.gov>
-now <david.robinson@sun.com> (January, 1993).
-
-Major reworking by Clayton O'Neill (coneill@oneill.net). Removed all the
-C News and backwards compatible cruft. Ripped out all the tagmask stuff
-and replaced it with hashed .pag entries. This removes the need for
-base file access. Primary bottleneck now appears to be the hash
-algorithm and search(). You can change DBZ_INTERNAL_HASH_SIZE in
-dbz.h to increase the size of the stored hash.
-
-These routines replace dbm as used by the usenet news software
-(it's not a full dbm replacement by any means). It's fast and
-simple. It contains no AT&T code.
-
-The dbz database exploits the fact that when news stores a <key,value>
-tuple, the `value' part is a seek offset into a text file, pointing to
-a copy of the `key' part. This avoids the need to store a copy of
-the key in the dbz files.
-
-The basic format of the database is two hash tables, each in it's own
-file. One contains the offsets into the history text file , and the
-other contains a hash of the message id. A value is stored by
-indexing into the tables using a hash value computed from the key;
-collisions are resolved by linear probing (just search forward for an
-empty slot, wrapping around to the beginning of the table if
-necessary). Linear probing is a performance disaster when the table
-starts to get full, so a complication is introduced. Each file actually
-contains one *or more* tables, stored sequentially in the files, and
-the length of the linear-probe sequences is limited. The search (for
-an existing item or an empy slot always starts in the first table of
-the hash file, and whenever MAXRUN probes have been done in table N,
-probing continues in table N+1. It is best not to overflow into more
-than 1-2 tables or else massive performance degradation may occur.
-Choosing the size of the database is extremely important because of this.
-
-The table size is fixed for any particular database, but is determined
-dynamically when a database is rebuilt. The strategy is to try to pick
-the size so the first table will be no more than 2/3 full, that being
-slightly before the point where performance starts to degrade. (It is
-desirable to be a bit conservative because the overflow strategy tends
-to produce files with holes in them, which is a nuisance.)
-
-Tagged hash + offset fuzzy technique merged by Sang-yong Suh (Nov, 1997)
-
-Fixed a bug handling larger than 1Gb history offset by Sang-yong Suh(1998)
-Similar fix was suggested by Mike Hucka <hucka@umich.edu> (Jan, 1998) for
-dbz-3.3.2.
-
-Limited can't tag warnings once per dbzinit() by Sang-yong Suh (May, 1998)
-
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include "dbz.h"
-#include "inn/messages.h"
-#include "inn/innconf.h"
-#include "inn/mmap.h"
-#include "libinn.h"
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-/*
- * "LIA" = "leave it alone unless you know what you're doing".
- *
- * DBZTEST Generate a standalone program for testing and benchmarking
- * DEFSIZE default table size (not as critical as in old dbz)
- * NMEMORY number of days of memory for use in sizing new table (LIA)
- * MAXRUN length of run which shifts to next table (see below) (LIA)
- */
-
-static int dbzversion = 6; /* for validating .dir file format */
-
-#ifdef DO_TAGGED_HASH
-/* assume that for tagged hash, we don't want more than 4byte of_t even if
- * off_t is 8 bytes -- people who use tagged-hash are usually short on
- * RAM.
- */
-#define of_t long
-#else
-#define of_t off_t
-#endif
-#define SOF (sizeof(of_t))
-#define NOTFOUND ((of_t)-1)
-#ifdef DO_TAGGED_HASH
-
-#define OVERFLOW
-#ifdef OVERFLOW
-#include <limits.h>
-#endif
-
-/* MAXDROPBITS is the maximum number of bits dropped from the offset value.
- The least significant bits are dropped. The space is used to
- store hash additional bits, thereby increasing the possibility of the
- hash detection */
-#define MAXDROPBITS 4 /* max # of bits to drop from the offset */
-
-/* MAXFUZZYLENGTH is the maximum in the offset value due to the MAXDROPBITS */
-#define MAXFUZZYLENGTH ((1 << MAXDROPBITS) - 1)
-
-/*
- * We assume that unused areas of a binary file are zeros, and that the
- * bit pattern of `(of_t)0' is all zeros. The alternative is rather
- * painful file initialization. Note that okayvalue(), if OVERFLOW is
- * defined, knows what value of an offset would cause overflow.
- */
-#define VACANT ((of_t)0)
-#define BIAS(o) ((o)+1) /* make any valid of_t non-VACANT */
-#define UNBIAS(o) ((o)-1) /* reverse BIAS() effect */
-
-#define HASTAG(o) ((o)&taghere)
-#define TAG(o) ((o)&tagbits)
-#define NOTAG(o) ((o)&~tagboth)
-#define CANTAG(o) (((o)&tagboth) == 0)
-#define MKTAG(v) (((v)<<conf.tagshift)&tagbits)
-
-#ifndef NOTAGS
-#define TAGENB 0x80 /* tag enable is top bit, tag is next 7 */
-#define TAGMASK 0x7f
-#define TAGSHIFT 24
-#else
-#define TAGENB 0 /* no tags */
-#define TAGMASK 0
-#define TAGSHIFT 0
-#endif
-
-/*
- * Stdio buffer for base-file reads. Message-IDs (all news ever needs to
- * read) are essentially never longer than 64 bytes, and the typical stdio
- * buffer is so much larger that it is much more expensive to fill.
- */
-
-static of_t tagbits; /* pre-shifted tag mask */
-static of_t taghere; /* pre-shifted tag-enable bit */
-static of_t tagboth; /* tagbits|taghere */
-static int canttag_warned; /* flag to control can't tag warning */
-
-#endif /* DO_TAGGED_HASH */
-
-/* Old dbz used a long as the record type for dbz entries, which became
- * really gross in places because of mixed references. We define these to
- * make it a bit easier if we want to store more in here.
- */
-
-/* A new, from-scratch database, not built as a rebuild of an old one, needs
- * to know table size. Normally the user supplies this info, but there have
- * to be defaults. Making this too small can have devestating effects on
- * history speed for the current history implementation whereas making it too
- * big just wastes disk space, so err on the side of caution. This may still
- * be a bit too small. Assume people using tagged hash are running somewhat
- * smaller servers.
- */
-#ifndef DEFSIZE
-
-#ifdef DO_TAGGED_HASH
-#define DEFSIZE 1000003 /* I need a prime number */
-#else
-#define DEFSIZE 10000000
-#endif
-
-#endif /* DEFSIZE */
-/*
- * We read configuration info from the .dir file into this structure,
- * so we can avoid wired-in assumptions for an existing database.
- *
- * Among the info is a record of recent peak usages, so that a new table
- * size can be chosen intelligently when rebuilding. 10 is a good
- * number of usages to keep, since news displays marked fluctuations
- * in volume on a 7-day cycle.
- */
-#ifndef NMEMORY
-#define NMEMORY 10 /* # days of use info to remember */
-#endif
-#define NUSEDS (1+NMEMORY)
-
-typedef struct {
- long tsize; /* table size */
- long used[NUSEDS]; /* entries used today, yesterday, ... */
- long vused[NUSEDS]; /* ditto for text size */
- int valuesize; /* size of table values, == sizeof(dbzrec) */
- int fillpercent; /* fillpercent/100 is the percent full we'll
- try to keep the .pag file */
- of_t tagenb; /* unshifted tag-enable bit */
- of_t tagmask; /* unshifted tag mask */
- int tagshift; /* shift count for tagmask and tagenb */
- int dropbits; /* number of bits to discard from offset */
- int lenfuzzy; /* num of fuzzy characters in offset */
-} dbzconfig;
-static dbzconfig conf;
-
-/*
- * Default dbzoptions to
- */
-static dbzoptions options = {
- false, /* write through off */
- INCORE_NO, /* index/pag from disk */
-#ifdef HAVE_MMAP
- INCORE_MMAP, /* exists mmap'ed. ignored in tagged hash mode */
-#else
- INCORE_NO, /* exists from disk. ignored in tagged hash mode */
-#endif
- true /* non-blocking writes */
-};
-
-/*
- * Data structure for recording info about searches.
- */
-typedef struct {
- of_t place; /* current location in file */
- int tabno; /* which table we're in */
- int run; /* how long we'll stay in this table */
-# ifndef MAXRUN
-# define MAXRUN 100
-# endif
- HASH hash; /* the key's hash code */
- unsigned long shorthash; /* integer version of the hash, used for
- determining the entries location.
- Tagged_hash stores the 31-bit hash here */
- of_t tag; /* tag we are looking for */
- int aborted; /* has i/o error aborted search? */
-} searcher;
-#define FRESH ((searcher *)NULL)
-
-/*
- * Arguably the searcher struct for a given routine ought to be local to
- * it, but a fetch() is very often immediately followed by a store(), and
- * in some circumstances it is a useful performance win to remember where
- * the fetch() completed. So we use a global struct and remember whether
- * it is current.
- */
-static searcher srch;
-static searcher *prevp; /* &srch or FRESH */
-
-/* Structure for hash tables */
-typedef struct {
- int fd; /* Non-blocking descriptor for writes */
- off_t pos; /* Current offset into the table */
- int reclen; /* Length of records in the table */
- dbz_incore_val incore; /* What we're using core for */
- void *core; /* Pointer to in-core table */
-} hash_table;
-
-/* central data structures */
-static bool opendb = false; /* Indicates if a database is currently open */
-static FILE *dirf; /* descriptor for .dir file */
-static bool readonly; /* database open read-only? */
-#ifdef DO_TAGGED_HASH
-static FILE *basef; /* descriptor for base file */
-static char *basefname; /* name for not-yet-opened base file */
-static hash_table pagtab; /* pag hash table, stores hash + offset */
-#else
-static hash_table idxtab; /* index hash table, used for data retrieval */
-static hash_table etab; /* existance hash table, used for existance checks */
-#endif
-static bool dirty; /* has a store() been done? */
-static erec empty_rec; /* empty rec to compare against
- initalized in dbzinit */
-
-/* misc. forwards */
-static bool getcore(hash_table *tab);
-static bool putcore(hash_table *tab);
-static bool getconf(FILE *df, dbzconfig *cp);
-static int putconf(FILE *f, dbzconfig *cp);
-static void start(searcher *sp, const HASH hash, searcher *osp);
-#ifdef DO_TAGGED_HASH
-static of_t search(searcher *sp);
-static bool set_pag(searcher *sp, of_t value);
-#else
-static bool search(searcher *sp);
-#endif
-static bool set(searcher *sp, hash_table *tab, void *value);
-
-/* file-naming stuff */
-static char dir[] = ".dir";
-#ifdef DO_TAGGED_HASH
-static char pag[] = ".pag";
-#else
-static char idx[] = ".index";
-static char exists[] = ".hash";
-#endif
-
-int dbzneedfilecount(void) {
-#ifdef DO_TAGGED_HASH
- return 2; /* basef and dirf are fopen()'ed and kept */
-#else
- return 1; /* dirf is fopen()'ed and kept */
-#endif
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - dbzconfbase - reconfigure dbzconf from base file size.
- */
-static void
-config_by_text_size(dbzconfig *c, of_t basesize)
-{
- int i;
- unsigned long m;
-
- /* if no tag requested, just return. */
- if ((c->tagmask | c->tagenb) == 0)
- return;
-
- /* Use 10 % larger base file size. Sometimes the offset overflows */
- basesize += basesize / 10;
-
- /* calculate tagging from old file */
- for (m = 1, i = 0; m < (unsigned long)basesize; i++, m <<= 1)
- continue;
-
- /* if we had more tags than the default, use the new data */
- c->dropbits = 0;
- while (m > (1 << TAGSHIFT)) {
- if (c->dropbits >= MAXDROPBITS)
- break;
- c->dropbits++;
- m >>= 1;
- i--;
- }
- c->tagenb = TAGENB;
- c->tagmask = TAGMASK;
- c->tagshift = TAGSHIFT;
- if ((c->tagmask | c->tagenb) && m > (1 << TAGSHIFT)) {
- c->tagshift = i;
- c->tagmask = (~(unsigned long)0) >> (i + 1);
- c->tagenb = (c->tagmask << 1) & ~c->tagmask;
- }
- c->lenfuzzy = (int)(1 << c->dropbits) - 1;
-
- m = (c->tagmask | c->tagenb) << c->tagshift;
- if (m & (basesize >> c->dropbits)) {
- fprintf(stderr, "m 0x%lx size 0x%lx\n", m, basesize);
- exit(1);
- }
-}
-#endif /* DO_TAGGED_HASH */
-
-/*
- - create and truncate .pag, .idx, or .hash files
- - return false on error
- */
-static bool
-create_truncate(const char *name, const char *pag1)
-{
- char *fn;
- FILE *f;
-
- fn = concat(name, pag1, (char *) 0);
- f = Fopen(fn, "w", TEMPORARYOPEN);
- free(fn);
- if (f == NULL) {
- syswarn("unable to create/truncate %s", pag1);
- return false;
- } else
- Fclose(f);
- return true;
-}
-
-/* dbzfresh - set up a new database, no historical info
- * Return true for success, false for failure
- * name - base name; .dir and .pag must exist
- * size - table size (0 means default)
- */
-bool
-dbzfresh(const char *name, off_t size)
-{
- char *fn;
- dbzconfig c;
- FILE *f;
-#ifdef DO_TAGGED_HASH
- struct stat sb;
- of_t m;
-#endif
-
- if (opendb) {
- warn("dbzfresh: database already open");
- return false;
- }
- if (size != 0 && size < 2) {
- warn("dbzfresh: preposterous size (%ld)", (long) size);
- return false;
- }
-
- /* get default configuration */
- if (!getconf(NULL, &c))
- return false; /* "can't happen" */
-
-#ifdef DO_TAGGED_HASH
- /* and mess with it as specified */
- if (size != 0)
- c.tsize = size;
- m = c.tagmask;
- c.tagshift = 0;
- while (!(m & 1)) {
- m >>= 1;
- c.tagshift++;
- }
- c.tagmask = m;
- c.tagenb = (m << 1) & ~m;
- c.dropbits = 0;
- c.lenfuzzy = 0;
-
- /* if big enough basb file exists, update config */
- if (stat(name, &sb) != -1)
- config_by_text_size(&c, sb.st_size);
-#else
- /* set the size as specified, make sure we get at least 2 bytes
- of implicit hash */
- if (size != 0)
- c.tsize = size > (64 * 1024) ? size : 64 * 1024;
-#endif
-
- /* write it out */
- fn = concat(name, dir, (char *) 0);
- f = Fopen(fn, "w", TEMPORARYOPEN);
- free(fn);
- if (f == NULL) {
- syswarn("dbzfresh: unable to write config");
- return false;
- }
- if (putconf(f, &c) < 0) {
- Fclose(f);
- return false;
- }
- if (Fclose(f) == EOF) {
- syswarn("dbzfresh: fclose failure");
- return false;
- }
-
- /* create and truncate .pag, or .index/.hash files */
-#ifdef DO_TAGGED_HASH
- if (!create_truncate(name, pag))
- return false;
-#else
- if (!create_truncate(name, idx))
- return false;
- if (!create_truncate(name, exists))
- return false;
-#endif /* DO_TAGGED_HASH */
-
- /* and punt to dbzinit for the hard work */
- return dbzinit(name);
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - isprime - is a number prime?
- */
-static bool
-isprime(long x)
-{
- static int quick[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 };
- int *ip;
- long div1, stop;
-
- /* hit the first few primes quickly to eliminate easy ones */
- /* this incidentally prevents ridiculously small tables */
- for (ip = quick; (div1 = *ip) != 0; ip++)
- if (x % div1 == 0) {
- debug("isprime: quick result on %ld", x);
- return false;
- }
-
- /* approximate square root of x */
- for (stop = x; x/stop < stop; stop >>= 1)
- continue;
- stop <<= 1;
-
- /* try odd numbers up to stop */
- for (div1 = *--ip; div1 < stop; div1 += 2)
- if (x%div1 == 0)
- return false;
-
- return true;
-}
-#endif
-
-/*
- * dbzsize - what's a good table size to hold this many entries?
- * contents - size of table (0 means return the default)
- */
-long
-dbzsize(off_t contents)
-{
- of_t n;
-
- if (contents <= 0) { /* foulup or default inquiry */
- debug("dbzsize: preposterous input (%ld)", (long) contents);
- return DEFSIZE;
- }
-
- if ((conf.fillpercent > 0) && (conf.fillpercent < 100))
- n = (contents / conf.fillpercent) * 100;
- else
- n = (contents * 3) / 2; /* try to keep table at most 2/3's full */
-
- /* Make sure that we get at least 2 bytes of implicit hash */
- if (n < (64 * 1024))
- n = 64 * 1024;
-
-#ifdef DO_TAGGED_HASH
- if (!(n & 1))
- n += 1; /* make it odd */
- debug("dbzsize: tentative size %ld", n);
- while (!isprime(n)) /* look for a prime */
- n += 2;
-#endif
-
- debug("dbzsize: final size %ld", (long) n);
- return n;
-}
-
-/* dbzagain - set up a new database to be a rebuild of an old one
- * Returns true on success, false on failure
- * name - base name; .dir and .pag must exist
- * oldname - basename, all must exist
- */
-bool
-dbzagain(const char *name, const char *oldname)
-{
- char *fn;
- dbzconfig c;
- bool result;
- int i;
- long top;
- FILE *f;
- int newtable;
- of_t newsize;
-#ifdef DO_TAGGED_HASH
- long vtop;
- struct stat sb;
-#endif
-
- if (opendb) {
- warn("dbzagain: database already open");
- return false;
- }
-
- /* pick up the old configuration */
- fn = concat(oldname, dir, (char *) 0);
- f = Fopen(fn, "r", TEMPORARYOPEN);
- free(fn);
- if (f == NULL) {
- syswarn("dbzagain: cannot open old .dir file");
- return false;
- }
- result = getconf(f, &c);
- Fclose(f);
- if (!result) {
- syswarn("dbzagain: getconf failed");
- return false;
- }
-
- /* tinker with it */
- top = 0;
- newtable = 0;
- for (i = 0; i < NUSEDS; i++) {
- if (top < c.used[i])
- top = c.used[i];
- if (c.used[i] == 0)
- newtable = 1; /* hasn't got full usage history yet */
- }
- if (top == 0) {
- debug("dbzagain: old table has no contents!");
- newtable = 1;
- }
- for (i = NUSEDS-1; i > 0; i--)
- c.used[i] = c.used[i-1];
- c.used[0] = 0;
-
-#ifdef DO_TAGGED_HASH
- vtop = 0;
- for (i = 0; i < NUSEDS; i++) {
- if (vtop < c.vused[i])
- vtop = c.vused[i];
- if (c.vused[i] == 0)
- newtable = 1; /* hasn't got full usage history yet */
- }
- if (top != 0 && vtop == 0) {
- debug("dbzagain: old table has no contents!");
- newtable = 1;
- }
- for (i = NUSEDS-1; i > 0; i--)
- c.vused[i] = c.vused[i-1];
- c.vused[0] = 0;
-
- /* calculate tagging from old file */
- if (stat(oldname, &sb) != -1 && vtop < sb.st_size)
- vtop = sb.st_size;
- config_by_text_size(&c, vtop);
-#endif
-
- newsize = dbzsize(top);
- if (!newtable || newsize > c.tsize) /* don't shrink new table */
- c.tsize = newsize;
-
- /* write it out */
- fn = concat(name, dir, (char *) 0);
- f = Fopen(fn, "w", TEMPORARYOPEN);
- free(fn);
- if (f == NULL) {
- syswarn("dbzagain: unable to write new .dir");
- return false;
- }
- i = putconf(f, &c);
- Fclose(f);
- if (i < 0) {
- warn("dbzagain: putconf failed");
- return false;
- }
-
- /* create and truncate .pag, or .index/.hash files */
-#ifdef DO_TAGGED_HASH
- if (!create_truncate(name, pag))
- return false;
-#else
- if (!create_truncate(name, idx))
- return false;
- if (!create_truncate(name, exists))
- return false;
-#endif
-
- /* and let dbzinit do the work */
- return dbzinit(name);
-}
-
-static bool
-openhashtable(const char *base, const char *ext, hash_table *tab,
- const size_t reclen, const dbz_incore_val incore)
-{
- char *name;
- int oerrno;
-
- name = concat(base, ext, (char *) 0);
- if ((tab->fd = open(name, readonly ? O_RDONLY : O_RDWR)) < 0) {
- syswarn("openhashtable: could not open raw");
- oerrno = errno;
- free(name);
- errno = oerrno;
- return false;
- }
- free(name);
-
- tab->reclen = reclen;
- close_on_exec(tab->fd, true);
- tab->pos = -1;
-
- /* get first table into core, if it looks desirable and feasible */
- tab->incore = incore;
- if (tab->incore != INCORE_NO) {
- if (!getcore(tab)) {
- syswarn("openhashtable: getcore failure");
- oerrno = errno;
- close(tab->fd);
- errno = oerrno;
- return false;
- }
- }
-
- if (options.nonblock && nonblocking(tab->fd, true) < 0) {
- syswarn("fcntl: could not set nonblock");
- oerrno = errno;
- close(tab->fd);
- errno = oerrno;
- return false;
- }
- return true;
-}
-
-static void closehashtable(hash_table *tab) {
- close(tab->fd);
- if (tab->incore == INCORE_MEM)
- free(tab->core);
- if (tab->incore == INCORE_MMAP) {
-#if defined(HAVE_MMAP)
- if (munmap(tab->core, conf.tsize * tab->reclen) == -1) {
- syswarn("closehashtable: munmap failed");
- }
-#else
- warn("closehashtable: can't mmap files");
-#endif
- }
-}
-
-#ifdef DO_TAGGED_HASH
-static bool
-openbasefile(const char *name)
-{
- basef = Fopen(name, "r", DBZ_BASE);
- if (basef == NULL) {
- syswarn("dbzinit: basefile open failed");
- basefname = xstrdup(name);
- } else
- basefname = NULL;
- if (basef != NULL)
- close_on_exec(fileno(basef), true);
- if (basef != NULL)
- setvbuf(basef, NULL, _IOFBF, 64);
- return true;
-}
-#endif /* DO_TAGGED_HASH */
-
-/*
- * dbzinit - open a database, creating it (using defaults) if necessary
- *
- * We try to leave errno set plausibly, to the extent that underlying
- * functions permit this, since many people consult it if dbzinit() fails.
- * return true for success, false for failure
- */
-bool
-dbzinit(const char *name)
-{
- char *fname;
-
- if (opendb) {
- warn("dbzinit: dbzinit already called once");
- errno = 0;
- return false;
- }
-
- /* open the .dir file */
- fname = concat(name, dir, (char *) 0);
- if ((dirf = Fopen(fname, "r+", DBZ_DIR)) == NULL) {
- dirf = Fopen(fname, "r", DBZ_DIR);
- readonly = true;
- } else
- readonly = false;
- free(fname);
- if (dirf == NULL) {
- syswarn("dbzinit: can't open .dir file");
- return false;
- }
- close_on_exec(fileno(dirf), true);
-
- /* pick up configuration */
- if (!getconf(dirf, &conf)) {
- warn("dbzinit: getconf failure");
- Fclose(dirf);
- errno = EDOM; /* kind of a kludge, but very portable */
- return false;
- }
-
- /* open pag or idx/exists file */
-#ifdef DO_TAGGED_HASH
- if (!openhashtable(name, pag, &pagtab, SOF, options.pag_incore)) {
- Fclose(dirf);
- return false;
- }
- if (!openbasefile(name)) {
- close(pagtab.fd);
- Fclose(dirf);
- return false;
- }
- tagbits = conf.tagmask << conf.tagshift;
- taghere = conf.tagenb << conf.tagshift;
- tagboth = tagbits | taghere;
- canttag_warned = 0;
-#else
- if (!openhashtable(name, idx, &idxtab, sizeof(of_t), options.pag_incore)) {
- Fclose(dirf);
- return false;
- }
- if (!openhashtable(name, exists, &etab, sizeof(erec),
- options.exists_incore)) {
- Fclose(dirf);
- return false;
- }
-#endif
-
- /* misc. setup */
- dirty = false;
- opendb = true;
- prevp = FRESH;
- memset(&empty_rec, '\0', sizeof(empty_rec));
- debug("dbzinit: succeeded");
- return true;
-}
-
-/* dbzclose - close a database
- */
-bool
-dbzclose(void)
-{
- bool ret = true;
-
- if (!opendb) {
- warn("dbzclose: not opened!");
- return false;
- }
-
- if (!dbzsync())
- ret = false;
-
-#ifdef DO_TAGGED_HASH
- closehashtable(&pagtab);
- if (Fclose(basef) == EOF) {
- syswarn("dbzclose: fclose(basef) failed");
- ret = false;
- }
- if (basefname != NULL)
- free(basefname);
- basef = NULL;
-#else
- closehashtable(&idxtab);
- closehashtable(&etab);
-#endif
-
- if (Fclose(dirf) == EOF) {
- syswarn("dbzclose: fclose(dirf) failed");
- ret = false;
- }
-
- debug("dbzclose: %s", (ret == true) ? "succeeded" : "failed");
- if (ret)
- opendb = false;
- return ret;
-}
-
-/* dbzsync - push all in-core data out to disk
- */
-bool
-dbzsync(void)
-{
- bool ret = true;
-
- if (!opendb) {
- warn("dbzsync: not opened!");
- return false;
- }
-
- if (!dirty)
- return true;;
-
-#ifdef DO_TAGGED_HASH
- if (!putcore(&pagtab)) {
-#else
- if (!putcore(&idxtab) || !putcore(&etab)) {
-#endif
- warn("dbzsync: putcore failed");
- ret = false;
- }
-
- if (putconf(dirf, &conf) < 0)
- ret = false;
-
- debug("dbzsync: %s", ret ? "succeeded" : "failed");
- return ret;
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - okayvalue - check that a value can be stored
- */
-static int
-okayvalue(of_t value)
-{
- if (HASTAG(value))
- return(0);
-#ifdef OVERFLOW
- if (value == LONG_MAX) /* BIAS() and UNBIAS() will overflow */
- return(0);
-#endif
- return(1);
-}
-#endif
-
-/* dbzexists - check if the given message-id is in the database */
-bool
-dbzexists(const HASH key)
-{
-#ifdef DO_TAGGED_HASH
- off_t value;
-
- return (dbzfetch(key, &value) != 0);
-#else
-
- if (!opendb) {
- warn("dbzexists: database not open!");
- return false;
- }
-
- prevp = FRESH;
- start(&srch, key, FRESH);
- return search(&srch);
-#endif
-}
-
-/*
- * dbzfetch - get offset of an entry from the database
- *
- * Returns the offset of the text file for input key,
- * or -1 if NOTFOUND or error occurs.
- */
-bool
-dbzfetch(const HASH key, off_t *value)
-{
-#ifdef DO_TAGGED_HASH
-#define MAX_NB2RD (DBZMAXKEY + MAXFUZZYLENGTH + 2)
-#define MIN_KEY_LENGTH 6 /* strlen("<1@a>") + strlen("\t") */
- char *bp, buffer[MAX_NB2RD];
- int keylen, j, nb2r;
- HASH hishash;
- char *keytext = NULL;
- of_t offset = NOTFOUND;
-#endif
-
- prevp = FRESH;
-
- if (!opendb) {
- warn("dbzfetch: database not open!");
- return false;
- }
-
- start(&srch, key, FRESH);
-#ifdef DO_TAGGED_HASH
- /*
- * nb2r: number of bytes to read from history file.
- * It can be reduced if history text is written as hashes only.
- */
- nb2r = sizeof(buffer) - 1;
-
- while ((offset = search(&srch)) != NOTFOUND) {
- debug("got 0x%lx", key_ptr);
-
- /* fetch the key */
- offset <<= conf.dropbits;
- if (offset) /* backspace 1 character to read '\n' */
- offset--;
- if (fseeko(basef, offset, SEEK_SET) != 0) {
- syswarn("dbzfetch: seek failed");
- return false;
- }
- keylen = fread(buffer, 1, nb2r, basef);
- if (keylen < MIN_KEY_LENGTH) {
- syswarn("dbzfetch: read failed");
- return false;
- }
- buffer[keylen] = '\0'; /* terminate the string */
-
- if (offset) { /* find the '\n', the previous EOL */
- if (keylen > conf.lenfuzzy)
- keylen = conf.lenfuzzy; /* keylen is fuzzy distance now */
- for (j=0,bp=buffer; j<keylen; j++,bp++)
- if (*bp == '\n')
- break;
- if (*bp != '\n') {
- debug("dbzfetch: can't locate EOL");
- /* pag entry should be deleted, but I'm lazy... */
- continue;
- }
- offset++;
- bp++; /* now *bp is the start of key */
- } else {
- j = 0; /* We are looking for the first history line. */
- bp = buffer;
- }
-
- /* Does this history line really have same key? */
- if (*bp == '[') {
- if (!keytext)
- keytext = HashToText(key);
- if (memcmp(keytext, bp+1, sizeof(HASH)*2) != 0)
- continue;
- } else if (*bp == '<') {
- char *p = strchr(bp+1, '\t');
- if (!p) /* history has a corrupted line */
- continue;
- *p = '\0';
- hishash = HashMessageID(bp);
- if (memcmp(&key, &hishash, sizeof(HASH)) != 0)
- continue;
- } else
- continue;
-
- /* we found it */
- offset += j;
- debug("fetch: successful");
- *value = offset;
- return true;
- }
-
- /* we didn't find it */
- debug("fetch: failed");
- prevp = &srch; /* remember where we stopped */
- return false;
-#else /* DO_TAGGED_HASH */
- if (search(&srch) == true) {
- /* Actually get the data now */
- if ((options.pag_incore != INCORE_NO) && (srch.place < conf.tsize)) {
- memcpy(value, &((of_t *)idxtab.core)[srch.place], sizeof(of_t));
- } else {
- if (pread(idxtab.fd, value, sizeof(of_t), srch.place * idxtab.reclen) != sizeof(of_t)) {
- syswarn("fetch: read failed");
- idxtab.pos = -1;
- srch.aborted = 1;
- return false;
- }
- }
- debug("fetch: successful");
- return true;
- }
-
- /* we didn't find it */
- debug("fetch: failed");
- prevp = &srch; /* remember where we stopped */
- return false;
-#endif
-}
-
-/*
- * dbzstore - add an entry to the database
- * returns true for success and false for failure
- */
-DBZSTORE_RESULT
-dbzstore(const HASH key, off_t data)
-{
-#ifdef DO_TAGGED_HASH
- of_t value;
-#else
- erec evalue;
-#endif
-
- if (!opendb) {
- warn("dbzstore: database not open!");
- return DBZSTORE_ERROR;
- }
- if (readonly) {
- warn("dbzstore: database open read-only");
- return DBZSTORE_ERROR;
- }
-
-#ifdef DO_TAGGED_HASH
- /* copy the value in to ensure alignment */
- memcpy(&value, &data, SOF);
-
- /* update maximum offset value if necessary */
- if (value > conf.vused[0])
- conf.vused[0] = value;
-
- /* now value is in fuzzy format */
- value >>= conf.dropbits;
- debug("dbzstore: (%ld)", (long) value);
-
- if (!okayvalue(value)) {
- warn("dbzstore: reserved bit or overflow in 0x%lx", value);
- return DBZSTORE_ERROR;
- }
-
- /* find the place, exploiting previous search if possible */
- start(&srch, key, prevp);
- while (search(&srch) != NOTFOUND)
- continue;
-
- prevp = FRESH;
- conf.used[0]++;
- debug("store: used count %ld", conf.used[0]);
- dirty = 1;
- if (!set_pag(&srch, value))
- return DBZSTORE_ERROR;
- return DBZSTORE_OK;
-#else /* DO_TAGGED_HASH */
-
- /* find the place, exploiting previous search if possible */
- start(&srch, key, prevp);
- if (search(&srch) == true)
- return DBZSTORE_EXISTS;
-
- prevp = FRESH;
- conf.used[0]++;
- debug("store: used count %ld", conf.used[0]);
- dirty = true;
-
- memcpy(&evalue.hash, &srch.hash,
- sizeof(evalue.hash) < sizeof(srch.hash) ? sizeof(evalue.hash) : sizeof(srch.hash));
-
- /* Set the value in the index first since we don't care if it's out of date */
- if (!set(&srch, &idxtab, (void *)&data))
- return DBZSTORE_ERROR;
- if (!set(&srch, &etab, &evalue))
- return DBZSTORE_ERROR;
- return DBZSTORE_OK;
-#endif /* DO_TAGGED_HASH */
-}
-
-/*
- * getconf - get configuration from .dir file
- * df - NULL means just give me the default
- * pf - NULL means don't care about .pag
- * returns true for success, false for failure
- */
-static bool
-getconf(FILE *df, dbzconfig *cp)
-{
- int i;
-
- /* empty file, no configuration known */
-#ifdef DO_TAGGED_HASH
- if (df == NULL) {
- cp->tsize = DEFSIZE;
- for (i = 0; i < NUSEDS; i++)
- cp->used[i] = 0;
- for (i = 0; i < NUSEDS; i++)
- cp->vused[i] = 0;
- cp->valuesize = sizeof(of_t);
- cp->fillpercent = 50;
- cp->tagenb = TAGENB;
- cp->tagmask = TAGMASK;
- cp->tagshift = TAGSHIFT;
- cp->dropbits = 0;
- cp->lenfuzzy = 0;
- debug("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d %d))",
- cp->tsize, cp->casemap, cp->tagenb,
- cp->tagmask, cp->tagshift, cp->dropbits);
- return true;
- }
-
- i = fscanf(df, "dbz 6 %ld %d %d %ld %ld %d %d\n", &cp->tsize,
- &cp->valuesize, &cp->fillpercent, &cp->tagenb,
- &cp->tagmask, &cp->tagshift, &cp->dropbits);
- if (i != 7) {
- warn("dbz: bad first line in config");
- return false;
- }
- if (cp->valuesize != sizeof(of_t)) {
- warn("dbz: wrong of_t size (%d)", cp->valuesize);
- return false;
- }
- cp->lenfuzzy = (int)(1 << cp->dropbits) - 1;
-#else /* DO_TAGGED_HASH */
- if (df == NULL) {
- cp->tsize = DEFSIZE;
- for (i = 0; i < NUSEDS; i++)
- cp->used[i] = 0;
- cp->valuesize = sizeof(of_t) + sizeof(erec);
- cp->fillpercent = 66;
- debug("getconf: defaults (%ld)", cp->tsize);
- return true;
- }
-
- i = fscanf(df, "dbz 6 %ld %d %d\n", &cp->tsize,
- &cp->valuesize, &cp->fillpercent);
- if (i != 3) {
- warn("dbz: bad first line in config");
- return false;
- }
- if (cp->valuesize != (sizeof(of_t) + sizeof(erec))) {
- warn("dbz: wrong of_t size (%d)", cp->valuesize);
- return false;
- }
-#endif /* DO_TAGGED_HASH */
- debug("size %ld", cp->tsize);
-
- /* second line, the usages */
- for (i = 0; i < NUSEDS; i++)
- if (!fscanf(df, "%ld", &cp->used[i])) {
- warn("dbz: bad usage value in config");
- return false;
- }
- debug("used %ld %ld %ld...", cp->used[0], cp->used[1], cp->used[2]);
-
-#ifdef DO_TAGGED_HASH
- /* third line, the text usages */
- for (i = 0; i < NUSEDS; i++)
- if (!fscanf(df, "%ld", &cp->vused[i])) {
- warn("dbz: bad text usage value in config");
- return false;
- }
- debug("vused %ld %ld %ld...", cp->vused[0], cp->vused[1], cp->vused[2]);
-#endif /* DO_TAGGED_HASH */
-
- return true;
-}
-
-/* putconf - write configuration to .dir file
- * Returns: 0 for success, -1 for failure
- */
-static int
-putconf(FILE *f, dbzconfig *cp)
-{
- int i;
- int ret = 0;
-
- if (fseeko(f, 0, SEEK_SET) != 0) {
- syswarn("dbz: fseeko failure in putconf");
- ret = -1;
- }
-
-#ifdef DO_TAGGED_HASH
- fprintf(f, "dbz %d %ld %d %d %ld %ld %d %d\n", dbzversion, cp->tsize,
- cp->valuesize, cp->fillpercent, cp->tagenb,
- cp->tagmask, cp->tagshift, cp->dropbits);
-#else /* DO_TAGGED_HASH */
- fprintf(f, "dbz %d %ld %d %d\n", dbzversion, cp->tsize,
- cp->valuesize, cp->fillpercent);
-#endif /* DO_TAGGED_HASH */
-
- for (i = 0; i < NUSEDS; i++)
- fprintf(f, "%ld%c", cp->used[i], (i < NUSEDS-1) ? ' ' : '\n');
-
-#ifdef DO_TAGGED_HASH
- for (i = 0; i < NUSEDS; i++)
- fprintf(f, "%ld%c", cp->vused[i], (i < NUSEDS-1) ? ' ' : '\n');
-#endif
-
- fflush(f);
- if (ferror(f))
- ret = -1;
-
- debug("putconf status %d", ret);
- return ret;
-}
-
-/* getcore - try to set up an in-core copy of file
- *
- * Returns: pointer to copy of file or NULL on errror
- */
-static bool
-getcore(hash_table *tab)
-{
- char *it;
- ssize_t nread;
- size_t i;
- struct stat st;
- size_t length = conf.tsize * tab->reclen;
-
- if (tab->incore == INCORE_MMAP) {
-#if defined(HAVE_MMAP)
- if (fstat(tab->fd, &st) == -1) {
- syswarn("dbz: getcore: fstat failed");
- return false;
- }
- if (length > st.st_size) {
- /* file too small; extend it */
- if (ftruncate(tab->fd, length) == -1) {
- syswarn("dbz: getcore: ftruncate failed");
- return false;
- }
- }
- it = mmap(NULL, length, readonly ? PROT_READ : PROT_WRITE | PROT_READ,
- MAP_SHARED, tab->fd, 0);
- if (it == (char *)-1) {
- syswarn("dbz: getcore: mmap failed");
- return false;
- }
-#if defined (MADV_RANDOM) && defined(HAVE_MADVISE)
- /* not present in all versions of mmap() */
- madvise(it, length, MADV_RANDOM);
-#endif
-#else
- warn("dbz: getcore: can't mmap files");
- return false;
-#endif
- } else {
- it = xmalloc(length);
-
- nread = read(tab->fd, it, length);
- if (nread < 0) {
- syswarn("dbz: getcore: read failed");
- free(it);
- return false;
- }
-
- i = length - nread;
- memset(it + nread, '\0', i);
- }
-
- tab->core = it;
- return true;
-}
-
-/* putcore - try to rewrite an in-core table
- *
- * Returns true on success, false on failure
- */
-static bool
-putcore(hash_table *tab)
-{
- size_t size;
- ssize_t result;
-
- if (tab->incore == INCORE_MEM) {
- if(options.writethrough)
- return true;
- nonblocking(tab->fd, false);
- size = tab->reclen * conf.tsize;
- result = xpwrite(tab->fd, tab->core, size, 0);
- if (result < 0 || (size_t) result != size) {
- nonblocking(tab->fd, options.nonblock);
- return false;
- }
- nonblocking(tab->fd, options.nonblock);
- }
-#ifdef HAVE_MMAP
- if(tab->incore == INCORE_MMAP) {
- msync(tab->core, conf.tsize * tab->reclen, MS_ASYNC);
- }
-#endif
- return true;
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - makehash31 : make 31-bit hash from HASH
- */
-static unsigned int
-makehash31(const HASH *hash)
-{
- unsigned int h;
- memcpy(&h, hash, sizeof(h));
- return (h >> 1);
-}
-#endif
-
-/* start - set up to start or restart a search
- * osp == NULL is acceptable
- */
-static void
-start(searcher *sp, const HASH hash, searcher *osp)
-{
-#ifdef DO_TAGGED_HASH
- unsigned int h;
-
- h = makehash31(&hash);
- if (osp != FRESH && osp->shorthash == h) {
- if (sp != osp)
- *sp = *osp;
- sp->run--;
- debug("search restarted");
- } else {
- sp->shorthash = h;
- sp->tag = MKTAG(h / conf.tsize);
- sp->place = h % conf.tsize;
- debug("hash %8.8lx tag %8.8lx place %ld",
- sp->shorthash, sp->tag, sp->place);
- sp->tabno = 0;
- sp->run = -1;
- sp->aborted = 0;
- }
-
-#else /* DO_TAGGED_HASH */
- int tocopy;
-
- if (osp != FRESH && !memcmp(&osp->hash, &hash, sizeof(hash))) {
- if (sp != osp)
- *sp = *osp;
- sp->run--;
- debug("search restarted");
- } else {
- sp->hash = hash;
- tocopy = sizeof(hash) < sizeof(sp->shorthash) ? sizeof(hash) : sizeof(sp->shorthash);
- /* Copy the bottom half of thhe hash into sp->shorthash */
- memcpy(&sp->shorthash, (const char *)&hash + (sizeof(hash) - tocopy),
- tocopy);
- sp->shorthash >>= 1;
- sp->tabno = 0;
- sp->run = -1;
- sp->aborted = 0;
- }
-#endif /* DO_TAGGED_HASH */
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - search - conduct part of a search
- */
-static of_t /* NOTFOUND if we hit VACANT or error */
-search(searcher *sp)
-{
- of_t value;
- unsigned long taboffset = sp->tabno * conf.tsize;
-
- if (sp->aborted)
- return(NOTFOUND);
-
- for (;;) {
- /* go to next location */
- if (sp->run++ == MAXRUN) {
- sp->tabno++;
- sp->run = 0;
- taboffset = sp->tabno * conf.tsize;
- }
- sp->place = ((sp->shorthash + sp->run) % conf.tsize) + taboffset;
- debug("search @ %ld", place);
-
- /* get the tagged value */
- if ((options.pag_incore != INCORE_NO) && (sp->place < conf.tsize)) {
- debug("search: in core");
- value = ((of_t *)pagtab.core)[sp->place];
- } else {
- off_t dest;
- dest = sp->place * SOF;
-
- /* read it */
- errno = 0;
- if (pread(pagtab.fd, &value, sizeof(value), dest) != sizeof(value)) {
- if (errno != 0) {
- syswarn("dbz: search: read failed");
- pagtab.pos = -1;
- sp->aborted = 1;
- return(NOTFOUND);
- } else
- value = VACANT;
- pagtab.pos = -1;
- } else
- pagtab.pos += sizeof(value);
- }
-
- /* vacant slot is always cause to return */
- if (value == VACANT) {
- debug("search: empty slot");
- return(NOTFOUND);
- };
-
- /* check the tag */
- value = UNBIAS(value);
- debug("got 0x%lx", value);
- if (!HASTAG(value)) {
- debug("tagless");
- return(value);
- } else if (TAG(value) == sp->tag) {
- debug("match");
- return(NOTAG(value));
- } else {
- debug("mismatch 0x%lx", TAG(value));
- }
- }
- /* NOTREACHED */
-}
-
-#else /* DO_TAGGED_HASH */
-
-/* search - conduct part of a search
- *
- * return false if we hit vacant rec's or error
- */
-static bool
-search(searcher *sp)
-{
- erec value;
- unsigned long taboffset = 0;
-
- if (sp->aborted)
- return false;
-
- for (;;) {
- /* go to next location */
- if (sp->run++ == MAXRUN) {
- sp->tabno++;
- sp->run = 0;
- taboffset = sp->tabno * conf.tsize;
- }
-
- sp->place = ((sp->shorthash + sp->run) % conf.tsize) + taboffset;
- debug("search @ %ld", (long) sp->place);
-
- /* get the value */
- if ((options.exists_incore != INCORE_NO) && (sp->place < conf.tsize)) {
- debug("search: in core");
- memcpy(&value, &((erec *)etab.core)[sp->place], sizeof(erec));
- } else {
- off_t dest;
- dest = sp->place * sizeof(erec);
-
- /* read it */
- errno = 0;
- if (pread(etab.fd, &value, sizeof(erec), dest) != sizeof(erec)) {
- if (errno != 0) {
- debug("search: read failed");
- etab.pos = -1;
- sp->aborted = 1;
- return false;
- } else {
- memset(&value, '\0', sizeof(erec));
- }
- }
-
- /* and finish up */
- etab.pos += sizeof(erec);
- }
-
- /* Check for an empty record */
- if (!memcmp(&value, &empty_rec, sizeof(erec))) {
- debug("search: empty slot");
- return false;
- }
-
- /* check the value */
- debug("got 0x%.*s", DBZ_INTERNAL_HASH_SIZE, value.hash);
- if (!memcmp(&value.hash, &sp->hash, DBZ_INTERNAL_HASH_SIZE)) {
- return true;
- }
- }
- /* NOTREACHED */
-}
-#endif /* DO_TAGGED_HASH */
-
-/* set - store a value into a location previously found by search
- *
- * Returns: true success, false failure
- */
-static bool
-set(searcher *sp, hash_table *tab, void *value)
-{
- off_t offset;
-
- if (sp->aborted)
- return false;
-
- /* If we have the index file in memory, use it */
- if ((tab->incore != INCORE_NO) && (sp->place < conf.tsize)) {
- void *where = (char *)tab->core + (sp->place * tab->reclen);
-
- memcpy(where, value, tab->reclen);
- debug("set: incore");
- if (tab->incore == INCORE_MMAP) {
- if (innconf->nfswriter) {
- inn_mapcntl(where, tab->reclen, MS_ASYNC);
- }
- return true;
- }
- if (!options.writethrough)
- return true;
- }
-
- /* seek to spot */
- tab->pos = -1; /* invalidate position memory */
- offset = sp->place * tab->reclen;
-
- /* write in data */
- while (pwrite(tab->fd, value, tab->reclen, offset) != tab->reclen) {
- if (errno == EAGAIN) {
- fd_set writeset;
-
- FD_ZERO(&writeset);
- FD_SET(tab->fd, &writeset);
- if (select(tab->fd + 1, NULL, &writeset, NULL, NULL) < 1) {
- syswarn("dbz: set: select failed");
- sp->aborted = 1;
- return false;
- }
- continue;
- }
- syswarn("dbz: set: write failed");
- sp->aborted = 1;
- return false;
- }
-
- debug("set: succeeded");
- return true;
-}
-
-#ifdef DO_TAGGED_HASH
-/*
- - set_pag - store a value into a location previously found by search
- - on the pag table.
- - Returns: true success, false failure
- */
-static bool
-set_pag(searcher *sp, of_t value)
-{
- of_t v = value;
-
- if (CANTAG(v)) {
- v |= sp->tag | taghere;
- if (v != UNBIAS(VACANT)) /* BIAS(v) won't look VACANT */
-#ifdef OVERFLOW
- if (v != LONG_MAX) /* and it won't overflow */
-#endif
- value = v;
- } else if (canttag_warned == 0) {
- fprintf(stderr, "dbz.c(set): can't tag value 0x%lx", v);
- fprintf(stderr, " tagboth = 0x%lx\n", tagboth);
- canttag_warned = 1;
- }
- debug("tagged value is 0x%lx", value);
- value = BIAS(value);
-
- return set(sp, &pagtab, &value);
-}
-#endif /* DO_TAGGED_HASH */
-
-/* dbzsetoptions - set runtime options for the database.
- */
-void
-dbzsetoptions(const dbzoptions o)
-{
- options = o;
-#ifndef HAVE_MMAP
- /* Without a working mmap on files, we should avoid it. */
- if (options.pag_incore == INCORE_MMAP) options.pag_incore = INCORE_NO;
- if (options.exists_incore == INCORE_MMAP) options.exists_incore = INCORE_NO;
-#endif
-}
-
-/* dbzgetoptions - get runtime options for the database.
- */
-void
-dbzgetoptions(dbzoptions *o)
-{
- *o = options;
-}
-
-
-#ifdef DBZTEST
-
-int
-timediffms(struct timeval start, struct timeval end)
-{
- return (((end.tv_sec - start.tv_sec) * 1000) +
- ((end.tv_usec - start.tv_usec)) / 1000);
-}
-
-void
-RemoveDBZ(char *filename)
-{
- char *fn;
-
-#ifdef DO_TAGGED_HASH
- fn = concat(filename, pag, (char *) 0);
- unlink(fn);
- free(fn);
-#else
- fn = concat(filename, exists, (char *) 0);
- unlink(fn);
- free(fn);
- fn = concat(filename, idx, (char *) 0);
- unlink(fn);
- free(fn);
-#endif
- fn = concat(filename, dir, (char *) 0);
- unlink(fn);
- free(fn);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: dbztest [-i] [-n|m] [-N] [-s size] <history>\n");
-#ifdef DO_TAGGED_HASH
- fprintf(stderr, " -i initialize history. deletes .pag files\n");
-#else
- fprintf(stderr, " -i initialize history. deletes .exists and .index files\n");
-#endif
- fprintf(stderr, " -n or m use INCORE_NO, INCORE_MMAP. default = INCORE_MEM\n");
- fprintf(stderr, " -N using nfswriter mode\n");
- fprintf(stderr, " -s size number of history lines[2500000]\n");
- fprintf(stderr, " history history text file\n");
- exit(1);
-}
-
-int
-main(int argc, char *argv[])
-{
- int i, line;
- FILE *fpi;
- char ibuf[2048], *p;
- HASH key;
- off_t where;
- int initialize = 0, size = 2500000;
- char *history = NULL;
- dbzoptions opt;
- dbz_incore_val incore = INCORE_MEM;
- struct timeval start, end;
- off_t ivalue;
-
- innconf = xcalloc(1, sizeof(struct innconf));
-
- for (i=1; i<argc; i++)
- if (strcmp(argv[i], "-i") == 0)
- initialize = 1;
- else if (strcmp(argv[i], "-n") == 0)
- incore = INCORE_NO;
- else if (strcmp(argv[i], "-N") == 0)
- innconf->nfswriter = true;
- else if (strcmp(argv[i], "-m") == 0)
-#if defined(HAVE_MMAP)
- incore = INCORE_MMAP;
-#else
- fprintf (stderr, "can't mmap files\n");
-#endif
- else if (strcmp(argv[i], "-s") == 0)
- size = atoi(argv[++i]);
- else if (*argv[i] != '-' && history == NULL)
- history = argv[i];
- else
- usage();
-
- if (history == NULL)
- usage();
- if ((fpi = fopen(history, "r")) == NULL) {
- fprintf(stderr, "can't open %s\n", history);
- usage();
- }
-
- dbzgetoptions(&opt);
- opt.pag_incore = incore;
- dbzsetoptions(opt);
-
- if (initialize) {
- RemoveDBZ(history);
- gettimeofday(&start, NULL);
- if (dbzfresh(history, dbzsize(size)) < 0) {
- fprintf(stderr, "cant dbzfresh %s\n", history);
- exit(1);
- }
- gettimeofday(&end, NULL);
- printf("dbzfresh: %d msec\n", timediffms(start, end));
- } else {
- gettimeofday(&start, NULL);
- if (dbzinit(history) < 0) {
- fprintf(stderr, "cant dbzinit %s\n", history);
- exit(1);
- }
- gettimeofday(&end, NULL);
- printf("dbzinit: %d msec\n", timediffms(start, end));
- }
-
- gettimeofday(&start, NULL);
- where = ftello(fpi);
- for (line=1; fgets(ibuf, sizeof(ibuf), fpi); line++, where=ftello(fpi)) {
- if (*ibuf == '<') {
- if ((p = strchr(ibuf, '\t')) == NULL) {
- fprintf(stderr, "ignoreing bad line: %s\n", ibuf);
- continue;
- }
- *p = '\0';
- key = HashMessageID(ibuf);
- } else if (*ibuf == '[')
- key = TextToHash(ibuf+1);
- else
- continue;
- if (initialize) {
- if (dbzstore(key, where) == DBZSTORE_ERROR) {
- fprintf(stderr, "cant store %s\n", ibuf);
- exit(1);
- }
- } else {
- if (!dbzfetch(key, &ivalue)) {
- fprintf(stderr, "line %d can't fetch %s\n", line, ibuf);
- exit(1);
- }
- }
- }
- line--;
- gettimeofday(&end, NULL);
- i = timediffms(start, end);
- printf("%s: %d lines %.3f msec/id\n",
- (initialize) ? "dbzstore" : "dbzfetch",
- line, (double)i / (double)line);
-
- gettimeofday(&end, NULL);
- dbzclose();
- gettimeofday(&end, NULL);
- printf("dbzclose: %d msec\n", timediffms(start, end));
- return(0);
-}
-#endif /* DBZTEST */
+++ /dev/null
-/* $Id: defdist.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "paths.h"
-
-
-typedef struct _DDENTRY {
- char *Pattern;
- char *Value;
- int Weight;
-} DDENTRY;
-
-struct _DDHANDLE {
- int Count;
- DDENTRY *Entries;
- DDENTRY *Current;
-};
-typedef struct _DDHANDLE DDHANDLE;
-
-struct _DDHANDLE *
-DDstart(FILE *FromServer, FILE *ToServer)
-{
- DDHANDLE *h;
- DDENTRY *ep;
- FILE *F;
- char buff[BUFSIZ];
- char *p;
- char *q;
- char *path;
- int i;
- int fd;
- char *name = NULL;
-
- /* Open the file. */
- path = concatpath(innconf->pathetc, _PATH_DISTPATS);
- F = fopen(path, "r");
- free(path);
- if (F == NULL) {
- /* Not available locally; try remotely. */
- if (FromServer == NULL || ToServer == NULL)
- /* We're probably nnrpd running on the server and the
- * file isn't installed. Oh well. */
- return NULL;
- name = concatpath(innconf->pathtmp, _PATH_TEMPACTIVE);
- fd = mkstemp(name);
- if (fd < 0)
- return NULL;
- close(fd);
- if ((F = CA_listopen(name, FromServer, ToServer,
- "distrib.pats")) == NULL)
- return NULL;
- }
-
- /* Count lines. */
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
-
- /* Allocate space for the handle. */
- if ((h = xmalloc(sizeof(DDHANDLE))) == NULL) {
- i = errno;
- fclose(F);
- if (name != NULL)
- unlink(name);
- errno = i;
- return NULL;
- }
- h->Count = 0;
- h->Current = NULL;
- if (i == 0) {
- return NULL ;
- } else if ((h->Entries = xmalloc(sizeof(DDENTRY) * i)) == NULL) {
- i = errno;
- free(h);
- fclose(F);
- if (name != NULL)
- unlink(name);
- errno = i;
- return NULL;
- }
-
- fseeko(F, 0, SEEK_SET);
- for (ep = h->Entries; fgets(buff, sizeof buff, F) != NULL; ) {
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '\0' || buff[0] == '#')
- continue;
- if ((p = strchr(buff, ':')) == NULL
- || (q = strchr(p + 1, ':')) == NULL)
- continue;
- *p++ = '\0';
- ep->Weight = atoi(buff);
- ep->Pattern = xstrdup(p);
- q = strchr(ep->Pattern, ':');
- *q++ = '\0';
- ep->Value = q;
- ep++;
- }
- h->Count = ep - h->Entries;
-
- fclose(F);
- if (name != NULL)
- unlink(name);
- return h;
-}
-
-
-void
-DDcheck(DDHANDLE *h, char *group)
-{
- DDENTRY *ep;
- int i;
- int w;
-
- if (h == NULL || group == NULL)
- return;
-
- w = h->Current ? h->Current->Weight : -1;
- for (ep = h->Entries, i = h->Count; --i >= 0; ep++)
- if (ep->Weight > w && uwildmat(group, ep->Pattern)) {
- h->Current = ep;
- w = ep->Weight;
- }
-}
-
-
-char *
-DDend(DDHANDLE *h)
-{
- static char NIL[] = "";
- char *p;
- int i;
- DDENTRY *ep;
-
- if (h == NULL) {
- p = NIL;
- return xstrdup(p);
- }
-
- if (h->Current == NULL)
- p = NIL;
- else
- p = h->Current->Value;
- p = xstrdup(p);
-
- for (ep = h->Entries, i = h->Count; --i >= 0; ep++)
- free(ep->Pattern);
- free(h->Entries);
- free(h);
- return p;
-}
-
-#if defined(TEST)
-int
-main(int ac, char *av[])
-{
- struct _DDHANDLE *h;
- char *p;
- FILE *FromServer;
- FILE *ToServer;
- char buff[SMBUF];
-
- if (NNTPremoteopen(NNTP_PORT, &FromServer, &ToServer, buff) < 0) {
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if (buff[0])
- fprintf(stderr, "%s\n", buff);
- else
- perror("Can't connect");
- exit(1);
- }
-
- if ((h = DDstart(FromServer, ToServer)) == NULL)
- perror("Init failed, proceeding anyway");
- while ((p = *++av) != NULL)
- DDcheck(h, p);
- p = DDend(h);
- printf(">%s<\n", p);
- exit(0);
- /* NOTREACHED */
-}
-#endif /* defined(TEST) */
+++ /dev/null
-/* $Id: fdflags.c 4740 2001-05-14 03:52:34Z rra $
-**
-** Set or clear file descriptor flags.
-**
-** Simple functions (wrappers around fcntl) to set or clear file descriptor
-** flags like close on exec or nonblocking I/O.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-#include <errno.h>
-#include <fcntl.h>
-
-/*
-** Set a file to close on exec.
-**
-** One is supposed to retrieve the flags, add FD_CLOEXEC, and then set
-** them, although I've never seen a system with any flags other than
-** close-on-exec. Do it right anyway; it's not that expensive. Avoid
-** changing errno. Errors are ignored, since it generally doesn't cause
-** significant harm to fail.
-*/
-void
-close_on_exec(int fd, bool flag)
-{
- int oerrno;
- int oflag;
-
- oerrno = errno;
- oflag = fcntl(fd, F_GETFD, 0);
- if (oflag < 0) {
- errno = oerrno;
- return;
- }
- fcntl(fd, F_SETFD, flag ? (oflag | FD_CLOEXEC) : (oflag & ~FD_CLOEXEC));
- errno = oerrno;
-}
-
-
-/*
-** Set a file descriptor to nonblocking (or clear the nonblocking flag if
-** flag is false).
-**
-** Always use O_NONBLOCK; O_NDELAY is *not* the same thing historically.
-** The semantics of O_NDELAY are that if the read would block, it returns 0
-** instead. This is indistinguishable from an end of file condition.
-** POSIX added O_NONBLOCK, which requires read to return -1 and set errno
-** to EAGAIN, which is what we want.
-**
-** FNDELAY (4.3BSD) originally did the correct thing, although it has a
-** different incompatibility (affecting all users of a socket rather than
-** just a file descriptor and returning EWOULDBLOCK instead of EAGAIN) that
-** we don't care about in INN. Using it is *probably* safe, but BSD should
-** also have the ioctl, and at least on Solaris FNDELAY does the same thing
-** as O_NDELAY, not O_NONBLOCK. So if we don't have O_NONBLOCK, fall back
-** to the ioctl instead.
-**
-** Reference: Stevens, Advanced Unix Programming, pg. 364.
-**
-** Note that O_NONBLOCK is known not to work on earlier versions of ULTRIX,
-** SunOS, and AIX, possibly not setting the socket nonblocking at all,
-** despite the fact that they do define it. It works in later SunOS and,
-** current AIX, however, and a 1999-10-25 survey of current operating
-** systems failed to turn up any that didn't handle it correctly (as
-** required by POSIX), while HP-UX 11.00 did use the broken return-zero
-** semantics of O_NDELAY (most other operating systems surveyed treated
-** O_NDELAY as synonymous with O_NONBLOCK). Accordingly, we currently
-** unconditionally use O_NONBLOCK. If this causes too many problems, an
-** autoconf test may be required.
-*/
-
-#ifdef O_NONBLOCK
-
-int
-nonblocking(int fd, bool flag)
-{
- int mode;
-
- mode = fcntl(fd, F_GETFL, 0);
- if (mode < 0)
- return -1;
- mode = (flag ? (mode | O_NONBLOCK) : (mode & ~O_NONBLOCK));
- return fcntl(fd, F_SETFL, mode);
-}
-
-#else /* !O_NONBLOCK */
-
-#include <sys/ioctl.h>
-#if HAVE_SYS_FILIO_H
-# include <sys/filio.h>
-#endif
-
-int
-nonblocking(int fd, bool flag)
-{
- int state;
-
- state = flag ? 1 : 0;
- return ioctl(fd, FIONBIO, &state);
-}
-
-#endif /* !O_NONBLOCK */
+++ /dev/null
-/* $Id: fdlimit.c 4511 2001-02-07 23:41:08Z rra $
-**
-** Portably determine or set the limit on open file descriptors.
-**
-** Pretty much all platforms these days have getrlimit and setrlimit, so
-** prefer those, but for determining the current limit preserve the old
-** portability (if we don't have getrlimit, try sysconf, then
-** getdtablesize, then ulimit, and then try to find a hard-coded constant
-** in <sys/param.h> and failing that fall back to the POSIX-guaranteed
-** minimum of 20.
-**
-** For setting the limit, only setrlimit is supported; if it isn't
-** available, return -1 always. We also refuse to set the limit to
-** something higher than select can handle, checking against FD_SETSIZE.
-**
-** Note that on some versions of Linux (2.2.x reported), sysconf may return
-** the wrong value for the maximum file descriptors. getrlimit is correct,
-** so always prefer it.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#if HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-/* FreeBSD 3.4 RELEASE needs <sys/time.h> before <sys/resource.h>. */
-#if HAVE_GETRLIMIT || HAVE_SETRLIMIT
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# endif
-# include <sys/resource.h>
-#endif
-
-#include "libinn.h"
-
-#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
-
-int
-setfdlimit(unsigned int limit)
-{
- struct rlimit rl;
-
-#ifdef FD_SETSIZE
- if (limit > FD_SETSIZE) {
- errno = EINVAL;
- return -1;
- }
-#endif
-
- rl.rlim_cur = 0;
- rl.rlim_max = 0;
-
-#if HAVE_GETRLIMIT
- if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
- rl.rlim_cur = 0;
- rl.rlim_max = 0;
- }
-#endif
-
- rl.rlim_cur = limit;
- if (limit > rl.rlim_max)
- rl.rlim_max = limit;
- return setrlimit(RLIMIT_NOFILE, &rl);
-}
-
-#else /* !(HAVE_SETRLIMIT && RLIMIT_NOFILE) */
-
-int
-setfdlimit(unsigned int limit UNUSED)
-{
- /* Unimplemented system call is close enough. */
- errno = ENOSYS;
- return -1;
-}
-
-#endif /* !(HAVE_SETRLIMIT && RLIMIT_NOFILE) */
-
-#if HAVE_GETRLIMIT && defined(RLIMIT_NOFILE)
-
-int
-getfdlimit(void)
-{
- struct rlimit rl;
-
- if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
- return -1;
- return rl.rlim_cur;
-}
-
-#elif HAVE_SYSCONF
-
-int
-getfdlimit(void)
-{
- return sysconf(_SC_OPEN_MAX);
-}
-
-#elif HAVE_GETDTABLESIZE
-
-int
-getfdlimit(void)
-{
- return getdtablesize();
-}
-
-#elif HAVE_ULIMIT
-
-int
-getfdlimit(void)
-{
-# ifdef UL_GDESLIM
- return ulimit(UL_GDESLIM, 0);
-# else
- return ulimit(4, 0);
-# endif
-}
-
-#else /* no function mechanism available */
-# if HAVE_LIMITS_H
-# include <limits.h>
-# endif
-# include <sys/param.h>
-
-int
-getfdcount(void)
-{
-# ifdef NOFILE
- return NOFILE;
-# else
- return 20;
-# endif
-}
-
-#endif
+++ /dev/null
-/* $Id: fseeko.c 3680 2000-07-29 22:54:52Z rra $
-**
-** Replacement for a missing fseeko.
-**
-** fseeko is a version of fseek that takes an off_t instead of a long. For
-** large file support (and because it's a more logical interface), INN uses
-** fseeko unconditionally; if fseeko isn't provided by a platform but
-** fpos_t is compatible with off_t (as in BSDI), define it in terms of
-** fsetpos. Otherwise, just call fseek (which won't work for files over
-** 2GB).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#if HAVE_LARGE_FPOS_T
-
-int
-fseeko(FILE *stream, off_t pos, int whence)
-{
- fpos_t fpos;
-
- switch (whence) {
- case SEEK_SET:
- fpos = pos;
- return fsetpos(stream, &fpos);
-
- case SEEK_END:
- if (fseek(stream, 0, SEEK_END) < 0)
- return -1;
- if (pos == 0)
- return 0;
- /* Fall through. */
-
- case SEEK_CUR:
- if (fgetpos(stream, &fpos) < 0)
- return -1;
- fpos += pos;
- return fsetpos(stream, &fpos);
-
- default:
- errno = EINVAL;
- return -1;
- }
-}
-
-#else /* !HAVE_LARGE_FPOS_T */
-
-int
-fseeko(FILE *stream, off_t pos, int whence)
-{
- return fseek(stream, (long) pos, whence);
-}
-
-#endif /* !HAVE_LARGE_FPOS_T */
+++ /dev/null
-/* $Id: ftello.c 3681 2000-07-29 22:55:18Z rra $
-**
-** Replacement for a missing ftello.
-**
-** ftello is a version of ftell that returns an off_t instead of a long.
-** For large file support (and because it's a more logical interface), INN
-** uses ftello unconditionally; if ftello isn't provided by a platform but
-** fpos_t is compatible with off_t (as in BSDI), define it in terms of
-** fgetpos. Otherwise, just call ftell (which won't work for files over
-** 2GB).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#if HAVE_LARGE_FPOS_T
-
-off_t
-ftello(FILE *stream)
-{
- fpos_t fpos;
-
- if (fgetpos(stream, &fpos) < 0) {
- return -1;
- } else {
- return (off_t) fpos;
- }
-}
-
-#else /* !HAVE_LARGE_FPOS_T */
-
-off_t
-ftello(FILE *stream)
-{
- return (off_t) ftell(stream);
-}
-
-#endif /* !HAVE_LARGE_FPOS_T */
+++ /dev/null
-/* $Id: genid.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Generate a message ID.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "libinn.h"
-
-/* Scale time back a bit, for shorter Message-ID's. */
-#define OFFSET 673416000L
-
-char *
-GenerateMessageID(char *domain)
-{
- static char buff[SMBUF];
- static int count;
- char *p;
- char sec32[10];
- char pid32[10];
- TIMEINFO Now;
-
- if (GetTimeInfo(&Now) < 0)
- return NULL;
- Radix32(Now.time - OFFSET, sec32);
- Radix32(getpid(), pid32);
- if ((domain != NULL && innconf->domain == NULL) ||
- (domain != NULL && innconf->domain != NULL
- && strcmp(domain, innconf->domain) != 0)) {
- p = domain;
- } else {
- if ((p = GetFQDN(domain)) == NULL)
- return NULL;
- }
- snprintf(buff, sizeof(buff), "<%s$%s$%d@%s>", sec32, pid32, ++count, p);
- return buff;
-}
+++ /dev/null
-/* $Id: getfqdn.c 6155 2003-01-19 19:58:25Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <netdb.h>
-
-#include "libinn.h"
-#include "paths.h"
-
-
-/*
-** Get the fully-qualified domain name for this host.
-*/
-char *GetFQDN(char *domain)
-{
- static char buff[SMBUF];
- struct hostent *hp;
- char *p;
- char **ap;
-#if 0
- /* See comments below. */
- char temp[SMBUF + 2];
-#endif /* 0 */
-
- /* Return any old results. */
- if (buff[0])
- return buff;
-
- /* Try gethostname. */
- if (gethostname(buff, (int)sizeof buff) < 0)
- return NULL;
- if (strchr(buff, '.') != NULL)
- return buff;
-
- /* See if DNS (or /etc/hosts) gives us a full domain name. */
- if ((hp = gethostbyname(buff)) == NULL)
- return NULL;
-#if 0
- /* This code is a "feature" that allows multiple domains (NIS or
- * DNS, I'm not sure) to work with a single INN server. However,
- * it turns out to cause more problems for people, and they have to
- * use hacks like __switch_gethostbyname, etc. So if you need this,
- * turn it on, but don't complain to me. */
- if (strchr(hp->h_name, '.') == NULL) {
- /* Try to force DNS lookup if NIS/whatever gets in the way. */
- strlcpy(temp, buff, sizeof(temp));
- strlcat(temp, ".", sizeof(temp));
- hp = gethostbyname(temp);
- }
-#endif /* 0 */
-
- /* First, see if the main name is a FQDN. It should be. */
- if (hp != NULL && strchr(hp->h_name, '.') != NULL) {
- if (strlen(hp->h_name) < sizeof buff - 1) {
- strlcpy(buff, hp->h_name, sizeof(buff));
- return buff;
- }
- /* Doesn't fit; make sure we don't return bad data next time. */
- buff[0] = '\0';
- return hp->h_name;
- }
-
- /* Second, see if any aliases are. */
- if ((ap = hp->h_aliases) != NULL)
- while ((p = *ap++) != NULL)
- if (strchr(p, '.') != NULL) {
- /* Deja-vous all over again. */
- if (strlen(p) < sizeof buff - 1) {
- strlcpy(buff, p, sizeof(buff));
- return buff;
- }
- buff[0] = '\0';
- return p ;
- }
-
- /* Give up: Get the domain config param and append it. */
- if ((p = domain) == NULL || *p == '\0')
- return NULL;
- if (strlen(buff) + 1 + strlen(p) > sizeof buff - 1)
- /* Doesn't fit. */
- return NULL;
- strlcat(buff, ".", sizeof(buff));
- strlcat(buff, p, sizeof(buff));
- return buff;
-}
+++ /dev/null
-/* $Id: getmodaddr.c 6155 2003-01-19 19:58:25Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-
-static char *GMApathname = NULL;
-static FILE *GMAfp = NULL;
-
-
-/*
-** Close the file opened by GMAlistopen.
-*/
-static void
-GMAclose(void)
-{
- if (GMAfp) {
- fclose(GMAfp);
- GMAfp = NULL;
- }
- if (GMApathname != NULL) {
- unlink(GMApathname);
- free(GMApathname);
- GMApathname = NULL;
- }
-}
-
-/*
-** Internal library routine.
-*/
-static FILE *
-GMA_listopen(int fd, FILE *FromServer, FILE *ToServer, const char *request)
-{
- char buff[BUFSIZ];
- char *p;
- int oerrno;
- FILE *F;
-
- F = fdopen(fd, "r+");
- if (F == NULL)
- return NULL;
-
- /* Send a LIST command to and capture the output. */
- if (request == NULL)
- fprintf(ToServer, "list moderators\r\n");
- else
- fprintf(ToServer, "list %s\r\n", request);
- fflush(ToServer);
-
- /* Get the server's reply to our command. */
- if (fgets(buff, sizeof buff, FromServer) == NULL
- || strncmp(buff, NNTP_LIST_FOLLOWS, strlen(NNTP_LIST_FOLLOWS)) != 0) {
- oerrno = errno;
- fclose(F);
- GMAclose();
- errno = oerrno;
- return NULL;
- }
-
- /* Slurp up the rest of the response. */
- while (fgets(buff, sizeof buff, FromServer) != NULL) {
- if ((p = strchr(buff, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '.' && buff[1] == '\0') {
- if (ferror(F) || fflush(F) == EOF || fseeko(F, 0, SEEK_SET) != 0)
- break;
- return F;
- }
- fprintf(F, "%s\n", buff);
- }
-
- /* Ran out of input before finding the terminator; quit. */
- oerrno = errno;
- fclose(F);
- GMAclose();
- errno = oerrno;
- return NULL;
-}
-
-/*
-** Read the moderators file, looking for a moderator.
-*/
-char *
-GetModeratorAddress(FILE *FromServer, FILE *ToServer, char *group,
- char *moderatormailer)
-{
- static char address[SMBUF];
- char *p;
- char *save;
- char *path;
- char buff[BUFSIZ];
- char name[SMBUF];
- int fd;
-
- strlcpy(name, group, sizeof(name));
- address[0] = '\0';
-
- if (FromServer==NULL || ToServer==NULL){
-
- /*
- * This should be part of nnrpd or the like running on the server.
- * Open the server copy of the moderators file.
- */
- path = concatpath(innconf->pathetc, _PATH_MODERATORS);
- GMAfp = fopen(path, "r");
- free(path);
- }else{
- /*
- * Get a local copy of the moderators file from the server.
- */
- GMApathname = concatpath(innconf->pathtmp, _PATH_TEMPMODERATORS);
- fd = mkstemp(GMApathname);
- if (fd >= 0)
- GMAfp = GMA_listopen(fd, FromServer, ToServer, "moderators");
- else
- GMAfp = NULL;
-
- /* Fallback to the local copy if the server doesn't have it */
- if (GMAfp == NULL) {
- path = concatpath(innconf->pathetc, _PATH_MODERATORS);
- GMAfp = fopen(path, "r");
- free(path);
- }
- }
-
- if (GMAfp != NULL) {
- while (fgets(buff, sizeof buff, GMAfp) != NULL) {
- /* Skip blank and comment lines. */
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '\0' || buff[0] == '#')
- continue;
-
- /* Snip off the first word. */
- if ((p = strchr(buff, ':')) == NULL)
- /* Malformed line... */
- continue;
- *p++ = '\0';
-
- /* If it pattern-matches the newsgroup, the second field is a
- * format for mailing, with periods changed to dashes. */
- if (uwildmat(name, buff)) {
- for (save = p; ISWHITE(*save); save++)
- continue;
- for (p = name; *p; p++)
- if (*p == '.')
- *p = '-';
- snprintf(address, sizeof(address), save, name);
- break;
- }
- }
-
- GMAclose();
- if (address[0])
- return address;
- }
-
- /* If we don't have an address, see if the config file has a default. */
- if ((save = moderatormailer) == NULL)
- return NULL;
-
- for (p = name; *p; p++)
- if (*p == '.')
- *p = '-';
- snprintf(address, sizeof(address), save, name);
- return address;
-}
+++ /dev/null
-/* $Id: getpagesize.c 5596 2002-08-17 21:29:35Z rra $
-**
-** Replacement for a missing getpagesize.
-**
-** Provides getpagesize implemented in terms of sysconf for those systems
-** that don't have the getpagesize function. Defaults to a page size of 16KB
-** if sysconf isn't available either.
-*/
-
-#include "config.h"
-#include <unistd.h>
-
-int
-getpagesize(void)
-{
- int pagesize;
-
-#ifdef _SC_PAGESIZE
- pagesize = sysconf(_SC_PAGESIZE);
-#else
- pagesize = 16 * 1024;
-#endif
- return pagesize;
-}
+++ /dev/null
-/* $Id: gettime.c 4135 2000-10-19 16:38:13Z kondou $
-**
-** Find and return time information portably.
-*/
-#include "config.h"
-#include "libinn.h"
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-#else
-# ifdef HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
-
-
-int
-GetTimeInfo(TIMEINFO *Now)
-{
- static time_t NextHour;
- static long LastTzone;
- struct tm *tm;
- int secondsUntilNextHour;
-
- struct timeval tv;
-
-#ifndef HAVE_TM_GMTOFF
- struct tm local;
- struct tm gmt;
-#endif
-
- /* Get the basic time. */
- if (gettimeofday(&tv, (struct timezone *) 0) == -1)
- return -1;
- Now->time = tv.tv_sec;
- Now->usec = tv.tv_usec;
-
- /* Now get the timezone if the last time < HH:00:00 <= now for some HH. */
- if (NextHour <= Now->time) {
- tm = localtime(&Now->time);
- if (tm == NULL)
- return -1;
- secondsUntilNextHour = 60 * (60 - tm->tm_min) - tm->tm_sec;
-
-#ifdef HAVE_TM_GMTOFF
- LastTzone = (0 - tm->tm_gmtoff) / 60;
-#else
- /* To get the timezone, compare localtime with GMT. */
- local = *tm;
- if ((tm = gmtime(&Now->time)) == NULL)
- return -1;
- gmt = *tm;
-
- /* Assume we are never more than 24 hours away. */
- LastTzone = gmt.tm_yday - local.tm_yday;
- if (LastTzone > 1)
- LastTzone = -24;
- else if (LastTzone < -1)
- LastTzone = 24;
- else
- LastTzone *= 24;
-
- /* Scale in the hours and minutes; ignore seconds. */
- LastTzone += gmt.tm_hour - local.tm_hour;
- LastTzone *= 60;
- LastTzone += gmt.tm_min - local.tm_min;
-#endif /* defined(HAVE_TM_GMTOFF) */
-
- NextHour = Now->time + secondsUntilNextHour;
- }
- Now->tzone = LastTzone;
- return 0;
-}
+++ /dev/null
-/* This provides a generic hash function for use w/INN. Currently
- is implemented using MD5, but should probably have a mechanism for
- choosing the hash algorithm and tagging the hash with the algorithm
- used */
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#include "inn/md5.h"
-#include "libinn.h"
-
-static HASH empty= { { 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0 }};
-
-/* cipoint - where in this message-ID does it become case-insensitive?
- *
- * The RFC822 code is not quite complete. Absolute, total, full RFC822
- * compliance requires a horrible parsing job, because of the arcane
- * quoting conventions -- abc"def"ghi is not equivalent to abc"DEF"ghi,
- * for example. There are three or four things that might occur in the
- * domain part of a message-id that are case-sensitive. They don't seem
- * to ever occur in real news, thank Cthulhu. (What? You were expecting
- * a merciful and forgiving deity to be invoked in connection with RFC822?
- * Forget it; none of them would come near it.)
- *
- * Returns: pointer into s, or NULL for "nowhere"
- */
-static const char *
-cipoint(const char *s, size_t size)
-{
- char *p;
- static const char post[] = "postmaster";
- static int plen = sizeof(post) - 1;
-
- if ((p = memchr(s, '@', size))== NULL) /* no local/domain split */
- return NULL; /* assume all local */
- if ((p - (s + 1) == plen) && !strncasecmp(post, s+1, plen)) {
- /* crazy -- "postmaster" is case-insensitive */
- return s;
- }
- return p;
-}
-
-HASH
-Hash(const void *value, const size_t len)
-{
- struct md5_context context;
- HASH hash;
-
- md5_init(&context);
- md5_update(&context, value, len);
- md5_final(&context);
- memcpy(&hash,
- &context.digest,
- (sizeof(hash) < sizeof(context.digest)) ? sizeof(hash) : sizeof(context.digest));
- return hash;
-}
-
-HASH
-HashMessageID(const char *MessageID)
-{
- char *new = NULL;
- const char *cip, *p = NULL;
- char *q;
- int len;
- HASH hash;
-
- len = strlen(MessageID);
- cip = cipoint(MessageID, len);
- if (cip != NULL) {
- for (p = cip + 1; *p != '\0'; p++) {
- if (!CTYPE(islower, *p)) {
- new = xstrdup(MessageID);
- break;
- }
- }
- }
- if (new != NULL)
- for (q = new + (p - MessageID); *q != '\0'; q++)
- *q = tolower(*q);
- hash = Hash(new ? new : MessageID, len);
- if (new != NULL)
- free(new);
- return hash;
-}
-
-/*
-** Check if the hash is all zeros, and subseqently empty, see HashClear
-** for more info on this.
-*/
-bool
-HashEmpty(const HASH h)
-{
- return (memcmp(&empty, &h, sizeof(HASH)) == 0);
-}
-
-/*
-** Set the hash to all zeros. Using all zeros as the value for empty
-** introduces the possibility of colliding w/a value that actually hashes
-** to all zeros, but that's fairly unlikely.
-*/
-void
-HashClear(HASH *hash)
-{
- memset(hash, '\0', sizeof(HASH));
-}
-
-/*
-** Convert the binary form of the hash to a form that we can use in error
-** messages and logs.
-*/
-char *
-HashToText(const HASH hash)
-{
- static const char hex[] = "0123456789ABCDEF";
- const char *p;
- unsigned int i;
- static char hashstr[(sizeof(HASH)*2) + 1];
-
- for (p = hash.hash, i = 0; i < sizeof(HASH); i++, p++) {
- hashstr[i * 2] = hex[(*p & 0xF0) >> 4];
- hashstr[(i * 2) + 1] = hex[*p & 0x0F];
- }
- hashstr[(sizeof(HASH) * 2)] = '\0';
- return hashstr;
-}
-
-/*
-** Converts a hex digit and converts it to a int
-*/
-static
-int hextodec(const int c)
-{
- return isdigit(c) ? (c - '0') : ((c - 'A') + 10);
-}
-
-/*
-** Convert the ASCII representation of the hash back to the canonical form
-*/
-HASH
-TextToHash(const char *text)
-{
- char *q;
- int i;
- HASH hash;
-
- for (q = (char *)&hash, i = 0; i != sizeof(HASH); i++) {
- q[i] = (hextodec(text[i * 2]) << 4) + hextodec(text[(i * 2) + 1]);
- }
- return hash;
-}
-
-/* This is rather gross, we compare like the last 4 bytes of the
- hash are at the beginning because dbz considers them to be the
- most significant bytes */
-int HashCompare(const HASH *h1, const HASH *h2) {
- int i;
- int tocomp = sizeof(HASH) - sizeof(unsigned long);
-
- if ((i = memcmp(&h1->hash[tocomp], &h1->hash[tocomp], sizeof(unsigned long))))
- return i;
- return memcmp(h1, h2, sizeof(HASH));
-}
+++ /dev/null
-/* $Id: hashtab.c 6135 2003-01-19 01:15:40Z rra $
-**
-** Generic hash table implementation.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** This is a generic hash table implementation with linear probing. It
-** takes a comparison function and a hashing function and stores void *.
-**
-** Included for the use of callers is the hash function LOOKUP2 by Bob
-** Jenkins, taken from <http://burtleburtle.net/bob/hash/>; see that web
-** page for analysis and performance comparisons. The performance of this
-** hash is slightly worse than the standard sum and modulus hash function
-** seen in many places but it produces fewer collisions.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "inn/hashtab.h"
-#include "libinn.h"
-
-/* Magic values for empty and deleted hash table slots. */
-#define HASH_EMPTY ((void *) 0)
-#define HASH_DELETED ((void *) 1)
-
-struct hash {
- size_t size; /* Allocated size. */
- size_t mask; /* Used to resolve a hash to an index. */
- size_t nelements; /* Total elements, including deleted. */
- size_t ndeleted; /* Number of deleted elements. */
-
- unsigned long searches; /* Count of lookups (for debugging). */
- unsigned long collisions; /* Count of collisions (for debugging). */
- unsigned long expansions; /* Count of hash resizes needed. */
-
- hash_func hash; /* Return hash of a key. */
- hash_key_func key; /* Given an element, returns its key. */
- hash_equal_func equal; /* Whether a key matches an element. */
- hash_delete_func delete; /* Called when a hash element is deleted. */
-
- void **table; /* The actual elements. */
-};
-
-
-/*
-** Given a target table size, return the nearest power of two that's
-** greater than or equal to that size, with a minimum size of four. The
-** minimum must be at least four to ensure that there is always at least
-** one empty slot in the table given hash_find_slot's resizing of the table
-** if it as least 75% full. Otherwise, it would be possible for
-** hash_find_slot to go into an infinite loop.
-*/
-static size_t
-hash_size(size_t target)
-{
- int n;
- size_t size;
-
- size = target - 1;
- for (n = 0; size > 0; n++)
- size >>= 1;
- size = 1 << n;
- return (size < 4) ? 4 : size;
-}
-
-
-/*
-** Create a new hash table. The given size is rounded up to the nearest
-** power of two for speed reasons (it greatly simplifies the use of the
-** hash function).
-*/
-struct hash *
-hash_create(size_t size, hash_func hash_f, hash_key_func key_f,
- hash_equal_func equal_f, hash_delete_func delete_f)
-{
- struct hash *hash;
-
- hash = xcalloc(1, sizeof(struct hash));
- hash->hash = hash_f;
- hash->key = key_f;
- hash->equal = equal_f;
- hash->delete = delete_f;
- hash->size = hash_size(size);
- hash->mask = hash->size - 1;
- hash->table = xcalloc(hash->size, sizeof(void *));
- return hash;
-}
-
-
-/*
-** Free a hash and all resources used by it, and call the delete function
-** on every element.
-*/
-void
-hash_free(struct hash *hash)
-{
- size_t i;
- void *entry;
-
- for (i = 0; i < hash->size; i++) {
- entry = hash->table[i];
- if (entry != HASH_EMPTY && entry != HASH_DELETED)
- (*hash->delete)(entry);
- }
- free(hash->table);
- free(hash);
-}
-
-
-/*
-** Internal search function used by hash_expand. This is an optimized
-** version of hash_find_slot that returns a pointer to the first empty
-** slot, not trying to call the equality function on non-empty slots and
-** assuming there are no HASH_DELETED slots.
-*/
-static void **
-hash_find_empty(struct hash *hash, const void *key)
-{
- size_t slot;
-
- slot = (*hash->hash)(key) & hash->mask;
- while (1) {
- if (hash->table[slot] == HASH_EMPTY)
- return &hash->table[slot];
-
- slot++;
- if (slot >= hash->size)
- slot -= hash->size;
- }
-}
-
-
-/*
-** Expand the hash table to be approximately 50% empty based on the number
-** of elements in the hash. This is done by allocating a new table and
-** then calling hash_find_empty for each element in the previous table,
-** recovering the key by calling hash->key on the element.
-*/
-static void
-hash_expand(struct hash *hash)
-{
- void **old, **slot;
- size_t i, size;
-
- old = hash->table;
- size = hash->size;
- hash->size = hash_size((hash->nelements - hash->ndeleted) * 2);
- hash->mask = hash->size - 1;
- hash->table = xcalloc(hash->size, sizeof(void *));
-
- hash->nelements = 0;
- hash->ndeleted = 0;
- for (i = 0; i < size; i++)
- if (old[i] != HASH_EMPTY && old[i] != HASH_DELETED) {
- slot = hash_find_empty(hash, (*hash->key)(old[i]));
- *slot = old[i];
- hash->nelements++;
- }
-
- hash->expansions++;
- free(old);
-}
-
-
-/*
-** Find a slot in the hash for a given key. This is used both for
-** inserting and deleting elements from the hash, as well as looking up
-** entries. Returns a pointer to the slot. If insert is true, return the
-** first empty or deleted slot. If insert is false, return NULL if the
-** element could not be found.
-**
-** This function assumes that there is at least one empty slot in the
-** hash; otherwise, it can loop infinitely. It attempts to ensure this by
-** always expanding the hash if it is at least 75% full; this will ensure
-** that property for any hash size of 4 or higher.
-*/
-static void **
-hash_find_slot(struct hash *hash, const void *key, bool insert)
-{
- void **deleted_slot = NULL;
- void *entry;
- size_t slot;
-
- if (insert && hash->nelements * 4 >= hash->size * 3)
- hash_expand(hash);
-
- hash->searches++;
-
- slot = (*hash->hash)(key) & hash->mask;
- while (1) {
- entry = hash->table[slot];
- if (entry == HASH_EMPTY) {
- if (!insert)
- return NULL;
-
- if (deleted_slot != NULL) {
- *deleted_slot = HASH_EMPTY;
- hash->ndeleted--;
- return deleted_slot;
- }
- hash->nelements++;
- return &hash->table[slot];
- } else if (entry == HASH_DELETED) {
- if (insert)
- deleted_slot = &hash->table[slot];
- } else if ((*hash->equal)(key, entry)) {
- return &hash->table[slot];
- }
-
- hash->collisions++;
- slot++;
- if (slot >= hash->size)
- slot -= hash->size;
- }
-}
-
-
-/*
-** Given a key, return the entry corresponding to that key or NULL if that
-** key isn't present in the hash table.
-*/
-void *
-hash_lookup(struct hash *hash, const void *key)
-{
- void **slot;
-
- slot = hash_find_slot(hash, key, false);
- return (slot == NULL) ? NULL : *slot;
-}
-
-
-/*
-** Insert a new key/value pair into the hash, returning true if the
-** insertion was successful and false if there is already a value in the
-** hash with that key.
-*/
-bool
-hash_insert(struct hash *hash, const void *key, void *datum)
-{
- void **slot;
-
- slot = hash_find_slot(hash, key, true);
- if (*slot != HASH_EMPTY)
- return false;
- *slot = datum;
- return true;
-}
-
-
-/*
-** Replace an existing hash value with a new data value, calling the delete
-** function for the old data. Returns true if the replacement was
-** successful or false (without changing the hash) if the key whose value
-** should be replaced was not found in the hash.
-*/
-bool
-hash_replace(struct hash *hash, const void *key, void *datum)
-{
- void **slot;
-
- slot = hash_find_slot(hash, key, false);
- if (slot == NULL)
- return false;
- (*hash->delete)(*slot);
- *slot = datum;
- return true;
-}
-
-
-/*
-** Delete a key out of the hash. Returns true if the deletion was
-** successful, false if the key could not be found in the hash.
-*/
-bool
-hash_delete(struct hash *hash, const void *key)
-{
- bool result;
-
- result = hash_replace(hash, key, HASH_DELETED);
- if (result)
- hash->ndeleted++;
- return result;
-}
-
-
-/*
-** For each element in the hash table, call the provided function, passing
-** it the element and the opaque token that's passed to this function.
-*/
-void
-hash_traverse(struct hash *hash, hash_traverse_func callback, void *data)
-{
- size_t i;
- void *entry;
-
- for (i = 0; i < hash->size; i++) {
- entry = hash->table[i];
- if (entry != HASH_EMPTY && entry != HASH_DELETED)
- (*callback)(entry, data);
- }
-}
-
-
-/*
-** Returns a count of undeleted elements in the hash.
-*/
-unsigned long
-hash_count(struct hash *hash)
-{
- return hash->nelements - hash->ndeleted;
-}
-
-
-/*
-** Accessor functions for the debugging statistics.
-*/
-unsigned long
-hash_searches(struct hash *hash)
-{
- return hash->searches;
-}
-
-unsigned long
-hash_collisions(struct hash *hash)
-{
- return hash->collisions;
-}
-
-unsigned long
-hash_expansions(struct hash *hash)
-{
- return hash->expansions;
-}
-
-
-/*
-** Mix three 32-bit values reversibly. This is the internal mixing
-** function for the hash function.
-**
-** For every delta with one or two bit set, and the deltas of all three
-** high bits or all three low bits, whether the original value of a,b,c
-** is almost all zero or is uniformly distributed,
-**
-** * If mix() is run forward or backward, at least 32 bits in a,b,c
-** have at least 1/4 probability of changing.
-**
-** * If mix() is run forward, every bit of c will change between 1/3 and
-** 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.)
-**
-** mix() takes 36 machine instructions, but only 18 cycles on a superscalar
-** machine (like a Pentium or a Sparc). No faster mixer seems to work,
-** that's the result of my brute-force search. There were about 2^68
-** hashes to choose from. I (Bob Jenkins) only tested about a billion of
-** those.
-*/
-#define MIX(a, b, c) \
- { \
- (a) -= (b); (a) -= (c); (a) ^= ((c) >> 13); \
- (b) -= (c); (b) -= (a); (b) ^= ((a) << 8); \
- (c) -= (a); (c) -= (b); (c) ^= ((b) >> 13); \
- (a) -= (b); (a) -= (c); (a) ^= ((c) >> 12); \
- (b) -= (c); (b) -= (a); (b) ^= ((a) << 16); \
- (c) -= (a); (c) -= (b); (c) ^= ((b) >> 5); \
- (a) -= (b); (a) -= (c); (a) ^= ((c) >> 3); \
- (b) -= (c); (b) -= (a); (b) ^= ((a) << 10); \
- (c) -= (a); (c) -= (b); (c) ^= ((b) >> 15); \
- }
-
-
-/*
-** Hash a variable-length key into a 32-bit value.
-**
-** Takes byte sequence to hash and returns a 32-bit value. A partial
-** result can be passed as the third parameter so that large amounts of
-** data can be hashed by subsequent calls, passing in the result of the
-** previous call each time. Every bit of the key affects every bit of the
-** return value. Every 1-bit and 2-bit delta achieves avalanche. About
-** (36 + 6n) instructions.
-**
-** The best hash table sizes are powers of 2. There is no need to mod with
-** a prime (mod is sooo slow!). If you need less than 32 bits, use a
-** bitmask. For example, if you need only 10 bits, do:
-**
-** h = h & ((1 << 10) - 1);
-**
-** In which case, the hash table should have 2^10 elements.
-**
-** Based on code by Bob Jenkins <bob_jenkins@burtleburtle.net>, originally
-** written in 1996. The original license was:
-**
-** By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use
-** this code any way you wish, private, educational, or commercial.
-** It's free.
-**
-** See <http://burlteburtle.net/bob/hash/evahash.html> for discussion of
-** this hash function. Use for hash table lookup, or anything where one
-** collision in 2^32 is acceptable. Do NOT use for cryptographic purposes.
-*/
-unsigned long
-hash_lookup2(const char *key, size_t length, unsigned long partial)
-{
- uint32_t a, b, c, len;
-
- /* Set up the internal state. a and b are initialized to a golden
- ratio, an arbitrary value intended to avoid mapping all zeroes to all
- zeroes. */
- len = length;
- a = b = 0x9e3779b9;
- c = partial;
-
-#define S0(c) ((uint32_t)(c))
-#define S1(c) ((uint32_t)(c) << 8)
-#define S2(c) ((uint32_t)(c) << 16)
-#define S3(c) ((uint32_t)(c) << 24)
-
- /* Handle most of the key. */
- while (len >= 12) {
- a += S0(key[0]) + S1(key[1]) + S2(key[2]) + S3(key[3]);
- b += S0(key[4]) + S1(key[5]) + S2(key[6]) + S3(key[7]);
- c += S0(key[8]) + S1(key[9]) + S2(key[10]) + S3(key[11]);
- MIX(a, b, c);
- key += 12;
- len -= 12;
- }
-
- /* Handle the last 11 bytes. All of the cases fall through. */
- c += length;
- switch (len) {
- case 11: c += S3(key[10]);
- case 10: c += S2(key[9]);
- case 9: c += S1(key[8]);
- /* The first byte of c is reserved for the length. */
- case 8: b += S3(key[7]);
- case 7: b += S2(key[6]);
- case 6: b += S1(key[5]);
- case 5: b += S0(key[4]);
- case 4: a += S3(key[3]);
- case 3: a += S2(key[2]);
- case 2: a += S1(key[1]);
- case 1: a += S0(key[0]);
- /* case 0: nothing left to add. */
- }
- MIX(a, b, c);
- return c;
-}
-
-
-/*
-** A hash function for nul-terminated strings using hash_lookup2, suitable
-** for passing to hash_create.
-*/
-unsigned long
-hash_string(const void *key)
-{
- return hash_lookup2(key, strlen(key), 0);
-}
+++ /dev/null
-/* $Id: hstrerror.c 5556 2002-08-11 22:23:14Z rra $
-**
-** Replacement for a missing hstrerror.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides hstrerror (strerror, but for h_errno from the resolver
-** libraries) on those platforms that don't have it (most non-BSD). This
-** function is thread-safe unless called with an unknown h_errno.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <netdb.h>
-
-static const char * const errors[] = {
- "No resolver error", /* 0 NETDB_SUCCESS */
- "Unknown host", /* 1 HOST_NOT_FOUND */
- "Host name lookup failure", /* 2 TRY_AGAIN */
- "Unknown server error", /* 3 NO_RECOVERY */
- "No address associated with name", /* 4 NO_ADDRESS / NO_DATA */
-};
-static int nerrors = (sizeof errors / sizeof errors[0]);
-
-/* If we're running the test suite, rename hstrerror to avoid conflicts with
- the system version. */
-#if TESTING
-# define hstrerror test_hstrerror
-const char *test_hstrerror(int);
-#endif
-
-const char *
-hstrerror(int error)
-{
- static char buf[32];
-
- if (error == -1)
- return "Internal resolver error";
- if (error >= 0 && error < nerrors)
- return errors[error];
- snprintf(buf, sizeof(buf), "Resolver error %d", error);
- return buf;
-}
+++ /dev/null
-/* $Id: inet_aton.c 5049 2001-12-12 09:06:00Z rra $
-**
-** Replacement for a missing inet_aton.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine
-** inet_aton for those platforms that don't have it. inet_aton is
-** thread-safe.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <netinet/in.h>
-
-/* If we're running the test suite, rename inet_ntoa to avoid conflicts with
- the system version. */
-#if TESTING
-# define inet_aton test_inet_aton
-int test_inet_aton(const char *, struct in_addr *);
-#endif
-
-int
-inet_aton(const char *s, struct in_addr *addr)
-{
- unsigned long octet[4], address;
- const char *p;
- int base, i;
- int part = 0;
-
- if (s == NULL) return 0;
-
- /* Step through each period-separated part of the address. If we see
- more than four parts, the address is invalid. */
- for (p = s; *p != 0; part++) {
- if (part > 3) return 0;
-
- /* Determine the base of the section we're looking at. Numbers are
- represented the same as in C; octal starts with 0, hex starts
- with 0x, and anything else is decimal. */
- if (*p == '0') {
- p++;
- if (*p == 'x') {
- p++;
- base = 16;
- } else {
- base = 8;
- }
- } else {
- base = 10;
- }
-
- /* Make sure there's actually a number. (A section of just "0"
- would set base to 8 and leave us pointing at a period; allow
- that.) */
- if (*p == '.' && base != 8) return 0;
- octet[part] = 0;
-
- /* Now, parse this segment of the address. For each digit, multiply
- the result so far by the base and then add the value of the
- digit. Be careful of arithmetic overflow in cases where an
- unsigned long is 32 bits; we need to detect it *before* we
- multiply by the base since otherwise we could overflow and wrap
- and then not detect the error. */
- for (; *p != 0 && *p != '.'; p++) {
- if (octet[part] > 0xffffffffUL / base) return 0;
-
- /* Use a switch statement to parse each digit rather than
- assuming ASCII. Probably pointless portability.... */
- switch (*p) {
- case '0': i = 0; break;
- case '1': i = 1; break;
- case '2': i = 2; break;
- case '3': i = 3; break;
- case '4': i = 4; break;
- case '5': i = 5; break;
- case '6': i = 6; break;
- case '7': i = 7; break;
- case '8': i = 8; break;
- case '9': i = 9; break;
- case 'A': case 'a': i = 10; break;
- case 'B': case 'b': i = 11; break;
- case 'C': case 'c': i = 12; break;
- case 'D': case 'd': i = 13; break;
- case 'E': case 'e': i = 14; break;
- case 'F': case 'f': i = 15; break;
- default: return 0;
- }
- if (i >= base) return 0;
- octet[part] = (octet[part] * base) + i;
- }
-
- /* Advance over periods; the top of the loop will increment the
- count of parts we've seen. We need a check here to detect an
- illegal trailing period. */
- if (*p == '.') {
- p++;
- if (*p == 0) return 0;
- }
- }
- if (part == 0) return 0;
-
- /* IPv4 allows three types of address specification:
-
- a.b
- a.b.c
- a.b.c.d
-
- If there are fewer than four segments, the final segment accounts for
- all of the remaining portion of the address. For example, in the a.b
- form, b is the final 24 bits of the address. We also allow a simple
- number, which is interpreted as the 32-bit number corresponding to
- the full IPv4 address.
-
- The first for loop below ensures that any initial segments represent
- only 8 bits of the address and builds the upper portion of the IPv4
- address. Then, the remaining segment is checked to make sure it's no
- bigger than the remaining space in the address and then is added into
- the result. */
- address = 0;
- for (i = 0; i < part - 1; i++) {
- if (octet[i] > 0xff) return 0;
- address |= octet[i] << (8 * (3 - i));
- }
- if (octet[i] > (0xffffffffUL >> (i * 8))) return 0;
- address |= octet[i];
- if (addr != NULL) addr->s_addr = htonl(address);
- return 1;
-}
+++ /dev/null
-/* $Id: inet_ntoa.c 5049 2001-12-12 09:06:00Z rra $
-**
-** Replacement for a missing or broken inet_ntoa.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine
-** inet_ntoa for those platforms that don't have it or where it doesn't
-** work right (such as on IRIX when using gcc to compile). inet_ntoa is
-** not thread-safe since it uses static storage (inet_ntop should be used
-** instead when available).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <netinet/in.h>
-
-/* If we're running the test suite, rename inet_ntoa to avoid conflicts with
- the system version. */
-#if TESTING
-# define inet_ntoa test_inet_ntoa
-const char *test_inet_ntoa(const struct in_addr);
-#endif
-
-const char *
-inet_ntoa(const struct in_addr in)
-{
- static char buf[16];
- const unsigned char *p;
-
- p = (const unsigned char *) &in.s_addr;
- sprintf(buf, "%u.%u.%u.%u",
- (unsigned int) (p[0] & 0xff), (unsigned int) (p[1] & 0xff),
- (unsigned int) (p[2] & 0xff), (unsigned int) (p[3] & 0xff));
- return buf;
-}
+++ /dev/null
-/* $Id: innconf.c 7751 2008-04-06 14:35:40Z iulius $
-**
-** Manage the global innconf struct.
-**
-** The functions in this file collapse the parse tree for inn.conf into the
-** innconf struct that's used throughout INN. The code to collapse a
-** configuration parse tree into a struct is fairly generic and should
-** probably be moved into a separate library.
-**
-** When adding new inn.conf parameters, make sure to add them in all of the
-** following places:
-**
-** * The table in this file.
-** * include/inn/innconf.h
-** * doc/pod/inn.conf.pod (and regenerate doc/man/inn.conf.5)
-** * Add the default value to samples/inn.conf.in
-**
-** Please maintain the current organization of parameters. There are two
-** different orders, one of which is a logical order used by the
-** documentation, the include file, and the sample file, and the other of
-** which is used in this file. The order in this file is documentation of
-** where each parameter is used, for later work at breaking up this mess
-** of parameters into separate configuration groups for each INN subsystem.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#include "inn/confparse.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "paths.h"
-
-/* Instantiation of the global innconf variable. */
-struct innconf *innconf = NULL;
-
-/* Data types used to express the mappings from the configuration parse into
- the innconf struct. */
-
-enum type {
- TYPE_BOOLEAN,
- TYPE_NUMBER,
- TYPE_STRING
-};
-
-struct config {
- const char *name;
- size_t location;
- enum type type;
- struct {
- bool boolean;
- long integer;
- const char *string;
- } defaults;
-};
-
-/* The following macros are helpers to make it easier to define the table that
- specifies how to convert the configuration file into a struct. */
-
-#define K(name) (#name), offsetof(struct innconf, name)
-
-#define BOOL(def) TYPE_BOOLEAN, { (def), 0, NULL }
-#define NUMBER(def) TYPE_NUMBER, { 0, (def), NULL }
-#define STRING(def) TYPE_STRING, { 0, 0, (def) }
-
-/* Accessor macros to get a pointer to a value inside a struct. */
-#define CONF_BOOL(conf, offset) (bool *) (void *)((char *) (conf) + (offset))
-#define CONF_LONG(conf, offset) (long *) (void *)((char *) (conf) + (offset))
-#define CONF_STRING(conf, offset) (char **)(void *)((char *) (conf) + (offset))
-
-/* Special notes:
-
- checkincludedtext and localmaxartisize are used by both nnrpd and inews,
- but inews should probably just let nnrpd do that checking.
-
- organization is used by both nnrpd and inews. Perhaps inews should just
- let nnrpd set it.
-
- mergetogroups is currently used by nnrpd for permission checking on
- posting. I think the check should always be performed based on the
- newsgroup to which the user is actually posting, and nnrpd should let
- innd do the merging.
-
- useoverchan is only used in innd and overchan. It should probably be
- something the storage system knows. Ideally, the storage system would
- handle overchan itself, but that would require a lot of infrastructure;
- in the interim, it could be something that programs could ask the
- overview subsystem about.
-
- doinnwatch and docnfsstat are used by rc.news currently, but really
- should be grouped with the appropriate subsystem.
-
- newsrequeue also uses nntplinklog, but the parameter should go away
- completely anyway.
-
- timer is currently used in various places, but it may be best to replace
- it with individual settings for innd and innfeed, and any other code that
- wants to use it.
-
- maxforks is used by rnews and nnrpd. I'm not sure this is that useful of
- a setting to have.
-*/
-
-const struct config config_table[] = {
- { K(domain), STRING (NULL) },
- { K(enableoverview), BOOL (true) },
- { K(fromhost), STRING (NULL) },
- { K(groupbaseexpiry), BOOL (true) },
- { K(mailcmd), STRING (NULL) },
- { K(maxforks), NUMBER (10) },
- { K(mta), STRING (NULL) },
- { K(nicekids), NUMBER (4) },
- { K(ovmethod), STRING (NULL) },
- { K(pathhost), STRING (NULL) },
- { K(rlimitnofile), NUMBER (-1) },
- { K(server), STRING (NULL) },
- { K(sourceaddress), STRING (NULL) },
- { K(sourceaddress6), STRING (NULL) },
- { K(timer), NUMBER (0) },
-
- { K(patharchive), STRING (NULL) },
- { K(patharticles), STRING (NULL) },
- { K(pathbin), STRING (NULL) },
- { K(pathcontrol), STRING (NULL) },
- { K(pathdb), STRING (NULL) },
- { K(pathetc), STRING (NULL) },
- { K(pathfilter), STRING (NULL) },
- { K(pathhttp), STRING (NULL) },
- { K(pathincoming), STRING (NULL) },
- { K(pathlog), STRING (NULL) },
- { K(pathnews), STRING (NULL) },
- { K(pathoutgoing), STRING (NULL) },
- { K(pathoverview), STRING (NULL) },
- { K(pathrun), STRING (NULL) },
- { K(pathspool), STRING (NULL) },
- { K(pathtmp), STRING (NULL) },
-
- /* The following settings are specific to innd. */
- { K(artcutoff), NUMBER (10) },
- { K(badiocount), NUMBER (5) },
- { K(bindaddress), STRING (NULL) },
- { K(bindaddress6), STRING (NULL) },
- { K(blockbackoff), NUMBER (120) },
- { K(chaninacttime), NUMBER (600) },
- { K(chanretrytime), NUMBER (300) },
- { K(datamovethreshold), NUMBER (8192) },
- { K(dontrejectfiltered), BOOL (false) },
- { K(hiscachesize), NUMBER (0) },
- { K(icdsynccount), NUMBER (10) },
- { K(ignorenewsgroups), BOOL (false) },
- { K(linecountfuzz), NUMBER (0) },
- { K(logartsize), BOOL (true) },
- { K(logcancelcomm), BOOL (false) },
- { K(logipaddr), BOOL (true) },
- { K(logsitename), BOOL (true) },
- { K(maxartsize), NUMBER (1000000) },
- { K(maxconnections), NUMBER (50) },
- { K(mergetogroups), BOOL (false) },
- { K(nntpactsync), NUMBER (200) },
- { K(nntplinklog), BOOL (false) },
- { K(noreader), BOOL (false) },
- { K(pathalias), STRING (NULL) },
- { K(pathcluster), STRING (NULL) },
- { K(pauseretrytime), NUMBER (300) },
- { K(peertimeout), NUMBER (3600) },
- { K(port), NUMBER (119) },
- { K(readerswhenstopped), BOOL (false) },
- { K(refusecybercancels), BOOL (false) },
- { K(remembertrash), BOOL (true) },
- { K(stathist), STRING (NULL) },
- { K(status), NUMBER (0) },
- { K(verifycancels), BOOL (false) },
- { K(wanttrash), BOOL (false) },
- { K(wipcheck), NUMBER (5) },
- { K(wipexpire), NUMBER (10) },
- { K(xrefslave), BOOL (false) },
-
- /* The following settings are specific to nnrpd. */
- { K(addnntppostingdate), BOOL (true) },
- { K(addnntppostinghost), BOOL (true) },
- { K(allownewnews), BOOL (true) },
- { K(backoffauth), BOOL (false) },
- { K(backoffdb), STRING (NULL) },
- { K(backoffk), NUMBER (1) },
- { K(backoffpostfast), NUMBER (0) },
- { K(backoffpostslow), NUMBER (1) },
- { K(backofftrigger), NUMBER (10000) },
- { K(checkincludedtext), BOOL (false) },
- { K(clienttimeout), NUMBER (600) },
- { K(complaints), STRING (NULL) },
- { K(initialtimeout), NUMBER (10) },
- { K(keyartlimit), NUMBER (100000) },
- { K(keylimit), NUMBER (512) },
- { K(keymaxwords), NUMBER (250) },
- { K(keywords), BOOL (false) },
- { K(localmaxartsize), NUMBER (1000000) },
- { K(maxcmdreadsize), NUMBER (BUFSIZ) },
- { K(msgidcachesize), NUMBER (10000) },
- { K(moderatormailer), STRING (NULL) },
- { K(nfsreader), BOOL (false) },
- { K(nfsreaderdelay), NUMBER (60) },
- { K(nicenewnews), NUMBER (0) },
- { K(nicennrpd), NUMBER (0) },
- { K(nnrpdflags), STRING ("") },
- { K(nnrpdauthsender), BOOL (false) },
- { K(nnrpdloadlimit), NUMBER (16) },
- { K(nnrpdoverstats), BOOL (false) },
- { K(organization), STRING (NULL) },
- { K(readertrack), BOOL (false) },
- { K(spoolfirst), BOOL (false) },
- { K(strippostcc), BOOL (false) },
-
- /* The following settings are used by nnrpd and rnews. */
- { K(nnrpdposthost), STRING (NULL) },
- { K(nnrpdpostport), NUMBER (119) },
-
- /* The following settings are specific to the storage subsystem. */
- { K(articlemmap), BOOL (false) },
- { K(cnfscheckfudgesize), NUMBER (0) },
- { K(immediatecancel), BOOL (false) },
- { K(keepmmappedthreshold), NUMBER (1024) },
- { K(nfswriter), BOOL (false) },
- { K(nnrpdcheckart), BOOL (true) },
- { K(overcachesize), NUMBER (15) },
- { K(ovgrouppat), STRING (NULL) },
- { K(storeonxref), BOOL (true) },
- { K(tradindexedmmap), BOOL (true) },
- { K(useoverchan), BOOL (false) },
- { K(wireformat), BOOL (false) },
-
- /* The following settings are specific to the history subsystem. */
- { K(hismethod), STRING (NULL) },
-
- /* The following settings are specific to rc.news. */
- { K(docnfsstat), BOOL (false) },
- { K(innflags), STRING (NULL) },
- { K(pgpverify), BOOL (false) },
-
- /* The following settings are specific to innwatch. */
- { K(doinnwatch), BOOL (true) },
- { K(innwatchbatchspace), NUMBER (800) },
- { K(innwatchlibspace), NUMBER (25000) },
- { K(innwatchloload), NUMBER (1000) },
- { K(innwatchhiload), NUMBER (2000) },
- { K(innwatchpauseload), NUMBER (1500) },
- { K(innwatchsleeptime), NUMBER (600) },
- { K(innwatchspoolnodes), NUMBER (200) },
- { K(innwatchspoolspace), NUMBER (8000) },
-
- /* The following settings are specific to scanlogs. */
- { K(logcycles), NUMBER (3) },
-};
-
-
-/*
-** Set some defaults that cannot be included in the table because they depend
-** on other elements or require function calls to set. Called after the
-** configuration file is read, so any that have to override what's read have
-** to free whatever values are set by the file.
-*/
-static void
-innconf_set_defaults(void)
-{
- char *value;
-
- /* Some environment variables override settings in inn.conf. */
- value = getenv("FROMHOST");
- if (value != NULL) {
- if (innconf->fromhost != NULL)
- free(innconf->fromhost);
- innconf->fromhost = xstrdup(value);
- }
- value = getenv("NNTPSERVER");
- if (value != NULL) {
- if (innconf->server != NULL)
- free(innconf->server);
- innconf->server = xstrdup(value);
- }
- value = getenv("ORGANIZATION");
- if (value != NULL) {
- if (innconf->organization != NULL)
- free(innconf->organization);
- innconf->organization = xstrdup(value);
- }
- value = getenv("INND_BIND_ADDRESS");
- if (value != NULL) {
- if (innconf->bindaddress != NULL)
- free(innconf->bindaddress);
- innconf->bindaddress = xstrdup(value);
- }
- value = getenv("INND_BIND_ADDRESS6");
- if (value != NULL) {
- if (innconf->bindaddress6 != NULL)
- free(innconf->bindaddress6);
- innconf->bindaddress6 = xstrdup(value);
- }
-
- /* Some parameters have defaults that depend on other parameters. */
- if (innconf->fromhost == NULL)
- innconf->fromhost = xstrdup(GetFQDN(innconf->domain));
- if (innconf->pathhost == NULL)
- innconf->pathhost = xstrdup(GetFQDN(innconf->domain));
- if (innconf->pathtmp == NULL)
- innconf->pathtmp = xstrdup(_PATH_TMP);
-
- /* All of the paths are relative to other paths if not set except for
- pathnews, which is required to be set by innconf_validate. */
- if (innconf->pathbin == NULL)
- innconf->pathbin = concatpath(innconf->pathnews, "bin");
- if (innconf->pathfilter == NULL)
- innconf->pathfilter = concatpath(innconf->pathbin, "filter");
- if (innconf->pathdb == NULL)
- innconf->pathdb = concatpath(innconf->pathnews, "db");
- if (innconf->pathetc == NULL)
- innconf->pathetc = concatpath(innconf->pathnews, "etc");
- if (innconf->pathrun == NULL)
- innconf->pathrun = concatpath(innconf->pathnews, "run");
- if (innconf->pathlog == NULL)
- innconf->pathlog = concatpath(innconf->pathnews, "log");
- if (innconf->pathhttp == NULL)
- innconf->pathhttp = xstrdup(innconf->pathlog);
- if (innconf->pathspool == NULL)
- innconf->pathspool = concatpath(innconf->pathnews, "spool");
- if (innconf->patharticles == NULL)
- innconf->patharticles = concatpath(innconf->pathspool, "articles");
- if (innconf->pathoverview == NULL)
- innconf->pathoverview = concatpath(innconf->pathspool, "overview");
- if (innconf->pathoutgoing == NULL)
- innconf->pathoutgoing = concatpath(innconf->pathspool, "outgoing");
- if (innconf->pathincoming == NULL)
- innconf->pathincoming = concatpath(innconf->pathspool, "incoming");
- if (innconf->patharchive == NULL)
- innconf->patharchive = concatpath(innconf->pathspool, "archive");
-
- /* One other parameter depends on pathbin. */
- if (innconf->mailcmd == NULL)
- innconf->mailcmd = concatpath(innconf->pathbin, "innmail");
-}
-
-
-/*
-** Given a config_group struct representing the inn.conf file, parse that
-** into an innconf struct and return the newly allocated struct. This
-** routine should be pulled out into a library for smashing configuration
-** file parse results into structs.
-*/
-static struct innconf *
-innconf_parse(struct config_group *group)
-{
- unsigned int i;
- bool *bool_ptr;
- long *long_ptr;
- const char *char_ptr;
- char **string;
- struct innconf *config;
-
- config = xmalloc(sizeof(struct innconf));
- for (i = 0; i < ARRAY_SIZE(config_table); i++)
- switch (config_table[i].type) {
- case TYPE_BOOLEAN:
- bool_ptr = CONF_BOOL(config, config_table[i].location);
- if (!config_param_boolean(group, config_table[i].name, bool_ptr))
- *bool_ptr = config_table[i].defaults.boolean;
- break;
- case TYPE_NUMBER:
- long_ptr = CONF_LONG(config, config_table[i].location);
- if (!config_param_integer(group, config_table[i].name, long_ptr))
- *long_ptr = config_table[i].defaults.integer;
- break;
- case TYPE_STRING:
- if (!config_param_string(group, config_table[i].name, &char_ptr))
- char_ptr = config_table[i].defaults.string;
- string = CONF_STRING(config, config_table[i].location);
- *string = (char_ptr == NULL) ? NULL : xstrdup(char_ptr);
- break;
- default:
- die("internal error: invalid type in row %u of config table", i);
- break;
- }
- return config;
-}
-
-
-/*
-** Check the configuration file for consistency and ensure that mandatory
-** settings are present. Returns true if the file is okay and false
-** otherwise.
-*/
-static bool
-innconf_validate(struct config_group *group)
-{
- bool okay = true;
- long threshold;
-
- if (GetFQDN(innconf->domain) == NULL) {
- warn("hostname does not resolve or domain not set in inn.conf");
- okay = false;
- }
- if (innconf->mta == NULL) {
- warn("must set mta in inn.conf");
- okay = false;
- }
- if (innconf->pathnews == NULL) {
- warn("must set pathnews in inn.conf");
- okay = false;
- }
- if (innconf->hismethod == NULL) {
- warn("must set hismethod in inn.conf");
- okay = false;
- }
- if (innconf->enableoverview && innconf->ovmethod == NULL) {
- warn("ovmethod must be set in inn.conf if enableoverview is true");
- okay = false;
- }
- threshold = innconf->datamovethreshold;
- if (threshold <= 0 || threshold > 1024 * 1024) {
- config_error_param(group, "datamovethreshold",
- "maximum value for datamovethreshold is 1MB");
- innconf->datamovethreshold = 1024 * 1024;
- }
- return okay;
-}
-
-
-/*
-** Read in inn.conf. Takes a single argument, which is either NULL to read
-** the default configuration file or a path to an alternate configuration
-** file to read. Returns true if the file was read successfully and false
-** otherwise.
-*/
-bool
-innconf_read(const char *path)
-{
- struct config_group *group;
- char *tmpdir;
-
- if (innconf != NULL)
- innconf_free(innconf);
- if (path == NULL)
- path = getenv("INNCONF");
- group = config_parse_file(path == NULL ? _PATH_CONFIG : path);
- if (group == NULL)
- return false;
-
- innconf = innconf_parse(group);
- if (!innconf_validate(group))
- return false;
- config_free(group);
- innconf_set_defaults();
-
- /* It's not clear that this belongs here, but it was done by the old
- configuration parser, so this is a convenient place to do it. */
- tmpdir = getenv("TMPDIR");
- if (tmpdir == NULL || strcmp(tmpdir, innconf->pathtmp) != 0)
- if (setenv("TMPDIR", innconf->pathtmp, true) != 0) {
- warn("cannot set TMPDIR in the environment");
- return false;
- }
-
- return true;
-}
-
-
-/*
-** Check an inn.conf file. This involves reading it in and then additionally
-** making sure that there are no keys defined in the inn.conf file that
-** aren't recognized. This doesn't have to be very fast (and isn't).
-** Returns true if everything checks out successfully, and false otherwise.
-**
-** A lot of code is duplicated with innconf_read here and should be
-** refactored.
-*/
-bool
-innconf_check(const char *path)
-{
- struct config_group *group;
- struct vector *params;
- size_t set, known;
- bool found;
- bool okay = true;
-
- if (innconf != NULL)
- innconf_free(innconf);
- if (path == NULL)
- path = getenv("INNCONF");
- group = config_parse_file(path == NULL ? _PATH_CONFIG : path);
- if (group == NULL)
- return false;
-
- innconf = innconf_parse(group);
- if (!innconf_validate(group))
- return false;
-
- /* Now, do the work that innconf_read doesn't do. Get a list of
- parameters defined in innconf and then walk our list of valid
- parameters and see if there are any set that we don't recognize. */
- params = config_params(group);
- for (set = 0; set < params->count; set++) {
- found = false;
- for (known = 0; known < ARRAY_SIZE(config_table); known++)
- if (strcmp(params->strings[set], config_table[known].name) == 0)
- found = true;
- if (!found) {
- config_error_param(group, params->strings[set],
- "unknown parameter %s", params->strings[set]);
- okay = false;
- }
- }
-
- /* Check and warn about a few other parameters. */
- if (innconf->peertimeout < 3 * 60)
- config_error_param(group, "peertimeout",
- "warning: NNTP draft (15) states inactivity"
- " timeouts MUST be at least three minutes");
- if (innconf->clienttimeout < 3 * 60)
- config_error_param(group, "clienttimeout",
- "warning: NNTP draft (15) states inactivity"
- " timeouts MUST be at least three minutes");
-
- /* All done. Free the parse tree and return. */
- config_free(group);
- return okay;
-}
-
-
-/*
-** Free innconf, requiring some complexity since all strings stored in the
-** innconf struct are allocated memory. This routine is mostly generic to
-** any struct smashed down from a configuration file parse.
-*/
-void
-innconf_free(struct innconf *config)
-{
- unsigned int i;
- char *p;
-
- for (i = 0; i < ARRAY_SIZE(config_table); i++)
- if (config_table[i].type == TYPE_STRING) {
- p = *CONF_STRING(config, config_table[i].location);
- if (p != NULL)
- free(p);
- }
- free(config);
-}
-
-
-/*
-** Print a single boolean value with appropriate quoting.
-*/
-static void
-print_boolean(FILE *file, const char *key, bool value,
- enum innconf_quoting quoting)
-{
- char *upper, *p;
-
- switch (quoting) {
- case INNCONF_QUOTE_NONE:
- fprintf(file, "%s\n", value ? "true" : "false");
- break;
- case INNCONF_QUOTE_SHELL:
- upper = xstrdup(key);
- for (p = upper; *p != '\0'; p++)
- *p = toupper(*p);
- fprintf(file, "%s=%s; export %s;\n", upper, value ? "true" : "false",
- upper);
- free(upper);
- break;
- case INNCONF_QUOTE_PERL:
- fprintf(file, "$%s = '%s';\n", key, value ? "true" : "false");
- break;
- case INNCONF_QUOTE_TCL:
- fprintf(file, "set inn_%s \"%s\"\n", key, value ? "true" : "false");
- break;
- }
-}
-
-
-/*
-** Print a single integer value with appropriate quoting.
-*/
-static void
-print_number(FILE *file, const char *key, long value,
- enum innconf_quoting quoting)
-{
- char *upper, *p;
-
- switch (quoting) {
- case INNCONF_QUOTE_NONE:
- fprintf(file, "%ld\n", value);
- break;
- case INNCONF_QUOTE_SHELL:
- upper = xstrdup(key);
- for (p = upper; *p != '\0'; p++)
- *p = toupper(*p);
- fprintf(file, "%s=%ld; export %s;\n", upper, value, upper);
- free(upper);
- break;
- case INNCONF_QUOTE_PERL:
- fprintf(file, "$%s = %ld;\n", key, value);
- break;
- case INNCONF_QUOTE_TCL:
- fprintf(file, "set inn_%s %ld\n", key, value);
- break;
- }
-}
-
-
-/*
-** Print a single string value with appropriate quoting.
-*/
-static void
-print_string(FILE *file, const char *key, const char *value,
- enum innconf_quoting quoting)
-{
- char *upper, *p;
- const char *letter;
- static const char tcl_unsafe[] = "$[]{}\"\\";
-
- switch (quoting) {
- case INNCONF_QUOTE_NONE:
- fprintf(file, "%s\n", value != NULL ? value : "");
- break;
- case INNCONF_QUOTE_SHELL:
- upper = xstrdup(key);
- for (p = upper; *p != '\0'; p++)
- *p = toupper(*p);
- fprintf(file, "%s='", upper);
- for (letter = value; letter != NULL && *letter != '\0'; letter++) {
- if (*letter == '\'')
- fputs("'\\''", file);
- else if (*letter == '\\')
- fputs("\\\\", file);
- else
- fputc(*letter, file);
- }
- fprintf(file, "'; export %s;\n", upper);
- free(upper);
- break;
- case INNCONF_QUOTE_PERL:
- fprintf(file, "$%s = '", key);
- for (letter = value; letter != NULL && *letter != '\0'; letter++) {
- if (*letter == '\'' || *letter == '\\')
- fputc('\\', file);
- fputc(*letter, file);
- }
- fputs("';\n", file);
- break;
- case INNCONF_QUOTE_TCL:
- fprintf(file, "set inn_%s \"", key);
- for (letter = value; letter != NULL && *letter != '\0'; letter++) {
- if (strchr(tcl_unsafe, *letter) != NULL)
- fputc('\\', file);
- fputc(*letter, file);
- }
- fputs("\"\n", file);
- break;
- }
-}
-
-
-/*
-** Print a single paramter to the given file. Takes an index into the table
-** specifying the attribute to print and the quoting.
-*/
-static void
-print_parameter(FILE *file, size_t i, enum innconf_quoting quoting)
-{
- bool bool_val;
- long long_val;
- const char *string_val;
-
- switch (config_table[i].type) {
- case TYPE_BOOLEAN:
- bool_val = *CONF_BOOL(innconf, config_table[i].location);
- print_boolean(file, config_table[i].name, bool_val, quoting);
- break;
- case TYPE_NUMBER:
- long_val = *CONF_LONG(innconf, config_table[i].location);
- print_number(file, config_table[i].name, long_val, quoting);
- break;
- case TYPE_STRING:
- string_val = *CONF_STRING(innconf, config_table[i].location);
- print_string(file, config_table[i].name, string_val, quoting);
- break;
- default:
- die("internal error: invalid type in row %d of config table", i);
- break;
- }
-}
-
-
-/*
-** Given a single parameter, find it in the table and print out its value.
-*/
-bool
-innconf_print_value(FILE *file, const char *key, enum innconf_quoting quoting)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(config_table); i++)
- if (strcmp(key, config_table[i].name) == 0) {
- print_parameter(file, i, quoting);
- return true;
- }
- return false;
-}
-
-
-/*
-** Dump the entire inn.conf configuration with appropriate quoting.
-*/
-void
-innconf_dump(FILE *file, enum innconf_quoting quoting)
-{
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(config_table); i++)
- print_parameter(file, i, quoting);
-}
-
-
-/*
-** Compare two innconf structs to see if they represent identical
-** configurations. This routine is mostly used for testing. Prints warnings
-** about where the two configurations differ and return false if they differ,
-** true if they match. This too should be moved into a config smashing
-** library.
-*/
-bool
-innconf_compare(struct innconf *conf1, struct innconf *conf2)
-{
- unsigned int i;
- bool bool1, bool2;
- long long1, long2;
- const char *string1, *string2;
- bool okay = true;
-
- for (i = 0; i < ARRAY_SIZE(config_table); i++)
- switch (config_table[i].type) {
- case TYPE_BOOLEAN:
- bool1 = *CONF_BOOL(conf1, config_table[i].location);
- bool2 = *CONF_BOOL(conf2, config_table[i].location);
- if (bool1 != bool2) {
- warn("boolean variable %s differs: %d != %d",
- config_table[i].name, bool1, bool2);
- okay = false;
- }
- break;
- case TYPE_NUMBER:
- long1 = *CONF_LONG(conf1, config_table[i].location);
- long2 = *CONF_LONG(conf2, config_table[i].location);
- if (long1 != long2) {
- warn("integer variable %s differs: %ld != %ld",
- config_table[i].name, long1, long2);
- okay = false;
- }
- break;
- case TYPE_STRING:
- string1 = *CONF_STRING(conf1, config_table[i].location);
- string2 = *CONF_STRING(conf2, config_table[i].location);
- if (string1 == NULL && string2 != NULL) {
- warn("string variable %s differs: NULL != %s",
- config_table[i].name, string2);
- okay = false;
- } else if (string1 != NULL && string2 == NULL) {
- warn("string variable %s differs: %s != NULL",
- config_table[i].name, string1);
- okay = false;
- } else if (string1 != NULL && string2 != NULL) {
- if (strcmp(string1, string2) != 0) {
- warn("string variable %s differs: %s != %s",
- config_table[i].name, string1, string2);
- okay = false;
- }
- }
- break;
- default:
- die("internal error: invalid type in row %d of config table", i);
- break;
- }
- return okay;
-}
+++ /dev/null
-/* $Id: inndcomm.c 7597 2007-01-16 23:11:05Z eagle $
-**
-** Library routines to let other programs control innd.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include "portable/socket.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <sys/stat.h>
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inndcomm.h"
-#include "libinn.h"
-#include "paths.h"
-
-static char *ICCsockname = NULL;
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-static struct sockaddr_un ICCserv;
-static struct sockaddr_un ICCclient;
-#endif
-static int ICCfd;
-static int ICCtimeout;
-const char *ICCfailure;
-
-
-/*
-** Set the timeout.
-*/
-void
-ICCsettimeout(int i)
-{
- ICCtimeout = i;
-}
-
-
-/*
-** Get ready to talk to the server.
-*/
-int
-ICCopen(void)
-{
- int mask, oerrno, fd;
- int size = 65535;
-
- if (innconf == NULL) {
- if (!innconf_read(NULL)) {
- ICCfailure = "innconf";
- return -1;
- }
- }
- /* Create a temporary name. mkstemp is complete overkill here and is used
- only because it's convenient. We don't use it properly, since we
- actually need to create a socket or named pipe, so there is a race
- condition here. It doesn't matter, since pathrun isn't world-writable
- (conceivably two processes could end up using the same temporary name
- at the same time, but the worst that will happen is that one process
- will delete the other's temporary socket). */
- if (ICCsockname == NULL)
- ICCsockname = concatpath(innconf->pathrun, _PATH_TEMPSOCK);
- fd = mkstemp(ICCsockname);
- if (fd < 0) {
- ICCfailure = "mkstemp";
- return -1;
- }
- close(fd);
- if (unlink(ICCsockname) < 0 && errno != ENOENT) {
- ICCfailure = "unlink";
- return -1;
- }
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-
- /* Make a socket and give it the name. */
- if ((ICCfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
- ICCfailure = "socket";
- return -1;
- }
-
- /* Adjust the socket buffer size to accomodate large responses. Ignore
- failure; the message may fit anyway, and if not, we'll fail below. */
- setsockopt(ICCfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
-
- memset(&ICCclient, 0, sizeof ICCclient);
- ICCclient.sun_family = AF_UNIX;
- strlcpy(ICCclient.sun_path, ICCsockname, sizeof(ICCclient.sun_path));
- mask = umask(0);
- if (bind(ICCfd, (struct sockaddr *) &ICCclient, SUN_LEN(&ICCclient)) < 0) {
- oerrno = errno;
- umask(mask);
- errno = oerrno;
- ICCfailure = "bind";
- return -1;
- }
- umask(mask);
-
- /* Name the server's socket. */
- memset(&ICCserv, 0, sizeof ICCserv);
- ICCserv.sun_family = AF_UNIX;
- strlcpy(ICCserv.sun_path, innconf->pathrun, sizeof(ICCserv.sun_path));
- strlcat(ICCserv.sun_path, "/", sizeof(ICCserv.sun_path));
- strlcat(ICCserv.sun_path, _PATH_NEWSCONTROL, sizeof(ICCserv.sun_path));
-
-#else /* !HAVE_UNIX_DOMAIN_SOCKETS */
-
- /* Make a named pipe and open it. */
- mask = umask(0);
- if (mkfifo(ICCsockname, 0666) < 0) {
- oerrno = errno;
- umask(mask);
- errno = oerrno;
- ICCfailure = "mkfifo";
- return -1;
- }
- umask(mask);
- if ((ICCfd = open(ICCsockname, O_RDWR)) < 0) {
- ICCfailure = "open";
- return -1;
- }
-#endif /* !HAVE_UNIX_DOMAIN_SOCKETS */
-
- ICCfailure = NULL;
- return 0;
-}
-
-
-/*
-** Close down.
-*/
-int
-ICCclose(void)
-{
- int i;
-
- ICCfailure = NULL;
- i = 0;
- if (close(ICCfd) < 0) {
- ICCfailure = "close";
- i = -1;
- }
- if (unlink(ICCsockname) < 0 && errno != ENOENT) {
- ICCfailure = "unlink";
- i = -1;
- }
- return i;
-}
-
-
-/*
-** Get the server's pid.
-*/
-static pid_t
-ICCserverpid(void)
-{
- pid_t pid;
- FILE *F;
- char *path;
- char buff[SMBUF];
-
- pid = 1;
- path = concatpath(innconf->pathrun, _PATH_SERVERPID);
- F = fopen(path, "r");
- free(path);
- if (F != NULL) {
- if (fgets(buff, sizeof buff, F) != NULL)
- pid = atol(buff);
- fclose(F);
- }
- return pid;
-}
-
-
-/*
-** See if the server is still there. When in doubt, assume yes. Cache the
-** PID since a rebooted server won't know about our pending message.
-*/
-static bool
-ICCserveralive(pid_t pid)
-{
- if (kill(pid, 0) > 0 || errno != ESRCH)
- return true;
- return false;
-}
-
-
-/*
-** Send an arbitrary command to the server.
-**
-** There is a protocol version (one-byte) on the front of the message,
-** followed by a two byte length count. The length includes the protocol
-** byte and the length itself. This differs from the protocol in much
-** earlier versions of INN.
-*/
-int
-ICCcommand(char cmd, const char *argv[], char **replyp)
-{
- char *buff;
- char *p;
- const char *q;
- char save;
- int i ;
-#ifndef HAVE_UNIX_DOMAIN_SOCKETS
- int fd;
- char *path;
-#endif
- int len;
- fd_set Rmask;
- struct timeval T;
- pid_t pid;
- ICC_MSGLENTYPE rlen;
- ICC_PROTOCOLTYPE protocol;
- size_t bufsiz = 64 * 1024 - 1;
-
- /* Is server there? */
- pid = ICCserverpid();
- if (!ICCserveralive(pid)) {
- ICCfailure = "dead server";
- return -1;
- }
-
- /* Get the length of the buffer. */
- buff = xmalloc(bufsiz);
- if (replyp)
- *replyp = NULL;
-
- /* Advance to leave space for length + protocol version info. */
- buff += HEADER_SIZE;
- bufsiz -= HEADER_SIZE;
-
- /* Format the message. */
- snprintf(buff, bufsiz, "%s%c%c", ICCsockname, SC_SEP, cmd);
- for (p = buff + strlen(buff), i = 0; (q = argv[i]) != NULL; i++) {
- *p++ = SC_SEP;
- *p = '\0';
- strlcat(buff, q, bufsiz);
- p += strlen(q);
- }
-
- /* Send message. */
- ICCfailure = NULL;
- len = p - buff + HEADER_SIZE;
- rlen = htons(len);
-
- /* now stick in the protocol version and the length. */
- buff -= HEADER_SIZE;
- bufsiz += HEADER_SIZE;
- protocol = ICC_PROTOCOL_1;
- memcpy(buff, &protocol, sizeof(protocol));
- memcpy(buff + sizeof(protocol), &rlen, sizeof(rlen));
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- if (sendto(ICCfd, buff, len, 0,(struct sockaddr *) &ICCserv,
- SUN_LEN(&ICCserv)) < 0) {
- free(buff);
- ICCfailure = "sendto";
- return -1;
- }
-#else /* !HAVE_UNIX_DOMAIN_SOCKETS */
- path = concatpath(innconf->pathrun, _PATH_NEWSCONTROL);
- fd = open(path, O_WRONLY);
- free(path);
- if (fd < 0) {
- free(buff);
- ICCfailure = "open";
- return -1;
- }
- if (write(fd, buff, len) != len) {
- i = errno;
- free(buff);
- close(fd);
- errno = i;
- ICCfailure = "write";
- return -1;
- }
- close(fd);
-#endif /* !HAVE_UNIX_DOMAIN_SOCKETS */
-
- /* Possibly get a reply. */
- switch (cmd) {
- default:
- if (ICCtimeout >= 0)
- break;
- /* FALLTHROUGH */
- case SC_SHUTDOWN:
- case SC_XABORT:
- case SC_XEXEC:
- free(buff);
- return 0;
- }
-
- /* Wait for the reply. */
- for ( ; ; ) {
- FD_ZERO(&Rmask);
- FD_SET(ICCfd, &Rmask);
- T.tv_sec = ICCtimeout ? ICCtimeout : 120;
- T.tv_usec = 0;
- i = select(ICCfd + 1, &Rmask, NULL, NULL, &T);
- if (i < 0) {
- free(buff);
- ICCfailure = "select";
- return -1;
- }
- if (i > 0 && FD_ISSET(ICCfd, &Rmask))
- /* Server reply is there; go handle it. */
- break;
-
- /* No data -- if we timed out, return. */
- if (ICCtimeout) {
- free(buff);
- errno = ETIMEDOUT;
- ICCfailure = "timeout";
- return -1;
- }
-
- if (!ICCserveralive(pid)) {
- free(buff);
- ICCfailure = "dead server";
- return -1;
- }
- }
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-
- /* Read the reply. */
- i = RECVorREAD(ICCfd, buff, bufsiz);
- if ((unsigned int) i < HEADER_SIZE) {
- free(buff);
- ICCfailure = "read";
- return -1;
- }
- memcpy(&protocol, buff, sizeof(protocol));
- memcpy(&rlen, buff + sizeof(protocol), sizeof(rlen));
- rlen = ntohs(rlen);
-
- if (i != rlen) {
- free(buff);
- ICCfailure = "short read";
- return -1;
- }
-
- if (protocol != ICC_PROTOCOL_1) {
- free(buff);
- ICCfailure = "protocol mismatch";
- return -1;
- }
-
- memmove(buff, buff + HEADER_SIZE, rlen - HEADER_SIZE);
- i -= HEADER_SIZE;
-
- buff[i] = '\0';
-
-#else /* !HAVE_UNIX_DOMAIN_SOCKETS */
-
- i = RECVorREAD(ICCfd, buff, HEADER_SIZE);
- if (i != HEADER_SIZE)
- return -1;
-
- memcpy(&protocol, buff, sizeof(protocol));
- memcpy(&rlen, buff + sizeof(protocol), sizeof(rlen));
- rlen = ntohs(rlen) - HEADER_SIZE;
- if (rlen > bufsiz) {
- ICCfailure = "bad length";
- return -1;
- }
-
- i = RECVorREAD(ICCfd, buff, rlen);
- if (i != rlen) {
- ICCfailure = "short read";
- return -1;
- }
-
- buff[i] = '\0';
-
- if (protocol != ICC_PROTOCOL_1) {
- ICCfailure = "protocol mismatch";
- return -1;
- }
-
-#endif /* !HAVE_UNIX_DOMAIN_SOCKETS */
-
- /* Parse the rest of the reply; expected to be like
- <exitcode><space><text>" */
- i = 0;
- if (CTYPE(isdigit, buff[0])) {
- for (p = buff; *p && CTYPE(isdigit, *p); p++)
- continue;
- if (*p) {
- save = *p;
- *p = '\0';
- i = atoi(buff);
- *p = save;
- }
- }
- if (replyp)
- *replyp = buff;
- else
- free(buff);
-
- return i;
-}
-
-
-/*
-** Send a "cancel" command.
-*/
-int
-ICCcancel(const char *msgid)
-{
- const char *args[2];
-
- args[0] = msgid;
- args[1] = NULL;
- return ICCcommand(SC_CANCEL, args, NULL);
-}
-
-
-/*
-** Send a "go" command.
-*/
-int
-ICCgo(const char *why)
-{
- const char *args[2];
-
- args[0] = why;
- args[1] = NULL;
- return ICCcommand(SC_GO, args, NULL);
-}
-
-
-/*
-** Send a "pause" command.
-*/
-int
-ICCpause(const char *why)
-{
- const char *args[2];
-
- args[0] = why;
- args[1] = NULL;
- return ICCcommand(SC_PAUSE, args, NULL);
-}
-
-
-/*
-** Send a "reserve" command.
-*/
-int
-ICCreserve(const char *why)
-{
- const char *args[2];
-
- args[0] = why;
- args[1] = NULL;
- return ICCcommand(SC_RESERVE, args, NULL);
-}
+++ /dev/null
-/* $Id: list.c 6168 2003-01-21 06:27:32Z alexk $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/list.h"
-
-void
-list_new(struct list *list)
-{
- list->head = (struct node *)&list->tail;
- list->tailpred = (struct node *)&list->head;
- list->tail = NULL;
-}
-
-struct node *
-list_addhead(struct list *list, struct node *node)
-{
- node->succ = list->head;
- node->pred = (struct node *)&list->head;
- list->head->pred = node;
- list->head = node;
- return node;
-}
-
-struct node *
-list_addtail(struct list *list, struct node *node)
-{
- node->succ = (struct node *)&list->tail;
- node->pred = list->tailpred;
- list->tailpred->succ = node;
- list->tailpred = node;
- return node;
-}
-
-struct node *
-list_remhead(struct list *list)
-{
- struct node *node;
-
- node = list->head->succ;
- if (node) {
- node->pred = (struct node *)&list->head;
- node = list->head;
- list->head = node->succ;
- }
- return node;
-}
-
-struct node *
-list_head(struct list *list)
-{
- if (list->head->succ)
- return list->head;
- return NULL;
-}
-
-struct node *
-list_tail(struct list *list)
-{
- if (list->tailpred->pred)
- return list->tailpred;
- return NULL;
-}
-
-struct node *
-list_succ(struct node *node)
-{
- if (node->succ->succ)
- return node->succ;
- return NULL;
-}
-
-struct node *
-list_pred(struct node *node)
-{
- if (node->pred->pred)
- return node->pred;
- return NULL;
-}
-
-struct node *
-list_remove(struct node *node)
-{
- node->pred->succ = node->succ;
- node->succ->pred = node->pred;
- return node;
-}
-
-struct node *
-list_remtail(struct list *list)
-{
- struct node *node;
-
- node = list_tail(list);
- if (node)
- list_remove(node);
- return node;
-}
-
-bool
-list_isempty(struct list *list)
-{
- return list->tailpred == (struct node *)list;
-}
-
-struct node *
-list_insert(struct list *list, struct node *node, struct node *pred)
-{
- if (pred) {
- if (pred->succ) {
- node->succ = pred->succ;
- node->pred = pred;
- pred->succ->pred = node;
- pred->succ = node;
- } else {
- list_addtail(list, node);
- }
- } else {
- list_addhead(list, node);
- }
- return node;
-}
+++ /dev/null
-/* $Id: localopen.c 6155 2003-01-19 19:58:25Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/socket.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-#if HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-#endif
-
-
-/*
-** Open a connection to the local InterNetNews NNTP server and optionally
-** create stdio FILE's for talking to it. Return -1 on error.
-*/
-int
-NNTPlocalopen(FILE **FromServerp, FILE **ToServerp, char *errbuff)
-{
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- int i;
- int j;
- int oerrno;
- struct sockaddr_un server;
- FILE *F;
- char mybuff[NNTP_STRLEN + 2];
- char *buff;
-
- buff = errbuff ? errbuff : mybuff;
- *buff = '\0';
-
- /* Create a socket. */
- if ((i = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
- return -1;
-
- /* Connect to the server. */
- memset(&server, 0, sizeof server);
- server.sun_family = AF_UNIX;
- strlcpy(server.sun_path, innconf->pathrun, sizeof(server.sun_path));
- strlcat(server.sun_path, "/", sizeof(server.sun_path));
- strlcat(server.sun_path, _PATH_NNTPCONNECT, sizeof(server.sun_path));
- if (connect(i, (struct sockaddr *)&server, SUN_LEN(&server)) < 0) {
- oerrno = errno;
- close(i);
- errno = oerrno;
- return -1;
- }
-
- /* Connected -- now make sure we can post. */
- if ((F = fdopen(i, "r")) == NULL) {
- oerrno = errno;
- close(i);
- errno = oerrno;
- return -1;
- }
- if (fgets(buff, sizeof mybuff, F) == NULL) {
- oerrno = errno;
- fclose(F);
- errno = oerrno;
- return -1;
- }
- j = atoi(buff);
- if (j != NNTP_POSTOK_VAL && j != NNTP_NOPOSTOK_VAL) {
- fclose(F);
- /* This seems like a reasonable error code to use... */
- errno = EPERM;
- return -1;
- }
-
- *FromServerp = F;
- if ((*ToServerp = fdopen(dup(i), "w")) == NULL) {
- oerrno = errno;
- fclose(F);
- errno = oerrno;
- return -1;
- }
- return 0;
-#else
- return NNTPconnect("127.0.0.1", innconf->port, FromServerp, ToServerp,
- errbuff);
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
-}
+++ /dev/null
-/* $Id: lockfile.c 6020 2002-12-20 00:19:58Z rra $
-**
-** Lock a file or a range in a file.
-**
-** Provides inn_lock_file and inn_lock_range functions to lock or unlock a
-** file or ranges within a file with a more convenient syntax than fcntl.
-** Assume that fcntl is available.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-
-#include "libinn.h"
-
-bool
-inn_lock_file(int fd, enum inn_locktype type, bool block)
-{
- return inn_lock_range(fd, type, block, 0, 0);
-}
-
-bool
-inn_lock_range(int fd, enum inn_locktype type, bool block, off_t offset,
- off_t size)
-{
- struct flock fl;
- int status;
-
- switch (type) {
- case INN_LOCK_READ: fl.l_type = F_RDLCK; break;
- case INN_LOCK_WRITE: fl.l_type = F_WRLCK; break;
- default:
- case INN_LOCK_UNLOCK: fl.l_type = F_UNLCK; break;
- }
-
- do {
- fl.l_whence = SEEK_SET;
- fl.l_start = offset;
- fl.l_len = size;
-
- status = fcntl(fd, block ? F_SETLKW : F_SETLK, &fl);
- } while (status == -1 && errno == EINTR);
- return (status != -1);
-}
+++ /dev/null
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "libinn.h"
-
-/*
-** Try to make one directory. Return false on error.
-*/
-static bool MakeDir(char *Name)
-{
- struct stat Sb;
-
- if (mkdir(Name, GROUPDIR_MODE) >= 0) {
- return true;
- }
-
- /* See if it failed because it already exists. */
- if (stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode)) {
- errno = 0;
- return true;
- }
- return false;
-}
-
-
-/*
-** Given a directory, comp/foo/bar, create that directory and all
-** intermediate directories needed. Return true if ok, else false.
-*/
-bool MakeDirectory(char *Name, bool Recurse)
-{
- char *p;
- bool made;
-
- /* Optimize common case -- parent almost always exists. */
- if (MakeDir(Name))
- return true;
-
- if (!Recurse)
- return false;
-
- /* Try to make each of comp and comp/foo in turn. */
- for (p = (Name[0] == '/') ? &Name[1] : Name; *p; p++)
- if (*p == '/') {
- *p = '\0';
- made = MakeDir(Name);
- *p = '/';
- if (!made)
- return false;
- }
-
- return MakeDir(Name);
-}
+++ /dev/null
-/* $Id: md5.c 4154 2000-10-31 16:28:53Z kondou $
-**
-** RSA Data Security, Inc. MD5 Message-Digest Algorithm
-**
-** The standard MD5 message digest routines, from RSA Data Security, Inc.
-** by way of Landon Curt Noll, modified and integrated into INN by Clayton
-** O'Neill and then simplified somewhat, converted to INN coding style,
-** and commented by Russ Allbery.
-**
-** To form the message digest for a message M:
-** (1) Initialize a context buffer md5_context using md5_init
-** (2) Call md5_update on md5_context and M
-** (3) Call md5_final on md5_context
-** The message digest is now in md5_context->digest[0...15].
-**
-** Alternately, just call md5_hash on M, passing it a buffer of at least
-** 16 bytes into which to put the digest. md5_hash does the above
-** internally for you and is the most convenient interface; the interface
-** described above, however, is better when all of the data to hash isn't
-** available neatly in a single buffer (such as hashing data aquired a
-** block at a time).
-**
-** For information about MD5, see RFC 1321.
-**
-** LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-** INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
-** EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
-** USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-** OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-** PERFORMANCE OF THIS SOFTWARE.
-**
-** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.
-**
-** License to copy and use this software is granted provided that it is
-** identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm"
-** in all material mentioning or referencing this software or this
-** function.
-**
-** License is also granted to make and use derivative works provided that
-** such works are identified as "derived from the RSA Data Security,
-** Inc. MD5 Message-Digest Algorithm" in all material mentioning or
-** referencing the derived work.
-**
-** RSA Data Security, Inc. makes no representations concerning either the
-** merchantability of this software or the suitability of this software for
-** any particular purpose. It is provided "as is" without express or
-** implied warranty of any kind.
-**
-** These notices must be retained in any copies of any part of this
-** documentation and/or software.
-*/
-
-/*
-** The actual mathematics and cryptography are at the bottom of this file,
-** as those parts should be fully debugged and very infrequently changed.
-** The core of actual work is done by md5_transform. The beginning of this
-** file contains the infrastructure around the mathematics.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "inn/md5.h"
-
-/* Rotate a 32-bit value left, used by both the MD5 mathematics and by the
- routine below to byteswap data on big-endian machines. */
-#define ROT(X, n) (((X) << (n)) | ((X) >> (32 - (n))))
-
-/* Almost zero fill padding, used by md5_final. The 0x80 is part of the MD5
- hash algorithm, from RFC 1321 section 3.1:
-
- Padding is performed as follows: a single "1" bit is appended to the
- message, and then "0" bits are appended so that the length in bits of
- the padded message becomes congruent to 448, modulo 512. In all, at
- least one bit and at most 512 bits are appended.
-
- Let the compiler zero the remainder of the array for us, guaranteed by
- ISO C99 6.7.8 paragraph 21. */
-static const unsigned char padding[MD5_CHUNKSIZE] = { 0x80, 0 /* 0, ... */ };
-
-/* Internal prototypes. */
-static void md5_transform(uint32_t *, const uint32_t *);
-static void md5_update_block(struct md5_context *, const unsigned char *,
- size_t);
-
-/* MD5 requires that input data be treated as words in little-endian byte
- order. From RFC 1321 section 2:
-
- Similarly, a sequence of bytes can be interpreted as a sequence of
- 32-bit words, where each consecutive group of four bytes is interpreted
- as a word with the low-order (least significant) byte given first.
-
- Input data must therefore be byteswapped on big-endian machines, as must
- the 16-byte result digest. Since we have to make a copy of the incoming
- data anyway to ensure alignment for 4-byte access, we can byteswap it in
- place. */
-#if !WORDS_BIGENDIAN
-# define decode(data) /* empty */
-# define encode(data, out) memcpy((out), (data), MD5_DIGESTSIZE)
-#else
-
-/* The obvious way to do this is to pull single bytes at a time out of the
- input array and build words from them; this requires three shifts and
- three Boolean or operations, but it requires four memory reads per word
- unless the compiler is really smart. Since we can assume four-byte
- alignment for the input data, use this optimized routine from J. Touch,
- USC/ISI. This requires four shifts, two ands, and two ors, but only one
- memory read per word. */
-#define swap(word) \
- do { \
- htmp = ROT((word), 16); \
- ltmp = htmp >> 8; \
- htmp &= 0x00ff00ff; \
- ltmp &= 0x00ff00ff; \
- htmp <<= 8; \
- (word) = htmp | ltmp; \
- } while (0)
-
-/* We process 16 words of data (one MD5 block) of data at a time, completely
- unrolling the loop manually since it should allow the compiler to take
- advantage of pipelining and parallel arithmetic units. */
-static void
-decode(uint32_t *data)
-{
- uint32_t ltmp, htmp;
-
- swap(data[ 0]); swap(data[ 1]); swap(data[ 2]); swap(data[ 3]);
- swap(data[ 4]); swap(data[ 5]); swap(data[ 6]); swap(data[ 7]);
- swap(data[ 8]); swap(data[ 9]); swap(data[10]); swap(data[11]);
- swap(data[12]); swap(data[13]); swap(data[14]); swap(data[15]);
-}
-
-/* Used by md5_final to generate the final digest. The digest is not
- guaranteed to be aligned for 4-byte access but we are allowed to be
- destructive, so byteswap first and then copy the result over. */
-static void
-encode(uint32_t *data, unsigned char *out)
-{
- uint32_t ltmp, htmp;
-
- swap(data[0]);
- swap(data[1]);
- swap(data[2]);
- swap(data[3]);
- memcpy(out, data, MD5_DIGESTSIZE);
-}
-
-#endif /* WORDS_BIGENDIAN */
-
-
-/*
-** That takes care of the preliminaries; now the real fun begins. The
-** initialization function for a struct md5_context; set lengths to zero
-** and initialize our working buffer with the magic constants (c.f. RFC
-** 1321 section 3.3).
-*/
-void
-md5_init(struct md5_context *context)
-{
- context->buf[0] = 0x67452301U;
- context->buf[1] = 0xefcdab89U;
- context->buf[2] = 0x98badcfeU;
- context->buf[3] = 0x10325476U;
-
- context->count[0] = 0;
- context->count[1] = 0;
- context->datalen = 0;
-}
-
-
-/*
-** The workhorse function, called for each chunk of data. Update the
-** message-digest context to account for the presence of each of the
-** characters data[0 .. count - 1] in the message whose digest is being
-** computed. Accepts any length of data; all whole blocks are processed
-** and the remaining data is buffered for later processing by either
-** another call to md5_update or by md5_final.
-*/
-void
-md5_update(struct md5_context *context, const unsigned char *data,
- size_t count)
-{
- unsigned int datalen = context->datalen;
- unsigned int left;
- size_t high_count, low_count, used;
-
- /* Update the count of hashed bytes. The machinations here are to do
- the right thing on a platform where size_t > 32 bits without causing
- compiler warnings on platforms where it's 32 bits. RFC 1321 section
- 3.2 says:
-
- A 64-bit representation of b (the length of the message before the
- padding bits were added) is appended to the result of the previous
- step. In the unlikely event that b is greater than 2^64, then only
- the low-order 64 bits of b are used.
-
- so we can just ignore the higher bits of count if size_t is larger
- than 64 bits. (Think ahead!) If size_t is only 32 bits, the
- compiler should kill the whole if statement as dead code. */
- if (sizeof(count) > 4) {
- high_count = count >> 31;
- context->count[1] += (high_count >> 1) & 0xffffffffU;
- }
-
- /* Now deal with count[0]. Add in the low 32 bits of count and
- increment count[1] if count[0] wraps. Isn't unsigned arithmetic
- cool? */
- low_count = count & 0xffffffffU;
- context->count[0] += low_count;
- if (context->count[0] < low_count)
- context->count[1]++;
-
- /* See if we already have some data queued. If so, try to complete a
- block and then deal with it first. If the new data still doesn't
- fill the buffer, add it to the buffer and return. Otherwise,
- transform that block and update data and count to account for the
- data we've already used. */
- if (datalen > 0) {
- left = MD5_CHUNKSIZE - datalen;
- if (left > count) {
- memcpy(context->in.byte + datalen, data, count);
- context->datalen += count;
- return;
- } else {
- memcpy(context->in.byte + datalen, data, left);
- decode(context->in.word);
- md5_transform(context->buf, context->in.word);
- data += left;
- count -= left;
- context->datalen = 0;
- }
- }
-
- /* If we have a block of data or more left, pass the rest off to
- md5_update_block to deal with all of the full blocks available. */
- if (count >= MD5_CHUNKSIZE) {
- md5_update_block(context, data, count);
- used = (count / MD5_CHUNKSIZE) * MD5_CHUNKSIZE;
- data += used;
- count -= used;
- }
-
- /* If there's anything left, buffer it until we can complete a block or
- for md5_final to deal with. */
- if (count > 0) {
- memcpy(context->in.byte, data, count);
- context->datalen = count;
- }
-}
-
-
-/*
-** Update the message-digest context to account for the presence of each of
-** the characters data[0 .. count - 1] in the message whose digest is being
-** computed, except that we only deal with full blocks of data. The data
-** is processed one block at a time, and partial blocks at the end are
-** ignored (they're dealt with by md5_update, which calls this routine.
-**
-** Note that we always make a copy of the input data into an array of
-** 4-byte values. If our input data were guaranteed to be aligned for
-** 4-byte access, we could just use the input buffer directly on
-** little-endian machines, and in fact this implementation used to do that.
-** However, a requirement to align isn't always easily detectable, even by
-** configure (an Alpha running Tru64 will appear to allow unaligned
-** accesses, but will spew errors to the terminal if you do it). On top of
-** that, even when it's allowed, unaligned access is quite frequently
-** slower; we're about to do four reads of each word of the input data for
-** the calculations, so doing one additional copy of the data up-front is
-** probably worth it.
-*/
-static void
-md5_update_block(struct md5_context *context, const unsigned char *data,
- size_t count)
-{
- uint32_t in[MD5_CHUNKWORDS];
-
- /* Process data in MD5_CHUNKSIZE blocks. */
- while (count >= MD5_CHUNKSIZE) {
- memcpy(in, data, MD5_CHUNKSIZE);
- decode(in);
- md5_transform(context->buf, in);
- data += MD5_CHUNKSIZE;
- count -= MD5_CHUNKSIZE;
- }
-}
-
-
-/*
-** Terminates the message-digest computation, accounting for any final
-** trailing data and adding the message length to the hashed data, and ends
-** with the desired message digest in context->digest[0...15].
-*/
-void
-md5_final(struct md5_context *context)
-{
- unsigned int pad_needed, left;
- uint32_t count[2];
- uint32_t *countloc;
-
- /* Save the count before appending the padding. */
- count[0] = context->count[0];
- count[1] = context->count[1];
-
- /* Pad the final block of data. RFC 1321 section 3.1:
-
- The message is "padded" (extended) so that its length (in bits) is
- congruent to 448, modulo 512. That is, the message is extended so
- that it is just 64 bits shy of being a multiple of 512 bits long.
- Padding is always performed, even if the length of the message is
- already congruent to 448, modulo 512.
-
- The 64 bits (two words) left are for the 64-bit count of bits
- hashed. We'll need at most 64 bytes of padding; lucky that the
- padding array is exactly that size! */
- left = context->datalen;
- pad_needed = (left < 64 - 8) ? (64 - 8 - left) : (128 - 8 - left);
- md5_update(context, padding, pad_needed);
-
- /* Append length in bits and transform. Note that we cheat slightly
- here to save a few operations on big-endian machines; the algorithm
- says that we should add the length, in little-endian byte order, to
- the last block of data. We'd then transform it into big-endian order
- on a big-endian machine. But the count is *already* in big-endian
- order on a big-endian machine, so effectively we'd be byteswapping it
- twice. Instead, add it to the block after doing byte swapping on the
- rest.
-
- Note that we've been counting *bytes*, but the algorithm demands the
- length in *bits*, so shift things around a bit. */
- decode(context->in.word);
- countloc = &context->in.word[MD5_CHUNKWORDS - 2];
- countloc[0] = count[0] << 3;
- countloc[1] = (count[1] << 3) | (count[0] >> 29);
- md5_transform(context->buf, context->in.word);
-
- /* Recover the final digest. Whoo-hoo, we're done! */
- encode(context->buf, context->digest);
-}
-
-
-/*
-** A convenience wrapper around md5_init, md5_update, and md5_final. Takes
-** a pointer to a buffer of data, the length of the data, and a pointer to
-** a buffer of at least 16 bytes into which to write the message digest.
-*/
-void
-md5_hash(const unsigned char *data, size_t length, unsigned char *digest)
-{
- struct md5_context context;
-
- md5_init(&context);
- md5_update(&context, data, length);
- md5_final(&context);
- memcpy(digest, context.digest, MD5_DIGESTSIZE);
-}
-
-
-/*
-** Look out, here comes the math.
-**
-** There are no user-serviceable parts below this point unless you know
-** quite a bit about MD5 or optimization of integer math. The only
-** function remaining, down below, is md5_transform; the rest of this is
-** setting up macros to make that function more readable.
-**
-** The F, G, H and I are basic MD5 functions. The following identity saves
-** one boolean operation.
-**
-** F: (((x) & (y)) | (~(x) & (z))) == ((z) ^ ((x) & ((y) ^ (z))))
-** G: (((x) & (z)) | ((y) & ~(z))) == ((y) ^ ((z) & ((x) ^ (y))))
-*/
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/*
-** FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation
-** is separate from addition to prevent recomputation. S?? are the shift
-** values for each round.
-*/
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define FF(a, b, c, d, x, s, ac) \
- { \
- (a) += F((b), (c), (d)) + (x) + (uint32_t) (ac); \
- (a) = ROT((a), (s)); \
- (a) += (b); \
- }
-
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define GG(a, b, c, d, x, s, ac) \
- { \
- (a) += G((b), (c), (d)) + (x) + (uint32_t) (ac); \
- (a) = ROT((a), (s)); \
- (a) += (b); \
- }
-
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define HH(a, b, c, d, x, s, ac) \
- { \
- (a) += H((b), (c), (d)) + (x) + (uint32_t) (ac); \
- (a) = ROT((a), (s)); \
- (a) += (b); \
- }
-
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-#define II(a, b, c, d, x, s, ac) \
- { \
- (a) += I((b), (c), (d)) + (x) + (uint32_t) (ac); \
- (a) = ROT((a), (s)); \
- (a) += (b); \
- }
-
-/*
-** Basic MD5 step. Transforms buf based on in.
-*/
-static void
-md5_transform(uint32_t *buf, const uint32_t *in)
-{
- uint32_t a = buf[0];
- uint32_t b = buf[1];
- uint32_t c = buf[2];
- uint32_t d = buf[3];
-
- /* Round 1 */
- FF(a, b, c, d, in[ 0], S11, 3614090360UL); /* 1 */
- FF(d, a, b, c, in[ 1], S12, 3905402710UL); /* 2 */
- FF(c, d, a, b, in[ 2], S13, 606105819UL); /* 3 */
- FF(b, c, d, a, in[ 3], S14, 3250441966UL); /* 4 */
- FF(a, b, c, d, in[ 4], S11, 4118548399UL); /* 5 */
- FF(d, a, b, c, in[ 5], S12, 1200080426UL); /* 6 */
- FF(c, d, a, b, in[ 6], S13, 2821735955UL); /* 7 */
- FF(b, c, d, a, in[ 7], S14, 4249261313UL); /* 8 */
- FF(a, b, c, d, in[ 8], S11, 1770035416UL); /* 9 */
- FF(d, a, b, c, in[ 9], S12, 2336552879UL); /* 10 */
- FF(c, d, a, b, in[10], S13, 4294925233UL); /* 11 */
- FF(b, c, d, a, in[11], S14, 2304563134UL); /* 12 */
- FF(a, b, c, d, in[12], S11, 1804603682UL); /* 13 */
- FF(d, a, b, c, in[13], S12, 4254626195UL); /* 14 */
- FF(c, d, a, b, in[14], S13, 2792965006UL); /* 15 */
- FF(b, c, d, a, in[15], S14, 1236535329UL); /* 16 */
-
- /* Round 2 */
- GG(a, b, c, d, in[ 1], S21, 4129170786UL); /* 17 */
- GG(d, a, b, c, in[ 6], S22, 3225465664UL); /* 18 */
- GG(c, d, a, b, in[11], S23, 643717713UL); /* 19 */
- GG(b, c, d, a, in[ 0], S24, 3921069994UL); /* 20 */
- GG(a, b, c, d, in[ 5], S21, 3593408605UL); /* 21 */
- GG(d, a, b, c, in[10], S22, 38016083UL); /* 22 */
- GG(c, d, a, b, in[15], S23, 3634488961UL); /* 23 */
- GG(b, c, d, a, in[ 4], S24, 3889429448UL); /* 24 */
- GG(a, b, c, d, in[ 9], S21, 568446438UL); /* 25 */
- GG(d, a, b, c, in[14], S22, 3275163606UL); /* 26 */
- GG(c, d, a, b, in[ 3], S23, 4107603335UL); /* 27 */
- GG(b, c, d, a, in[ 8], S24, 1163531501UL); /* 28 */
- GG(a, b, c, d, in[13], S21, 2850285829UL); /* 29 */
- GG(d, a, b, c, in[ 2], S22, 4243563512UL); /* 30 */
- GG(c, d, a, b, in[ 7], S23, 1735328473UL); /* 31 */
- GG(b, c, d, a, in[12], S24, 2368359562UL); /* 32 */
-
- /* Round 3 */
- HH(a, b, c, d, in[ 5], S31, 4294588738UL); /* 33 */
- HH(d, a, b, c, in[ 8], S32, 2272392833UL); /* 34 */
- HH(c, d, a, b, in[11], S33, 1839030562UL); /* 35 */
- HH(b, c, d, a, in[14], S34, 4259657740UL); /* 36 */
- HH(a, b, c, d, in[ 1], S31, 2763975236UL); /* 37 */
- HH(d, a, b, c, in[ 4], S32, 1272893353UL); /* 38 */
- HH(c, d, a, b, in[ 7], S33, 4139469664UL); /* 39 */
- HH(b, c, d, a, in[10], S34, 3200236656UL); /* 40 */
- HH(a, b, c, d, in[13], S31, 681279174UL); /* 41 */
- HH(d, a, b, c, in[ 0], S32, 3936430074UL); /* 42 */
- HH(c, d, a, b, in[ 3], S33, 3572445317UL); /* 43 */
- HH(b, c, d, a, in[ 6], S34, 76029189UL); /* 44 */
- HH(a, b, c, d, in[ 9], S31, 3654602809UL); /* 45 */
- HH(d, a, b, c, in[12], S32, 3873151461UL); /* 46 */
- HH(c, d, a, b, in[15], S33, 530742520UL); /* 47 */
- HH(b, c, d, a, in[ 2], S34, 3299628645UL); /* 48 */
-
- /* Round 4 */
- II(a, b, c, d, in[ 0], S41, 4096336452UL); /* 49 */
- II(d, a, b, c, in[ 7], S42, 1126891415UL); /* 50 */
- II(c, d, a, b, in[14], S43, 2878612391UL); /* 51 */
- II(b, c, d, a, in[ 5], S44, 4237533241UL); /* 52 */
- II(a, b, c, d, in[12], S41, 1700485571UL); /* 53 */
- II(d, a, b, c, in[ 3], S42, 2399980690UL); /* 54 */
- II(c, d, a, b, in[10], S43, 4293915773UL); /* 55 */
- II(b, c, d, a, in[ 1], S44, 2240044497UL); /* 56 */
- II(a, b, c, d, in[ 8], S41, 1873313359UL); /* 57 */
- II(d, a, b, c, in[15], S42, 4264355552UL); /* 58 */
- II(c, d, a, b, in[ 6], S43, 2734768916UL); /* 59 */
- II(b, c, d, a, in[13], S44, 1309151649UL); /* 60 */
- II(a, b, c, d, in[ 4], S41, 4149444226UL); /* 61 */
- II(d, a, b, c, in[11], S42, 3174756917UL); /* 62 */
- II(c, d, a, b, in[ 2], S43, 718787259UL); /* 63 */
- II(b, c, d, a, in[ 9], S44, 3951481745UL); /* 64 */
-
- buf[0] += a;
- buf[1] += b;
- buf[2] += c;
- buf[3] += d;
-}
+++ /dev/null
-/* $Id: memcmp.c 5049 2001-12-12 09:06:00Z rra $
-**
-** Replacement for a missing or broken memcmp.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine memcmp
-** for those platforms that don't have it or where it doesn't work right
-** (such as on SunOS where it can't deal with eight-bit characters).
-*/
-
-#include "config.h"
-#include <sys/types.h>
-
-/* If we're running the test suite, rename memcmp to avoid conflicts with
- the system version. */
-#if TESTING
-# define memcmp test_memcmp
-int test_memcmp(const void *, const void *, size_t);
-#endif
-
-int
-memcmp(const void *s1, const void *s2, size_t n)
-{
- size_t i;
- const unsigned char *p1, *p2;
-
- /* It's technically illegal to call memcmp with NULL pointers, but we
- may as well check anyway. */
- if (!s1)
- return !s2 ? 0 : -1;
- if (!s2)
- return 1;
-
- p1 = (const unsigned char *) s1;
- p2 = (const unsigned char *) s2;
- for (i = 0; i < n; i++, p1++, p2++)
- if (*p1 != *p2)
- return (int) *p1 - (int) *p2;
- return 0;
-}
+++ /dev/null
-/* $Id: messages.c 5496 2002-06-07 13:59:06Z alexk $
-**
-** Message and error reporting (possibly fatal).
-**
-** Usage:
-**
-** extern int cleanup(void);
-** extern void log(int, const char *, va_list, int);
-**
-** message_fatal_cleanup = cleanup;
-** message_program_name = argv[0];
-**
-** warn("Something horrible happened at %lu", time);
-** syswarn("Couldn't unlink temporary file %s", tmpfile);
-**
-** die("Something fatal happened at %lu", time);
-** sysdie("open of %s failed", filename);
-**
-** debug("Some debugging message about %s", string);
-** trace(TRACE_PROGRAM, "Program trace output");
-** notice("Informational notices");
-**
-** message_handlers_warn(1, log);
-** warn("This now goes through our log function");
-**
-** These functions implement message reporting through user-configurable
-** handler functions. debug() only does something if DEBUG is defined,
-** trace() supports sending trace messages in one of a number of configurable
-** classes of traces so that they can be turned on or off independently, and
-** notice() and warn() just output messages as configured. die() similarly
-** outputs a message but then exits, normally with a status of 1.
-**
-** The sys* versions do the same, but append a colon, a space, and the
-** results of strerror(errno) to the end of the message. All functions
-** accept printf-style formatting strings and arguments.
-**
-** If message_fatal_cleanup is non-NULL, it is called before exit by die and
-** sysdie and its return value is used as the argument to exit. It is a
-** pointer to a function taking no arguments and returning an int, and can be
-** used to call cleanup functions or to exit in some alternate fashion (such
-** as by calling _exit).
-**
-** If message_program_name is non-NULL, the string it points to, followed by
-** a colon and a space, is prepended to all error messages logged through the
-** message_log_stdout and message_log_stderr message handlers (the former is
-** the default for notice, and the latter is the default for warn and die).
-**
-** Honoring error_program_name and printing to stderr is just the default
-** handler; with message_handlers_* the handlers for any message function can
-** be changed. By default, notice prints to stdout, warn and die print to
-** stderr, and the others don't do anything at all. These functions take a
-** count of handlers and then that many function pointers, each one to a
-** function that takes a message length (the number of characters snprintf
-** generates given the format and arguments), a format, an argument list as a
-** va_list, and the applicable errno value (if any).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <syslog.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-/* The default handler lists. */
-static message_handler_func stdout_handlers[2] = {
- message_log_stdout, NULL
-};
-static message_handler_func stderr_handlers[2] = {
- message_log_stderr, NULL
-};
-
-/* The list of logging functions currently in effect. */
-static message_handler_func *debug_handlers = NULL;
-static message_handler_func *trace_handlers = NULL;
-static message_handler_func *notice_handlers = stdout_handlers;
-static message_handler_func *warn_handlers = stderr_handlers;
-static message_handler_func *die_handlers = stderr_handlers;
-
-/* If non-NULL, called before exit and its return value passed to exit. */
-int (*message_fatal_cleanup)(void) = NULL;
-
-/* If non-NULL, prepended (followed by ": ") to messages. */
-const char *message_program_name = NULL;
-
-/* Whether or not we're currently outputting a particular type of trace. */
-static bool tracing[TRACE_ALL] = { false /* false, ... */ };
-
-
-/*
-** Set the handlers for a particular message function. Takes a pointer to
-** the handler list, the count of handlers, and the argument list.
-*/
-static void
-message_handlers(message_handler_func **list, int count, va_list args)
-{
- int i;
-
- if (*list != stdout_handlers && *list != stderr_handlers)
- free(*list);
- *list = xmalloc(sizeof(message_handler_func) * (count + 1));
- for (i = 0; i < count; i++)
- (*list)[i] = (message_handler_func) va_arg(args, message_handler_func);
- (*list)[count] = NULL;
-}
-
-
-/*
-** There's no good way of writing these handlers without a bunch of code
-** duplication since we can't assume variadic macros, but I can at least make
-** it easier to write and keep them consistent.
-*/
-#define HANDLER_FUNCTION(type) \
- void \
- message_handlers_ ## type(int count, ...) \
- { \
- va_list args; \
- \
- va_start(args, count); \
- message_handlers(& type ## _handlers, count, args); \
- va_end(args); \
- }
-HANDLER_FUNCTION(debug)
-HANDLER_FUNCTION(trace)
-HANDLER_FUNCTION(notice)
-HANDLER_FUNCTION(warn)
-HANDLER_FUNCTION(die)
-
-
-/*
-** Print a message to stdout, supporting message_program_name.
-*/
-void
-message_log_stdout(int len UNUSED, const char *fmt, va_list args, int err)
-{
- if (message_program_name != NULL)
- fprintf(stdout, "%s: ", message_program_name);
- vfprintf(stdout, fmt, args);
- if (err)
- fprintf(stdout, ": %s", strerror(err));
- fprintf(stdout, "\n");
-}
-
-
-/*
-** Print a message to stderr, supporting message_program_name. Also flush
-** stdout so that errors and regular output occur in the right order.
-*/
-void
-message_log_stderr(int len UNUSED, const char *fmt, va_list args, int err)
-{
- fflush(stdout);
- if (message_program_name != NULL)
- fprintf(stderr, "%s: ", message_program_name);
- vfprintf(stderr, fmt, args);
- if (err)
- fprintf(stderr, ": %s", strerror(err));
- fprintf(stderr, "\n");
-}
-
-
-/*
-** Log a message to syslog. This is a helper function used to implement all
-** of the syslog message log handlers. It takes the same arguments as a
-** regular message handler function but with an additional priority
-** argument.
-*/
-static void
-message_log_syslog(int pri, int len, const char *fmt, va_list args, int err)
-{
- char *buffer;
-
- buffer = malloc(len + 1);
- if (buffer == NULL) {
- fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s",
- len + 1, __FILE__, __LINE__, strerror(errno));
- exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
- }
- vsnprintf(buffer, len + 1, fmt, args);
- syslog(pri, err ? "%s: %m" : "%s", buffer);
- free(buffer);
-}
-
-
-/*
-** Do the same sort of wrapper to generate all of the separate syslog logging
-** functions.
-*/
-#define SYSLOG_FUNCTION(name, type) \
- void \
- message_log_syslog_ ## name(int l, const char *f, va_list a, int e) \
- { \
- message_log_syslog(LOG_ ## type, l, f, a, e); \
- }
-SYSLOG_FUNCTION(debug, DEBUG)
-SYSLOG_FUNCTION(info, INFO)
-SYSLOG_FUNCTION(notice, NOTICE)
-SYSLOG_FUNCTION(warning, WARNING)
-SYSLOG_FUNCTION(err, ERR)
-SYSLOG_FUNCTION(crit, CRIT)
-
-
-/*
-** Enable or disable tracing for particular classes of messages.
-*/
-void
-message_trace_enable(enum message_trace type, bool enable)
-{
- if (type > TRACE_ALL)
- return;
- if (type == TRACE_ALL) {
- int i;
-
- for (i = 0; i < TRACE_ALL; i++)
- tracing[i] = enable;
- } else {
- tracing[type] = enable;
- }
-}
-
-
-/*
-** All of the message handlers. There's a lot of code duplication here too,
-** but each one is still *slightly* different and va_start has to be called
-** multiple times, so it's hard to get rid of the duplication.
-*/
-
-#ifdef DEBUG
-void
-debug(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
-
- if (debug_handlers == NULL)
- return;
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = debug_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, 0);
- va_end(args);
- }
-}
-#elif !INN_HAVE_C99_VAMACROS && !INN_HAVE_GNU_VAMACROS
-void debug(const char *format UNUSED, ...) { }
-#endif
-
-void
-trace(enum message_trace type, const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
-
- if (trace_handlers == NULL || !tracing[type])
- return;
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = trace_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, 0);
- va_end(args);
- }
-}
-
-void
-notice(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = notice_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, 0);
- va_end(args);
- }
-}
-
-void
-sysnotice(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
- int error = errno;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = notice_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, error);
- va_end(args);
- }
-}
-
-void
-warn(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = warn_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, 0);
- va_end(args);
- }
-}
-
-void
-syswarn(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
- int error = errno;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length < 0)
- return;
- for (log = warn_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, error);
- va_end(args);
- }
-}
-
-void
-die(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length >= 0)
- for (log = die_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, 0);
- va_end(args);
- }
- exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
-}
-
-void
-sysdie(const char *format, ...)
-{
- va_list args;
- message_handler_func *log;
- int length;
- int error = errno;
-
- va_start(args, format);
- length = vsnprintf(NULL, 0, format, args);
- va_end(args);
- if (length >= 0)
- for (log = die_handlers; *log != NULL; log++) {
- va_start(args, format);
- (**log)(length, format, args, error);
- va_end(args);
- }
- exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);
-}
+++ /dev/null
-/* $Id: mkstemp.c 5329 2002-03-17 07:39:14Z rra $
-**
-** Replacement for a missing mkstemp.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the library function mkstemp for those
-** systems that don't have it.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <errno.h>
-#include <fcntl.h>
-
-/* If we're running the test suite, rename mkstemp to avoid conflicts with the
- system version. #undef it first because some systems may define it to
- another name. */
-#if TESTING
-# undef mkstemp
-# define mkstemp test_mkstemp
-int test_mkstemp(char *);
-#endif
-
-/* Pick the longest available integer type. */
-#if HAVE_LONG_LONG
-typedef unsigned long long long_int_type;
-#else
-typedef unsigned long long_int_type;
-#endif
-
-int
-mkstemp(char *template)
-{
- static const char letters[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- size_t length;
- char *XXXXXX;
- struct timeval tv;
- long_int_type randnum, working;
- int i, tries, fd;
-
- /* Make sure we have a valid template and initialize p to point at the
- beginning of the template portion of the string. */
- length = strlen(template);
- if (length < 6) {
- errno = EINVAL;
- return -1;
- }
- XXXXXX = template + length - 6;
- if (strcmp(XXXXXX, "XXXXXX") != 0) {
- errno = EINVAL;
- return -1;
- }
-
- /* Get some more-or-less random information. */
- gettimeofday(&tv, NULL);
- randnum = ((long_int_type) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();
-
- /* Now, try to find a working file name. We try no more than TMP_MAX file
- names. */
- for (tries = 0; tries < TMP_MAX; tries++) {
- for (working = randnum, i = 0; i < 6; i++) {
- XXXXXX[i] = letters[working % 62];
- working /= 62;
- }
- fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fd >= 0 || errno != EEXIST)
- return fd;
-
- /* This is a relatively random increment. Cut off the tail end of
- tv_usec since it's often predictable. */
- randnum += (tv.tv_usec >> 10) & 0xfff;
- }
- errno = EEXIST;
- return -1;
-}
+++ /dev/null
-/* $Id: mmap.c 7598 2007-02-09 02:40:51Z eagle $
-**
-** MMap manipulation routines
-**
-** Written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** These routines work with mmap()ed memory
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-
-#include "inn/messages.h"
-#include "inn/mmap.h"
-
-/*
-** Figure out what page an address is in and flush those pages
-*/
-void
-inn__mapcntl(void *p, size_t length, int flags)
-{
- int pagesize;
-
- pagesize = getpagesize();
- if (pagesize == -1)
- syswarn("getpagesize failed");
- else {
- char *start, *end;
-
- start = (char *)((size_t)p & ~(size_t)(pagesize - 1));
- end = (char *)((size_t)((char *)p + length + pagesize) &
- ~(size_t)(pagesize - 1));
- msync(start, end - start, flags);
- }
-}
+++ /dev/null
-%{
-/* $Id: parsedate.y 6372 2003-05-31 19:48:28Z rra $
-**
-** Originally written by Steven M. Bellovin <smb@research.att.com> while
-** at the University of North Carolina at Chapel Hill. Later tweaked by
-** a couple of people on Usenet. Completely overhauled by Rich $alz
-** <rsalz@osf.org> and Jim Berets <jberets@bbn.com> in August, 1990.
-** Further revised (removed obsolete constructs and cleaned up timezone
-** names) in August, 1991, by Rich. Paul Eggert <eggert@twinsun.com>
-** helped in September, 1992.
-**
-** This grammar has six shift/reduce conflicts.
-**
-** This code is in the public domain and has no copyright.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#if defined(_HPUX_SOURCE)
-# include <alloca.h>
-#endif
-
-#ifdef TM_IN_SYS_TIME
-# include <sys/time.h>
-#else
-# include <time.h>
-#endif
-
-#include "libinn.h"
-
-
-#define yylhs date_yylhs
-#define yylen date_yylen
-#define yydefred date_yydefred
-#define yydgoto date_yydgoto
-#define yysindex date_yysindex
-#define yyrindex date_yyrindex
-#define yygindex date_yygindex
-#define yytable date_yytable
-#define yycheck date_yycheck
-#define yyparse date_parse
-#define yylex date_lex
-#define yyerror date_error
-#define yymaxdepth date_yymaxdepth
-
-
-static int date_lex(void);
-
-int yyparse(void);
-
- /* See the LeapYears table in Convert. */
-#define EPOCH 1970
-#define END_OF_TIME 2038
- /* Constants for general time calculations. */
-#define DST_OFFSET 1
-#define SECSPERDAY (24L * 60L * 60L)
- /* Readability for TABLE stuff. */
-#define HOUR(x) (x * 60)
-
-#define LPAREN '('
-#define RPAREN ')'
-#define IS7BIT(x) ((unsigned int)(x) < 0200)
-
-
-/*
-** An entry in the lexical lookup table.
-*/
-typedef struct _TABLE {
- const char * name;
- int type;
- time_t value;
-} TABLE;
-
-/*
-** Daylight-savings mode: on, off, or not yet known.
-*/
-typedef enum _DSTMODE {
- DSTon, DSToff, DSTmaybe
-} DSTMODE;
-
-/*
-** Meridian: am, pm, or 24-hour style.
-*/
-typedef enum _MERIDIAN {
- MERam, MERpm, MER24
-} MERIDIAN;
-
-
-/*
-** Global variables. We could get rid of most of them by using a yacc
-** union, but this is more efficient. (This routine predates the
-** yacc %union construct.)
-*/
-static char *yyInput;
-static DSTMODE yyDSTmode;
-static int yyHaveDate;
-static int yyHaveRel;
-static int yyHaveTime;
-static time_t yyTimezone;
-static time_t yyDay;
-static time_t yyHour;
-static time_t yyMinutes;
-static time_t yyMonth;
-static time_t yySeconds;
-static time_t yyYear;
-static MERIDIAN yyMeridian;
-static time_t yyRelMonth;
-static time_t yyRelSeconds;
-
-
-/* extern struct tm *localtime(); */
-
-static void date_error(const char *s);
-%}
-
-%union {
- time_t Number;
- enum _MERIDIAN Meridian;
-}
-
-%token tDAY tDAYZONE tMERIDIAN tMONTH tMONTH_UNIT tSEC_UNIT tSNUMBER
-%token tUNUMBER tZONE
-
-%type <Number> tDAYZONE tMONTH tMONTH_UNIT tSEC_UNIT
-%type <Number> tSNUMBER tUNUMBER tZONE numzone zone
-%type <Meridian> tMERIDIAN o_merid
-
-%%
-
-spec : /* NULL */
- | spec item
- ;
-
-item : time {
- yyHaveTime++;
-#if defined(lint)
- /* I am compulsive about lint natterings... */
- if (yyHaveTime == -1) {
- YYERROR;
- }
-#endif /* defined(lint) */
- }
- | time zone {
- yyHaveTime++;
- yyTimezone = $2;
- }
- | date {
- yyHaveDate++;
- }
- | rel {
- yyHaveRel = 1;
- }
- ;
-
-time : tUNUMBER o_merid {
- if ($1 < 100) {
- yyHour = $1;
- yyMinutes = 0;
- }
- else {
- yyHour = $1 / 100;
- yyMinutes = $1 % 100;
- }
- yySeconds = 0;
- yyMeridian = $2;
- }
- | tUNUMBER ':' tUNUMBER o_merid {
- yyHour = $1;
- yyMinutes = $3;
- yySeconds = 0;
- yyMeridian = $4;
- }
- | tUNUMBER ':' tUNUMBER numzone {
- yyHour = $1;
- yyMinutes = $3;
- yyTimezone = $4;
- yyMeridian = MER24;
- yyDSTmode = DSToff;
- }
- | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
- yyHour = $1;
- yyMinutes = $3;
- yySeconds = $5;
- yyMeridian = $6;
- }
- | tUNUMBER ':' tUNUMBER ':' tUNUMBER numzone {
- yyHour = $1;
- yyMinutes = $3;
- yySeconds = $5;
- yyTimezone = $6;
- yyMeridian = MER24;
- yyDSTmode = DSToff;
- }
- ;
-
-zone : tZONE {
- $$ = $1;
- yyDSTmode = DSToff;
- }
- | tDAYZONE {
- $$ = $1;
- yyDSTmode = DSTon;
- }
- | tZONE numzone {
- /* Only allow "GMT+300" and "GMT-0800" */
- if ($1 != 0) {
- YYABORT;
- }
- $$ = $2;
- yyDSTmode = DSToff;
- }
- | numzone {
- $$ = $1;
- yyDSTmode = DSToff;
- }
- ;
-
-numzone : tSNUMBER {
- int i;
-
- /* Unix and GMT and numeric timezones -- a little confusing. */
- if ($1 < 0) {
- /* Don't work with negative modulus. */
- $1 = -$1;
- if ($1 > 9999 || (i = $1 % 100) >= 60) {
- YYABORT;
- }
- $$ = ($1 / 100) * 60 + i;
- }
- else {
- if ($1 > 9999 || (i = $1 % 100) >= 60) {
- YYABORT;
- }
- $$ = -(($1 / 100) * 60 + i);
- }
- }
- ;
-
-date : tUNUMBER '/' tUNUMBER {
- yyMonth = $1;
- yyDay = $3;
- }
- | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
- if ($1 > 100) {
- /* assume YYYY/MM/DD format, so need not to add 1900 */
- if ($1 > 999) {
- yyYear = $1;
- } else {
- yyYear = 1900 + $1;
- }
- yyMonth = $3;
- yyDay = $5;
- }
- else {
- /* assume MM/DD/YY* format */
- yyMonth = $1;
- yyDay = $3;
- if ($5 > 999) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $5;
- } else if ($5 < 100) {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100;
- } else {
- yyYear = 1900 + $5;
- }
- }
- }
- | tMONTH tUNUMBER {
- yyMonth = $1;
- yyDay = $2;
- }
- | tMONTH tUNUMBER ',' tUNUMBER {
- yyMonth = $1;
- yyDay = $2;
- if ($4 > 999) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $4;
- } else if ($4 < 100) {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $4 + (yyYear / 100 + (yyYear % 100 - $4) / 50) * 100;
- } else {
- yyYear = 1900 + $4;
- }
- }
- | tUNUMBER tMONTH {
- yyDay = $1;
- yyMonth = $2;
- }
- | tUNUMBER tMONTH tUNUMBER {
- yyDay = $1;
- yyMonth = $2;
- if ($3 > 999) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $3;
- } else if ($3 < 100) {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $3 + (yyYear / 100 + (yyYear % 100 - $3) / 50) * 100;
- } else {
- yyYear = 1900 + $3;
- }
- }
- | tDAY ',' tUNUMBER tMONTH tUNUMBER {
- yyDay = $3;
- yyMonth = $4;
- if ($5 > 999) {
- /* assume year is YYYY format, so need not to add 1900 */
- yyYear = $5;
- } else if ($5 < 100) {
- /* assume year is YY format, so need to add 1900 */
- yyYear = $5 + (yyYear / 100 + (yyYear % 100 - $5) / 50) * 100;
- } else {
- yyYear = 1900 + $5;
- }
- }
- ;
-
-rel : tSNUMBER tSEC_UNIT {
- yyRelSeconds += $1 * $2;
- }
- | tUNUMBER tSEC_UNIT {
- yyRelSeconds += $1 * $2;
- }
- | tSNUMBER tMONTH_UNIT {
- yyRelMonth += $1 * $2;
- }
- | tUNUMBER tMONTH_UNIT {
- yyRelMonth += $1 * $2;
- }
- ;
-
-o_merid : /* NULL */ {
- $$ = MER24;
- }
- | tMERIDIAN {
- $$ = $1;
- }
- ;
-
-%%
-
-/* Month and day table. */
-static TABLE MonthDayTable[] = {
- { "january", tMONTH, 1 },
- { "february", tMONTH, 2 },
- { "march", tMONTH, 3 },
- { "april", tMONTH, 4 },
- { "may", tMONTH, 5 },
- { "june", tMONTH, 6 },
- { "july", tMONTH, 7 },
- { "august", tMONTH, 8 },
- { "september", tMONTH, 9 },
- { "october", tMONTH, 10 },
- { "november", tMONTH, 11 },
- { "december", tMONTH, 12 },
- /* The value of the day isn't used... */
- { "sunday", tDAY, 0 },
- { "monday", tDAY, 0 },
- { "tuesday", tDAY, 0 },
- { "wednesday", tDAY, 0 },
- { "thursday", tDAY, 0 },
- { "friday", tDAY, 0 },
- { "saturday", tDAY, 0 },
-};
-
-/* Time units table. */
-static TABLE UnitsTable[] = {
- { "year", tMONTH_UNIT, 12 },
- { "month", tMONTH_UNIT, 1 },
- { "week", tSEC_UNIT, 7 * 24 * 60 * 60 },
- { "day", tSEC_UNIT, 1 * 24 * 60 * 60 },
- { "hour", tSEC_UNIT, 60 * 60 },
- { "minute", tSEC_UNIT, 60 },
- { "min", tSEC_UNIT, 60 },
- { "second", tSEC_UNIT, 1 },
- { "sec", tSEC_UNIT, 1 },
-};
-
-/* Timezone table. */
-static TABLE TimezoneTable[] = {
- { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "ut", tZONE, HOUR( 0) }, /* Universal */
- { "utc", tZONE, HOUR( 0) }, /* Universal Coordinated */
- { "cut", tZONE, HOUR( 0) }, /* Coordinated Universal */
- { "z", tZONE, HOUR( 0) }, /* Greenwich Mean */
- { "wet", tZONE, HOUR( 0) }, /* Western European */
- { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
- { "nst", tZONE, HOUR(3)+30 }, /* Newfoundland Standard */
- { "ndt", tDAYZONE, HOUR(3)+30 }, /* Newfoundland Daylight */
- { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
- { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
- { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
- { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
- { "cst", tZONE, HOUR( 6) }, /* Central Standard */
- { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
- { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
- { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
- { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
- { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
- { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
- { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
- { "akst", tZONE, HOUR( 9) }, /* Alaska Standard */
- { "akdt", tDAYZONE, HOUR( 9) }, /* Alaska Daylight */
- { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
- { "hast", tZONE, HOUR(10) }, /* Hawaii-Aleutian Standard */
- { "hadt", tDAYZONE, HOUR(10) }, /* Hawaii-Aleutian Daylight */
- { "ces", tDAYZONE, -HOUR(1) }, /* Central European Summer */
- { "cest", tDAYZONE, -HOUR(1) }, /* Central European Summer */
- { "mez", tZONE, -HOUR(1) }, /* Middle European */
- { "mezt", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
- { "cet", tZONE, -HOUR(1) }, /* Central European */
- { "met", tZONE, -HOUR(1) }, /* Middle European */
- { "eet", tZONE, -HOUR(2) }, /* Eastern Europe */
- { "msk", tZONE, -HOUR(3) }, /* Moscow Winter */
- { "msd", tDAYZONE, -HOUR(3) }, /* Moscow Summer */
- { "wast", tZONE, -HOUR(8) }, /* West Australian Standard */
- { "wadt", tDAYZONE, -HOUR(8) }, /* West Australian Daylight */
- { "hkt", tZONE, -HOUR(8) }, /* Hong Kong */
- { "cct", tZONE, -HOUR(8) }, /* China Coast */
- { "jst", tZONE, -HOUR(9) }, /* Japan Standard */
- { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
- { "kdt", tZONE, -HOUR(9) }, /* Korean Daylight */
- { "cast", tZONE, -(HOUR(9)+30) }, /* Central Australian Standard */
- { "cadt", tDAYZONE, -(HOUR(9)+30) }, /* Central Australian Daylight */
- { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
- { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
- { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
- { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
-
- /* For completeness we include the following entries. */
-#if 0
-
- /* Duplicate names. Either they conflict with a zone listed above
- * (which is either more likely to be seen or just been in circulation
- * longer), or they conflict with another zone in this section and
- * we could not reasonably choose one over the other. */
- { "fst", tZONE, HOUR( 2) }, /* Fernando De Noronha Standard */
- { "fdt", tDAYZONE, HOUR( 2) }, /* Fernando De Noronha Daylight */
- { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
- { "est", tZONE, HOUR( 3) }, /* Eastern Standard (Brazil) */
- { "edt", tDAYZONE, HOUR( 3) }, /* Eastern Daylight (Brazil) */
- { "wst", tZONE, HOUR( 4) }, /* Western Standard (Brazil) */
- { "wdt", tDAYZONE, HOUR( 4) }, /* Western Daylight (Brazil) */
- { "cst", tZONE, HOUR( 5) }, /* Chile Standard */
- { "cdt", tDAYZONE, HOUR( 5) }, /* Chile Daylight */
- { "ast", tZONE, HOUR( 5) }, /* Acre Standard */
- { "adt", tDAYZONE, HOUR( 5) }, /* Acre Daylight */
- { "cst", tZONE, HOUR( 5) }, /* Cuba Standard */
- { "cdt", tDAYZONE, HOUR( 5) }, /* Cuba Daylight */
- { "est", tZONE, HOUR( 6) }, /* Easter Island Standard */
- { "edt", tDAYZONE, HOUR( 6) }, /* Easter Island Daylight */
- { "sst", tZONE, HOUR(11) }, /* Samoa Standard */
- { "ist", tZONE, -HOUR(2) }, /* Israel Standard */
- { "idt", tDAYZONE, -HOUR(2) }, /* Israel Daylight */
- { "idt", tDAYZONE, -(HOUR(3)+30) }, /* Iran Daylight */
- { "ist", tZONE, -(HOUR(3)+30) }, /* Iran Standard */
- { "cst", tZONE, -HOUR(8) }, /* China Standard */
- { "cdt", tDAYZONE, -HOUR(8) }, /* China Daylight */
- { "sst", tZONE, -HOUR(8) }, /* Singapore Standard */
-
- /* Dubious (e.g., not in Olson's TIMEZONE package) or obsolete. */
- { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
- { "wat", tZONE, -HOUR(1) }, /* West Africa */
- { "at", tZONE, HOUR( 2) }, /* Azores */
- { "gst", tZONE, -HOUR(10) }, /* Guam Standard */
- { "nft", tZONE, HOUR(3)+30 }, /* Newfoundland */
- { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
- { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
- { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
- { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
- { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
- { "fwt", tZONE, -HOUR(1) }, /* French Winter */
- { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
- { "bt", tZONE, -HOUR(3) }, /* Baghdad */
- { "it", tZONE, -(HOUR(3)+30) }, /* Iran */
- { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
- { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
- { "ist", tZONE, -(HOUR(5)+30) }, /* Indian Standard */
- { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
- { "nst", tZONE, -HOUR(7) }, /* North Sumatra */
- { "sst", tZONE, -HOUR(7) }, /* South Sumatra */
- { "jt", tZONE, -(HOUR(7)+30) }, /* Java (3pm in Cronusland!) */
- { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
- { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
- { "cat", tZONE, HOUR(10) }, /* -- expired 1967 */
- { "nt", tZONE, HOUR(11) }, /* -- expired 1967 */
- { "ahst", tZONE, HOUR(10) }, /* -- expired 1983 */
- { "hdt", tDAYZONE, HOUR(10) }, /* -- expired 1986 */
-#endif /* 0 */
-};
-
-\f
-
-static void
-date_error(const char *s)
-{
- s = s; /* ARGSUSED */
- /* NOTREACHED */
-}
-
-
-static time_t
-ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
-{
- if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 61)
- return -1;
- if (Meridian == MER24) {
- if (Hours < 0 || Hours > 23)
- return -1;
- }
- else {
- if (Hours < 1 || Hours > 12)
- return -1;
- if (Hours == 12)
- Hours = 0;
- if (Meridian == MERpm)
- Hours += 12;
- }
- return (Hours * 60L + Minutes) * 60L + Seconds;
-}
-
-
-static time_t
-Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes,
- time_t Seconds, MERIDIAN Meridian, DSTMODE dst)
-{
- static int DaysNormal[13] = {
- 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- static int DaysLeap[13] = {
- 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- static int LeapYears[] = {
- 1972, 1976, 1980, 1984, 1988, 1992, 1996,
- 2000, 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2032, 2036
- };
- int *yp;
- int *mp;
- time_t Julian;
- int i;
- time_t tod;
-
- /* Year should not be passed as a relative value, but absolute one.
- so this should not happen, but just ensure it */
- if (Year < 0)
- Year = -Year;
- if (Year < 100) {
- Year += 1900;
- if (Year < EPOCH)
- Year += 100;
- }
- for (mp = DaysNormal, yp = LeapYears; yp < ARRAY_END(LeapYears); yp++)
- if (Year == *yp) {
- mp = DaysLeap;
- break;
- }
- if (Year < EPOCH || Year > END_OF_TIME
- || Month < 1 || Month > 12
- /* NOSTRICT *//* conversion from long may lose accuracy */
- || Day < 1 || Day > mp[(int)Month])
- return -1;
-
- Julian = Day - 1 + (Year - EPOCH) * 365;
- for (yp = LeapYears; yp < ARRAY_END(LeapYears); yp++, Julian++)
- if (Year <= *yp)
- break;
- for (i = 1; i < Month; i++)
- Julian += *++mp;
- Julian *= SECSPERDAY;
- Julian += yyTimezone * 60L;
- if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
- return -1;
- Julian += tod;
- tod = Julian;
- if (dst == DSTon || (dst == DSTmaybe && localtime(&tod)->tm_isdst))
- Julian -= DST_OFFSET * 60 * 60;
- return Julian;
-}
-
-
-static time_t
-DSTcorrect(time_t Start, time_t Future)
-{
- time_t StartDay;
- time_t FutureDay;
-
- StartDay = (localtime(&Start)->tm_hour + 1) % 24;
- FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
- return (Future - Start) + (StartDay - FutureDay) * DST_OFFSET * 60 * 60;
-}
-
-
-static time_t
-RelativeMonth(time_t Start, time_t RelMonth)
-{
- struct tm *tm;
- time_t Month;
- time_t Year;
-
- tm = localtime(&Start);
- Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
- Year = Month / 12;
- Year += 1900;
- Month = Month % 12 + 1;
- return DSTcorrect(Start,
- Convert(Month, (time_t)tm->tm_mday, Year,
- (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
- MER24, DSTmaybe));
-}
-
-
-static int
-LookupWord(char *buff, int length)
-{
- char *p;
- const char *q;
- TABLE *tp;
- int c;
-
- p = buff;
- c = p[0];
-
- /* See if we have an abbreviation for a month. */
- if (length == 3 || (length == 4 && p[3] == '.'))
- for (tp = MonthDayTable; tp < ARRAY_END(MonthDayTable); tp++) {
- q = tp->name;
- if (c == q[0] && p[1] == q[1] && p[2] == q[2]) {
- yylval.Number = tp->value;
- return tp->type;
- }
- }
- else
- for (tp = MonthDayTable; tp < ARRAY_END(MonthDayTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- /* Try for a timezone. */
- for (tp = TimezoneTable; tp < ARRAY_END(TimezoneTable); tp++)
- if (c == tp->name[0] && p[1] == tp->name[1]
- && strcmp(p, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- /* Try the units table. */
- for (tp = UnitsTable; tp < ARRAY_END(UnitsTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
-
- /* Strip off any plural and try the units table again. */
- if (--length > 0 && p[length] == 's') {
- p[length] = '\0';
- for (tp = UnitsTable; tp < ARRAY_END(UnitsTable); tp++)
- if (c == tp->name[0] && strcmp(p, tp->name) == 0) {
- p[length] = 's';
- yylval.Number = tp->value;
- return tp->type;
- }
- p[length] = 's';
- }
- length++;
-
- /* Drop out any periods. */
- for (p = buff, q = buff; *q; q++)
- if (*q != '.')
- *p++ = *q;
- *p = '\0';
-
- /* Try the meridians. */
- if (buff[1] == 'm' && buff[2] == '\0') {
- if (buff[0] == 'a') {
- yylval.Meridian = MERam;
- return tMERIDIAN;
- }
- if (buff[0] == 'p') {
- yylval.Meridian = MERpm;
- return tMERIDIAN;
- }
- }
-
- /* If we saw any periods, try the timezones again. */
- if (p - buff != length) {
- c = buff[0];
- for (p = buff, tp = TimezoneTable; tp < ARRAY_END(TimezoneTable); tp++)
- if (c == tp->name[0] && p[1] == tp->name[1]
- && strcmp(p, tp->name) == 0) {
- yylval.Number = tp->value;
- return tp->type;
- }
- }
-
- /* Unknown word -- assume GMT timezone. */
- yylval.Number = 0;
- return tZONE;
-}
-
-
-static int
-date_lex(void)
-{
- char c;
- char *p;
- char buff[20];
- int sign;
- int i;
- int nesting;
-
- for ( ; ; ) {
- /* Get first character after the whitespace. */
- for ( ; ; ) {
- while (CTYPE(isspace, (int)*yyInput))
- yyInput++;
- c = *yyInput;
-
- /* Ignore RFC 822 comments, typically time zone names. */
- if (c != LPAREN)
- break;
- for (nesting = 1; (c = *++yyInput) != RPAREN || --nesting; )
- if (c == LPAREN)
- nesting++;
- else if (!IS7BIT(c) || c == '\0' || c == '\r'
- || (c == '\\' && ((c = *++yyInput) == '\0' || !IS7BIT(c))))
- /* Lexical error: bad comment. */
- return '?';
- yyInput++;
- }
-
- /* A number? */
- if (CTYPE(isdigit, (int)c) || c == '-' || c == '+') {
- if (c == '-' || c == '+') {
- sign = c == '-' ? -1 : 1;
- yyInput++;
- if (!CTYPE(isdigit, (int)*yyInput))
- /* Skip the plus or minus sign. */
- continue;
- }
- else
- sign = 0;
- for (i = 0; (c = *yyInput++) != '\0' && CTYPE(isdigit, (int)c); )
- i = 10 * i + c - '0';
- yyInput--;
- yylval.Number = sign < 0 ? -i : i;
- return sign ? tSNUMBER : tUNUMBER;
- }
-
- /* A word? */
- if (CTYPE(isalpha, (int)c)) {
- for (p = buff; (c = *yyInput++) == '.' || CTYPE(isalpha, (int)c); )
- if (p < &buff[sizeof buff - 1])
- *p++ = CTYPE(isupper, (int)c) ? tolower(c) : c;
- *p = '\0';
- yyInput--;
- return LookupWord(buff, p - buff);
- }
-
- return *yyInput++;
- }
-}
-
-
-time_t
-parsedate(char *p, TIMEINFO *now)
-{
- struct tm *tm;
- TIMEINFO ti;
- time_t Start;
-
- yyInput = p;
- if (now == NULL) {
- now = &ti;
- GetTimeInfo(&ti);
- }
-
- tm = localtime(&now->time);
- yyYear = tm->tm_year + 1900;
- yyMonth = tm->tm_mon + 1;
- yyDay = tm->tm_mday;
- yyTimezone = now->tzone;
- yyDSTmode = DSTmaybe;
- yyHour = 0;
- yyMinutes = 0;
- yySeconds = 0;
- yyMeridian = MER24;
- yyRelSeconds = 0;
- yyRelMonth = 0;
- yyHaveDate = 0;
- yyHaveRel = 0;
- yyHaveTime = 0;
-
- if (date_parse() || yyHaveTime > 1 || yyHaveDate > 1)
- return -1;
-
- if (yyHaveDate || yyHaveTime) {
- Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
- yyMeridian, yyDSTmode);
- if (Start < 0)
- return -1;
- }
- else {
- Start = now->time;
- if (!yyHaveRel)
- Start -= (tm->tm_hour * 60L + tm->tm_min) * 60L + tm->tm_sec;
- }
-
- Start += yyRelSeconds;
- if (yyRelMonth)
- Start += RelativeMonth(Start, yyRelMonth);
-
- /* Have to do *something* with a legitimate -1 so it's distinguishable
- * from the error return value. (Alternately could set errno on error.) */
- return Start == -1 ? 0 : Start;
-}
-
-
-#if defined(TEST)
-
-#if YYDEBUG
-extern int yydebug;
-#endif /* YYDEBUG */
-
-/* ARGSUSED */
-int
-main(int ac, char *av[])
-{
- char buff[128];
- time_t d;
-
-#if YYDEBUG
- yydebug = 1;
-#endif /* YYDEBUG */
-
- printf("Enter date, or blank line to exit.\n\t> ");
- for ( ; ; ) {
- printf("\t> ");
- fflush(stdout);
- if (gets(buff) == NULL || buff[0] == '\n')
- break;
-#if YYDEBUG
- if (strcmp(buff, "yydebug") == 0) {
- yydebug = !yydebug;
- printf("yydebug = %s\n", yydebug ? "on" : "off");
- continue;
- }
-#endif /* YYDEBUG */
- d = parsedate(buff, (TIMEINFO *)NULL);
- if (d == -1)
- printf("Bad format - couldn't convert.\n");
- else
- printf("%s", ctime(&d));
- }
-
- exit(0);
- /* NOTREACHED */
-}
-#endif /* defined(TEST) */
+++ /dev/null
-/* $Id: perl.c 7929 2008-06-29 17:55:04Z iulius $
-**
-** Embedded Perl support for INN.
-**
-** Originally written by Christophe Wolfhugel <wolf@pasteur.fr> (although
-** he wouldn't recongize it any more, so don't blame him) and modified,
-** expanded, and tweaked by James Brister, Dave Hayes, and Russ Allbery
-** among others.
-**
-** This file contains the Perl linkage shared by both nnrpd and innd. It
-** assumes Perl 5.004 or later.
-*/
-
-#include "config.h"
-
-/* Skip this entire file if DO_PERL (./configure --with-perl) isn't set. */
-#if DO_PERL
-
-#include "clibrary.h"
-#include <fcntl.h>
-#include <syslog.h>
-
-#include "libinn.h"
-
-#include <EXTERN.h>
-#include <perl.h>
-#include <XSUB.h>
-#include "ppport.h"
-
-#include "innperl.h"
-
-/* Provided by DynaLoader but not declared in Perl's header files. */
-extern void boot_DynaLoader(CV *cv);
-
-/* Forward declarations. */
-void PerlSilence(void);
-void PerlUnSilence(void);
-void xs_init(void);
-
-/* Whether Perl filtering is currently active. */
-bool PerlFilterActive = false;
-
-/* The filter sub called (filter_art or filter_post). */
-CV *perl_filter_cv;
-
-/* The embedded Perl interpretor. */
-static PerlInterpreter *PerlCode;
-
-
-static void LogPerl(void)
-{
- syslog(L_NOTICE, "SERVER perl filtering %s", PerlFilterActive ? "enabled" : "disabled");
-}
-
-
-/*
-** Enable or disable the Perl filter. Takes the desired state of the filter
-** as an argument and returns success or failure. Failure to enable
-** indicates that the filter is not defined.
-*/
-bool
-PerlFilter(bool value)
-{
- dSP;
- char *argv[] = { NULL };
-
- if (value == PerlFilterActive)
- return true;
-
- if (!value) {
- /* Execute an end function, if one is defined. */
- if (perl_get_cv("filter_end", false) != NULL) {
- ENTER;
- SAVETMPS;
- perl_call_argv("filter_end", G_EVAL | G_DISCARD | G_NOARGS, argv);
- if (SvTRUE(ERRSV)) {
- syslog (L_ERROR, "SERVER perl function filter_end died: %s",
- SvPV(ERRSV, PL_na));
- (void) POPs;
- }
- FREETMPS;
- LEAVE;
- }
- PerlFilterActive = value;
- LogPerl();
- return true;
- } else {
- if (perl_filter_cv == NULL) {
- syslog (L_ERROR, "SERVER perl filter not defined");
- return false;
- } else {
- PerlFilterActive = value;
- LogPerl();
- return true;
- }
- }
-}
-
-
-
-/*
-** Loads a setup Perl module. startupfile is the name of the file loaded
-** one-time at startup. filterfile is the file containing the filter
-** functions which is loaded at startup and at each reload. function is a
-** function name that must be defined after the filterfile file is loaded for
-** filtering to be turned on to start with.
-*/
-void PERLsetup (char *startupfile, char *filterfile, const char *function)
-{
- if (PerlCode == NULL) {
- /* Perl waits on standard input if not called with '-e'. */
- int argc = 3;
- const char *argv[] = { "innd", "-e", "0", NULL };
- char *env[] = { NULL };
-#ifdef PERL_SYS_INIT3
- PERL_SYS_INIT3(&argc, &argv, &env);
-#endif
- PerlCode = perl_alloc();
- perl_construct(PerlCode);
- perl_parse(PerlCode, xs_init, argc, (char **)argv, env) ;
- }
-
- if (startupfile != NULL && filterfile != NULL) {
- char *evalfile = NULL;
- size_t length;
- dSP;
-
- ENTER ;
- SAVETMPS ;
-
- /* The Perl expression which will be evaluated. */
- length = strlen("do '%s'") + strlen(startupfile);
- evalfile = xmalloc(length);
- snprintf(evalfile, length, "do '%s'", startupfile);
-
- PerlSilence();
- perl_eval_pv(evalfile, TRUE);
- PerlUnSilence();
-
- SPAGAIN ;
-
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog(L_ERROR,"SERVER perl loading %s failed: %s",
- startupfile, SvPV(ERRSV, PL_na)) ;
- PerlFilter (false) ;
-
- } else {
- PERLreadfilter (filterfile,function) ;
- }
-
- FREETMPS ;
- LEAVE ;
- } else {
- PERLreadfilter (filterfile,function) ;
- }
-}
-
-
-/* Load the perl file FILTERFILE. After it is load check that the give
- function is defined. If yes filtering is turned on. If not it is turned
- off. We remember whether the filter function was defined properly so
- that we can catch when the use tries to turn filtering on without the
- the funciton there. */
-int PERLreadfilter(char *filterfile, const char *function)
-{
- dSP ;
- char *argv[] = { NULL };
- char *evalfile = NULL;
- size_t length;
-
- ENTER ;
- SAVETMPS ;
-
- if (perl_get_cv("filter_before_reload", false) != NULL) {
- perl_call_argv("filter_before_reload", G_EVAL|G_DISCARD|G_NOARGS, argv);
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog (L_ERROR,"SERVER perl function filter_before_reload died: %s",
- SvPV(ERRSV, PL_na)) ;
- (void)POPs ;
- PerlFilter (false) ;
- }
- }
-
- /* The Perl expression which will be evaluated. */
- length = strlen("do '%s'") + strlen(filterfile);
- evalfile = xmalloc(length);
- snprintf(evalfile, length, "do '%s'", filterfile);
-
- PerlSilence();
- perl_eval_pv(evalfile, TRUE);
- PerlUnSilence();
-
- free(evalfile);
- evalfile = NULL;
-
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog (L_ERROR,"SERVER perl loading %s failed: %s",
- filterfile, SvPV(ERRSV, PL_na)) ;
- PerlFilter (false) ;
-
- /* If the reload failed we don't want the old definition hanging
- around. */
- length = strlen("undef &%s") + strlen(function);
- evalfile = xmalloc(length);
- snprintf(evalfile, length, "undef &%s", function);
- perl_eval_pv(evalfile, TRUE);
-
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog (L_ERROR,"SERVER perl undef &%s failed: %s",
- function, SvPV(ERRSV, PL_na)) ;
- }
- } else if ((perl_filter_cv = perl_get_cv(function, false)) == NULL) {
- PerlFilter (false) ;
- }
-
- if (perl_get_cv("filter_after_reload", false) != NULL) {
- perl_call_argv("filter_after_reload", G_EVAL|G_DISCARD|G_NOARGS, argv);
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog (L_ERROR,"SERVER perl function filter_after_reload died: %s",
- SvPV(ERRSV, PL_na)) ;
- (void)POPs ;
- PerlFilter (false) ;
- }
- }
-
- FREETMPS ;
- LEAVE ;
-
- return (perl_filter_cv != NULL) ;
-}
-
-
-/*
-** Stops using the Perl filter
-*/
-void PerlClose(void)
-{
- perl_destruct(PerlCode);
- perl_free(PerlCode);
-#ifdef PERL_SYS_TERM
- PERL_SYS_TERM();
-#endif
- PerlFilterActive = false;
-}
-
-/*
-** Redirects STDOUT/STDERR briefly (otherwise PERL complains to the net
-** connection for NNRPD and that just won't do) -- dave@jetcafe.org
-*/
-static int savestdout = 0;
-static int savestderr = 0;
-void PerlSilence(void)
-{
- int newfd;
-
- /* Save the descriptors */
- if ( (savestdout = dup(1)) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant redirect stdout: %m");
- savestdout = 0;
- return;
- }
- if ( (savestderr = dup(2)) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant redirect stderr: %m");
- savestdout = 0;
- savestderr = 0;
- return;
- }
-
- /* Open /dev/null */
- if ((newfd = open("/dev/null",O_WRONLY)) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant open /dev/null: %m");
- savestdout = 0;
- savestderr = 0;
- return;
- }
-
- /* Redirect descriptors */
- if (dup2(newfd,1) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant redirect stdout: %m");
- savestdout = 0;
- return;
- }
-
- if (dup2(newfd,2) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant redirect stderr: %m");
- savestderr = 0;
- return;
- }
- close(newfd);
-}
-
-void PerlUnSilence(void) {
- if (savestdout != 0) {
- if (dup2(savestdout,1) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant restore stdout: %m");
- }
- close(savestdout);
- savestdout = 0;
- }
-
- if (savestderr != 0) {
- if (dup2(savestderr,2) < 0) {
- syslog(L_ERROR,"SERVER perl silence cant restore stderr: %m");
- }
- close(savestderr);
- savestderr = 0;
- }
-}
-
-/*
-** The remainder of this file consists of XS callbacks usable by either
-** innd or nnrpd and initialized automatically when the Perl filter is
-** initialized, as well as the function that initializes them.
-*/
-
-/*
-** Log a message via syslog. Only the first letter of the priority
-** matters, and this function assumes that the controlling program has
-** already done an openlog(). The argument must be a complete message, not
-** a printf-style format.
-*/
-XS(XS_INN_syslog)
-{
- dXSARGS;
- const char *loglevel;
- const char *logmsg;
- int priority;
-
- if (items != 2)
- croak("Usage: INN::syslog(level, message)");
-
- loglevel = (const char *) SvPV(ST(0), PL_na);
- logmsg = (const char *) SvPV(ST(1), PL_na);
-
- switch (*loglevel) {
- default: priority = LOG_NOTICE;
- case 'a': case 'A': priority = LOG_ALERT; break;
- case 'c': case 'C': priority = LOG_CRIT; break;
- case 'e': case 'E': priority = LOG_ERR; break;
- case 'w': case 'W': priority = LOG_WARNING; break;
- case 'n': case 'N': priority = LOG_NOTICE; break;
- case 'i': case 'I': priority = LOG_INFO; break;
- case 'd': case 'D': priority = LOG_DEBUG; break;
- }
- syslog(priority, "filter: %s", logmsg);
- XSRETURN_UNDEF;
-}
-
-extern void
-xs_init()
-{
- dXSUB_SYS;
- newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, "perl.c");
- newXS("INN::syslog", XS_INN_syslog, "perl.c");
-}
-
-#endif /* defined(DO_PERL) */
+++ /dev/null
-/* $Id: pread.c 5049 2001-12-12 09:06:00Z rra $
-**
-** Replacement for a missing pread.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine pread
-** for those platforms that don't have it. Note that pread requires that
-** the file pointer not move and without the library function, we can't
-** copy that behavior; instead, we approximate it by moving the file
-** pointer and then moving it back. This may break threaded programs.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-/* If we're running the test suite, rename pread to avoid conflicts with the
- system version. #undef first because large file support may define a
- macro pread (pointing to pread64) on some platforms (e.g. Solaris). */
-#if TESTING
-# undef pread
-# define pread test_pread
-ssize_t test_pread(int, void *, size_t, off_t);
-#endif
-
-ssize_t
-pread(int fd, void *buf, size_t nbyte, off_t offset)
-{
- off_t current;
- ssize_t nread;
- int oerrno;
-
- current = lseek(fd, 0, SEEK_CUR);
- if (current == (off_t) -1 || lseek(fd, offset, SEEK_SET) == (off_t) -1)
- return -1;
-
- nread = read(fd, buf, nbyte);
-
- /* Ignore errors in restoring the file position; this isn't ideal, but
- reporting a failed read when the read succeeded is worse. Make sure
- that errno, if set, is set by read and not lseek. */
- oerrno = errno;
- lseek(fd, current, SEEK_SET);
- errno = oerrno;
- return nread;
-}
+++ /dev/null
-/* $Id: pwrite.c 5049 2001-12-12 09:06:00Z rra $
-**
-** Replacement for a missing pwrite.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine pwrite
-** for those platforms that don't have it. Note that pwrite requires that
-** the file pointer not move and without the library function, we can't
-** copy that behavior; instead, we approximate it by moving the file
-** pointer and then moving it back. This may break threaded programs.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-/* If we're running the test suite, rename pread to avoid conflicts with the
- system version. #undef first because large file support may define a
- macro pwrite (pointing to pwrite64) on some platforms (e.g. Solaris). */
-#if TESTING
-# undef pwrite
-# define pwrite test_pwrite
-ssize_t test_pwrite(int, const void *, size_t, off_t);
-#endif
-
-ssize_t
-pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
-{
- off_t current;
- ssize_t nwritten;
- int oerrno;
-
- current = lseek(fd, 0, SEEK_CUR);
- if (current == (off_t) -1 || lseek(fd, offset, SEEK_SET) == (off_t) -1)
- return -1;
-
- nwritten = write(fd, buf, nbyte);
-
- /* Ignore errors in restoring the file position; this isn't ideal, but
- reporting a failed write when the write succeeded is worse. Make
- sure that errno, if set, is set by write and not lseek. */
- oerrno = errno;
- lseek(fd, current, SEEK_SET);
- errno = oerrno;
- return nwritten;
-}
+++ /dev/null
-/* $Id: qio.c 6943 2004-06-10 22:20:24Z hkehoe $
-**
-** Quick I/O package.
-**
-** A set of routines optimized for reading through files line by line.
-** This package uses internal buffering like stdio, but is even more
-** aggressive about its buffering. The basic read call reads a single line
-** and returns the whole line, provided that it can fit in the buffer.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/qio.h"
-#include "libinn.h"
-
-/* A reasonable default buffer size to use. */
-#define QIO_BUFFERSIZE 8192
-
-/*
-** Given a file descriptor, return a reasonable buffer size to use for that
-** file. Uses st_blksize if available and reasonable, QIO_BUFFERSIZE
-** otherwise.
-*/
-static size_t
-buffer_size(int fd)
-{
- size_t size = QIO_BUFFERSIZE;
-
-#if HAVE_ST_BLKSIZE
- struct stat st;
-
- /* The Solaris 2.6 man page says that st_blksize is not defined for
- block or character special devices (and could contain garbage), so
- only use this value for regular files. */
- if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
- size = st.st_blksize;
- if (size > (4 * QIO_BUFFERSIZE) || size == 0)
- size = QIO_BUFFERSIZE;
- else
- while(size < QIO_BUFFERSIZE)
- size += st.st_blksize;
- }
-#endif /* HAVE_ST_BLKSIZE */
-
- return size;
-}
-
-
-/*
-** Open a quick file from a descriptor.
-*/
-QIOSTATE *
-QIOfdopen(const int fd)
-{
- QIOSTATE *qp;
-
- qp = xmalloc(sizeof(*qp));
- qp->_fd = fd;
- qp->_length = 0;
- qp->_size = buffer_size(fd);
- qp->_buffer = xmalloc(qp->_size);
- qp->_start = qp->_buffer;
- qp->_end = qp->_buffer;
- qp->_count = 0;
- qp->_flag = QIO_ok;
-
- return qp;
-}
-
-
-/*
-** Open a quick file from a file name.
-*/
-QIOSTATE *
-QIOopen(const char *name)
-{
- int fd;
-
- fd = open(name, O_RDONLY);
- if (fd < 0)
- return NULL;
- return QIOfdopen(fd);
-}
-
-
-/*
-** Close an open quick file.
-*/
-void
-QIOclose(QIOSTATE *qp)
-{
- close(qp->_fd);
- free(qp->_buffer);
- free(qp);
-}
-
-
-/*
-** Rewind a quick file. Reads the first buffer full of data automatically,
-** anticipating the first read from the file. Returns -1 on error, 0 on
-** success.
-*/
-int
-QIOrewind(QIOSTATE *qp)
-{
- ssize_t nread;
-
- if (lseek(qp->_fd, 0, SEEK_SET) < 0)
- return -1;
- nread = read(qp->_fd, qp->_buffer, qp->_size);
- if (nread < 0)
- return nread;
- qp->_count = nread;
- qp->_start = qp->_buffer;
- qp->_end = qp->_buffer + nread;
- return 0;
-}
-
-
-/*
-** Get the next newline-terminated line from a quick file, replacing the
-** newline with a nul. Returns a pointer to that line on success and NULL
-** on failure or end of file, with _flag set appropriately.
-*/
-char *
-QIOread(QIOSTATE *qp)
-{
- char *p, *line;
- ssize_t nread;
- size_t nleft;
-
- /* Loop until we get a result or fill the buffer. */
- qp->_flag = QIO_ok;
- while (1) {
- nleft = qp->_end - qp->_start;
-
- /* If nleft <= 0, the buffer currently contains no data that hasn't
- previously been returned by QIOread, so we can overwrite the
- buffer with new data. Otherwise, first check the existing data
- to see if we have a full line. */
- if (nleft <= 0) {
- qp->_start = qp->_buffer;
- qp->_end = qp->_buffer;
- } else {
- p = memchr(qp->_start, '\n', nleft);
- if (p != NULL) {
- *p = '\0';
- qp->_length = p - qp->_start;
- line = qp->_start;
- qp->_start = p + 1;
- return (qp->_flag == QIO_long) ? NULL : line;
- }
-
- /* Not there. See if our buffer is full. If so, tag as having
- seen too long of a line. This will cause us to keep reading
- as normal until we finally see the end of a line and then
- return NULL. */
- if (nleft >= qp->_size) {
- qp->_flag = QIO_long;
- qp->_start = qp->_end;
- nleft = 0;
- }
-
- /* We need to read more data. If there's read data in buffer,
- then move the unread data down to the beginning of the buffer
- first. */
- if (qp->_start > qp->_buffer) {
- if (nleft > 0)
- memmove(qp->_buffer, qp->_start, nleft);
- qp->_start = qp->_buffer;
- qp->_end = qp->_buffer + nleft;
- }
- }
-
- /* Read in some more data, and then let the loop try to find the
- newline again or discover that the line is too long. */
- do {
- nread = read(qp->_fd, qp->_end, qp->_size - nleft);
- } while (nread == -1 && errno == EINTR);
- if (nread <= 0) {
- if (nread < 0)
- qp->_flag = QIO_error;
- return NULL;
- }
- qp->_count += nread;
- qp->_end += nread;
- }
-}
+++ /dev/null
-/* $Id: radix32.c 6118 2003-01-13 06:44:24Z rra $
-**
-** Radix-32 strings divide a number into five-bit nibbles and use the
-** alphabet 0..9a..v to represent 0..32.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <time.h>
-
-#include "libinn.h"
-
-
-static char ALPHABET[] =
- "0123456789abcdefghijklmnopqrstuv";
-
-
-/*
-** Turn a number into a Radix-32 string. Assume the number fits into
-** 32 bits.
-*/
-void Radix32(unsigned long l, char *buff)
-{
- char *p;
- int i;
- char temp[10];
-
- /* Simple sanity checks. */
- if ((l &= 0xFFFFFFFFL) == 0) {
- *buff++ = ALPHABET[0];
- *buff = '\0';
- return;
- }
-
- /* Format the string, in reverse. */
- for (p = temp; l; l >>= 5)
- *p++ = ALPHABET[(int)(l & 037)];
-
- /* Reverse it. */
- for (i = p - temp; --i >= 0; )
- *buff++ = *--p;
- *buff = '\0';
-}
-
-
-#if 0
-/*
-** Return a Radix-32 string as a number, or ~0 on error.
-*/
-unsigned long
-Decode32(p)
- char *p;
-{
- unsigned long l;
- char *cp;
-
- for (l = 0; *p; p++) {
- if ((cp = strchr(ALPHABET, *p)) == NULL)
- return ~0;
- l = (l << 6) + cp - ALPHABET;
- }
- return l;
-}
-#endif /* 0 */
+++ /dev/null
-/* $Id: readin.c 6394 2003-07-12 19:13:14Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "libinn.h"
-
-
-/*
-** Read a big amount, looping until it is all done. Return true if
-** successful.
-*/
-int xread(int fd, char *p, off_t i)
-{
- int count;
-
- for ( ; i; p += count, i -= count) {
- do {
- count = read(fd, p, i);
- } while (count == -1 && errno == EINTR);
- if (count <= 0)
- return -1;
- }
- return 0;
-}
-
-
-/*
-** Read an already-open file into memory.
-*/
-char *ReadInDescriptor(int fd, struct stat *Sbp)
-{
- struct stat mystat;
- char *p;
- int oerrno;
-
- if (Sbp == NULL)
- Sbp = &mystat;
-
- /* Get the size, and enough memory. */
- if (fstat(fd, Sbp) < 0) {
- oerrno = errno;
- close(fd);
- errno = oerrno;
- return NULL;
- }
- p = xmalloc(Sbp->st_size + 1);
-
- /* Slurp, slurp. */
- if (xread(fd, p, Sbp->st_size) < 0) {
- oerrno = errno;
- free(p);
- close(fd);
- errno = oerrno;
- return NULL;
- }
-
- /* Terminate the string; terminate the routine. */
- p[Sbp->st_size] = '\0';
- return p;
-}
-
-
-/*
-** Read a file into allocated memory. Optionally fill in the stat(2) data.
-** Return a pointer to the file contents, or NULL on error.
-*/
-char *ReadInFile(const char *name, struct stat *Sbp)
-{
- char *p;
- int fd;
-
- if ((fd = open(name, O_RDONLY)) < 0)
- return NULL;
-
- p = ReadInDescriptor(fd, Sbp);
- close(fd);
- return p;
-}
+++ /dev/null
-/* $Id: reservedfd.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <fcntl.h>
-
-#include "libinn.h"
-
-
-static FILE **Reserved_fd = NULL;
-static int Maxfd = -1;
-
-bool
-fdreserve(int fdnum)
-{
- static int allocated = 0;
- int i, start = allocated;
-
- if (fdnum <= 0) {
- if (Reserved_fd != NULL) {
- for (i = 0 ; i < Maxfd ; i++) {
- fclose(Reserved_fd[i]);
- }
- free(Reserved_fd);
- Reserved_fd = NULL;
- }
- Maxfd = -1;
- allocated = 0;
- return true;
- }
- if (Reserved_fd == NULL) {
- Reserved_fd = xmalloc(fdnum * sizeof(FILE *));
- allocated = fdnum;
- } else {
- if (allocated < fdnum) {
- Reserved_fd = xrealloc(Reserved_fd, fdnum * sizeof(FILE *));
- allocated = fdnum;
- } else if (Maxfd > fdnum) {
- for (i = fdnum ; i < Maxfd ; i++) {
- fclose(Reserved_fd[i]);
- }
- }
- }
- for (i = start ; i < fdnum ; i++) {
- if (((Reserved_fd[i] = fopen("/dev/null", "r")) == NULL)){
- for (--i ; i >= 0 ; i--)
- fclose(Reserved_fd[i]);
- free(Reserved_fd);
- Reserved_fd = NULL;
- allocated = 0;
- Maxfd = -1;
- return false;
- }
- }
- Maxfd = fdnum;
- return true;
-}
-
-FILE *
-Fopen(const char *p, const char *type, int xindex)
-{
- FILE *nfp;
- if (p == NULL || *p == '\0')
- return NULL;
- if (xindex < 0 || xindex > Maxfd || Reserved_fd[xindex] == NULL)
- return fopen(p, type);
- if ((nfp = freopen(p, type, Reserved_fd[xindex])) == NULL) {
- Reserved_fd[xindex] = freopen("/dev/null", "r", Reserved_fd[xindex]);
- return NULL;
- }
- return (Reserved_fd[xindex] = nfp);
-}
-
-int
-Fclose(FILE *fp)
-{
- int i;
-
- if (fp == NULL)
- return 0;
- for (i = 0 ; i < Maxfd ; i++) {
- if (Reserved_fd[i] == fp)
- break;
- }
- if (i >= Maxfd)
- return fclose(fp);
- Reserved_fd[i] = freopen("/dev/null", "r", Reserved_fd[i]);
- return 0;
-}
+++ /dev/null
-/* $Id: resource.c 6135 2003-01-19 01:15:40Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-
-#ifdef HAVE_GETRUSAGE
-
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#define TIMEVALasDOUBLE(t) \
- ((double)(t).tv_sec + ((double)(t).tv_usec) / 1000000.0)
-
-int getrusage(int who, struct rusage *rusage);
-
-int GetResourceUsage(double *usertime, double *systime)
-{
- struct rusage R;
-
- if (getrusage(RUSAGE_SELF, &R) < 0)
- return -1;
- *usertime = TIMEVALasDOUBLE(R.ru_utime);
- *systime = TIMEVALasDOUBLE(R.ru_stime);
- return 0;
-}
-
-#else /* HAVE_GETRUSAGE */
-
-#include <sys/param.h>
-#include <sys/times.h>
-
-#if !defined(HZ)
-#define HZ 60
-#endif /* !defined(HZ) */
-
-#define CPUTIMEasDOUBLE(t1, t2) ((double)(t1 + t2) / (double)HZ)
-
-int GetResourceUsage(double *usertime, double *systime)
-{
- struct tms T;
-
- if (times(&T) == -1)
- return -1;
- *usertime = CPUTIMEasDOUBLE(T.tms_utime, T.tms_cutime);
- *systime = CPUTIMEasDOUBLE(T.tms_stime, T.tms_cstime);
- return 0;
-}
-
-#endif /* !HAVE_GETRUSAGE */
+++ /dev/null
-/* $Id: sendarticle.c 4076 2000-10-05 00:36:52Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-#include "nntp.h"
-
-
-/*
-** Send a string of one or more lines down a stdio FILE using RFC977
-** conventions. Return -1 on error.
-*/
-int NNTPsendarticle(char *p, FILE *F, bool Terminate)
-{
- char *next;
-
- for (; p && *p; next[-1] = '\n', p = next) {
- /* Get pointer to next line. Truncate long lines. */
- if ((next = strchr(p, '\n')) != NULL)
- *next++ = '\0';
-
- /* Write line. */
- if (*p == '.' && putc('.', F) == EOF)
- return -1;
- if (fprintf(F, "%s\r\n", p) == EOF)
- return -1;
-
- /* Done? */
- if (next == NULL)
- break;
- }
-
- if (Terminate && fprintf(F, ".\r\n") == EOF)
- return -1;
-
- return fflush(F) == EOF || ferror(F) ? -1 : 0;
-}
+++ /dev/null
-/* $Id: sendpass.c 7145 2005-04-10 03:28:01Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-
-
-/*
-** Send authentication information to an NNTP server.
-*/
-int NNTPsendpassword(char *server, FILE *FromServer, FILE *ToServer)
-{
- FILE *F;
- char *p;
- char *path;
- char buff[SMBUF];
- char input[SMBUF];
- char *user;
- char *pass;
- char *style;
- int oerrno;
-
- /* Default to innconf->server. If that's not set either, error out. Fake
- errno since some of our callers rely on it. */
- if (server == NULL)
- server = innconf->server;
- if (server == NULL) {
- errno = EINVAL;
- return -1;
- }
-
- /* Open the password file; coarse check on errno, but good enough. */
- path = concatpath(innconf->pathetc, _PATH_NNTPPASS);
- F = fopen(path, "r");
- free(path);
- if (F == NULL)
- return errno == EPERM ? -1 : 0;
-
- /* Scan the file, skipping blank and comment lines. */
- while (fgets(buff, sizeof buff, F) != NULL) {
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if (buff[0] == '\0' || buff[0] == '#')
- continue;
-
- /* Parse the line. */
- if ((user = strchr(buff, ':')) == NULL)
- continue;
- *user++ = '\0';
- if ((pass = strchr(user, ':')) == NULL)
- continue;
- *pass++ = '\0';
- if ((style = strchr(pass, ':')) != NULL) {
- *style++ = '\0';
- if (strcmp(style, "authinfo") != 0) {
- errno = EDOM;
- break;
- }
- }
-
- if (strcasecmp(server, buff) != 0)
- continue;
-
- if (*user) {
- /* Send the first part of the command, get a reply. */
- fprintf(ToServer, "authinfo user %s\r\n", user);
- if (fflush(ToServer) == EOF || ferror(ToServer))
- break;
- if (fgets(input, sizeof input, FromServer) == NULL
- || atoi(input) != NNTP_AUTH_NEXT_VAL)
- break;
- }
-
- if (*pass) {
- /* Send the second part of the command, get a reply. */
- fprintf(ToServer, "authinfo pass %s\r\n", pass);
- if (fflush(ToServer) == EOF || ferror(ToServer))
- break;
- if (fgets(input, sizeof input, FromServer) == NULL
- || atoi(input) != NNTP_AUTH_OK_VAL)
- break;
- }
-
- /* Authenticated. */
- fclose(F);
- return 0;
- }
-
- /* End of file without finding a password, that's okay. */
- if (feof(F)) {
- fclose(F);
- return 0;
- }
-
- /* Save errno, close the file, fail. */
- oerrno = errno;
- fclose(F);
- errno = oerrno;
- return -1;
-}
+++ /dev/null
-/* $Id: sequence.c 4871 2001-07-09 08:09:58Z alexk $
-**
-** Sequence space arithmetic routines.
-**
-** This is a set of routines for implementing so called sequence
-** space arithmetic (typically used for DNS serial numbers). The
-** implementation here is taken from RFC 1982.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <limits.h>
-#include "inn/sequence.h"
-
-
-/*
-** compare two unsigned long numbers using sequence space arithmetic
-**
-** returns:
-** 0 - i1 = i2
-** -1 - i1 < i2
-** 1 - i1 > i2
-** INT_MAX - undefined
-*/
-int
-seq_lcompare(unsigned long i1, unsigned long i2)
-{
- if (i1 == i2)
- return 0;
- else if ((i1 < i2 && i2 - i1 < (1 + ULONG_MAX / 2)) ||
- (i1 > i2 && i1 - i2 > (1 + ULONG_MAX / 2)))
- return -1;
- else if ((i1 < i2 && i2 - i1 > (1 + ULONG_MAX / 2)) ||
- (i1 > i2 && i1 - i2 < (1 + ULONG_MAX / 2)))
- return 1;
- return INT_MAX;
-}
+++ /dev/null
-/* $Id: setenv.c 5713 2002-09-01 03:04:10Z rra $
-**
-** Replacement for a missing setenv.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine setenv
-** for those platforms that don't have it.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-/* If we're running the test suite, rename setenv to avoid conflicts with
- the system version. */
-#if TESTING
-# define setenv test_setenv
-int test_setenv(const char *, const char *, int);
-#endif
-
-int
-setenv(const char *name, const char *value, int overwrite)
-{
- char *envstring;
-
- if (!overwrite && getenv(name) != NULL)
- return 0;
-
- /* Allocate memory for the environment string. We intentionally don't
- use concat here, or the xmalloc family of allocation routines, since
- the intention is to provide a replacement for the standard library
- function which sets errno and returns in the event of a memory
- allocation failure. */
- envstring = malloc(strlen(name) + 1 + strlen(value) + 1);
- if (envstring == NULL)
- return -1;
-
- /* Build the environment string and add it to the environment using
- putenv. Systems without putenv lose, but XPG4 requires it. */
- strcpy(envstring, name);
- strcat(envstring, "=");
- strcat(envstring, value);
- return putenv(envstring);
-
- /* Note that the memory allocated is not freed. This is intentional;
- many implementations of putenv assume that the string passed to
- putenv will never be freed and don't make a copy of it. Repeated use
- of this function will therefore leak memory, since most
- implementations of putenv also don't free strings removed from the
- environment (due to being overwritten). */
-}
+++ /dev/null
-/* $Id: seteuid.c 3839 2000-08-29 04:50:18Z rra $
-**
-** Replacement for a missing seteuid.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Some systems don't have seteuid but do have setreuid. setreuid with
-** -1 given for the real UID is equivalent to seteuid on systems with
-** POSIX saved UIDs. On systems without POSIX saved UIDs, we'd lose our
-** ability to regain privileges if we just set the effective UID, so
-** instead fake a saved UID by setting the real UID to the current
-** effective UID, using the real UID as the saved UID.
-**
-** Note that swapping UIDs doesn't work on AIX, but AIX has saved UIDs.
-** Note also that systems without setreuid lose, and that we assume that
-** any system with seteuid has saved UIDs.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-int
-seteuid(uid_t euid)
-{
- int ruid;
-
-#ifdef _POSIX_SAVED_IDS
- ruid = -1;
-#else
- ruid = geteuid();
-#endif
- return setreuid(ruid, euid);
-}
+++ /dev/null
-/* $Id: setproctitle.c 5943 2002-12-08 02:28:06Z rra $
-**
-** Replacement for a missing setproctitle.
-**
-** Provides the same functionality as the BSD function setproctitle on hosts
-** where modifying argv will produce those results, or on HP-UX (which has
-** its own peculiar way of doing this). This may be ineffective on some
-** platforms.
-**
-** Before calling setproctitle, it is *required* that setproctitle_init be
-** called, passing it argc and argv as arguments. setproctitle_init will be
-** stubbed out on those platforms that don't need it.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/setproctitle.h"
-
-#include "inn/messages.h"
-
-#if HAVE_PSTAT
-
-#include <sys/param.h>
-#include <sys/pstat.h>
-
-void
-setproctitle(const char *format, ...)
-{
- va_list args;
- char title[BUFSIZ];
- union pstun un;
- ssize_t delta = 0;
-
- if (message_program_name != NULL) {
- delta = snprintf(title, sizeof(title), "%s: ", message_program_name);
- if (delta < 0)
- delta = 0;
- }
- va_start(args, format);
- vsnprintf(title + delta, sizeof(title) - delta, format, args);
- va_end(args);
- un.pst_command = title;
- pstat(PSTAT_SETCMD, un, strlen(title), 0, 0);
-}
-
-#else
-
-static char *title_start = NULL;
-static char *title_end = NULL;
-
-void
-setproctitle_init(int argc, char *argv[])
-{
- title_start = argv[0];
- title_end = argv[argc - 1] + strlen(argv[argc - 1]) - 1;
-}
-
-void
-setproctitle(const char *format, ...)
-{
- va_list args;
- size_t length;
- ssize_t delta;
- char *title;
-
- if (title_start == NULL || title_end == NULL) {
- warn("setproctitle called without setproctitle_init");
- return;
- }
-
- /* setproctitle prepends the program name to its arguments. Our emulation
- should therefore do the same thing. However, some operating systems
- seem to do that automatically even when we completely overwrite argv,
- so start our title with a - so that they'll instead put (nnrpd) at the
- end, thinking we're swapped out. */
- title = title_start;
- *title++ = '-';
- *title++ = ' ';
- length = title_end - title_start - 2;
-
- /* Now, put in the actual content. Get the program name from
- message_program_name if it's set. */
- if (message_program_name != NULL) {
- delta = snprintf(title, length, "%s: ", message_program_name);
- if (delta < 0 || (size_t) delta > length)
- return;
- if (delta > 0) {
- title += delta;
- length -= delta;
- }
- }
- va_start(args, format);
- delta = vsnprintf(title, length, format, args);
- va_end(args);
- if (delta < 0 || (size_t) delta > length)
- return;
- if (delta > 0) {
- title += delta;
- length -= delta;
- }
- for (; length > 1; length--, title++)
- *title = ' ';
- *title = '\0';
-}
-
-#endif /* !HAVE_PSTAT */
+++ /dev/null
-/* $Id: snprintf.c 7230 2005-04-16 23:33:17Z rra $
-**
-** Replacement for a missing snprintf or vsnprintf.
-**
-** The following implementation of snprintf was taken mostly verbatim from
-** <http://www.fiction.net/~blong/programs/>; it is the version of snprintf
-** used in Mutt.
-**
-** Please do not reformat or otherwise change this file more than
-** necessary so that later merges with the original source are easy.
-** Bug fixes and improvements should be sent back to the original author.
-*/
-
-/* If we're running the test suite, rename snprintf and vsnprintf to avoid
- conflicts with the system version. */
-#if TESTING
-# define snprintf test_snprintf
-# define vsnprintf test_vsnprintf
-#endif
-
-/*
- * Copyright Patrick Powell 1995
- * This code is based on code written by Patrick Powell (papowell@astart.com)
- * It may be used for any purpose as long as this notice remains intact
- * on all source code distributions
- */
-
-/**************************************************************
- * Original:
- * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
- * A bombproof version of doprnt (dopr) included.
- * Sigh. This sort of thing is always nasty do deal with. Note that
- * the version here does not include floating point...
- *
- * snprintf() is used instead of sprintf() as it does limit checks
- * for string length. This covers a nasty loophole.
- *
- * The other functions are there to prevent NULL pointers from
- * causing nast effects.
- *
- * More Recently:
- * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
- * This was ugly. It is still ugly. I opted out of floating point
- * numbers, but the formatter understands just about everything
- * from the normal C string format, at least as far as I can tell from
- * the Solaris 2.5 printf(3S) man page.
- *
- * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
- * Ok, added some minimal floating point support, which means this
- * probably requires libm on most operating systems. Don't yet
- * support the exponent (e,E) and sigfig (g,G). Also, fmtint()
- * was pretty badly broken, it just wasn't being exercised in ways
- * which showed it, so that's been fixed. Also, formated the code
- * to mutt conventions, and removed dead code left over from the
- * original. Also, there is now a builtin-test, just compile with:
- * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
- * and run snprintf for results.
- *
- * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
- * The PGP code was using unsigned hexadecimal formats.
- * Unfortunately, unsigned formats simply didn't work.
- *
- * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
- * The original code assumed that both snprintf() and vsnprintf() were
- * missing. Some systems only have snprintf() but not vsnprintf(), so
- * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
- *
- * Andrew Tridgell (tridge@samba.org) Oct 1998
- * fixed handling of %.0f
- * added test for HAVE_LONG_DOUBLE
- *
- * Russ Allbery <rra@stanford.edu> 2000-08-26
- * fixed return value to comply with C99
- * fixed handling of snprintf(NULL, ...)
- *
- * Hrvoje Niksic <hniksic@arsdigita.com> 2000-11-04
- * include <stdio.h> for NULL.
- * added support for long long.
- * don't declare argument types to (v)snprintf if stdarg is not used.
- *
- **************************************************************/
-
-#include "config.h"
-#include <string.h>
-#include <ctype.h>
-#include <sys/types.h>
-
-#ifndef NULL
-# define NULL 0
-#endif
-
-/* varargs declarations: */
-
-#include <stdarg.h>
-#define HAVE_STDARGS /* let's hope that works everywhere (mj) */
-#define VA_LOCAL_DECL va_list ap
-#define VA_START(f) va_start(ap, f)
-#define VA_SHIFT(v,t) ; /* no-op for ANSI */
-#define VA_END va_end(ap)
-
-#ifdef HAVE_LONG_DOUBLE
-#define LDOUBLE long double
-#else
-#define LDOUBLE double
-#endif
-
-#ifdef HAVE_LONG_LONG
-# define LLONG long long
-#else
-# define LLONG long
-#endif
-
-int snprintf (char *str, size_t count, const char *fmt, ...);
-int vsnprintf (char *str, size_t count, const char *fmt, va_list arg);
-
-static int dopr (char *buffer, size_t maxlen, const char *format,
- va_list args);
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- const char *value, int flags, int min, int max);
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags);
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags);
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
-
-/*
- * dopr(): poor man's version of doprintf
- */
-
-/* format read states */
-#define DP_S_DEFAULT 0
-#define DP_S_FLAGS 1
-#define DP_S_MIN 2
-#define DP_S_DOT 3
-#define DP_S_MAX 4
-#define DP_S_MOD 5
-#define DP_S_MOD_L 6
-#define DP_S_CONV 7
-#define DP_S_DONE 8
-
-/* format flags - Bits */
-#define DP_F_MINUS (1 << 0)
-#define DP_F_PLUS (1 << 1)
-#define DP_F_SPACE (1 << 2)
-#define DP_F_NUM (1 << 3)
-#define DP_F_ZERO (1 << 4)
-#define DP_F_UP (1 << 5)
-#define DP_F_UNSIGNED (1 << 6)
-
-/* Conversion Flags */
-#define DP_C_SHORT 1
-#define DP_C_LONG 2
-#define DP_C_LLONG 3
-#define DP_C_LDOUBLE 4
-
-#define char_to_int(p) (p - '0')
-#define MAX(p,q) ((p >= q) ? p : q)
-#define MIN(p,q) ((p <= q) ? p : q)
-
-static int dopr (char *buffer, size_t maxlen, const char *format, va_list args)
-{
- char ch;
- LLONG value;
- LDOUBLE fvalue;
- char *strvalue;
- int min;
- int max;
- int state;
- int flags;
- int cflags;
- int total;
- size_t currlen;
-
- state = DP_S_DEFAULT;
- currlen = flags = cflags = min = 0;
- max = -1;
- ch = *format++;
- total = 0;
-
- while (state != DP_S_DONE)
- {
- if (ch == '\0')
- state = DP_S_DONE;
-
- switch(state)
- {
- case DP_S_DEFAULT:
- if (ch == '%')
- state = DP_S_FLAGS;
- else
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- ch = *format++;
- break;
- case DP_S_FLAGS:
- switch (ch)
- {
- case '-':
- flags |= DP_F_MINUS;
- ch = *format++;
- break;
- case '+':
- flags |= DP_F_PLUS;
- ch = *format++;
- break;
- case ' ':
- flags |= DP_F_SPACE;
- ch = *format++;
- break;
- case '#':
- flags |= DP_F_NUM;
- ch = *format++;
- break;
- case '0':
- flags |= DP_F_ZERO;
- ch = *format++;
- break;
- default:
- state = DP_S_MIN;
- break;
- }
- break;
- case DP_S_MIN:
- if ('0' <= ch && ch <= '9')
- {
- min = 10*min + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- min = va_arg (args, int);
- ch = *format++;
- state = DP_S_DOT;
- }
- else
- state = DP_S_DOT;
- break;
- case DP_S_DOT:
- if (ch == '.')
- {
- state = DP_S_MAX;
- ch = *format++;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MAX:
- if ('0' <= ch && ch <= '9')
- {
- if (max < 0)
- max = 0;
- max = 10*max + char_to_int (ch);
- ch = *format++;
- }
- else if (ch == '*')
- {
- max = va_arg (args, int);
- ch = *format++;
- state = DP_S_MOD;
- }
- else
- state = DP_S_MOD;
- break;
- case DP_S_MOD:
- switch (ch)
- {
- case 'h':
- cflags = DP_C_SHORT;
- ch = *format++;
- break;
- case 'l':
- cflags = DP_C_LONG;
- ch = *format++;
- break;
- case 'L':
- cflags = DP_C_LDOUBLE;
- ch = *format++;
- break;
- default:
- break;
- }
- if (cflags != DP_C_LONG)
- state = DP_S_CONV;
- else
- state = DP_S_MOD_L;
- break;
- case DP_S_MOD_L:
- switch (ch)
- {
- case 'l':
- cflags = DP_C_LLONG;
- ch = *format++;
- break;
- default:
- break;
- }
- state = DP_S_CONV;
- break;
- case DP_S_CONV:
- switch (ch)
- {
- case 'd':
- case 'i':
- if (cflags == DP_C_SHORT)
- value = (short int) va_arg (args, int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, LLONG);
- else
- value = va_arg (args, int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'o':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = (unsigned short int) va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
- break;
- case 'u':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = (unsigned short int) va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
- break;
- case 'X':
- flags |= DP_F_UP;
- case 'x':
- flags |= DP_F_UNSIGNED;
- if (cflags == DP_C_SHORT)
- value = (unsigned short int) va_arg (args, unsigned int);
- else if (cflags == DP_C_LONG)
- value = va_arg (args, unsigned long int);
- else if (cflags == DP_C_LLONG)
- value = va_arg (args, unsigned LLONG);
- else
- value = va_arg (args, unsigned int);
- total += fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
- break;
- case 'f':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- /* um, floating point? */
- total += fmtfp (buffer, &currlen, maxlen, fvalue, min, max, flags);
- break;
- case 'E':
- flags |= DP_F_UP;
- case 'e':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- break;
- case 'G':
- flags |= DP_F_UP;
- case 'g':
- if (cflags == DP_C_LDOUBLE)
- fvalue = va_arg (args, LDOUBLE);
- else
- fvalue = va_arg (args, double);
- break;
- case 'c':
- total += dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
- break;
- case 's':
- strvalue = va_arg (args, char *);
- total += fmtstr (buffer, &currlen, maxlen, strvalue, flags, min, max);
- break;
- case 'p':
- strvalue = va_arg (args, void *);
- total += fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min,
- max, flags);
- break;
- case 'n':
- if (cflags == DP_C_SHORT)
- {
- short int *num;
- num = va_arg (args, short int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LONG)
- {
- long int *num;
- num = va_arg (args, long int *);
- *num = currlen;
- }
- else if (cflags == DP_C_LLONG)
- {
- LLONG *num;
- num = va_arg (args, LLONG *);
- *num = currlen;
- }
- else
- {
- int *num;
- num = va_arg (args, int *);
- *num = currlen;
- }
- break;
- case '%':
- total += dopr_outch (buffer, &currlen, maxlen, ch);
- break;
- case 'w':
- /* not supported yet, treat as next char */
- ch = *format++;
- break;
- default:
- /* Unknown, skip */
- break;
- }
- ch = *format++;
- state = DP_S_DEFAULT;
- flags = cflags = min = 0;
- max = -1;
- break;
- case DP_S_DONE:
- break;
- default:
- /* hmm? */
- break; /* some picky compilers need this */
- }
- }
- if (buffer != NULL)
- {
- if (currlen < maxlen - 1)
- buffer[currlen] = '\0';
- else
- buffer[maxlen - 1] = '\0';
- }
- return total;
-}
-
-static int fmtstr (char *buffer, size_t *currlen, size_t maxlen,
- const char *value, int flags, int min, int max)
-{
- int padlen, strln; /* amount to pad */
- int cnt = 0;
- int total = 0;
-
- if (value == 0)
- {
- value = "<NULL>";
- }
-
- for (strln = 0; value[strln]; ++strln); /* strlen */
- if (max >= 0 && max < strln)
- strln = max;
- padlen = min - strln;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justify */
-
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- while (*value && ((max < 0) || (cnt < max)))
- {
- total += dopr_outch (buffer, currlen, maxlen, *value++);
- ++cnt;
- }
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
- return total;
-}
-
-/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
-
-static int fmtint (char *buffer, size_t *currlen, size_t maxlen,
- LLONG value, int base, int min, int max, int flags)
-{
- int signvalue = 0;
- unsigned LLONG uvalue;
- char convert[24];
- unsigned int place = 0;
- int spadlen = 0; /* amount to space pad */
- int zpadlen = 0; /* amount to zero pad */
- const char *digits;
- int total = 0;
-
- if (max < 0)
- max = 0;
-
- uvalue = value;
-
- if(!(flags & DP_F_UNSIGNED))
- {
- if( value < 0 ) {
- signvalue = '-';
- uvalue = -value;
- }
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
- }
-
- if (flags & DP_F_UP)
- /* Should characters be upper case? */
- digits = "0123456789ABCDEF";
- else
- digits = "0123456789abcdef";
-
- do {
- convert[place++] = digits[uvalue % (unsigned)base];
- uvalue = (uvalue / (unsigned)base );
- } while(uvalue && (place < sizeof (convert)));
- if (place == sizeof (convert)) place--;
- convert[place] = 0;
-
- zpadlen = max - place;
- spadlen = min - MAX ((unsigned int)max, place) - (signvalue ? 1 : 0);
- if (zpadlen < 0) zpadlen = 0;
- if (spadlen < 0) spadlen = 0;
- if (flags & DP_F_ZERO)
- {
- zpadlen = MAX(zpadlen, spadlen);
- spadlen = 0;
- }
- if (flags & DP_F_MINUS)
- spadlen = -spadlen; /* Left Justifty */
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
- zpadlen, spadlen, min, max, place));
-#endif
-
- /* Spaces */
- while (spadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --spadlen;
- }
-
- /* Sign */
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- /* Zeros */
- if (zpadlen > 0)
- {
- while (zpadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
- }
-
- /* Digits */
- while (place > 0)
- total += dopr_outch (buffer, currlen, maxlen, convert[--place]);
-
- /* Left Justified spaces */
- while (spadlen < 0) {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++spadlen;
- }
-
- return total;
-}
-
-static LDOUBLE abs_val (LDOUBLE value)
-{
- LDOUBLE result = value;
-
- if (value < 0)
- result = -value;
-
- return result;
-}
-
-static LDOUBLE pow10 (int exp)
-{
- LDOUBLE result = 1;
-
- while (exp)
- {
- result *= 10;
- exp--;
- }
-
- return result;
-}
-
-static LLONG round (LDOUBLE value)
-{
- LLONG intpart;
-
- intpart = value;
- value = value - intpart;
- if (value >= 0.5)
- intpart++;
-
- return intpart;
-}
-
-static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
- LDOUBLE fvalue, int min, int max, int flags)
-{
- int signvalue = 0;
- LDOUBLE ufvalue;
- char iconvert[20];
- char fconvert[20];
- int iplace = 0;
- int fplace = 0;
- int padlen = 0; /* amount to pad */
- int zpadlen = 0;
- int caps = 0;
- int total = 0;
- LLONG intpart;
- LLONG fracpart;
-
- /*
- * AIX manpage says the default is 0, but Solaris says the default
- * is 6, and sprintf on AIX defaults to 6
- */
- if (max < 0)
- max = 6;
-
- ufvalue = abs_val (fvalue);
-
- if (fvalue < 0)
- signvalue = '-';
- else
- if (flags & DP_F_PLUS) /* Do a sign (+/i) */
- signvalue = '+';
- else
- if (flags & DP_F_SPACE)
- signvalue = ' ';
-
-#if 0
- if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
-#endif
-
- intpart = ufvalue;
-
- /*
- * Sorry, we only support 9 digits past the decimal because of our
- * conversion method
- */
- if (max > 9)
- max = 9;
-
- /* We "cheat" by converting the fractional part to integer by
- * multiplying by a factor of 10
- */
- fracpart = round ((pow10 (max)) * (ufvalue - intpart));
-
- if (fracpart >= pow10 (max))
- {
- intpart++;
- fracpart -= pow10 (max);
- }
-
-#ifdef DEBUG_SNPRINTF
- dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
-#endif
-
- /* Convert integer part */
- do {
- iconvert[iplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
- intpart = (intpart / 10);
- } while(intpart && (iplace < 20));
- if (iplace == 20) iplace--;
- iconvert[iplace] = 0;
-
- /* Convert fractional part */
- do {
- fconvert[fplace++] =
- (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
- fracpart = (fracpart / 10);
- } while(fracpart && (fplace < 20));
- if (fplace == 20) fplace--;
- fconvert[fplace] = 0;
-
- /* -1 for decimal point, another -1 if we are printing a sign */
- padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
- zpadlen = max - fplace;
- if (zpadlen < 0)
- zpadlen = 0;
- if (padlen < 0)
- padlen = 0;
- if (flags & DP_F_MINUS)
- padlen = -padlen; /* Left Justifty */
-
- if ((flags & DP_F_ZERO) && (padlen > 0))
- {
- if (signvalue)
- {
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
- --padlen;
- signvalue = 0;
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --padlen;
- }
- }
- while (padlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- --padlen;
- }
- if (signvalue)
- total += dopr_outch (buffer, currlen, maxlen, signvalue);
-
- while (iplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]);
-
- /*
- * Decimal point. This should probably use locale to find the correct
- * char to print out.
- */
- if (max > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '.');
-
- while (fplace > 0)
- total += dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]);
- }
-
- while (zpadlen > 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, '0');
- --zpadlen;
- }
-
- while (padlen < 0)
- {
- total += dopr_outch (buffer, currlen, maxlen, ' ');
- ++padlen;
- }
-
- return total;
-}
-
-static int dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
-{
- if (*currlen + 1 < maxlen)
- buffer[(*currlen)++] = c;
- return 1;
-}
-
-int vsnprintf (char *str, size_t count, const char *fmt, va_list args)
-{
- if (str != NULL)
- str[0] = 0;
- return dopr(str, count, fmt, args);
-}
-
-/* VARARGS3 */
-#ifdef HAVE_STDARGS
-int snprintf (char *str,size_t count,const char *fmt,...)
-#else
-int snprintf (va_alist) va_dcl
-#endif
-{
-#ifndef HAVE_STDARGS
- char *str;
- size_t count;
- char *fmt;
-#endif
- VA_LOCAL_DECL;
- int total;
-
- VA_START (fmt);
- VA_SHIFT (str, char *);
- VA_SHIFT (count, size_t );
- VA_SHIFT (fmt, char *);
- total = vsnprintf(str, count, fmt, ap);
- VA_END;
- return total;
-}
-
-#ifdef TEST_SNPRINTF
-#ifndef LONG_STRING
-#define LONG_STRING 1024
-#endif
-int main (void)
-{
- char buf1[LONG_STRING];
- char buf2[LONG_STRING];
- char *fp_fmt[] = {
- "%-1.5f",
- "%1.5f",
- "%123.9f",
- "%10.5f",
- "% 10.5f",
- "%+22.9f",
- "%+4.9f",
- "%01.3f",
- "%4f",
- "%3.1f",
- "%3.2f",
- "%.0f",
- "%.1f",
- NULL
- };
- double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
- 0.9996, 1.996, 4.136, 0};
- char *int_fmt[] = {
- "%-1.5d",
- "%1.5d",
- "%123.9d",
- "%5.5d",
- "%10.5d",
- "% 10.5d",
- "%+22.33d",
- "%01.3d",
- "%4d",
- NULL
- };
- long int_nums[] = { -1, 134, 91340, 341, 0203, 0};
- int x, y;
- int fail = 0;
- int num = 0;
-
- printf ("Testing snprintf format codes against system sprintf...\n");
-
- for (x = 0; fp_fmt[x] != NULL ; x++)
- for (y = 0; fp_nums[y] != 0 ; y++)
- {
- snprintf (buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
- sprintf (buf2, fp_fmt[x], fp_nums[y]);
- if (strcmp (buf1, buf2))
- {
- printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
- fp_fmt[x], buf1, buf2);
- fail++;
- }
- num++;
- }
-
- for (x = 0; int_fmt[x] != NULL ; x++)
- for (y = 0; int_nums[y] != 0 ; y++)
- {
- snprintf (buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
- sprintf (buf2, int_fmt[x], int_nums[y]);
- if (strcmp (buf1, buf2))
- {
- printf("snprintf doesn't match Format: %s\n\tsnprintf = %s\n\tsprintf = %s\n",
- int_fmt[x], buf1, buf2);
- fail++;
- }
- num++;
- }
- printf ("%d tests failed out of %d.\n", fail, num);
-}
-#endif /* SNPRINTF_TEST */
+++ /dev/null
-/* $Id: sockaddr.c 5381 2002-03-31 22:35:47Z rra $
-**
-** Routines for manipulating sockaddr structs
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include <netdb.h>
-
-#include "libinn.h"
-
-char *sprint_sockaddr(const struct sockaddr *sa)
-{
-#ifdef HAVE_INET6
- static char buff[256];
- const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) sa;
-
- *buff = '\0';
- if (sa->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
- struct sockaddr_in sin;
- memcpy(&sin.sin_addr, sin6->sin6_addr.s6_addr + 12,
- sizeof sin.sin_addr);
- sin.sin_port = sin6->sin6_port;
- sin.sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_LEN
- sin.sin_len = sizeof(struct sockaddr_in);
-#endif
- return inet_ntoa(sin.sin_addr);
- }
- getnameinfo(sa, SA_LEN(sa), buff, sizeof buff, NULL, 0, NI_NUMERICHOST);
-
- return buff;
-#else
- return inet_ntoa(((const struct sockaddr_in *)sa)->sin_addr);
-#endif
-}
-
-void make_sin(struct sockaddr_in *s, const struct in_addr *src)
-{
- memset(s, 0, sizeof( struct sockaddr_in ));
- s->sin_family = AF_INET;
-#ifdef HAVE_SOCKADDR_LEN
- s->sin_len = sizeof( struct sockaddr_in );
-#endif
- s->sin_addr = *src;
-}
+++ /dev/null
-#include "config.h"
-#include "clibrary.h"
-
-
-/* $Revision: 6118 $
- *
- * Copyright (c) 1987 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement: ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 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.
- */
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static const char sccsid[] = "@(#)strcasecmp.c 5.9 (Berkeley) 6/1/90";
-#endif /* LIBC_SCCS and not lint */
-
-typedef unsigned char u_char;
-
-/*
- * This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
- * based upon ascii character sequences.
- */
-static const u_char charmap[] = {
- '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
- '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
- '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
- '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
- '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
- '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
- '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
- '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
- '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
- '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
- '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
- '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
- '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
- '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
- '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
- '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
- '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
- '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
- '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
- '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
- '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
- '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
- '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
- '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
- '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
- '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
- '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
- '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
- '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
-};
-
-int
-strcasecmp(s1, s2)
- const char *s1, *s2;
-{
- const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- while (cm[*us1] == cm[*us2++])
- if (*us1++ == '\0')
- return (0);
- return (cm[*us1] - cm[*--us2]);
-}
-
-int
-strncasecmp(s1, s2, n)
- const char *s1, *s2;
- size_t n;
-{
- if (n != 0) {
- const u_char *cm = charmap,
- *us1 = (const u_char *)s1,
- *us2 = (const u_char *)s2;
-
- do {
- if (cm[*us1] != cm[*us2++])
- return (cm[*us1] - cm[*--us2]);
- if (*us1++ == '\0')
- break;
- } while (--n != 0);
- }
- return (0);
-}
+++ /dev/null
-/* $Id: strerror.c 6127 2003-01-18 22:25:37Z rra $
-**
-** Replacement for a missing strerror.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the standard library routine strerror
-** for those platforms that don't have it (e.g. Ultrix). Assume that we
-** have sys_nerr and sys_errlist available to use instead. Calling
-** strerror should be thread-safe unless it is called for an unknown errno.
-*/
-
-#include "config.h"
-
-/* Our declarations of sys_nerr and sys_errlist may conflict with the ones
- provided by stdio.h from glibc. This trick hides the declarations in the
- system header from the compiler while we test. (The conflicts are just
- whether or not to const, so there are no negative effects from using our
- declarations.) */
-#if TESTING
-# define sys_nerr hidden_sys_nerr
-# define sys_errlist hidden_sys_errlist
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-
-#if TESTING
-# undef sys_nerr
-# undef sys_errlist
-#endif
-
-extern const int sys_nerr;
-extern const char *sys_errlist[];
-
-/* If we're running the test suite, rename strerror to avoid conflicts with
- the system version. */
-#if TESTING
-# define strerror test_strerror
-const char *test_strerror(int);
-int snprintf(char *, size_t, const char *, ...);
-#endif
-
-const char *
-strerror(int error)
-{
- static char buff[32];
- int oerrno;
-
- if (error >= 0 && error < sys_nerr)
- return sys_errlist[error];
- oerrno = errno;
- snprintf(buff, sizeof(buff), "Error code %d", error);
- errno = oerrno;
- return buff;
-}
+++ /dev/null
-/* $Id: strlcat.c 5681 2002-08-29 04:07:50Z rra $
-**
-** Replacement for a missing strlcat.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the *BSD function strlcat, originally
-** developed by Todd Miller and Theo de Raadt. strlcat works similarly to
-** strncat, except simpler. The result is always nul-terminated even if the
-** source string is longer than the space remaining in the destination
-** string, and the total space required is returned. The third argument is
-** the total space available in the destination buffer, not just the amount
-** of space remaining.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-/* If we're running the test suite, rename strlcat to avoid conflicts with
- the system version. */
-#if TESTING
-# define strlcat test_strlcat
-size_t test_strlcat(char *, const char *, size_t);
-#endif
-
-size_t
-strlcat(char *dst, const char *src, size_t size)
-{
- size_t used, length, copy;
-
- used = strlen(dst);
- length = strlen(src);
- if (size > 0 && used < size - 1) {
- copy = (length >= size - used) ? size - used - 1 : length;
- memcpy(dst + used, src, copy);
- dst[used + copy] = '\0';
- }
- return used + length;
-}
+++ /dev/null
-/* $Id: strlcpy.c 5681 2002-08-29 04:07:50Z rra $
-**
-** Replacement for a missing strlcpy.
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** Provides the same functionality as the *BSD function strlcpy, originally
-** developed by Todd Miller and Theo de Raadt. strlcpy works similarly to
-** strncpy, except saner and simpler. The result is always nul-terminated
-** even if the source string is longer than the destination string, and the
-** total space required is returned. The destination string is not
-** nul-filled like strncpy does, just nul-terminated.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-/* If we're running the test suite, rename strlcpy to avoid conflicts with
- the system version. */
-#if TESTING
-# define strlcpy test_strlcpy
-size_t test_strlcpy(char *, const char *, size_t);
-#endif
-
-size_t
-strlcpy(char *dst, const char *src, size_t size)
-{
- size_t length, copy;
-
- length = strlen(src);
- if (size > 0) {
- copy = (length >= size) ? size - 1 : length;
- memcpy(dst, src, copy);
- dst[copy] = '\0';
- }
- return length;
-}
+++ /dev/null
-/* $Id: strspn.c 6118 2003-01-13 06:44:24Z rra $
-**
-** This file has been modified to get it to compile more easily
-** on pre-4.4BSD systems. Rich $alz, June 1991.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-
-/*
- * Copyright (c) 1989 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement: ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 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.
- */
-
-#if 0
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strspn.c 5.7 (Berkeley) 6/1/90";
-#endif /* LIBC_SCCS and not lint */
-
-#include <sys/stdc.h>
-#include <string.h>
-#endif
-
-/*
- * Span the string s2 (skip characters that are in s2).
- */
-size_t
-strspn(s1, s2)
- const char *s1;
- const char *s2;
-{
- const char *p = s1, *spanp;
- char c, sc;
-
- /*
- * Skip any characters in s2, excluding the terminating \0.
- */
-cont:
- c = *p++;
- for (spanp = s2; (sc = *spanp++) != 0;)
- if (sc == c)
- goto cont;
- return (p - 1 - s1);
-}
+++ /dev/null
-/* $Id: strtok.c 6118 2003-01-13 06:44:24Z rra $
-**
-** This file has been modified to get it to compile more easily
-** on pre-4.4BSD systems. Rich $alz, June 1991.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted
- * provided that: (1) source distributions retain this entire copyright
- * notice and comment, and (2) distributions including binaries display
- * the following acknowledgement: ``This product includes software
- * developed by the University of California, Berkeley and its contributors''
- * in the documentation or other materials provided with the distribution
- * and in all advertising materials mentioning features or use of this
- * software. Neither the name of the University nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * 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.
- */
-
-#if 0
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strtok.c 5.7 (Berkeley) 6/1/90";
-#endif /* LIBC_SCCS and not lint */
-
-#include <stddef.h>
-#include <string.h>
-#endif
-
-char *
-strtok(s, delim)
- char *s, *delim;
-{
- char *spanp;
- int c, sc;
- char *tok;
- static char *last;
-
-
- if (s == NULL && (s = last) == NULL)
- return (NULL);
-
- /*
- * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
- */
-cont:
- c = *s++;
- for (spanp = delim; (sc = *spanp++) != 0;) {
- if (c == sc)
- goto cont;
- }
-
- if (c == 0) { /* no non-delimiter characters */
- last = NULL;
- return (NULL);
- }
- tok = s - 1;
-
- /*
- * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
- * Note that delim must have one NUL; we stop if we see that, too.
- */
- for (;;) {
- c = *s++;
- spanp = delim;
- do {
- if ((sc = *spanp++) == c) {
- if (c == 0)
- s = NULL;
- else
- s[-1] = 0;
- last = s;
- return (tok);
- }
- } while (sc != 0);
- }
- /* NOTREACHED */
-}
+++ /dev/null
-/* $Id: timer.c 6129 2003-01-19 00:39:49Z rra $
-**
-** Timer functions, to gather profiling data.
-**
-** These functions log profiling information about where the server spends
-** its time. While this doesn't provide as detailed of information as a
-** profiling build would, it's much faster and simpler, and since it's fast
-** enough to always leave on even on production servers, it can gather
-** information *before* it's needed and show long-term trends.
-**
-** Functions that should have their time monitored need to call TMRstart(n)
-** at the beginning of the segment of code and TMRstop(n) at the end. The
-** time spent will be accumulated and added to the total for the counter n,
-** where n should be one of the constants in timer.h or defined in your
-** application. If you add new timers in the library code, add them to
-** timer.h and also add a description to TMRsummary; if you add them in
-** your application add them to your own description array. Also add them
-** to innreport.
-**
-** Calls are sanity-checked to some degree and errors reported via
-** warn/die, so all callers should have the proper warn and die handlers
-** set up, if appropriate.
-**
-** Recursion is not allowed on a given timer. Setting multiple timers
-** at once is fine (i.e., you may have a timer for the total time to write
-** an article, how long the disk write takes, how long the history update
-** takes, etc. which are components of the total article write time). If a
-** timer is started while another timer is running, the new timer is
-** considered to be a sub-timer of the running timer, and must be stopped
-** before the parent timer is stopped. Note that the same timer number can
-** be a sub-timer of more than one timer or a timer without a parent, and
-** each of those counts will be reported separately.
-**
-** Note that this code is not thread-safe and in fact would need to be
-** completely overhauled for a threaded server (since the idea of global
-** timing statistics doesn't make as much sense when different tasks are
-** done in different threads).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/time.h"
-#include <syslog.h>
-
-#include "inn/messages.h"
-#include "inn/timer.h"
-#include "libinn.h"
-
-/* Timer values are stored in a series of trees. This allows use to use
- nested timers. Each nested timer node is linked to three of its
- neighbours to make lookups easy and fast. The current position in the
- graph is given by timer_current.
-
- As an optimization, since most timers aren't nested, timer_list holds an
- array of pointers to non-nested timers that's filled in as TMRstart is
- called so that the non-nested case remains O(1). That array is stored in
- timers. This is the "top level" of the timer trees; if timer_current is
- NULL, any timer that's started is found in this array. If timer_current
- isn't NULL, there's a running timer, and starting a new timer adds to
- that tree.
-
- Note that without the parent pointer, this is a tree. id is the
- identifier of the timer. start stores the time (relative to the last
- summary) at which TMRstart was last called for each timer. total is
- the total time accrued by that timer since the last summary. count is
- the number of times the timer has been stopped since the last summary. */
-struct timer {
- unsigned int id;
- unsigned long start;
- unsigned long total;
- unsigned long count;
-
- struct timer *parent;
- struct timer *brother;
- struct timer *child;
-};
-static struct timer **timers = NULL;
-static struct timer *timer_current = NULL;
-unsigned int timer_count = 0;
-
-/* Names for all of the timers. These must be given in the same order
- as the definition of the enum in timer.h. */
-static const char *const timer_name[TMR_APPLICATION] = {
- "hishave", "hisgrep", "hiswrite", "hissync",
-};
-
-
-/*
-** Returns the current time as a double. This is not used by any of the
-** other timer code, but is used by various programs right now to keep track
-** of elapsed time.
-*/
-double
-TMRnow_double(void)
-{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
- return (tv.tv_sec + tv.tv_usec * 1.0e-6);
-}
-
-
-/*
-** Returns the number of milliseconds since the base time. This gives
-** better resolution than time, but the return value is a lot easier to
-** work with than a struct timeval. If the argument is true, also reset
-** the base time.
-*/
-static unsigned long
-TMRgettime(bool reset)
-{
- unsigned long now;
- struct timeval tv;
-
- /* The time of the last summary, used as a base for times returned by
- TMRnow. Formerly, times were relative to the last call to TMRinit,
- which was only called once when innd was starting up; with that
- approach, times may overflow a 32-bit unsigned long about 50 days
- after the server starts up. While this may still work due to unsigned
- arithmetic, this approach is less confusing to follow. */
- static struct timeval base;
-
- gettimeofday(&tv, NULL);
- now = (tv.tv_sec - base.tv_sec) * 1000;
- now += (tv.tv_usec - base.tv_usec) / 1000;
- if (reset)
- base = tv;
- return now;
-}
-
-
-/*
-** Initialize the timer. Zero out even variables that would initially be
-** zero so that this function can be called multiple times if wanted.
-*/
-void
-TMRinit(unsigned int count)
-{
- unsigned int i;
-
- /* TMRinit(0) disables all timers. */
- TMRfree();
- if (count != 0) {
- timers = xmalloc(count * sizeof(struct timer *));
- for (i = 0; i < count; i++)
- timers[i] = NULL;
- TMRgettime(true);
- }
- timer_count = count;
-}
-
-
-/*
-** Recursively destroy a timer node.
-*/
-static void
-TMRfreeone(struct timer *timer)
-{
- if (timer == NULL)
- return;
- if (timer->child != NULL)
- TMRfreeone(timer->child);
- if (timer->brother != NULL)
- TMRfreeone(timer->brother);
- free(timer);
-}
-
-
-/*
-** Free all timers and the resources devoted to them.
-*/
-void
-TMRfree(void)
-{
- unsigned int i;
-
- if (timers != NULL)
- for (i = 0; i < timer_count; i++)
- TMRfreeone(timers[i]);
- free(timers);
- timers = NULL;
- timer_count = 0;
-}
-
-
-/*
-** Allocate a new timer node. Takes the id and the parent pointer.
-*/
-static struct timer *
-TMRnew(unsigned int id, struct timer *parent)
-{
- struct timer *timer;
-
- timer = xmalloc(sizeof(struct timer));
- timer->parent = parent;
- timer->brother = NULL;
- timer->child = NULL;
- timer->id = id;
- timer->start = 0;
- timer->total = 0;
- timer->count = 0;
- return timer;
-}
-
-
-/*
-** Start a particular timer. If no timer is currently running, start one
-** of the top-level timers in the timers array (creating a new one if
-** needed). Otherwise, search for the timer among the children of the
-** currently running timer, again creating a new timer if necessary.
-*/
-void
-TMRstart(unsigned int timer)
-{
- struct timer *search;
-
- if (timer_count == 0) {
- /* this should happen if innconf->timer == 0 */
- return;
- }
- if (timer >= timer_count) {
- warn("timer %u is larger than the maximum timer %u, ignored",
- timer, timer_count - 1);
- return;
- }
-
- /* timers will be non-NULL if timer_count > 0. */
- if (timer_current == NULL) {
- if (timers[timer] == NULL)
- timers[timer] = TMRnew(timer, NULL);
- timer_current = timers[timer];
- } else {
- search = timer_current;
-
- /* Go to the "child" level and look for the good "brother"; the
- "brothers" are a simple linked list. */
- if (search->child == NULL) {
- search->child = TMRnew(timer, search);
- timer_current = search->child;
- } else {
- search = search->child;
- while (search->id != timer && search->brother != NULL)
- search = search->brother;
- if (search->id != timer) {
- search->brother = TMRnew(timer, search->parent);
- timer_current = search->brother;
- } else {
- timer_current = search;
- }
- }
- }
- timer_current->start = TMRgettime(false);
-}
-
-
-/*
-** Stop a particular timer, adding the total time to total and incrementing
-** the count of times that timer has been invoked.
-*/
-void
-TMRstop(unsigned int timer)
-{
- if (timer_count == 0) {
- /* this should happen if innconf->timer == 0 */
- return;
- }
- if (timer_current == NULL)
- warn("timer %u stopped when no timer was running", timer);
- else if (timer != timer_current->id)
- warn("timer %u stopped doesn't match running timer %u", timer,
- timer_current->id);
- else {
- timer_current->total += TMRgettime(false) - timer_current->start;
- timer_current->count++;
- timer_current = timer_current->parent;
- }
-}
-
-
-/*
-** Return the current time in milliseconds since the last summary or the
-** initialization of the timer. This is intended for use by the caller to
-** determine when next to call TMRsummary.
-*/
-unsigned long
-TMRnow(void)
-{
- return TMRgettime(false);
-}
-
-
-/*
-** Return the label associated with timer number id. Used internally
-** to do the right thing when fetching from the timer_name or labels
-** arrays
-*/
-static const char *
-TMRlabel(const char *const *labels, unsigned int id)
-{
- if (id >= TMR_APPLICATION)
- return labels[id - TMR_APPLICATION];
- else
- return timer_name[id];
-}
-
-
-
-/*
-** Recursively summarize a single timer tree into the supplied buffer,
-** returning the number of characters added to the buffer.
-*/
-static size_t
-TMRsumone(const char *const *labels, struct timer *timer, char *buf,
- size_t len)
-{
- struct timer *node;
- size_t off = 0;
-
- /* This results in "child/parent nn(nn)" instead of the arguably more
- intuitive "parent/child" but it's easy. Since we ensure sane snprintf
- semantics, it's safe to defer checking for overflow until after
- formatting all of the timer data. */
- for (node = timer; node != NULL; node = node->parent)
- off += snprintf(buf + off, len - off, "%s/",
- TMRlabel(labels, node->id));
- off--;
- off += snprintf(buf + off, len - off, " %lu(%lu) ", timer->total,
- timer->count);
- if (off == len) {
- warn("timer log too long while processing %s",
- TMRlabel(labels, timer->id));
- return 0;
- }
-
- timer->total = 0;
- timer->count = 0;
- if (timer->child != NULL)
- off += TMRsumone(labels, timer->child, buf + off, len - off);
- if (timer->brother != NULL)
- off += TMRsumone(labels, timer->brother, buf + off, len - off);
- return off;
-}
-
-
-/*
-** Summarize the current timer statistics, report them to syslog, and then
-** reset them for the next polling interval.
-*/
-void
-TMRsummary(const char *prefix, const char *const *labels)
-{
- char *buf;
- unsigned int i;
- size_t len, off;
-
- /* To find the needed buffer size, note that a 64-bit unsigned number can
- be up to 20 digits long, so each timer can be 52 characters. We also
- allow another 27 characters for the introductory timestamp, plus some
- for the prefix. We may have timers recurring at multiple points in
- the structure, so this may not be long enough, but this is over-sized
- enough that it shouldn't be a problem. We use snprintf, so if the
- buffer isn't large enough it will just result in logged errors. */
- len = 52 * timer_count + 27 + (prefix == NULL ? 0 : strlen(prefix)) + 1;
- buf = xmalloc(len);
- if (prefix == NULL)
- off = 0;
- else
- off = snprintf(buf, len, "%s ", prefix);
- off += snprintf(buf + off, len - off, "time %ld ", TMRgettime(true));
- for (i = 0; i < timer_count; i++)
- if (timers[i] != NULL)
- off += TMRsumone(labels, timers[i], buf + off, len - off);
- syslog(LOG_NOTICE, "%s", buf);
- free(buf);
-}
+++ /dev/null
-/* $Id: tst.c 6083 2002-12-27 07:24:36Z rra $
-**
-** Ternary search trie implementation.
-**
-** A ternary search trie stores key/value pairs where the key is a
-** nul-terminated string and the value is an arbitrary pointer. It uses a
-** data structure designed for fast lookups, where each level of the trie
-** represents a character in the string being searched for.
-**
-** This implementation is based on the implementation by Peter A. Friend
-** (version 1.3), but has been assimilated into INN and modified to use INN
-** formatting conventions. If new versions are released, examine the
-** differences between that version and version 1.3 (which was checked into
-** INN as individual files in case it's no longer available) and then apply
-** the changes to this file.
-**
-** Copyright (c) 2002, Peter A. Friend
-** All rights reserved.
-**
-** Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-**
-** Redistributions of source code must retain the above copyright notice,
-** this list of conditions and the following disclaimer.
-**
-** Redistributions in binary form must reproduce the above copyright notice,
-** this list of conditions and the following disclaimer in the documentation
-** and/or other materials provided with the distribution.
-**
-** Neither the name of Peter A. Friend nor the names of his contributors may
-** be used to endorse or promote products derived from this software without
-** specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
-** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/tst.h"
-#include "libinn.h"
-
-
-/* A single node in the ternary search trie. Stores a character, which is
- part of the string formed by walking the tree from its root down to the
- node, and left, right, and middle pointers to child nodes. If value is
- non-zero (not a nul), middle is the pointer to follow if the desired
- string's character matches value. left is used if it's less than value and
- right is used if it's greater than value. If value is zero, this is a
- terminal node, and middle holds a pointer to the data associated with the
- string that ends at this point. */
-struct node {
- unsigned char value;
- struct node *left;
- struct node *middle;
- struct node *right;
-};
-
-/* The search trie structure. node_line_width is the number of nodes that are
- allocated at a time, and node_lines holds a linked list of groups of nodes.
- The free_list is a linked list (through the middle pointers) of available
- nodes to use, and head holds pointers to the first nodes for each possible
- first letter of the string. */
-struct tst {
- int node_line_width;
- struct node_lines *node_lines;
- struct node *free_list;
- struct node *head[256];
-};
-
-/* A simple linked list structure used to hold all the groups of nodes. */
-struct node_lines {
- struct node *node_line;
- struct node_lines *next;
-};
-
-
-/*
-** Given a node and a character, decide whether a new node for that character
-** should be placed as the left child of that node. (If false, it should be
-** placed as the right child.)
-*/
-#define LEFTP(n, c) (((n)->value == 0) ? ((c) < 64) : ((c) < (n)->value))
-
-
-/*
-** Allocate new nodes for the free list, called when the free list is empty.
-*/
-static void
-tst_grow_node_free_list(struct tst *tst)
-{
- struct node *current_node;
- struct node_lines *new_line;
- int i;
-
- new_line = xmalloc(sizeof(struct node_lines));
- new_line->node_line = xcalloc(tst->node_line_width, sizeof(struct node));
- new_line->next = tst->node_lines;
- tst->node_lines = new_line;
-
- current_node = tst->node_lines->node_line;
- tst->free_list = current_node;
- for (i = 1; i < tst->node_line_width; i++) {
- current_node->middle = &(tst->node_lines->node_line[i]);
- current_node = current_node->middle;
- }
- current_node->middle = NULL;
-}
-
-
-/*
-** Grab a node from the free list and initialize it with the given value.
-*/
-static struct node *
-tst_get_free_node(struct tst *tst, unsigned char value)
-{
- struct node *free_node;
-
- if (tst->free_list == NULL)
- tst_grow_node_free_list(tst);
- free_node = tst->free_list;
- tst->free_list = tst->free_list->middle;
- free_node->middle = NULL;
- free_node->value = value;
- return free_node;
-}
-
-
-/*
-** tst_init allocates memory for members of struct tst, and allocates the
-** first node_line_width nodes. The value for width must be chosen very
-** carefully. One node is required for every character in the tree. If you
-** choose a value that is too small, your application will spend too much
-** time calling malloc and your node space will be too spread out. Too large
-** a value is just a waste of space.
-*/
-struct tst *
-tst_init(int width)
-{
- struct tst *tst;
-
- tst = xcalloc(1, sizeof(struct tst));
- tst->node_lines = NULL;
- tst->node_line_width = width;
- tst_grow_node_free_list(tst);
- return tst;
-}
-
-
-/*
-** tst_insert inserts the string key into the tree. Behavior when a
-** duplicate key is inserted is controlled by option. If key is already in
-** the tree then TST_DUPLICATE_KEY is returned, and the data pointer for the
-** existing key is placed in exist_ptr. If option is set to TST_REPLACE then
-** the existing data pointer for the existing key is replaced by data. The
-** old data pointer will still be placed in exist_ptr.
-**
-** If a duplicate key is encountered and option is not set to TST_REPLACE
-** then TST_DUPLICATE_KEY is returned. If key is zero-length, then
-** TST_NULL_KEY is returned. A successful insert or replace returns TST_OK.
-**
-** The data argument may not be NULL; if it is, TST_NULL_DATA is returned.
-** If you just want a simple existence tree, use the tst pointer as the data
-** pointer.
-*/
-int
-tst_insert(struct tst *tst, const unsigned char *key, void *data, int option,
- void **exist_ptr)
-{
- struct node *current_node = NULL;
- struct node **root_node = NULL;
- int key_index;
-
- if (data == NULL)
- return TST_NULL_DATA;
-
- if (key == NULL || *key == '\0')
- return TST_NULL_KEY;
-
- key_index = 1;
- if (tst->head[*key] == NULL)
- root_node = &tst->head[*key];
- else
- current_node = tst->head[*key];
-
- while (root_node == NULL) {
- if (key[key_index] == current_node->value) {
- if (key[key_index] == '\0') {
- if (exist_ptr != NULL)
- *exist_ptr = current_node->middle;
- if (option == TST_REPLACE) {
- current_node->middle = data;
- return TST_OK;
- } else
- return TST_DUPLICATE_KEY;
- }
- if (current_node->middle == NULL)
- root_node = ¤t_node->middle;
- else {
- current_node = current_node->middle;
- key_index++;
- }
- } else if (LEFTP(current_node, key[key_index])) {
- if (current_node->left == NULL)
- root_node = ¤t_node->left;
- else
- current_node = current_node->left;
- } else {
- if (current_node->right == NULL)
- root_node = ¤t_node->right;
- else
- current_node = current_node->right;
- }
-
- }
-
- *root_node = tst_get_free_node(tst, key[key_index]);
- current_node = *root_node;
-
- while (key[key_index] != '\0') {
- key_index++;
- current_node->middle = tst_get_free_node(tst, key[key_index]);
- current_node = current_node->middle;
- }
-
- current_node->middle = data;
- return TST_OK;
-}
-
-
-/*
-** tst_search finds the string key in the tree if it exists and returns the
-** data pointer associated with that key or NULL if it's not found.
-*/
-void *
-tst_search(struct tst *tst, const unsigned char *key)
-{
- struct node *current_node;
- int key_index;
-
- if (key == NULL || *key == '\0')
- return NULL;
-
- if (tst->head[*key] == NULL)
- return NULL;
-
- current_node = tst->head[*key];
- key_index = 1;
- while (current_node != NULL) {
- if (key[key_index] == current_node->value) {
- if (current_node->value == '\0')
- return current_node->middle;
- else {
- current_node = current_node->middle;
- key_index++;
- continue;
- }
- } else if (LEFTP(current_node, key[key_index]))
- current_node = current_node->left;
- else
- current_node = current_node->right;
- }
- return NULL;
-}
-
-
-/*
-** tst_delete deletes the string key from the tree if it exists and returns
-** the data pointer assocaited with that key, or NULL if it wasn't found.
-*/
-void *
-tst_delete(struct tst *tst, const unsigned char *key)
-{
- struct node *current_node;
- struct node *current_node_parent;
- struct node *last_branch;
- struct node *last_branch_parent;
- struct node *next_node;
- struct node *last_branch_replacement;
- struct node *last_branch_dangling_child;
- int key_index;
-
- if (key == NULL || *key == '\0')
- return NULL;
-
- if (tst->head[*key] == NULL)
- return NULL;
-
- last_branch = NULL;
- last_branch_parent = NULL;
- current_node = tst->head[*key];
- current_node_parent = NULL;
- key_index = 1;
- while (current_node != NULL) {
- if (key[key_index] == current_node->value) {
- if (current_node->left != NULL || current_node->right != NULL) {
- last_branch = current_node;
- last_branch_parent = current_node_parent;
- }
- if (key[key_index] == '\0')
- break;
- else {
- current_node_parent = current_node;
- current_node = current_node->middle;
- key_index++;
- }
- } else if (LEFTP(current_node, key[key_index])) {
- last_branch_parent = current_node;
- current_node_parent = current_node;
- current_node = current_node->left;
- last_branch = current_node;
- } else {
- last_branch_parent = current_node;
- current_node_parent = current_node;
- current_node = current_node->right;
- last_branch = current_node;
- }
- }
- if (current_node == NULL)
- return NULL;
-
- if (last_branch == NULL) {
- next_node = tst->head[*key];
- tst->head[*key] = NULL;
- } else if (last_branch->left == NULL && last_branch->right == NULL) {
- if (last_branch_parent->left == last_branch)
- last_branch_parent->left = NULL;
- else
- last_branch_parent->right = NULL;
- next_node = last_branch;
- } else {
- if (last_branch->left != NULL && last_branch->right != NULL) {
- last_branch_replacement = last_branch->right;
- last_branch_dangling_child = last_branch->left;
- } else if (last_branch->right != NULL) {
- last_branch_replacement = last_branch->right;
- last_branch_dangling_child = NULL;
- } else {
- last_branch_replacement = last_branch->left;
- last_branch_dangling_child = NULL;
- }
-
- if (last_branch_parent == NULL)
- tst->head[*key] = last_branch_replacement;
- else {
- if (last_branch_parent->left == last_branch)
- last_branch_parent->left = last_branch_replacement;
- else if (last_branch_parent->right == last_branch)
- last_branch_parent->right = last_branch_replacement;
- else
- last_branch_parent->middle = last_branch_replacement;
- }
-
- if (last_branch_dangling_child != NULL) {
- current_node = last_branch_replacement;
- while (current_node->left != NULL)
- current_node = current_node->left;
- current_node->left = last_branch_dangling_child;
- }
-
- next_node = last_branch;
- }
-
- do {
- current_node = next_node;
- next_node = current_node->middle;
-
- current_node->left = NULL;
- current_node->right = NULL;
- current_node->middle = tst->free_list;
- tst->free_list = current_node;
- } while (current_node->value != 0);
-
- return next_node;
-}
-
-
-/*
-** tst_cleanup frees all memory allocated to nodes, internal structures,
-** as well as tst itself.
-*/
-void
-tst_cleanup(struct tst *tst)
-{
- struct node_lines *current_line;
- struct node_lines *next_line;
-
- next_line = tst->node_lines;
- do {
- current_line = next_line;
- next_line = current_line->next;
- free(current_line->node_line);
- free(current_line);
- } while (next_line != NULL);
-
- free(tst);
-}
+++ /dev/null
-/* $Id: uwildmat.c 6779 2004-05-17 07:25:28Z rra $
-**
-** wildmat pattern matching with Unicode UTF-8 extensions.
-**
-** 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 8-bit clean. (Robustness hopefully fixed
-** July 2000; all malformed patterns should now just fail to match anything.)
-**
-** Original 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.
-**
-** June, 1991: Robert Elz <kre@munnari.oz.au> added minus and close bracket
-** handling for character sets.
-**
-** July, 2000: Largely rewritten by Russ Allbery <rra@stanford.edu> to add
-** support for ',', '!', and optionally '@' to the core wildmat routine.
-** Broke the character class matching into a separate function for clarity
-** since it's infrequently used in practice, and added some simple lookahead
-** to significantly decrease the recursive calls in the '*' matching code.
-** Added support for UTF-8 as the default character set for any high-bit
-** characters.
-**
-** For more information on UTF-8, see RFC 2279.
-**
-** Please note that this file is intentionally written so that conditionally
-** executed expressions are on separate lines from the condition to
-** facilitate analysis of the coverage of the test suite using purecov.
-** Please preserve this. As of March 11, 2001, purecov reports that the
-** accompanying test suite achieves 100% coverage of this file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-
-#define ABORT -1
-
-/* Whether or not an octet looks like the start of a UTF-8 character. */
-#define ISUTF8(c) (((c) & 0xc0) == 0xc0)
-
-
-/*
-** Determine the length of a non-ASCII character in octets (for advancing
-** pointers when skipping over characters). Takes a pointer to the start of
-** the character and to the last octet of the string. If end is NULL, expect
-** the string pointed to by start to be nul-terminated. If the character is
-** malformed UTF-8, return 1 to treat it like an eight-bit local character.
-*/
-static int
-utf8_length(const unsigned char *start, const unsigned char *end)
-{
- unsigned char mask = 0x80;
- const unsigned char *p;
- int length = 0;
- int left;
-
- for (; mask > 0 && (*start & mask) == mask; mask >>= 1)
- length++;
- if (length < 2 || length > 6)
- return 1;
- if (end != NULL && (end - start + 1) < length)
- return 1;
- left = length - 1;
- p = start + 1;
- for (p = start + 1; left > 0 && (*p & 0xc0) == 0x80; p++)
- left--;
- return (left == 0) ? length : 1;
-}
-
-
-/*
-** Convert a UTF-8 character to UCS-4. Takes a pointer to the start of the
-** character and to the last octet of the string, and to a uint32_t into
-** which to put the decoded UCS-4 value. If end is NULL, expect the string
-** pointed to by start to be nul-terminated. Returns the number of octets in
-** the UTF-8 encoding. If the UTF-8 character is malformed, set result to
-** the decimal value of the first octet; this is wrong, but it will generally
-** cause the rest of the wildmat matching to do the right thing for non-UTF-8
-** input.
-*/
-static int
-utf8_decode(const unsigned char *start, const unsigned char *end,
- uint32_t *result)
-{
- uint32_t value = 0;
- int length, i;
- const unsigned char *p = start;
- unsigned char mask;
-
- length = utf8_length(start, end);
- if (length < 2) {
- *result = *start;
- return 1;
- }
- mask = (1 << (7 - length)) - 1;
- value = *p & mask;
- p++;
- for (i = length - 1; i > 0; i--) {
- value = (value << 6) | (*p & 0x3f);
- p++;
- }
- *result = value;
- return length;
-}
-
-
-/*
-** Match a character class against text, a UCS-4 character. start is a
-** pointer to the first character of the character class, end a pointer to
-** the last. Returns whether the class matches that character.
-*/
-static bool
-match_class(uint32_t text, const unsigned char *start,
- const unsigned char *end)
-{
- bool reversed, allowrange;
- const unsigned char *p = start;
- uint32_t first, last;
-
- /* Check for an inverted character class (starting with ^). If the
- character matches the character class, we return !reversed; that way,
- we return true if it's a regular character class and false if it's a
- reversed one. If the character doesn't match, we return reversed. */
- reversed = (*p == '^');
- if (reversed)
- p++;
-
- /* Walk through the character class until we reach the end or find a
- match, handling character ranges as we go. Only permit a range to
- start when allowrange is true; this allows - to be treated like a
- normal character as the first character of the class and catches
- malformed ranges like a-e-n. We treat the character at the beginning
- of a range as both a regular member of the class and the beginning of
- the range; this is harmless (although it means that malformed ranges
- like m-a will match m and nothing else). */
- allowrange = false;
- while (p <= end) {
- if (allowrange && *p == '-' && p < end) {
- p++;
- p += utf8_decode(p, end, &last);
- if (text >= first && text <= last)
- return !reversed;
- allowrange = false;
- } else {
- p += utf8_decode(p, end, &first);
- if (text == first)
- return !reversed;
- allowrange = true;
- }
- }
- return reversed;
-}
-
-
-/*
-** Match the text against the pattern between start and end. This is a
-** single pattern; a leading ! or @ must already be taken care of, and
-** commas must be dealt with outside of this routine.
-*/
-static int
-match_pattern(const unsigned char *text, const unsigned char *start,
- const unsigned char *end)
-{
- const unsigned char *q, *endclass;
- const unsigned char *p = start;
- bool ismeta;
- int matched, width;
- uint32_t c;
-
- for (; p <= end; p++) {
- if (!*text && *p != '*')
- return ABORT;
-
- switch (*p) {
- case '\\':
- if (!*++p)
- return ABORT;
- /* Fall through. */
-
- default:
- if (*text++ != *p)
- return false;
- break;
-
- case '?':
- text += ISUTF8(*text) ? utf8_length(text, NULL) : 1;
- break;
-
- case '*':
- /* Consecutive stars are equivalent to one. Advance pattern to
- the character after the star. */
- for (++p; *p == '*'; p++)
- ;
-
- /* A trailing star will match anything. */
- if (p > end)
- return true;
-
- /* Basic algorithm: Recurse at each point where the * could
- possibly match. If the match succeeds or aborts, return
- immediately; otherwise, try the next position.
-
- Optimization: If the character after the * in the pattern
- isn't a metacharacter (the common case), then the * has to
- consume characters at least up to the next occurance of that
- character in the text. Scan forward for those points rather
- than recursing at every possible point to save the extra
- function call overhead. */
- ismeta = (*p == '[' || *p == '?' || *p == '\\');
- while (*text) {
- width = ISUTF8(*text) ? utf8_length(text, NULL) : 1;
- if (ismeta) {
- matched = match_pattern(text, p, end);
- text += width;
- } else {
- while (*text && *text != *p) {
- text += width;
- width = ISUTF8(*text) ? utf8_length(text, NULL) : 1;
- }
- if (!*text)
- return ABORT;
- matched = match_pattern(++text, p + 1, end);
- }
- if (matched != false)
- return matched;
- }
- return ABORT;
-
- case '[':
- /* Find the end of the character class, making sure not to pick
- up a close bracket at the beginning of the class. */
- p++;
- q = p + (*p == '^') + 1;
- if (q > end)
- return ABORT;
- endclass = memchr(q, ']', (size_t) (end - q + 1));
- if (!endclass)
- return ABORT;
-
- /* Do the heavy lifting in another function for clarity, since
- character classes are an uncommon case. */
- text += utf8_decode(text, NULL, &c);
- if (!match_class(c, p, endclass - 1))
- return false;
- p = endclass;
- break;
- }
- }
-
- return (*text == '\0');
-}
-
-
-/*
-** Takes text and a wildmat expression; a wildmat expression is a
-** comma-separated list of wildmat patterns, optionally preceeded by ! to
-** invert the sense of the expression. Returns WILDMAT_MATCH if that
-** expression matches the text, WILDMAT_FAIL otherwise. If allowpoison is
-** set, allow @ to introduce a poison expression (the same as !, but if it
-** triggers the failed match the routine returns WILDMAT_POISON instead).
-*/
-static enum uwildmat
-match_expression(const unsigned char *text, const unsigned char *start,
- bool allowpoison)
-{
- const unsigned char *end, *split;
- const unsigned char *p = start;
- bool reverse, escaped;
- bool match = false;
- bool poison = false;
- bool poisoned = false;
-
- /* Handle the empty expression separately, since otherwise end will be
- set to an invalid pointer. */
- if (!*p)
- return !*text ? UWILDMAT_MATCH : UWILDMAT_FAIL;
- end = start + strlen((const char *) start) - 1;
-
- /* Main match loop. Find each comma that separates patterns, and attempt
- to match the text with each pattern in order. The last matching
- pattern determines whether the whole expression matches. */
- for (; p <= end + 1; p = split + 1) {
- if (allowpoison)
- poison = (*p == '@');
- reverse = (*p == '!') || poison;
- if (reverse)
- p++;
-
- /* Find the first unescaped comma, if any. If there is none, split
- will be one greater than end and point at the nul at the end of
- the string. */
- for (escaped = false, split = p; split <= end; split++) {
- if (*split == '[') {
- split++;
- if (*split == ']')
- split++;
- while (split <= end && *split != ']')
- split++;
- }
- if (*split == ',' && !escaped)
- break;
- escaped = (*split == '\\') ? !escaped : false;
- }
-
- /* Optimization: If match == !reverse and poison == poisoned, this
- pattern can't change the result, so don't do any work. */
- if (match == !reverse && poison == poisoned)
- continue;
- if (match_pattern(text, p, split - 1) == true) {
- poisoned = poison;
- match = !reverse;
- }
- }
- if (poisoned)
- return UWILDMAT_POISON;
- return match ? UWILDMAT_MATCH : UWILDMAT_FAIL;
-}
-
-
-/*
-** User-level routine used for wildmats where @ should be treated as a
-** regular character.
-*/
-bool
-uwildmat(const char *text, const char *pat)
-{
- const unsigned char *utext = (const unsigned char *) text;
- const unsigned char *upat = (const unsigned char *) pat;
-
- if (upat[0] == '*' && upat[1] == '\0')
- return true;
- else
- return (match_expression(utext, upat, false) == UWILDMAT_MATCH);
-}
-
-
-/*
-** User-level routine used for wildmats that support poison matches.
-*/
-enum uwildmat
-uwildmat_poison(const char *text, const char *pat)
-{
- const unsigned char *utext = (const unsigned char *) text;
- const unsigned char *upat = (const unsigned char *) pat;
-
- if (upat[0] == '*' && upat[1] == '\0')
- return UWILDMAT_MATCH;
- else
- return match_expression(utext, upat, true);
-}
-
-
-/*
-** User-level routine for simple expressions (neither , nor ! are special).
-*/
-bool
-uwildmat_simple(const char *text, const char *pat)
-{
- const unsigned char *utext = (const unsigned char *) text;
- const unsigned char *upat = (const unsigned char *) pat;
- size_t length;
-
- if (upat[0] == '*' && upat[1] == '\0')
- return true;
- else {
- length = strlen(pat);
- return (match_pattern(utext, upat, upat + length - 1) == true);
- }
-}
+++ /dev/null
-/* $Id: vector.c 6699 2004-04-07 06:47:44Z rra $
-**
-** Vector handling (counted lists of char *'s).
-**
-** Written by Russ Allbery <rra@stanford.edu>
-** This work is hereby placed in the public domain by its author.
-**
-** A vector is a table for handling a list of strings with less overhead than
-** linked list. The intention is for vectors, once allocated, to be reused;
-** this saves on memory allocations once the array of char *'s reaches a
-** stable size.
-**
-** There are two types of vectors. Standard vectors copy strings when
-** they're inserted into the vector, whereas cvectors just accept pointers
-** to external strings to store. There are therefore two entry points for
-** every vector function, one for vectors and one for cvectors.
-**
-** There's a whole bunch of code duplication here. This would be a lot
-** cleaner with C++ features (either inheritance or templates would
-** probably help). One could probably in some places just cast a cvector
-** to a vector and perform the same operations, but I'm leery of doing that
-** as I'm not sure if it's a violation of the C type aliasing rules.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#include "inn/vector.h"
-#include "libinn.h"
-
-/*
-** Allocate a new, empty vector.
-*/
-struct vector *
-vector_new(void)
-{
- struct vector *vector;
-
- vector = xmalloc(sizeof(struct vector));
- vector->count = 0;
- vector->allocated = 0;
- vector->strings = NULL;
- return vector;
-}
-
-struct cvector *
-cvector_new(void)
-{
- struct cvector *vector;
-
- vector = xmalloc(sizeof(struct cvector));
- vector->count = 0;
- vector->allocated = 0;
- vector->strings = NULL;
- return vector;
-}
-
-
-/*
-** Resize a vector (using realloc to resize the table).
-*/
-void
-vector_resize(struct vector *vector, size_t size)
-{
- size_t i;
-
- if (vector->count > size) {
- for (i = size; i < vector->count; i++)
- free(vector->strings[i]);
- vector->count = size;
- }
- if (size == 0) {
- free(vector->strings);
- vector->strings = NULL;
- } else {
- vector->strings = xrealloc(vector->strings, size * sizeof(char *));
- }
- vector->allocated = size;
-}
-
-void
-cvector_resize(struct cvector *vector, size_t size)
-{
- if (vector->count > size)
- vector->count = size;
- if (size == 0) {
- free(vector->strings);
- vector->strings = NULL;
- } else {
- vector->strings =
- xrealloc(vector->strings, size * sizeof(const char *));
- }
- vector->allocated = size;
-}
-
-
-/*
-** Add a new string to the vector, resizing the vector as necessary. The
-** vector is resized an element at a time; if a lot of resizes are expected,
-** vector_resize should be called explicitly with a more suitable size.
-*/
-void
-vector_add(struct vector *vector, const char *string)
-{
- size_t next = vector->count;
-
- if (vector->count == vector->allocated)
- vector_resize(vector, vector->allocated + 1);
- vector->strings[next] = xstrdup(string);
- vector->count++;
-}
-
-void
-cvector_add(struct cvector *vector, const char *string)
-{
- size_t next = vector->count;
-
- if (vector->count == vector->allocated)
- cvector_resize(vector, vector->allocated + 1);
- vector->strings[next] = string;
- vector->count++;
-}
-
-
-/*
-** Empty a vector but keep the allocated memory for the pointer table.
-*/
-void
-vector_clear(struct vector *vector)
-{
- size_t i;
-
- for (i = 0; i < vector->count; i++)
- free(vector->strings[i]);
- vector->count = 0;
-}
-
-void
-cvector_clear(struct cvector *vector)
-{
- vector->count = 0;
-}
-
-
-/*
-** Free a vector completely.
-*/
-void
-vector_free(struct vector *vector)
-{
- vector_clear(vector);
- free(vector->strings);
- free(vector);
-}
-
-void
-cvector_free(struct cvector *vector)
-{
- cvector_clear(vector);
- free(vector->strings);
- free(vector);
-}
-
-
-/*
-** Given a vector that we may be reusing, clear it out. If the first
-** argument is NULL, allocate a new vector. Used by vector_split*.
-*/
-static struct vector *
-vector_reuse(struct vector *vector)
-{
- if (vector == NULL)
- return vector_new();
- else {
- vector_clear(vector);
- return vector;
- }
-}
-
-static struct cvector *
-cvector_reuse(struct cvector *vector)
-{
- if (vector == NULL)
- return cvector_new();
- else {
- cvector_clear(vector);
- return vector;
- }
-}
-
-
-/*
-** Given a string and a separator character, count the number of strings
-** that it will split into.
-*/
-static size_t
-split_count(const char *string, char separator)
-{
- const char *p;
- size_t count;
-
- if (*string == '\0')
- return 1;
- for (count = 1, p = string; *p; p++)
- if (*p == separator)
- count++;
- return count;
-}
-
-
-/*
-** Given a string and a separator character, form a vector by splitting the
-** string at those separators. Do a first pass to size the vector, and if
-** the third argument isn't NULL, reuse it. Otherwise, allocate a new one.
-*/
-struct vector *
-vector_split(const char *string, char separator, struct vector *vector)
-{
- const char *p, *start;
- size_t i, count;
-
- vector = vector_reuse(vector);
-
- count = split_count(string, separator);
- if (vector->allocated < count)
- vector_resize(vector, count);
-
- for (start = string, p = string, i = 0; *p; p++)
- if (*p == separator) {
- vector->strings[i++] = xstrndup(start, p - start);
- start = p + 1;
- }
- vector->strings[i++] = xstrndup(start, p - start);
- vector->count = i;
-
- return vector;
-}
-
-
-/*
-** Given a modifiable string and a separator character, form a cvector by
-** modifying the string in-place to add nuls at the separators and then
-** building a vector of pointers into the string. Do a first pass to size
-** the vector, and if the third argument isn't NULL, reuse it. Otherwise,
-** allocate a new one.
-*/
-struct cvector *
-cvector_split(char *string, char separator, struct cvector *vector)
-{
- char *p, *start;
- size_t i, count;
-
- vector = cvector_reuse(vector);
-
- count = split_count(string, separator);
- if (vector->allocated < count)
- cvector_resize(vector, count);
-
- for (start = string, p = string, i = 0; *p; p++)
- if (*p == separator) {
- *p = '\0';
- vector->strings[i++] = start;
- start = p + 1;
- }
- vector->strings[i++] = start;
- vector->count = i;
-
- return vector;
-}
-
-
-/*
-** Given a string, count the number of strings that it will split into when
-** splitting on whitespace.
-*/
-static size_t
-split_space_count(const char *string)
-{
- const char *p;
- size_t count;
-
- if (*string == '\0')
- return 0;
- for (count = 1, p = string + 1; *p != '\0'; p++)
- if ((*p == ' ' || *p == '\t') && !(p[-1] == ' ' || p[-1] == '\t'))
- count++;
-
- /* If the string ends in whitespace, we've overestimated the number of
- strings by one. */
- if (p[-1] == ' ' || p[-1] == '\t')
- count--;
- return count;
-}
-
-
-/*
-** Given a string, split it at whitespace to form a vector, copying each
-** string segment. If the fourth argument isn't NULL, reuse that vector;
-** otherwise, allocate a new one. Any number of consecutive whitespace
-** characters is considered a single separator.
-*/
-struct vector *
-vector_split_space(const char *string, struct vector *vector)
-{
- const char *p, *start;
- size_t i, count;
-
- vector = vector_reuse(vector);
-
- count = split_space_count(string);
- if (vector->allocated < count)
- vector_resize(vector, count);
-
- for (start = string, p = string, i = 0; *p; p++)
- if (*p == ' ' || *p == '\t') {
- if (start != p)
- vector->strings[i++] = xstrndup(start, p - start);
- start = p + 1;
- }
- if (start != p)
- vector->strings[i++] = xstrndup(start, p - start);
- vector->count = i;
-
- return vector;
-}
-
-
-/*
-** Given a string, split it at whitespace to form a vector, destructively
-** modifying the string to nul-terminate each segment. If the fourth
-** argument isn't NULL, reuse that vector; otherwise, allocate a new one.
-** Any number of consecutive whitespace characters is considered a single
-** separator.
-*/
-struct cvector *
-cvector_split_space(char *string, struct cvector *vector)
-{
- char *p, *start;
- size_t i, count;
-
- vector = cvector_reuse(vector);
-
- count = split_space_count(string);
- if (vector->allocated < count)
- cvector_resize(vector, count);
-
- for (start = string, p = string, i = 0; *p; p++)
- if (*p == ' ' || *p == '\t') {
- if (start != p) {
- *p = '\0';
- vector->strings[i++] = start;
- }
- start = p + 1;
- }
- if (start != p)
- vector->strings[i++] = start;
- vector->count = i;
-
- return vector;
-}
-
-
-/*
-** Given a vector and a separator string, allocate and build a new string
-** composed of all the strings in the vector separated from each other by the
-** seperator string. Caller is responsible for freeing.
-*/
-char *
-vector_join(const struct vector *vector, const char *seperator)
-{
- char *string;
- size_t i, size, seplen;
-
- seplen = strlen(seperator);
- for (size = 0, i = 0; i < vector->count; i++)
- size += strlen(vector->strings[i]);
- size += (vector->count - 1) * seplen + 1;
-
- string = xmalloc(size);
- strlcpy(string, vector->strings[0], size);
- for (i = 1; i < vector->count; i++) {
- strlcat(string, seperator, size);
- strlcat(string, vector->strings[i], size);
- }
-
- return string;
-}
-
-char *
-cvector_join(const struct cvector *vector, const char *seperator)
-{
- char *string;
- size_t i, size, seplen;
-
- seplen = strlen(seperator);
- for (size = 0, i = 0; i < vector->count; i++)
- size += strlen(vector->strings[i]);
- size += (vector->count - 1) * seplen + 1;
-
- string = xmalloc(size);
- strlcpy(string, vector->strings[0], size);
- for (i = 1; i < vector->count; i++) {
- strlcat(string, seperator, size);
- strlcat(string, vector->strings[i], size);
- }
-
- return string;
-}
+++ /dev/null
-/* $Id: version.c 3989 2000-10-01 01:59:45Z rra $
-**
-** INN compile-time version information.
-*/
-
-#include "config.h"
-#include "inn/version.h"
-
-const int inn_version[3] = {
- INN_VERSION_MAJOR, INN_VERSION_MINOR, INN_VERSION_PATCH
-};
-const char inn_version_extra[] = INN_VERSION_EXTRA;
-const char inn_version_string[] = INN_VERSION_STRING;
+++ /dev/null
-/* $Id: wire.c 7258 2005-06-06 03:14:45Z eagle $
-**
-** Wire format article utilities.
-**
-** Originally written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** These routines manipulate wire format articles; in particular, they should
-** be safe in the presence of embedded NULs. They assume wire format
-** conventions (\r\n as a line ending, in particular) and will not work with
-** articles in native format.
-**
-** The functions in this file take const char * pointers and return char *
-** pointers so that they can work on both const char * and char * article
-** bodies without changing the const sense. This unfortunately means that
-** the routines in this file will produce warnings about const being cast
-** away. To avoid those, one would need to duplicate all the code in this
-** file or use C++.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <assert.h>
-
-#include "inn/wire.h"
-#include "libinn.h"
-
-/*
-** Given a pointer to the start of an article, locate the first octet of the
-** body (which may be the octet beyond the end of the buffer if your article
-** is bodiless).
-*/
-char *
-wire_findbody(const char *article, size_t length)
-{
- char *p;
- const char *end;
-
- /* Handle the degenerate case of an article with no headers. */
- if (length > 5 && article[0] == '\r' && article[1] == '\n')
- return (char *) article + 2;
-
- /* Jump from \r to \r and give up if we're too close to the end. */
- end = article + length;
- for (p = (char *) article; (p + 4) <= end; ++p) {
- p = memchr(p, '\r', end - p - 3);
- if (p == NULL)
- break;
- if (memcmp(p, "\r\n\r\n", 4) == 0) {
- p += 4;
- return p;
- }
- }
- return NULL;
-}
-
-
-/*
-** Given a pointer into an article and a pointer to the last octet of the
-** article, find the next line ending and return a pointer to the first
-** character after that line ending. If no line ending is found in the
-** article or if it is at the end of the article, return NULL.
-*/
-char *
-wire_nextline(const char *article, const char *end)
-{
- char *p;
-
- for (p = (char *) article; (p + 2) <= end; ++p) {
- p = memchr(p, '\r', end - p - 2);
- if (p == NULL)
- break;
- if (p[1] == '\n') {
- p += 2;
- return p;
- }
- }
- return NULL;
-}
-
-
-/*
-** Returns true if line is the beginning of a valid header for header, also
-** taking the length of the header name as a third argument. Assumes that
-** there is at least length + 2 bytes of data at line, and that the header
-** name doesn't contain nul.
-*/
-static bool
-isheader(const char *line, const char *header, size_t length)
-{
- if (line[length] != ':' || !ISWHITE(line[length + 1]))
- return false;
- return strncasecmp(line, header, length) == 0;
-}
-
-
-/*
-** Skip over folding whitespace, as defined by RFC 2822. Takes a pointer to
-** where to start skipping and a pointer to the end of the data, and will not
-** return a pointer past the end pointer. If skipping folding whitespace
-** takes us past the end of data, return NULL.
-*/
-static char *
-skip_fws(char *text, const char *end)
-{
- char *p;
-
- for (p = text; p <= end; p++) {
- if (p < end + 1 && p[0] == '\r' && p[1] == '\n' && ISWHITE(p[2]))
- p += 2;
- if (!ISWHITE(*p))
- return p;
- }
- return NULL;
-}
-
-
-/*
-** Given a pointer to the start of the article, the article length, and the
-** header to look for, find the first occurance of that header in the
-** article. Skip over headers with no content, but allow for headers that
-** are folded before the first text in the header. If no matching headers
-** with content other than spaces and tabs are found, return NULL.
-*/
-char *
-wire_findheader(const char *article, size_t length, const char *header)
-{
- char *p;
- const char *end;
- ptrdiff_t headerlen;
-
- headerlen = strlen(header);
- end = article + length - 1;
-
- /* There has to be enough space left in the article for at least the
- header, the colon, whitespace, and one non-whitespace character, hence
- 3, minus 1 since the character pointed to by end is part of the
- article. */
- p = (char *) article;
- while (p != NULL && end - p > headerlen + 2) {
- if (p[0] == '\r' && p[1] == '\n')
- return NULL;
- else if (isheader(p, header, headerlen)) {
- p = skip_fws(p + headerlen + 2, end);
- if (p == NULL)
- return NULL;
- if (p >= end || p[0] != '\r' || p[1] != '\n')
- return p;
- }
- p = wire_nextline(p, end);
- }
- return NULL;
-}
-
-
-/*
-** Given a pointer to a header and a pointer to the last octet of the
-** article, find the end of the header (a pointer to the final \n of the
-** header value). If the header contents don't end in \r\n, return NULL.
-*/
-char *
-wire_endheader(const char *header, const char *end)
-{
- char *p;
-
- p = wire_nextline(header, end);
- while (p != NULL) {
- if (!ISWHITE(*p))
- return p - 1;
- p = wire_nextline(p, end);
- }
- if (end - header >= 1 && *end == '\n' && *(end - 1) == '\r')
- return (char *) end;
- return NULL;
-}
+++ /dev/null
-/* $Id: xfopena.c 5381 2002-03-31 22:35:47Z rra $
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <fcntl.h>
-
-#include "libinn.h"
-
-/*
-** Open a file in append mode. Since not all fopen's set the O_APPEND
-** flag, we do it by hand.
-*/
-FILE *xfopena(const char *p)
-{
- int fd;
-
- /* We can't trust stdio to really use O_APPEND, so open, then fdopen. */
- fd = open(p, O_WRONLY | O_APPEND | O_CREAT, 0666);
- return fd >= 0 ? fdopen(fd, "a") : NULL;
-}
+++ /dev/null
-/* $Id: xmalloc.c 5381 2002-03-31 22:35:47Z rra $
-**
-** malloc routines with failure handling.
-**
-** Usage:
-**
-** extern xmalloc_handler_t memory_error;
-** extern const char *string;
-** char *buffer;
-**
-** xmalloc_error_handler = memory_error;
-** buffer = xmalloc(1024);
-** xrealloc(buffer, 2048);
-** free(buffer);
-** buffer = xcalloc(1024);
-** free(buffer);
-** buffer = xstrdup(string);
-** free(buffer);
-** buffer = xstrndup(string, 25);
-**
-** xmalloc, xcalloc, xrealloc, and xstrdup behave exactly like their C
-** library counterparts without the leading x except that they will never
-** return NULL. Instead, on error, they call xmalloc_error_handler,
-** passing it the name of the function whose memory allocation failed, the
-** amount of the allocation, and the file and line number where the
-** allocation function was invoked (from __FILE__ and __LINE__). This
-** function may do whatever it wishes, such as some action to free up
-** memory or a call to sleep to hope that system resources return. If the
-** handler returns, the interrupted memory allocation function will try its
-** allocation again (calling the handler again if it still fails).
-**
-** xstrndup behaves like xstrdup but only copies the given number of
-** characters. It allocates an additional byte over its second argument and
-** always nul-terminates the string.
-**
-** The default error handler, if none is set by the caller, prints an error
-** message to stderr and exits with exit status 1. An error handler must
-** take a const char * (function name), size_t (bytes allocated), const
-** char * (file), and int (line).
-**
-** xmalloc will return a pointer to a valid memory region on an xmalloc of 0
-** bytes, ensuring this by allocating space for one character instead of 0
-** bytes.
-**
-** The functions defined here are actually x_malloc, x_realloc, etc. The
-** header file defines macros named xmalloc, etc. that pass the file name
-** and line number to these functions.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-/* The default error handler. */
-void
-xmalloc_fail(const char *function, size_t size, const char *file, int line)
-{
- sysdie("failed to %s %lu bytes at %s line %d", function,
- (unsigned long) size, file, line);
-}
-
-/* Assign to this variable to choose a handler other than the default. */
-xmalloc_handler_t xmalloc_error_handler = xmalloc_fail;
-
-void *
-x_malloc(size_t size, const char *file, int line)
-{
- void *p;
- size_t real_size;
-
- real_size = (size > 0) ? size : 1;
- p = malloc(real_size);
- while (p == NULL) {
- (*xmalloc_error_handler)("malloc", size, file, line);
- p = malloc(real_size);
- }
- return p;
-}
-
-void *
-x_calloc(size_t n, size_t size, const char *file, int line)
-{
- void *p;
-
- n = (n > 0) ? n : 1;
- size = (size > 0) ? size : 1;
- p = calloc(n, size);
- while (p == NULL) {
- (*xmalloc_error_handler)("calloc", n * size, file, line);
- p = calloc(n, size);
- }
- return p;
-}
-
-void *
-x_realloc(void *p, size_t size, const char *file, int line)
-{
- void *newp;
-
- newp = realloc(p, size);
- while (newp == NULL && size > 0) {
- (*xmalloc_error_handler)("realloc", size, file, line);
- newp = realloc(p, size);
- }
- return newp;
-}
-
-char *
-x_strdup(const char *s, const char *file, int line)
-{
- char *p;
- size_t len;
-
- len = strlen(s) + 1;
- p = malloc(len);
- while (p == NULL) {
- (*xmalloc_error_handler)("strdup", len, file, line);
- p = malloc(len);
- }
- memcpy(p, s, len);
- return p;
-}
-
-char *
-x_strndup(const char *s, size_t size, const char *file, int line)
-{
- char *p;
-
- p = malloc(size + 1);
- while (p == NULL) {
- (*xmalloc_error_handler)("strndup", size + 1, file, line);
- p = malloc(size + 1);
- }
- memcpy(p, s, size);
- p[size] = '\0';
- return p;
-}
+++ /dev/null
-/* $Id: xsignal.c 5610 2002-08-18 22:22:52Z rra $
-**
-** A reliable implementation of signal for System V systems.
-**
-** Two functions are provided, xsignal and xsignal_norestart. The former
-** attempts to set system calls to be restarted and the latter does not.
-**
-** Be aware that there's weird declaration stuff going on here; a signal
-** handler is a pointer to a function taking an int and returning void.
-** We typedef this as sig_handler_type for clearer code.
-*/
-
-#include "config.h"
-#include "libinn.h"
-#include <signal.h>
-
-typedef void (*sig_handler_type)(int);
-
-#ifdef HAVE_SIGACTION
-
-sig_handler_type
-xsignal(int signum, sig_handler_type sigfunc)
-{
- struct sigaction act, oact;
-
- act.sa_handler = sigfunc;
- sigemptyset(&act.sa_mask);
-
- /* Try to restart system calls if possible. */
-#ifdef SA_RESTART
- act.sa_flags = SA_RESTART;
-#else
- act.sa_flags = 0;
-#endif
-
- if (sigaction(signum, &act, &oact) < 0)
- return SIG_ERR;
- return oact.sa_handler;
-}
-
-sig_handler_type
-xsignal_norestart(int signum, sig_handler_type sigfunc)
-{
- struct sigaction act, oact;
-
- act.sa_handler = sigfunc;
- sigemptyset(&act.sa_mask);
-
- /* Try not to restart system calls. */
-#ifdef SA_INTERRUPT
- act.sa_flags = SA_INTERRUPT;
-#else
- act.sa_flags = 0;
-#endif
-
- if (sigaction(signum, &act, &oact) < 0)
- return SIG_ERR;
- return oact.sa_handler;
-}
-
-#else /* !HAVE_SIGACTION */
-
-sig_handler_type
-xsignal(int signum, sig_handler_type sigfunc)
-{
- return signal(signum, sigfunc);
-}
-
-sig_handler_type
-xsignal_norestart(int signum, sig_handler_type sigfunc)
-{
- return signal(signum, sigfunc);
-}
-
-#endif /* !HAVE_SIGACTION */
+++ /dev/null
-/* $Id: xwrite.c 5771 2002-09-17 17:00:05Z alexk $
-**
-** write and writev replacements to handle partial writes.
-**
-** Usage:
-**
-** ssize_t xwrite(int fildes, const void *buf, size_t nbyte);
-** ssize_t xpwrite(int fildes, const void *buf, size_t nbyte,
-** off_t offset);
-** ssize_t xwritev(int fildes, const struct iovec *iov, int iovcnt);
-**
-** xwrite, xpwrite, and xwritev behave exactly like their C library
-** counterparts except that, if write or writev succeeds but returns a number
-** of bytes written less than the total bytes, the write is repeated picking
-** up where it left off until the full amount of the data is written. The
-** write is also repeated if it failed with EINTR. The write will be aborted
-** after 10 successive writes with no forward progress.
-**
-** Both functions return the number of bytes written on success or -1 on an
-** error, and will leave errno set to whatever the underlying system call
-** set it to. Note that it is possible for a write to fail after some data
-** was written, on the subsequent additional write; in that case, these
-** functions will return -1 and the number of bytes actually written will
-** be lost.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/uio.h>
-
-#include "libinn.h"
-
-/* If we're running the test suite, call testing versions of the write
- functions. #undef pwrite first because large file support may define a
- macro pwrite (pointing to pwrite64) on some platforms (e.g. Solaris). */
-#if TESTING
-# undef pwrite
-# define pwrite fake_pwrite
-# define write fake_write
-# define writev fake_writev
-ssize_t fake_pwrite(int, const void *, size_t, off_t);
-ssize_t fake_write(int, const void *, size_t);
-ssize_t fake_writev(int, const struct iovec *, int);
-#endif
-
-ssize_t
-xwrite(int fd, const void *buffer, size_t size)
-{
- size_t total;
- ssize_t status;
- int count = 0;
-
- if (size == 0)
- return 0;
-
- /* Abort the write if we try ten times with no forward progress. */
- for (total = 0; total < size; total += status) {
- if (++count > 10)
- break;
- status = write(fd, (const char *) buffer + total, size - total);
- if (status > 0)
- count = 0;
- if (status < 0) {
- if (errno != EINTR)
- break;
- status = 0;
- }
- }
- return (total < size) ? -1 : (ssize_t) total;
-}
-
-ssize_t
-xpwrite(int fd, const void *buffer, size_t size, off_t offset)
-{
- size_t total;
- ssize_t status;
- int count = 0;
-
- if (size == 0)
- return 0;
-
- /* Abort the write if we try ten times with no forward progress. */
- for (total = 0; total < size; total += status) {
- if (++count > 10)
- break;
- status = pwrite(fd, (const char *) buffer + total, size - total,
- offset + total);
- if (status > 0)
- count = 0;
- if (status < 0) {
- if (errno != EINTR)
- break;
- status = 0;
- }
- }
- return (total < size) ? -1 : (ssize_t) total;
-}
-
-ssize_t
-xwritev(int fd, const struct iovec iov[], int iovcnt)
-{
- ssize_t total, status = 0;
- size_t left, offset;
- int iovleft, i, count;
- struct iovec *tmpiov;
-
- if (iovcnt == 0)
- return 0;
-
- /* Get a count of the total number of bytes in the iov array. */
- for (total = 0, i = 0; i < iovcnt; i++)
- total += iov[i].iov_len;
-
- if (total == 0)
- return 0;
-
- /* First, try just writing it all out. Most of the time this will
- succeed and save us lots of work. Abort the write if we try ten times
- with no forward progress. */
- count = 0;
- do {
- if (++count > 10)
- break;
- status = writev(fd, iov, iovcnt);
- if (status > 0)
- count = 0;
- } while (status < 0 && errno == EINTR);
- if (status < 0)
- return -1;
- if (status == total)
- return total;
-
- /* If we fell through to here, the first write partially succeeded.
- Figure out how far through the iov array we got, and then duplicate
- the rest of it so that we can modify it to reflect how much we manage
- to write on successive tries. */
- offset = status;
- left = total - offset;
- for (i = 0; offset >= (size_t) iov[i].iov_len; i++)
- offset -= iov[i].iov_len;
- iovleft = iovcnt - i;
- tmpiov = xmalloc(iovleft * sizeof(struct iovec));
- memcpy(tmpiov, iov + i, iovleft * sizeof(struct iovec));
-
- /* status now contains the offset into the first iovec struct in tmpiov.
- Go into the write loop, trying to write out everything remaining at
- each point. At the top of the loop, status will contain a count of
- bytes written out at the beginning of the set of iovec structs. */
- i = 0;
- do {
- if (++count > 10)
- break;
-
- /* Skip any leading data that has been written out. */
- for (; offset >= (size_t) tmpiov[i].iov_len && iovleft > 0; i++) {
- offset -= tmpiov[i].iov_len;
- iovleft--;
- }
- tmpiov[i].iov_base = (char *) tmpiov[i].iov_base + offset;
- tmpiov[i].iov_len -= offset;
-
- /* Write out what's left and return success if it's all written. */
- status = writev(fd, tmpiov + i, iovleft);
- if (status <= 0)
- offset = 0;
- else {
- offset = status;
- left -= offset;
- count = 0;
- }
- } while (left > 0 && (status >= 0 || errno == EINTR));
-
- /* We're either done or got an error; if we're done, left is now 0. */
- free(tmpiov);
- return (left == 0) ? total : -1;
-}
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) $(SSLINC)
-
-ALL = nnrpd
-
-SOURCES = article.c cache.c group.c commands.c line.c list.c misc.c \
- newnews.c nnrpd.c perl.c perm.c post.c python.c \
- sasl_config.c tls.c track.c
-
-INCLUDES = cache.h nnrpd.h post.h sasl_config.h tls.h
-
-OBJECTS = $(SOURCES:.c=.o)
-
-INSTALLED = $(D)$(PATHBIN)/nnrpd
-
-all: $(ALL)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPUB) nnrpd $D$(PATHBIN)/nnrpd
-
-clean:
- rm -f *.o $(ALL) nnrpdp profiled
- rm -rf .libs
-
-clobber distclean: clean
- rm -f tags
-
-tags ctags: $(SOURCES) $(INCLUDES)
- $(CTAGS) $(SOURCES) $(INCLUDES) ../lib/*.c ../include/*.h
-
-
-## Compilation rules.
-
-NNRPDLIBS = $(LIBHIST) $(LIBSTORAGE) $(LIBINN) $(EXTSTORAGELIBS) \
- $(PERLLIB) $(PYTHONLIB) $(SSLLIB) $(LIBS)
-
-perl.o: perl.c ; $(CC) $(CFLAGS) $(PERLINC) -c perl.c
-python.o: python.c ; $(CC) $(CFLAGS) $(PYTHONINC) -c python.c
-
-nnrpd: $(OBJECTS) $(LIBHIST) $(LIBSTORAGE) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(OBJECTS) $(NNRPDLIBS)
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBSTORAGE): ; (cd ../storage ; $(MAKE))
-$(LIBHIST): ; (cd ../history ; $(MAKE))
-
-
-## Profiling. These rules have not been checked for a while and may need
-## some work.
-
-profiled: nnrpdp
- date >$@
-
-nnrpdp: $(SOURCES)
- rm -f $(OBJECTS)
- $(MAKEPROFILING) nnrpd
- mv nnrpd nnrpdp
- rm -f $(OBJECTS)
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: $(SOURCES)
- $(MAKEDEPEND) '$(CFLAGS) $(PERLINC) $(PYTHONINC) $(TCLINC)' $(SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-article.o: article.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/wire.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h tls.h cache.h
-cache.o: cache.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/tst.h \
- ../include/inn/list.h ../include/libinn.h ../include/storage.h cache.h
-group.o: group.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h
-commands.o: commands.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/wait.h ../include/config.h nnrpd.h \
- ../include/portable/socket.h ../include/portable/time.h \
- ../include/inn/qio.h ../include/inn/defines.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ../include/inn/innconf.h \
- ../include/inn/messages.h
-line.o: line.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/messages.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h
-list.o: list.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- nnrpd.h ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h \
- ../include/inn/defines.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/inn/vector.h \
- ../include/inn/timer.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../include/inn/innconf.h \
- ../include/inn/messages.h
-misc.o: misc.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h tls.h sasl_config.h
-newnews.o: newnews.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/inn/wire.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h cache.h
-nnrpd.o: nnrpd.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/setproctitle.h ../include/config.h \
- ../include/portable/wait.h ../include/inn/innconf.h \
- ../include/inn/defines.h ../include/inn/messages.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h nnrpd.h \
- ../include/portable/socket.h ../include/portable/time.h \
- ../include/inn/qio.h ../include/nntp.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h tls.h sasl_config.h
-perl.o: perl.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h post.h
-perm.o: perm.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/wait.h ../include/config.h ../include/conffile.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/innperl.h \
- nnrpd.h ../include/portable/socket.h ../include/portable/time.h \
- ../include/inn/qio.h ../include/libinn.h ../include/nntp.h \
- ../include/paths.h ../include/storage.h ../include/inn/vector.h \
- ../include/inn/timer.h
-post.o: post.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h post.h
-python.o: python.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h ../include/inn/hashtab.h
-sasl_config.o: sasl_config.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h sasl_config.h
-tls.o: tls.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h nnrpd.h ../include/portable/socket.h \
- ../include/config.h ../include/portable/time.h ../include/inn/qio.h \
- ../include/inn/defines.h ../include/libinn.h ../include/config.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h tls.h sasl_config.h
-track.o: track.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h nnrpd.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/inn/qio.h ../include/libinn.h \
- ../include/nntp.h ../include/paths.h ../include/storage.h \
- ../include/inn/vector.h ../include/inn/timer.h
+++ /dev/null
-/* $Id: article.c 7538 2006-08-26 05:44:06Z eagle $
-**
-** Article-related routines.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <assert.h>
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <sys/uio.h>
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/wire.h"
-#include "nnrpd.h"
-#include "ov.h"
-#include "tls.h"
-#include "cache.h"
-
-#ifdef HAVE_SSL
-extern SSL *tls_conn;
-#endif
-
-/*
-** Data structures for use in ARTICLE/HEAD/BODY/STAT common code.
-*/
-typedef enum _SENDTYPE {
- STarticle,
- SThead,
- STbody,
- STstat
-} SENDTYPE;
-
-typedef struct _SENDDATA {
- SENDTYPE Type;
- int ReplyCode;
- const char *Item;
-} SENDDATA;
-
-static char ARTnotingroup[] = NNTP_NOTINGROUP;
-static char ARTnoartingroup[] = NNTP_NOARTINGRP;
-static char ARTnocurrart[] = NNTP_NOCURRART;
-static ARTHANDLE *ARThandle = NULL;
-static SENDDATA SENDbody = {
- STbody, NNTP_BODY_FOLLOWS_VAL, "body"
-};
-static SENDDATA SENDarticle = {
- STarticle, NNTP_ARTICLE_FOLLOWS_VAL, "article"
-};
-static SENDDATA SENDstat = {
- STstat, NNTP_NOTHING_FOLLOWS_VAL, "status"
-};
-static SENDDATA SENDhead = {
- SThead, NNTP_HEAD_FOLLOWS_VAL, "head"
-};
-
-
-static struct iovec iov[IOV_MAX > 1024 ? 1024 : IOV_MAX];
-static int queued_iov = 0;
-
-static void PushIOvHelper(struct iovec* vec, int* countp) {
- int result;
- TMRstart(TMR_NNTPWRITE);
-#ifdef HAVE_SSL
- if (tls_conn) {
-Again:
- result = SSL_writev(tls_conn, vec, *countp);
- switch (SSL_get_error(tls_conn, result)) {
- case SSL_ERROR_NONE:
- case SSL_ERROR_SYSCALL:
- break;
- case SSL_ERROR_WANT_WRITE:
- goto Again;
- break;
- case SSL_ERROR_SSL:
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- }
- } else {
- result = xwritev(STDOUT_FILENO, vec, *countp);
- }
-#else
- result = xwritev(STDOUT_FILENO, vec, *countp);
-#endif
- TMRstop(TMR_NNTPWRITE);
- if (result == -1) {
- /* we can't recover, since we can't resynchronise with our
- * peer */
- ExitWithStats(1, true);
- }
- *countp = 0;
-}
-
-static void
-PushIOvRateLimited(void) {
- double start, end, elapsed, target;
- struct iovec newiov[IOV_MAX > 1024 ? 1024 : IOV_MAX];
- int newiov_len;
- int sentiov;
- int i;
- int bytesfound;
- int chunkbittenoff;
- struct timeval waittime;
-
- while (queued_iov) {
- bytesfound = newiov_len = 0;
- sentiov = 0;
- for (i = 0; (i < queued_iov) && (bytesfound < MaxBytesPerSecond); i++) {
- if ((signed)iov[i].iov_len + bytesfound > MaxBytesPerSecond) {
- chunkbittenoff = MaxBytesPerSecond - bytesfound;
- newiov[newiov_len].iov_base = iov[i].iov_base;
- newiov[newiov_len++].iov_len = chunkbittenoff;
- iov[i].iov_base = (char *)iov[i].iov_base + chunkbittenoff;
- iov[i].iov_len -= chunkbittenoff;
- bytesfound += chunkbittenoff;
- } else {
- newiov[newiov_len++] = iov[i];
- sentiov++;
- bytesfound += iov[i].iov_len;
- }
- }
- assert(sentiov <= queued_iov);
- start = TMRnow_double();
- PushIOvHelper(newiov, &newiov_len);
- end = TMRnow_double();
- target = (double) bytesfound / MaxBytesPerSecond;
- elapsed = end - start;
- if (elapsed < 1 && elapsed < target) {
- waittime.tv_sec = 0;
- waittime.tv_usec = (target - elapsed) * 1e6;
- start = TMRnow_double();
- if (select(0, NULL, NULL, NULL, &waittime) != 0)
- syswarn("%s: select in PushIOvRateLimit failed", ClientHost);
- end = TMRnow_double();
- IDLEtime += end - start;
- }
- memmove(iov, &iov[sentiov], (queued_iov - sentiov) * sizeof(struct iovec));
- queued_iov -= sentiov;
- }
-}
-
-static void
-PushIOv(void) {
- TMRstart(TMR_NNTPWRITE);
- fflush(stdout);
- TMRstop(TMR_NNTPWRITE);
- if (MaxBytesPerSecond != 0)
- PushIOvRateLimited();
- else
- PushIOvHelper(iov, &queued_iov);
-}
-
-static void
-SendIOv(const char *p, int len) {
- char *q;
-
- if (queued_iov) {
- q = (char *)iov[queued_iov - 1].iov_base + iov[queued_iov - 1].iov_len;
- if (p == q) {
- iov[queued_iov - 1].iov_len += len;
- return;
- }
- }
- iov[queued_iov].iov_base = (char*)p;
- iov[queued_iov++].iov_len = len;
- if (queued_iov == IOV_MAX)
- PushIOv();
-}
-
-static char *_IO_buffer_ = NULL;
-static int highwater = 0;
-
-static void
-PushIOb(void) {
- TMRstart(TMR_NNTPWRITE);
- fflush(stdout);
-#ifdef HAVE_SSL
- if (tls_conn) {
- int r;
-Again:
- r = SSL_write(tls_conn, _IO_buffer_, highwater);
- switch (SSL_get_error(tls_conn, r)) {
- case SSL_ERROR_NONE:
- case SSL_ERROR_SYSCALL:
- break;
- case SSL_ERROR_WANT_WRITE:
- goto Again;
- break;
- case SSL_ERROR_SSL:
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- }
- if (r != highwater) {
- TMRstop(TMR_NNTPWRITE);
- highwater = 0;
- return;
- }
- } else {
- if (xwrite(STDOUT_FILENO, _IO_buffer_, highwater) != highwater) {
- TMRstop(TMR_NNTPWRITE);
- highwater = 0;
- return;
- }
- }
-#else
- if (xwrite(STDOUT_FILENO, _IO_buffer_, highwater) != highwater) {
- TMRstop(TMR_NNTPWRITE);
- highwater = 0;
- return;
- }
-#endif
- TMRstop(TMR_NNTPWRITE);
- highwater = 0;
-}
-
-static void
-SendIOb(const char *p, int len) {
- int tocopy;
-
- if (_IO_buffer_ == NULL)
- _IO_buffer_ = xmalloc(BIG_BUFFER);
-
- while (len > 0) {
- tocopy = (len > (BIG_BUFFER - highwater)) ? (BIG_BUFFER - highwater) : len;
- memcpy(&_IO_buffer_[highwater], p, tocopy);
- p += tocopy;
- highwater += tocopy;
- len -= tocopy;
- if (highwater == BIG_BUFFER)
- PushIOb();
- }
-}
-
-
-/*
-** If we have an article open, close it.
-*/
-void ARTclose(void)
-{
- if (ARThandle) {
- SMfreearticle(ARThandle);
- ARThandle = NULL;
- }
-}
-
-bool ARTinstorebytoken(TOKEN token)
-{
- ARTHANDLE *art;
- struct timeval stv, etv;
-
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&stv, NULL);
- }
- art = SMretrieve(token, RETR_STAT); /* XXX This isn't really overstats, is it? */
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&etv, NULL);
- OVERartcheck+=(etv.tv_sec - stv.tv_sec) * 1000;
- OVERartcheck+=(etv.tv_usec - stv.tv_usec) / 1000;
- }
- if (art) {
- SMfreearticle(art);
- return true;
- }
- return false;
-}
-
-/*
-** If the article name is valid, open it and stuff in the ID.
-*/
-static bool ARTopen(ARTNUM artnum)
-{
- static ARTNUM save_artnum;
- TOKEN token;
-
- /* Re-use article if it's the same one. */
- if (save_artnum == artnum) {
- if (ARThandle)
- return true;
- }
- ARTclose();
-
- if (!OVgetartinfo(GRPcur, artnum, &token))
- return false;
-
- TMRstart(TMR_READART);
- ARThandle = SMretrieve(token, RETR_ALL);
- TMRstop(TMR_READART);
- if (ARThandle == NULL) {
- return false;
- }
-
- save_artnum = artnum;
- return true;
-}
-
-
-/*
-** Open the article for a given Message-ID.
-*/
-static bool
-ARTopenbyid(char *msg_id, ARTNUM *ap, bool final)
-{
- TOKEN token;
-
- *ap = 0;
- token = cache_get(HashMessageID(msg_id), final);
- if (token.type == TOKEN_EMPTY) {
- if (History == NULL) {
- time_t statinterval;
-
- /* Do lazy opens of the history file - lots of clients
- * will never ask for anything by message id, so put off
- * doing the work until we have to */
- History = HISopen(HISTORY, innconf->hismethod, HIS_RDONLY);
- if (!History) {
- syslog(L_NOTICE, "cant initialize history");
- Reply("%d NNTP server unavailable. Try later.\r\n",
- NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- statinterval = 30;
- HISctl(History, HISCTLS_STATINTERVAL, &statinterval);
- }
- if (!HISlookup(History, msg_id, NULL, NULL, NULL, &token))
- return false;
- }
- if (token.type == TOKEN_EMPTY)
- return false;
- TMRstart(TMR_READART);
- ARThandle = SMretrieve(token, RETR_ALL);
- TMRstop(TMR_READART);
- if (ARThandle == NULL) {
- return false;
- }
-
- return true;
-}
-
-/*
-** Send a (part of) a file to stdout, doing newline and dot conversion.
-*/
-static void ARTsendmmap(SENDTYPE what)
-{
- const char *p, *q, *r;
- const char *s, *path, *xref, *endofpath;
- long bytecount;
- char lastchar;
-
- ARTcount++;
- GRParticles++;
- bytecount = 0;
- lastchar = -1;
-
- /* Get the headers and detect if wire format. */
- if (what == STarticle) {
- q = ARThandle->data;
- p = ARThandle->data + ARThandle->len;
- } else {
- for (q = p = ARThandle->data; p < (ARThandle->data + ARThandle->len); p++) {
- if (*p == '\r')
- continue;
- if (*p == '\n') {
- if (lastchar == '\n') {
- if (what == SThead) {
- if (*(p-1) == '\r')
- p--;
- break;
- } else {
- q = p + 1;
- p = ARThandle->data + ARThandle->len;
- break;
- }
- }
- }
- lastchar = *p;
- }
- }
-
- /* q points to the start of the article buffer, p to the end of it */
- if (VirtualPathlen > 0 && (what != STbody)) {
- path = wire_findheader(ARThandle->data, ARThandle->len, "Path");
- if (path == NULL) {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- PushIOv();
- ARTget++;
- return;
- } else {
- xref = wire_findheader(ARThandle->data, ARThandle->len, "Xref");
- if (xref == NULL) {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- PushIOv();
- ARTget++;
- return;
- }
- }
- endofpath = wire_endheader(path, ARThandle->data + ARThandle->len - 1);
- if (endofpath == NULL) {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- PushIOv();
- ARTget++;
- return;
- }
- if ((r = memchr(xref, ' ', p - xref)) == NULL || r == p) {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- PushIOv();
- ARTget++;
- return;
- }
- /* r points to the first space in the Xref header */
- for (s = path, lastchar = '\0';
- s + VirtualPathlen + 1 < endofpath;
- lastchar = *s++) {
- if ((lastchar != '\0' && lastchar != '!') || *s != *VirtualPath ||
- strncmp(s, VirtualPath, VirtualPathlen - 1) != 0)
- continue;
- if (*(s + VirtualPathlen - 1) != '\0' &&
- *(s + VirtualPathlen - 1) != '!')
- continue;
- break;
- }
- if (s + VirtualPathlen + 1 < endofpath) {
- if (xref > path) {
- SendIOv(q, path - q);
- SendIOv(s, xref - s);
- SendIOv(VirtualPath, VirtualPathlen - 1);
- SendIOv(r, p - r);
- } else {
- SendIOv(q, xref - q);
- SendIOv(VirtualPath, VirtualPathlen - 1);
- SendIOv(r, path - r);
- SendIOv(s, p - s);
- }
- } else {
- if (xref > path) {
- SendIOv(q, path - q);
- SendIOv(VirtualPath, VirtualPathlen);
- SendIOv(path, xref - path);
- SendIOv(VirtualPath, VirtualPathlen - 1);
- SendIOv(r, p - r);
- } else {
- SendIOv(q, xref - q);
- SendIOv(VirtualPath, VirtualPathlen - 1);
- SendIOv(r, path - r);
- SendIOv(VirtualPath, VirtualPathlen);
- SendIOv(path, p - path);
- }
- }
- } else
- SendIOv(q, p - q);
- ARTgetsize += p - q;
- if (what == SThead) {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- } else if (memcmp((ARThandle->data + ARThandle->len - 5), "\r\n.\r\n", 5)) {
- if (memcmp((ARThandle->data + ARThandle->len - 2), "\r\n", 2)) {
- SendIOv("\r\n.\r\n", 5);
- ARTgetsize += 5;
- } else {
- SendIOv(".\r\n", 3);
- ARTgetsize += 3;
- }
- }
- PushIOv();
-
- ARTget++;
-}
-
-/*
-** Return the header from the specified file, or NULL if not found.
-*/
-char *GetHeader(const char *header)
-{
- const char *p, *q, *r, *s, *t;
- char *w, prevchar;
- /* Bogus value here to make sure that it isn't initialized to \n */
- char lastchar = ' ';
- const char *limit;
- const char *cmplimit;
- static char *retval = NULL;
- static int retlen = 0;
- int headerlen;
- bool pathheader = false;
- bool xrefheader = false;
-
- limit = ARThandle->data + ARThandle->len;
- cmplimit = ARThandle->data + ARThandle->len - strlen(header) - 1;
- for (p = ARThandle->data; p < cmplimit; p++) {
- if (*p == '\r')
- continue;
- if ((lastchar == '\n') && (*p == '\n')) {
- return NULL;
- }
- if ((lastchar == '\n') || (p == ARThandle->data)) {
- headerlen = strlen(header);
- if (strncasecmp(p, header, headerlen) == 0 && p[headerlen] == ':') {
- for (; (p < limit) && !isspace((int)*p) ; p++);
- for (; (p < limit) && isspace((int)*p) ; p++);
- for (q = p; q < limit; q++)
- if ((*q == '\r') || (*q == '\n')) {
- /* Check for continuation header lines */
- t = q + 1;
- if (t < limit) {
- if ((*q == '\r' && *t == '\n')) {
- t++;
- if (t == limit)
- break;
- }
- if ((*t == '\t' || *t == ' ')) {
- for (; (t < limit) && isspace((int)*t) ; t++);
- q = t;
- } else {
- break;
- }
- } else {
- break;
- }
- }
- if (q == limit)
- return NULL;
- if (strncasecmp("Path", header, headerlen) == 0)
- pathheader = true;
- else if (strncasecmp("Xref", header, headerlen) == 0)
- xrefheader = true;
- if (retval == NULL) {
- retlen = q - p + VirtualPathlen + 1;
- retval = xmalloc(retlen);
- } else {
- if ((q - p + VirtualPathlen + 1) > retlen) {
- retlen = q - p + VirtualPathlen + 1;
- retval = xrealloc(retval, retlen);
- }
- }
- if (pathheader && (VirtualPathlen > 0)) {
- const char *endofpath;
- const char *endofarticle;
-
- endofarticle = ARThandle->data + ARThandle->len - 1;
- endofpath = wire_endheader(p, endofarticle);
- if (endofpath == NULL)
- return NULL;
- for (s = p, prevchar = '\0';
- s + VirtualPathlen + 1 < endofpath;
- prevchar = *s++) {
- if ((prevchar != '\0' && prevchar != '!') ||
- *s != *VirtualPath ||
- strncmp(s, VirtualPath, VirtualPathlen - 1) != 0)
- continue;
- if (*(s + VirtualPathlen - 1) != '\0' &&
- *(s + VirtualPathlen - 1) != '!')
- continue;
- break;
- }
- if (s + VirtualPathlen + 1 < endofpath) {
- memcpy(retval, s, q - s);
- *(retval + (int)(q - s)) = '\0';
- } else {
- memcpy(retval, VirtualPath, VirtualPathlen);
- memcpy(retval + VirtualPathlen, p, q - p);
- *(retval + (int)(q - p) + VirtualPathlen) = '\0';
- }
- } else if (xrefheader && (VirtualPathlen > 0)) {
- if ((r = memchr(p, ' ', q - p)) == NULL)
- return NULL;
- for (; (r < q) && isspace((int)*r) ; r++);
- if (r == q)
- return NULL;
- memcpy(retval, VirtualPath, VirtualPathlen - 1);
- memcpy(retval + VirtualPathlen - 1, r - 1, q - r + 1);
- *(retval + (int)(q - r) + VirtualPathlen) = '\0';
- } else {
- memcpy(retval, p, q - p);
- *(retval + (int)(q - p)) = '\0';
- }
- for (w = retval; *w; w++)
- if (*w == '\n' || *w == '\r')
- *w = ' ';
- return retval;
- }
- }
- lastchar = *p;
- }
- return NULL;
-}
-
-/*
-** Fetch part or all of an article and send it to the client.
-*/
-void CMDfetch(int ac, char *av[])
-{
- char buff[SMBUF];
- SENDDATA *what;
- bool ok;
- ARTNUM art;
- char *msgid;
- ARTNUM tart;
- bool final = false;
-
- /* Find what to send; get permissions. */
- ok = PERMcanread;
- switch (*av[0]) {
- default:
- what = &SENDbody;
- final = true;
- break;
- case 'a': case 'A':
- what = &SENDarticle;
- final = true;
- break;
- case 's': case 'S':
- what = &SENDstat;
- break;
- case 'h': case 'H':
- what = &SENDhead;
- /* Poster might do a "head" command to verify the article. */
- ok = PERMcanread || PERMcanpost;
- break;
- }
-
- if (!ok) {
- Reply("%s\r\n", NOACCESS);
- return;
- }
-
- /* Requesting by Message-ID? */
- if (ac == 2 && av[1][0] == '<') {
- if (!ARTopenbyid(av[1], &art, final)) {
- Reply("%d No such article\r\n", NNTP_DONTHAVEIT_VAL);
- return;
- }
- if (!PERMartok()) {
- ARTclose();
- Reply("%s\r\n", NOACCESS);
- return;
- }
- tart=art;
- Reply("%d %lu %s %s\r\n", what->ReplyCode, (unsigned long) art,
- av[1], what->Item);
- if (what->Type != STstat) {
- ARTsendmmap(what->Type);
- }
- ARTclose();
- return;
- }
-
- /* Trying to read. */
- if (GRPcount == 0) {
- Reply("%s\r\n", ARTnotingroup);
- return;
- }
-
- /* Default is to get current article, or specified article. */
- if (ac == 1) {
- if (ARTnumber < ARTlow || ARTnumber > ARThigh) {
- Reply("%s\r\n", ARTnocurrart);
- return;
- }
- snprintf(buff, sizeof(buff), "%d", ARTnumber);
- tart=ARTnumber;
- }
- else {
- if (strspn(av[1], "0123456789") != strlen(av[1])) {
- Reply("%s\r\n", ARTnoartingroup);
- return;
- }
- strlcpy(buff, av[1], sizeof(buff));
- tart=(ARTNUM)atol(buff);
- }
-
- /* Open the article and send the reply. */
- if (!ARTopen(atol(buff))) {
- Reply("%s\r\n", ARTnoartingroup);
- return;
- }
- if (ac > 1)
- ARTnumber = tart;
- if ((msgid = GetHeader("Message-ID")) == NULL) {
- ARTclose();
- Reply("%s\r\n", ARTnoartingroup);
- return;
- }
- Reply("%d %s %.512s %s\r\n", what->ReplyCode, buff, msgid, what->Item);
- if (what->Type != STstat)
- ARTsendmmap(what->Type);
- ARTclose();
-}
-
-
-/*
-** Go to the next or last (really previous) article in the group.
-*/
-void CMDnextlast(int ac UNUSED, char *av[])
-{
- char *msgid;
- int save, delta, errcode;
- bool next;
- const char *message;
-
- if (!PERMcanread) {
- Reply("%s\r\n", NOACCESS);
- return;
- }
- if (GRPcount == 0) {
- Reply("%s\r\n", ARTnotingroup);
- return;
- }
- if (ARTnumber < ARTlow || ARTnumber > ARThigh) {
- Reply("%s\r\n", ARTnocurrart);
- return;
- }
-
- next = (av[0][0] == 'n' || av[0][0] == 'N');
- if (next) {
- delta = 1;
- errcode = NNTP_NONEXT_VAL;
- message = "next";
- }
- else {
- delta = -1;
- errcode = NNTP_NOPREV_VAL;
- message = "previous";
- }
-
- save = ARTnumber;
- msgid = NULL;
- do {
- ARTnumber += delta;
- if (ARTnumber < ARTlow || ARTnumber > ARThigh) {
- Reply("%d No %s to retrieve.\r\n", errcode, message);
- ARTnumber = save;
- return;
- }
- if (!ARTopen(ARTnumber))
- continue;
- msgid = GetHeader("Message-ID");
- ARTclose();
- } while (msgid == NULL);
-
- Reply("%d %d %s Article retrieved; request text separately.\r\n",
- NNTP_NOTHING_FOLLOWS_VAL, ARTnumber, msgid);
-}
-
-
-static bool CMDgetrange(int ac, char *av[], ARTRANGE *rp, bool *DidReply)
-{
- char *p;
-
- *DidReply = false;
- if (GRPcount == 0) {
- Reply("%s\r\n", ARTnotingroup);
- *DidReply = true;
- return false;
- }
-
- if (ac == 1) {
- /* No argument, do only current article. */
- if (ARTnumber < ARTlow || ARTnumber > ARThigh) {
- Reply("%s\r\n", ARTnocurrart);
- *DidReply = true;
- return false;
- }
- rp->High = rp->Low = ARTnumber;
- return true;
- }
-
- /* Got just a single number? */
- if ((p = strchr(av[1], '-')) == NULL) {
- rp->Low = rp->High = atol(av[1]);
- return true;
- }
-
- /* Parse range. */
- *p++ = '\0';
- rp->Low = atol(av[1]);
- if (*p == '\0' || (rp->High = atol(p)) < rp->Low)
- /* "XHDR 234-0 header" gives everything to the end. */
- rp->High = ARThigh;
- else if (rp->High > ARThigh)
- rp->High = ARThigh;
- if (rp->Low < ARTlow)
- rp->Low = ARTlow;
- p--;
- *p = '-';
-
- return true;
-}
-
-
-/*
-** Apply virtual hosting to an Xref field.
-*/
-static char *
-vhost_xref(char *p)
-{
- char *space;
- size_t offset;
- char *field = NULL;
-
- space = strchr(p, ' ');
- if (space == NULL) {
- warn("malformed Xref `%s'", field);
- goto fail;
- }
- offset = space + 1 - p;
- space = strchr(p + offset, ' ');
- if (space == NULL) {
- warn("malformed Xref `%s'", field);
- goto fail;
- }
- field = concat(PERMaccessconf->domain, space, NULL);
- fail:
- free(p);
- return field;
-}
-
-/*
-** XOVER another extension. Dump parts of the overview database.
-*/
-void CMDxover(int ac, char *av[])
-{
- bool DidReply;
- ARTRANGE range;
- struct timeval stv, etv;
- ARTNUM artnum;
- void *handle;
- char *data, *r;
- const char *p, *q;
- int len, useIOb = 0;
- TOKEN token;
- struct cvector *vector = NULL;
-
- if (!PERMcanread) {
- Printf("%s\r\n", NOACCESS);
- return;
- }
-
- /* Trying to read. */
- if (GRPcount == 0) {
- Reply("%s\r\n", ARTnotingroup);
- return;
- }
-
- /* Parse range. */
- if (!CMDgetrange(ac, av, &range, &DidReply)) {
- if (DidReply) {
- return;
- }
- }
-
- OVERcount++;
- gettimeofday(&stv, NULL);
- if ((handle = (void *)OVopensearch(GRPcur, range.Low, range.High)) == NULL) {
- if (av[1] != NULL)
- Reply("%d %s fields follow\r\n.\r\n", NNTP_OVERVIEW_FOLLOWS_VAL, av[1]);
- else
- Reply("%d %d fields follow\r\n.\r\n", NNTP_OVERVIEW_FOLLOWS_VAL, ARTnumber);
- return;
- }
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&etv, NULL);
- OVERtime+=(etv.tv_sec - stv.tv_sec) * 1000;
- OVERtime+=(etv.tv_usec - stv.tv_usec) / 1000;
- }
-
- if (av[1] != NULL)
- Reply("%d %s fields follow\r\n", NNTP_OVERVIEW_FOLLOWS_VAL, av[1]);
- else
- Reply("%d %d fields follow\r\n", NNTP_OVERVIEW_FOLLOWS_VAL, ARTnumber);
- fflush(stdout);
- if (PERMaccessconf->nnrpdoverstats)
- gettimeofday(&stv, NULL);
-
- /* If OVSTATICSEARCH is true, then the data returned by OVsearch is only
- valid until the next call to OVsearch. In this case, we must use
- SendIOb because it copies the data. */
- OVctl(OVSTATICSEARCH, &useIOb);
-
- while (OVsearch(handle, &artnum, &data, &len, &token, NULL)) {
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&etv, NULL);
- OVERtime+=(etv.tv_sec - stv.tv_sec) * 1000;
- OVERtime+=(etv.tv_usec - stv.tv_usec) / 1000;
- }
- if (len == 0 || (PERMaccessconf->nnrpdcheckart && !ARTinstorebytoken(token))) {
- if (PERMaccessconf->nnrpdoverstats) {
- OVERmiss++;
- gettimeofday(&stv, NULL);
- }
- continue;
- }
- if (PERMaccessconf->nnrpdoverstats) {
- OVERhit++;
- OVERsize += len;
- }
- vector = overview_split(data, len, NULL, vector);
- r = overview_getheader(vector, OVERVIEW_MESSAGE_ID, OVextra);
- cache_add(HashMessageID(r), token);
- free(r);
- if (VirtualPathlen > 0 && overhdr_xref != -1) {
- if ((overhdr_xref + 1) >= vector->count)
- continue;
- p = vector->strings[overhdr_xref] + sizeof("Xref: ") - 1;
- while ((p < data + len) && *p == ' ')
- ++p;
- q = memchr(p, ' ', data + len - p);
- if (q == NULL)
- continue;
- if(useIOb) {
- SendIOb(data, p - data);
- SendIOb(VirtualPath, VirtualPathlen - 1);
- SendIOb(q, len - (q - data));
- } else {
- SendIOv(data, p - data);
- SendIOv(VirtualPath, VirtualPathlen - 1);
- SendIOv(q, len - (q - data));
- }
- } else {
- if(useIOb)
- SendIOb(data, len);
- else
- SendIOv(data, len);
- }
- if (PERMaccessconf->nnrpdoverstats)
- gettimeofday(&stv, NULL);
- }
-
- if (vector)
- cvector_free(vector);
-
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&etv, NULL);
- OVERtime+=(etv.tv_sec - stv.tv_sec) * 1000;
- OVERtime+=(etv.tv_usec - stv.tv_usec) / 1000;
- }
- if(useIOb) {
- SendIOb(".\r\n", 3);
- PushIOb();
- } else {
- SendIOv(".\r\n", 3);
- PushIOv();
- }
- if (PERMaccessconf->nnrpdoverstats)
- gettimeofday(&stv, NULL);
- OVclosesearch(handle);
- if (PERMaccessconf->nnrpdoverstats) {
- gettimeofday(&etv, NULL);
- OVERtime+=(etv.tv_sec - stv.tv_sec) * 1000;
- OVERtime+=(etv.tv_usec - stv.tv_usec) / 1000;
- }
-
-}
-
-/*
-** XHDR and XPAT extensions. Note that HDR as specified in the new NNTP
-** draft works differently than XHDR has historically, so don't just use this
-** function to implement it without reviewing the differences.
-*/
-/* ARGSUSED */
-void CMDpat(int ac, char *av[])
-{
- char *p;
- int i;
- ARTRANGE range;
- bool IsLines;
- bool DidReply;
- char *header;
- char *pattern;
- char *text;
- int Overview;
- ARTNUM artnum;
- char buff[SPOOLNAMEBUFF];
- void *handle;
- char *data;
- int len;
- TOKEN token;
- struct cvector *vector = NULL;
-
- if (!PERMcanread) {
- Printf("%s\r\n", NOACCESS);
- return;
- }
-
- header = av[1];
- IsLines = (strcasecmp(header, "lines") == 0);
-
- if (ac > 3) /* XPAT */
- pattern = Glom(&av[3]);
- else
- pattern = NULL;
-
- do {
- /* Message-ID specified? */
- if (ac > 2 && av[2][0] == '<') {
- p = av[2];
- if (!ARTopenbyid(p, &artnum, false)) {
- Printf("%d No such article.\r\n", NNTP_DONTHAVEIT_VAL);
- break;
- }
- if (!PERMartok()) {
- ARTclose();
- Printf("%s\r\n", NOACCESS);
- break;
- }
-
- Printf("%d %s matches follow (ID)\r\n", NNTP_HEAD_FOLLOWS_VAL,
- header);
- if ((text = GetHeader(header)) != NULL
- && (!pattern || uwildmat_simple(text, pattern)))
- Printf("%s %s\r\n", p, text);
-
- ARTclose();
- Printf(".\r\n");
- break;
- }
-
- if (GRPcount == 0) {
- Reply("%s\r\n", ARTnotingroup);
- break;
- }
-
- /* Range specified. */
- if (!CMDgetrange(ac - 1, av + 1, &range, &DidReply)) {
- if (DidReply) {
- break;
- }
- }
-
- /* In overview? */
- Overview = overview_index(header, OVextra);
-
- /* Not in overview, we have to fish headers out from the articles */
- if (Overview < 0 ) {
- Reply("%d %s matches follow (art)\r\n", NNTP_HEAD_FOLLOWS_VAL,
- header);
- for (i = range.Low; i <= range.High && range.High > 0; i++) {
- if (!ARTopen(i))
- continue;
- p = GetHeader(header);
- if (p && (!pattern || uwildmat_simple(p, pattern))) {
- snprintf(buff, sizeof(buff), "%u ", i);
- SendIOb(buff, strlen(buff));
- SendIOb(p, strlen(p));
- SendIOb("\r\n", 2);
- }
- ARTclose();
- }
- SendIOb(".\r\n", 3);
- PushIOb();
- break;
- }
-
- /* Okay then, we can grab values from overview. */
- handle = (void *)OVopensearch(GRPcur, range.Low, range.High);
- if (handle == NULL) {
- Reply("%d %s no matches follow (NOV)\r\n.\r\n",
- NNTP_HEAD_FOLLOWS_VAL, header);
- break;
- }
-
- Printf("%d %s matches follow (NOV)\r\n", NNTP_HEAD_FOLLOWS_VAL,
- header);
- while (OVsearch(handle, &artnum, &data, &len, &token, NULL)) {
- if (len == 0 || (PERMaccessconf->nnrpdcheckart
- && !ARTinstorebytoken(token)))
- continue;
- vector = overview_split(data, len, NULL, vector);
- p = overview_getheader(vector, Overview, OVextra);
- if (p != NULL) {
- if (PERMaccessconf->virtualhost &&
- Overview == overhdr_xref) {
- p = vhost_xref(p);
- if (p == NULL)
- continue;
- }
- if (!pattern || uwildmat_simple(p, pattern)) {
- snprintf(buff, sizeof(buff), "%lu ", artnum);
- SendIOb(buff, strlen(buff));
- SendIOb(p, strlen(p));
- SendIOb("\r\n", 2);
- }
- free(p);
- }
- }
- SendIOb(".\r\n", 3);
- PushIOb();
- OVclosesearch(handle);
- } while (0);
-
- if (vector)
- cvector_free(vector);
-
- if (pattern)
- free(pattern);
-}
+++ /dev/null
-/* $Id: cache.c 6169 2003-01-21 06:31:40Z alexk $
-**
-** MessageID to storage token cache
-**
-** Written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** Implementation of a message ID to storage token cache which can be
-** built during XOVER/XHDR/NEWNEWS. If we hit in the cache when
-** retrieving articles the (relatively) expensive cost of a trip
-** through the history database is saved.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/tst.h"
-#include "inn/list.h"
-#include "libinn.h"
-#include "storage.h"
-
-#include "cache.h"
-
-/*
-** Pointer to the message ID to storage token ternary search tree
-*/
-static struct tst *msgidcache;
-
-/*
-** Count of message IDs in the cache so that someone doing GROUP,
-** XOVER, GROUP, XOVER etc. for example doesn't blow up with out of
-** memory
-*/
-static int msgcachecount;
-
-struct cache_entry {
- struct node node;
- HASH hash;
- TOKEN token;
-};
-
-static struct list unused, used;
-
-/*
-** Add a translation from HASH, h, to TOKEN, t, to the message ID
-** cache
-*/
-void
-cache_add(const HASH h, const TOKEN t)
-{
- if (innconf->msgidcachesize != 0) {
- struct cache_entry *entry;
- const unsigned char *p;
- struct cache_entry *exist;
-
- if (!msgidcache) {
- msgidcache = tst_init((innconf->msgidcachesize + 9) / 10);
- list_new(&unused);
- list_new(&used);
- }
-
- entry = xmalloc(sizeof *entry);
- entry->hash = h;
- entry->token = t;
- p = (unsigned char *) HashToText(h);
- if (tst_insert(msgidcache, p, entry,
- 0, (void **)&exist) == TST_DUPLICATE_KEY) {
- free(entry);
- list_remove(&exist->node);
- list_addtail(&unused, &exist->node);
- } else {
- list_addtail(&unused, &entry->node);
- ++msgcachecount;
- }
- if (msgcachecount >= innconf->msgidcachesize) {
- /* need to throw away a node */
- entry = (struct cache_entry *)list_remhead(&used);
- if (entry == NULL)
- entry = (struct cache_entry *)list_remhead(&unused);
- if (entry != NULL) {
- tst_delete(msgidcache,
- (unsigned char *) HashToText(entry->hash));
- free(entry);
- }
- }
- }
-}
-
-
-/*
-** Lookup (and remove if found) a MessageID to TOKEN mapping. If this
-** is a final lookup (ARTICLE or BODY) we remove it if we find it
-** since this matches the observed behaviour of most clients, but
-** cache it just in case we can reuse it if they issue multiple
-** commands against the same message ID (e.g. HEAD, BODY).
-*/
-TOKEN
-cache_get(const HASH h, bool final)
-{
- static HASH last_hash;
- static TOKEN last_token;
- static const TOKEN empty_token = { TOKEN_EMPTY, 0, "" };
-
- if (HashCompare(&h, &last_hash) == 0 && !HashEmpty(last_hash))
- return last_token;
-
- if (msgidcache) {
- struct cache_entry *entry;
-
- entry = tst_search(msgidcache, (unsigned char *) HashToText(h));
- if (entry != NULL) {
- list_remove(&entry->node);
- if (!final)
- list_addtail(&unused, &entry->node);
- else
- list_addtail(&used, &entry->node);
- last_hash = entry->hash;
- last_token = entry->token;
- return last_token;
- }
- }
- return empty_token;
-}
+++ /dev/null
-#ifndef CACHE_H
-#define CACHE_H
-
-#include "libinn.h"
-#include "storage.h"
-
-BEGIN_DECLS
-
-void cache_add(const HASH, const TOKEN);
-TOKEN cache_get(const HASH, bool final);
-
-END_DECLS
-
-#endif /* CACHE_H */
+++ /dev/null
-/* $Id: commands.c 7542 2006-08-26 05:57:11Z eagle $
-**
-** Miscellaneous commands.
-*/
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-
-#include "nnrpd.h"
-#include "ov.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-
-typedef struct {
- char *name;
- int high;
- int low;
- int count;
-} GROUPDATA;
-
-
-extern const char *NNRPinstance;
-
-/* returns:
- -1 for problem (such as no such authenticator etc.)
- 0 for authentication succeeded
- 1 for authentication failed
- */
-
-static char *PERMauthstring;
-
-static int
-PERMgeneric(char *av[], char *accesslist)
-{
- char path[BIG_BUFFER], *fields[6], *p;
- int i, pan[2], status;
- pid_t pid;
- struct stat stb;
-
- av += 2;
-
- PERMcanread = false;
- PERMcanpost = false;
- PERMaccessconf->locpost = false;
- PERMaccessconf->allowapproved = false;
-
- if (!*av) {
- Reply("%d no authenticator\r\n", NNTP_SYNTAX_VAL);
- return(-1);
- }
-
- /* check for ../. I'd use strstr, but there doesn't appear to
- be any other references for it, and I don't want to break
- portability */
- for (p = av[0]; *p; p++)
- if (strncmp(p, "../", 3) == 0) {
- Reply("%d ../ in authenticator %s\r\n", NNTP_SYNTAX_VAL, av[0]);
- return(-1);
- }
-
- if (strchr(_PATH_AUTHDIR,'/') == NULL)
- snprintf(path, sizeof(path), "%s/%s/%s/%s", innconf->pathbin,
- _PATH_AUTHDIR, _PATH_AUTHDIR_GENERIC, av[0]);
- else
- snprintf(path, sizeof(path), "%s/%s/%s", _PATH_AUTHDIR,
- _PATH_AUTHDIR_GENERIC, av[0]);
-
-#if !defined(S_IXUSR) && defined(_S_IXUSR)
-#define S_IXUSR _S_IXUSR
-#endif /* !defined(S_IXUSR) && defined(_S_IXUSR) */
-
-#if !defined(S_IXUSR) && defined(S_IEXEC)
-#define S_IXUSR S_IEXEC
-#endif /* !defined(S_IXUSR) && defined(S_IEXEC) */
-
- if (stat(path, &stb) || !(stb.st_mode&S_IXUSR)) {
- Reply("%d No such authenticator %s\r\n", NNTP_TEMPERR_VAL, av[0]);
- return -1;
- }
-
-
- /* Create a pipe. */
- if (pipe(pan) < 0) {
- syslog(L_FATAL, "cant pipe for %s %m", av[0]);
- return -1;
- }
-
- for (i = 0; (pid = fork()) < 0; i++) {
- if (i == innconf->maxforks) {
- Reply("%d Can't fork %s\r\n", NNTP_TEMPERR_VAL,
- strerror(errno));
- syslog(L_FATAL, "cant fork %s %m", av[0]);
- return -1;
- }
- syslog(L_NOTICE, "cant fork %s -- waiting", av[0]);
- sleep(5);
- }
-
- /* Run the child, with redirection. */
- if (pid == 0) {
- close(STDERR_FILENO); /* Close existing stderr */
- close(pan[PIPE_READ]);
-
- /* stderr goes down the pipe. */
- if (pan[PIPE_WRITE] != STDERR_FILENO) {
- if ((i = dup2(pan[PIPE_WRITE], STDERR_FILENO)) != STDERR_FILENO) {
- syslog(L_FATAL, "cant dup2 %d to %d got %d %m",
- pan[PIPE_WRITE], STDERR_FILENO, i);
- _exit(1);
- }
- close(pan[PIPE_WRITE]);
- }
-
- close_on_exec(STDIN_FILENO, false);
- close_on_exec(STDOUT_FILENO, false);
- close_on_exec(STDERR_FILENO, false);
-
- execv(path, av);
- Reply("%s\r\n", NNTP_BAD_COMMAND);
-
- syslog(L_FATAL, "cant execv %s %m", path);
- _exit(1);
- }
-
- close(pan[PIPE_WRITE]);
- i = read(pan[PIPE_READ], path, sizeof(path));
-
- waitpid(pid, &status, 0);
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- return 1;
-
- if ((p = strchr(path, '\n')) != NULL)
- *p = '\0';
-
- if (PERMauthstring)
- free(PERMauthstring);
-
- PERMauthstring = xstrdup(path);
-
- /*syslog(L_NOTICE, "%s (%ld) returned: %d %s %d\n", av[0], (long) pid, i, path, status);*/
- /* Split "host:permissions:user:pass:groups" into fields. */
- for (fields[0] = path, i = 0, p = path; *p; p++)
- if (*p == ':') {
- *p = '\0';
- fields[++i] = p + 1;
- }
-
- PERMcanread = strchr(fields[1], 'R') != NULL;
- PERMcanpost = strchr(fields[1], 'P') != NULL;
- PERMaccessconf->allowapproved = strchr(fields[1], 'A') != NULL;
- PERMaccessconf->locpost = strchr(fields[1], 'L') != NULL;
- PERMaccessconf->allowihave = strchr(fields[1], 'I') != NULL;
- if (strchr(fields[1], 'N') != NULL) PERMaccessconf->allownewnews = true;
- snprintf(PERMuser, sizeof(PERMuser), "%s@%s", fields[2], fields[0]);
- strlcpy(PERMpass, fields[3], sizeof(PERMpass));
- strcpy(accesslist, fields[4]);
- /*strcpy(writeaccess, fields[5]); future work? */
-
- /*for (i = 0; fields[i] && i < 6; i++)
- printf("fields[%d] = %s\n", i, fields[i]);*/
-
- return 0;
-}
-
-/* ARGSUSED */
-void
-CMDauthinfo(ac, av)
- int ac;
- char *av[];
-{
- static char User[SMBUF];
- static char Password[SMBUF];
- char accesslist[BIG_BUFFER];
- char errorstr[BIG_BUFFER];
-
- if (strcasecmp(av[1], "generic") == 0) {
- char *logrec = Glom(av);
-
- strlcpy(PERMuser, "<none>", sizeof(PERMuser));
-
- switch (PERMgeneric(av, accesslist)) {
- case 1:
- PERMspecified = NGgetlist(&PERMreadlist, accesslist);
- PERMpostlist = PERMreadlist;
- syslog(L_NOTICE, "%s auth %s (%s -> %s)", ClientHost, PERMuser,
- logrec, PERMauthstring? PERMauthstring: "" );
- Reply("%d Authentication succeeded\r\n", NNTP_AUTH_OK_VAL);
- PERMneedauth = false;
- PERMauthorized = true;
- free(logrec);
- return;
- case 0:
- syslog(L_NOTICE, "%s bad_auth %s (%s)", ClientHost, PERMuser,
- logrec);
- Reply("%d Authentication failed\r\n", NNTP_ACCESS_VAL);
- free(logrec);
- ExitWithStats(1, false);
- default:
- /* lower level has issued Reply */
- return;
- }
-
- } else {
-
- if (strcasecmp(av[1], "simple") == 0) {
- if (ac != 4) {
- Reply("%d AUTHINFO SIMPLE <USER> <PASS>\r\n", NNTP_BAD_COMMAND_VAL);
- return;
- }
- strlcpy(User, av[2], sizeof(User));
- strlcpy(Password, av[3], sizeof(Password));
- } else {
- if (strcasecmp(av[1], "user") == 0) {
- strlcpy(User, av[2], sizeof(User));
- Reply("%d PASS required\r\n", NNTP_AUTH_NEXT_VAL);
- return;
- }
-
- if (strcasecmp(av[1], "pass") != 0) {
- Reply("%d bad authinfo param\r\n", NNTP_BAD_COMMAND_VAL);
- return;
- }
- if (User[0] == '\0') {
- Reply("%d USER required\r\n", NNTP_AUTH_REJECT_VAL);
- return;
- }
-
- strlcpy(Password, av[2], sizeof(Password));
- }
-
- if (strcmp(User, PERMuser) == 0 && strcmp(Password, PERMpass) == 0) {
- syslog(L_NOTICE, "%s user %s", ClientHost, PERMuser);
- if (LLOGenable) {
- fprintf(locallog, "%s user (%s):%s\n", ClientHost, Username, PERMuser);
- fflush(locallog);
- }
- Reply("%d Ok\r\n", NNTP_AUTH_OK_VAL);
- PERMneedauth = false;
- PERMauthorized = true;
- return;
- }
-
- errorstr[0] = '\0';
-
- PERMlogin(User, Password, errorstr);
- PERMgetpermissions();
- if (!PERMneedauth) {
- syslog(L_NOTICE, "%s user %s", ClientHost, PERMuser);
- if (LLOGenable) {
- fprintf(locallog, "%s user (%s):%s\n", ClientHost, Username, PERMuser);
- fflush(locallog);
- }
- Reply("%d Ok\r\n", NNTP_AUTH_OK_VAL);
- PERMneedauth = false;
- PERMauthorized = true;
- return;
- }
-
- syslog(L_NOTICE, "%s bad_auth", ClientHost);
- if (errorstr[0] != '\0') {
- syslog(L_NOTICE, "%s script error str: %s", ClientHost, errorstr);
- Reply("%d %s\r\n", NNTP_ACCESS_VAL, errorstr);
- } else {
- Reply("%d Authentication error\r\n", NNTP_ACCESS_VAL);
- }
- ExitWithStats(1, false);
- }
-
-}
-
-
-/*
-** The "DATE" command. Part of NNTPv2.
-*/
-/* ARGSUSED0 */
-void
-CMDdate(ac, av)
- int ac UNUSED;
- char *av[] UNUSED;
-{
- TIMEINFO t;
- struct tm *gmt;
-
- if (GetTimeInfo(&t) < 0 || (gmt = gmtime(&t.time)) == NULL) {
- Reply("%d Can't get time, %s\r\n", NNTP_TEMPERR_VAL, strerror(errno));
- return;
- }
- Reply("%d %04.4d%02.2d%02.2d%02.2d%02.2d%02.2d\r\n",
- NNTP_DATE_FOLLOWS_VAL,
- gmt->tm_year + 1900, gmt->tm_mon + 1, gmt->tm_mday,
- gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
-}
-
-
-/*
-** Handle the "mode" command.
-*/
-/* ARGSUSED */
-void
-CMDmode(ac, av)
- int ac UNUSED;
- char *av[];
-{
- if (strcasecmp(av[1], "reader") == 0)
- Reply("%d %s InterNetNews NNRP server %s ready (%s).\r\n",
- PERMcanpost ? NNTP_POSTOK_VAL : NNTP_NOPOSTOK_VAL,
- PERMaccessconf->pathhost, inn_version_string,
- PERMcanpost ? "posting ok" : "no posting");
- else
- Reply("%d What?\r\n", NNTP_SYNTAX_VAL);
-}
-
-static int GroupCompare(const void *a1, const void* b1) {
- const GROUPDATA *a = a1;
- const GROUPDATA *b = b1;
-
- return strcmp(a->name, b->name);
-}
-
-/*
-** Display new newsgroups since a given date and time for specified
-** <distributions>.
-*/
-void CMDnewgroups(int ac, char *av[])
-{
- char *p;
- char *q;
- QIOSTATE *qp;
- time_t date;
- char *grplist[2];
- int hi, lo, count, flag;
- GROUPDATA *grouplist = NULL;
- GROUPDATA key;
- GROUPDATA *gd;
- int listsize = 0;
- int numgroups = 0;
- int numfound = 0;
- int i;
- bool local;
-
- /* Parse the date. */
- local = !(ac > 3 && strcasecmp(av[3], "GMT") == 0);
- date = parsedate_nntp(av[1], av[2], local);
- if (date == (time_t) -1) {
- Reply("%d Bad date\r\n", NNTP_SYNTAX_VAL);
- return;
- }
-
- /* Log an error if active.times doesn't exist, but don't return an error
- to the client. The most likely cause of this is a new server
- installation that's yet to have any new groups created, and returning
- an error was causing needless confusion. Just return the empty list
- of groups. */
- if ((qp = QIOopen(ACTIVETIMES)) == NULL) {
- syslog(L_ERROR, "%s cant fopen %s %m", ClientHost, ACTIVETIMES);
- Reply("%d New newsgroups follow.\r\n", NNTP_NEWGROUPS_FOLLOWS_VAL);
- Printf(".\r\n");
- return;
- }
-
- /* Read the file, ignoring long lines. */
- while ((p = QIOread(qp)) != NULL) {
- if ((q = strchr(p, ' ')) == NULL)
- continue;
- *q++ = '\0';
- if ((time_t) atol(q) < date)
- continue;
- if (!OVgroupstats(p, &lo, &hi, &count, &flag))
- continue;
-
- if (PERMspecified) {
- grplist[0] = p;
- grplist[1] = NULL;
- if (!PERMmatch(PERMreadlist, grplist))
- continue;
- }
- else
- continue;
-
- if (grouplist == NULL) {
- grouplist = xmalloc(1000 * sizeof(GROUPDATA));
- listsize = 1000;
- }
- if (listsize <= numgroups) {
- listsize += 1000;
- grouplist = xrealloc(grouplist, listsize * sizeof(GROUPDATA));
- }
-
- grouplist[numgroups].high = hi;
- grouplist[numgroups].low = lo;
- grouplist[numgroups].count = count;
- grouplist[numgroups].name = xstrdup(p);
- numgroups++;
- }
- QIOclose(qp);
-
- if ((qp = QIOopen(ACTIVE)) == NULL) {
- syslog(L_ERROR, "%s cant fopen %s %m", ClientHost, ACTIVE);
- Reply("%d Cannot open active file.\r\n", NNTP_TEMPERR_VAL);
- return;
- }
- qsort(grouplist, numgroups, sizeof(GROUPDATA), GroupCompare);
- Reply("%d New newsgroups follow.\r\n", NNTP_NEWGROUPS_FOLLOWS_VAL);
- for (numfound = numgroups; (p = QIOread(qp)) && numfound;) {
- if ((q = strchr(p, ' ')) == NULL)
- continue;
- *q++ = '\0';
- if ((q = strchr(q, ' ')) == NULL)
- continue;
- q++;
- if ((q = strchr(q, ' ')) == NULL)
- continue;
- q++;
- key.name = p;
- if ((gd = bsearch(&key, grouplist, numgroups, sizeof(GROUPDATA), GroupCompare)) == NULL)
- continue;
- Printf("%s %u %u %s\r\n", p, gd->high, gd->low, q);
- numfound--;
- }
- for (i = 0; i < numgroups; i++) {
- free(grouplist[i].name);
- }
- free(grouplist);
- QIOclose(qp);
- Printf(".\r\n");
-}
-
-
-/*
-** Post an article.
-*/
-/* ARGSUSED */
-void
-CMDpost(int ac UNUSED, char *av[] UNUSED)
-{
- static char *article;
- static int size;
- char *p, *q;
- char *end;
- int longline;
- READTYPE r;
- int i;
- long l;
- long sleeptime;
- char *path;
- const char *response;
- char idbuff[SMBUF];
- static int backoff_inited = false;
- bool ihave, permanent;
-
- ihave = (strcasecmp(av[0], "ihave") == 0);
- if (ihave && (!PERMaccessconf->allowihave || !PERMcanpost)) {
- syslog(L_NOTICE, "%s noperm ihave without permission", ClientHost);
- Reply("%s\r\n", NNTP_ACCESS);
- return;
- }
- if (!ihave && !PERMcanpost) {
- syslog(L_NOTICE, "%s noperm post without permission", ClientHost);
- Reply("%s\r\n", NNTP_CANTPOST);
- return;
- }
-
- if (!backoff_inited) {
- /* Exponential posting backoff */
- InitBackoffConstants();
- backoff_inited = true;
- }
-
- /* Dave's posting limiter - Limit postings to a certain rate
- * And now we support multiprocess rate limits. Questions?
- * Email dave@jetcafe.org.
- */
- if (BACKOFFenabled) {
-
- /* Acquire lock (this could be in RateLimit but that would
- * invoke the spaghetti factor).
- */
- if ((path = (char *) PostRecFilename(ClientIpString,PERMuser)) == NULL) {
- Reply("%s\r\n", NNTP_CANTPOST);
- return;
- }
-
- if (LockPostRec(path) == 0) {
- syslog(L_ERROR, "%s Error write locking '%s'",
- ClientHost, path);
- Reply("%s\r\n", NNTP_CANTPOST);
- return;
- }
-
- if (!RateLimit(&sleeptime,path)) {
- syslog(L_ERROR, "%s can't check rate limit info", ClientHost);
- Reply("%s\r\n", NNTP_CANTPOST);
- UnlockPostRec(path);
- return;
- } else if (sleeptime != 0L) {
- syslog(L_NOTICE,"%s post sleep time is now %ld", ClientHost, sleeptime);
- sleep(sleeptime);
- }
-
- /* Remove the lock here so that only one nnrpd process does the
- * backoff sleep at once. Other procs are sleeping for the lock.
- */
- UnlockPostRec(path);
-
- } /* end backoff code */
-
- /* Start at beginning of buffer. */
- if (article == NULL) {
- size = 4096;
- article = xmalloc(size);
- }
- idbuff[0] = 0;
- if (ihave) {
- Reply(NNTP_SENDIT "\r\n");
- } else {
- if ((p = GenerateMessageID(PERMaccessconf->domain)) != NULL) {
- if (VirtualPathlen > 0) {
- q = p;
- if ((p = strchr(p, '@')) != NULL) {
- *p = '\0';
- snprintf(idbuff, sizeof(idbuff), "%s%s@%s>", q,
- NNRPinstance, PERMaccessconf->domain);
- }
- } else {
- strlcpy(idbuff, p, sizeof(idbuff));
- }
- }
- Reply("%d Ok, recommended ID %s\r\n", NNTP_START_POST_VAL, idbuff);
- }
- fflush(stdout);
-
- p = article;
- end = &article[size];
-
- longline = 0;
- for (l = 1; ; l++) {
- size_t len;
- const char *line;
-
- r = line_read(&NNTPline, PERMaccessconf->clienttimeout, &line, &len);
- switch (r) {
- default:
- warn("%s internal %d in post", ClientHost, r);
- /* FALLTHROUGH */
- case RTtimeout:
- warn("%s timeout in post", ClientHost);
- ExitWithStats(1, false);
- /* NOTREACHED */
- case RTeof:
- warn("%s eof in post", ClientHost);
- ExitWithStats(1, false);
- /* NOTREACHED */
- case RTlong:
- if (longline == 0)
- longline = l;
- continue;
- case RTok:
- break;
- }
-
- /* if its the terminator, break out */
- if (strcmp(line, ".") == 0) {
- break;
- }
-
- /* if they broke our line length limit, there's little point
- * in processing any more of their input */
- if (longline != 0) {
- continue;
- }
-
- /* +2 because of the \n\0 we append; note we don't add the 2
- * when increasing the size of the buffer as ART_LINE_MALLOC
- * will always be larger than 2 bytes */
- if ((len + 2) > (size_t)(end - p)) {
- i = p - article;
- size += len + ART_LINE_MALLOC;
- article = xrealloc(article, size);
- end = &article[size];
- p = i + article;
- }
-
- /* reverse any byte-stuffing */
- if (*line == '.') {
- ++line;
- --len;
- }
- memcpy(p, line, len);
- p += len;
- *p++ = '\n';
- *p = '\0';
- }
-
- if (longline) {
- warn("%s toolong in post", ClientHost);
- Printf("%d Line %d too long\r\n",
- ihave ? NNTP_REJECTIT_VAL : NNTP_POSTFAIL_VAL, longline);
- POSTrejected++;
- return;
- }
-
- /* Send the article to the server. */
- response = ARTpost(article, idbuff, ihave, &permanent);
- if (response == NULL) {
- notice("%s post ok %s", ClientHost, idbuff);
- Reply("%s %s\r\n", ihave ? NNTP_TOOKIT : NNTP_POSTEDOK, idbuff);
- POSTreceived++;
- }
- else {
- if ((p = strchr(response, '\r')) != NULL)
- *p = '\0';
- if ((p = strchr(response, '\n')) != NULL)
- *p = '\0';
- notice("%s post failed %s", ClientHost, response);
- if (!ihave || permanent) {
- /* for permanent errors reject the message */
- Reply("%d %s\r\n", ihave ? NNTP_REJECTIT_VAL : NNTP_POSTFAIL_VAL,
- response);
- } else {
- /* non-permanent errors only have relevance to ihave, for
- * these we have the error status from the upstream
- * server to report */
- Reply("%s\r\n", response);
- }
- POSTrejected++;
- }
-}
-
-/*
-** The "xpath" command. An uncommon extension.
-*/
-/* ARGSUSED */
-void
-CMDxpath(ac, av)
- int ac UNUSED;
- char *av[] UNUSED;
-{
- Reply("%d Syntax error or bad command\r\n", NNTP_BAD_COMMAND_VAL);
-}
+++ /dev/null
-/* $Id: group.c 7538 2006-08-26 05:44:06Z eagle $
-**
-** Newsgroups and the active file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "ov.h"
-
-/*
-** Change to or list the specified newsgroup. If invalid, stay in the old
-** group.
-*/
-void CMDgroup(int ac, char *av[])
-{
- static char NOSUCHGROUP[] = NNTP_NOSUCHGROUP;
- ARTNUM i;
- char *grplist[2];
- char *group;
- void *handle;
- TOKEN token;
- int count;
- bool boolval;
- bool hookpresent = false;
-
-#ifdef DO_PYTHON
- hookpresent = PY_use_dynamic;
-#endif /* DO_PYTHON */
-
- if (!hookpresent && !PERMcanread) {
- if (PERMspecified)
- Reply("%d Permission denied\r\n", NNTP_ACCESS_VAL);
- else
- Reply("%d Authentication required\r\n", NNTP_AUTH_NEEDED_VAL);
- return;
- }
-
- /* Parse arguments. */
- if (ac == 1) {
- if (GRPcur == NULL) {
- Printf("%d No group specified\r\n", NNTP_XGTITLE_BAD);
- return;
- } else {
- group = xstrdup(GRPcur);
- }
- } else {
- group = xstrdup(av[1]);
- }
-
- if (!OVgroupstats(group, &ARTlow, &ARThigh, &count, NULL)) {
- Reply("%s %s\r\n", NOSUCHGROUP, group);
- free(group);
- return;
- }
-
-#ifdef DO_PYTHON
- if (PY_use_dynamic) {
- char *reply;
-
- /* Authorize user using Python module method dynamic*/
- if (PY_dynamic(PERMuser, group, false, &reply) < 0) {
- syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
- } else {
- if (reply != NULL) {
- syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, group, reply);
- Reply("%d %s\r\n", NNTP_ACCESS_VAL, reply);
- free(group);
- free(reply);
- return;
- }
- }
- }
-#endif /* DO_PYTHON */
-
- if (!hookpresent) {
- if (PERMspecified) {
- grplist[0] = group;
- grplist[1] = NULL;
- if (!PERMmatch(PERMreadlist, grplist)) {
- Reply("%d Permission denied\r\n", NNTP_ACCESS_VAL);
- free(group);
- return;
- }
- } else {
- Reply("%d Authentication required\r\n", NNTP_AUTH_NEEDED_VAL);
- free(group);
- return;
- }
- }
-
- /* Close out any existing article, report group stats. */
- ARTclose();
- GRPreport();
-
- /* Doing a "group" command? */
- if (strcasecmp(av[0], "group") == 0) {
- if (count == 0)
- Reply("%d 0 0 0 %s\r\n", NNTP_GROUPOK_VAL, group);
- else {
- /* if we're an NFS reader, check the last nfsreaderdelay
- * articles in the group to see if they arrived in the
- * last nfsreaderdelay (default 60) seconds. If they did,
- * don't report them as we don't want them to appear too
- * soon */
- if (innconf->nfsreader) {
- ARTNUM low, prev;
- time_t now, arrived;
-
- time(&now);
- if (ARTlow + innconf->nfsreaderdelay > ARThigh)
- low = ARTlow;
- else
- low = ARThigh - innconf->nfsreaderdelay;
- handle = OVopensearch(group, low, ARThigh);
- if (!handle) {
- Reply("%d group disappeared\r\n", NNTP_TEMPERR_VAL);
- free(group);
- return;
- }
- prev = low;
- while (OVsearch(handle, &i, NULL, NULL, NULL, &arrived)) {
- if (arrived + innconf->nfsreaderdelay > now) {
- ARThigh = prev;
- break;
- }
- prev = i;
- }
- OVclosesearch(handle);
- }
- Reply("%d %d %lu %lu %s\r\n", NNTP_GROUPOK_VAL, count,
- (unsigned long) ARTlow, (unsigned long) ARThigh, group);
- }
- GRPcount++;
- ARTnumber = ARTlow;
- if (GRPcur) {
- if (strcmp(GRPcur, group) != 0) {
- OVctl(OVCACHEFREE, &boolval);
- free(GRPcur);
- GRPcur = xstrdup(group);
- }
- } else
- GRPcur = xstrdup(group);
- } else {
- /* Must be doing a "listgroup" command. We used to just return
- something bland here ("Article list follows"), but reference NNTP
- returns the same data as GROUP does and since we have it all
- available it shouldn't hurt to return the same thing. */
- if (count == 0) {
- Reply("%d 0 0 0 %s\r\n", NNTP_GROUPOK_VAL, group);
- Printf(".\r\n");
- } else if ((handle = OVopensearch(group, ARTlow, ARThigh)) != NULL) {
- Reply("%d %d %lu %lu %s\r\n", NNTP_GROUPOK_VAL, count,
- (unsigned long) ARTlow, (unsigned long) ARThigh, group);
- while (OVsearch(handle, &i, NULL, NULL, &token, NULL)) {
- if (PERMaccessconf->nnrpdcheckart && !ARTinstorebytoken(token))
- continue;
- Printf("%lu\r\n", (unsigned long) i);
- }
- OVclosesearch(handle);
- Printf(".\r\n");
- GRPcount++;
- ARTnumber = ARTlow;
- if (GRPcur) {
- if (strcmp(GRPcur, group) != 0) {
- OVctl(OVCACHEFREE, &boolval);
- free(GRPcur);
- GRPcur = xstrdup(group);
- }
- } else
- GRPcur = xstrdup(group);
- } else {
- Reply("%s %s\r\n", NOSUCHGROUP, group);
- }
- }
- free(group);
-}
-
-
-/*
-** Report on the number of articles read in the group, and clear the count.
-*/
-void
-GRPreport()
-{
- char buff[SPOOLNAMEBUFF];
- char repbuff[1024];
-
- if (GRPcur) {
- strlcpy(buff, GRPcur, sizeof(buff));
- syslog(L_NOTICE, "%s group %s %lu", ClientHost, buff,
- (unsigned long) GRParticles);
- GRParticles = 0;
- repbuff[0]='\0';
- }
-}
-
-
-/*
-** Used by ANU-News clients.
-*/
-void
-CMDxgtitle(ac, av)
- int ac;
- char *av[];
-{
- QIOSTATE *qp;
- char *line;
- char *p;
- char *q;
- char *grplist[2];
- char save;
-
- /* Parse the arguments. */
- if (ac == 1) {
- if (GRPcount == 0) {
- Printf("%d No group specified\r\n", NNTP_XGTITLE_BAD);
- return;
- }
- p = GRPcur;
- }
- else
- p = av[1];
-
- if (!PERMspecified) {
- Printf("%d list follows\r\n", NNTP_XGTITLE_OK);
- Printf(".\r\n");
- return;
- }
-
- /* Open the file, get ready to scan. */
- if ((qp = QIOopen(NEWSGROUPS)) == NULL) {
- syslog(L_ERROR, "%s cant open %s %m", ClientHost, NEWSGROUPS);
- Printf("%d Can't open %s\r\n", NNTP_XGTITLE_BAD, NEWSGROUPS);
- return;
- }
- Printf("%d list follows\r\n", NNTP_XGTITLE_OK);
-
- /* Print all lines with matching newsgroup name. */
- while ((line = QIOread(qp)) != NULL) {
- for (q = line; *q && !ISWHITE(*q); q++)
- continue;
- save = *q;
- *q = '\0';
- if (uwildmat(line, p)) {
- if (PERMspecified) {
- grplist[0] = line;
- grplist[1] = NULL;
- if (!PERMmatch(PERMreadlist, grplist))
- continue;
- }
- *q = save;
- Printf("%s\r\n", line);
- }
- }
-
- /* Done. */
- QIOclose(qp);
- Printf(".\r\n");
-}
+++ /dev/null
-/* $Id: line.c 7837 2008-05-19 17:14:15Z iulius $
-**
-** Line by line reading support from sockets/pipes
-**
-** Written by Alex Kiernan (alex.kiernan@thus.net)
-**
-** This code implements a infinitely (well size_t) long single line
-** read routine, to protect against eating all available memory it
-** actually starts discarding characters if you try to send more than
-** the maximum article size in a single line.
-**
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <assert.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/messages.h"
-#include "nnrpd.h"
-
-#ifdef HAVE_SSL
-#include <openssl/ssl.h>
-#include <signal.h>
-extern SSL *tls_conn;
-#endif
-
-/*
-** free a previously allocated line structure
-*/
-void
-line_free(struct line *line)
-{
- static const struct line nullline = {0, 0, 0, 0};
-
- if (line && line->start) {
- free(line->start);
- *line = nullline;
- }
-}
-
-#ifdef HAVE_SSL
-/*
-** Alarm signal handler for client timeout.
-*/
-static void
-alarmHandler(int s)
-{
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
-}
-#endif
-
-/*
-** initialise a new line structure
-*/
-void
-line_init(struct line *line)
-{
- assert(line);
- line->allocated = NNTP_STRLEN;
- line->where = line->start = xmalloc(line->allocated);
- line->remaining = 0;
-}
-
-static ssize_t
-line_doread(void *p, size_t len, int timeout)
-{
- ssize_t n;
-
-#ifdef HAVE_SSL
- if (tls_conn) {
- int err;
- xsignal(SIGALRM, alarmHandler);
- do {
- alarm(timeout);
- n = SSL_read(tls_conn, p, len);
- alarm(0);
- if (tls_conn == NULL) {
- break;
- }
- err = SSL_get_error(tls_conn, n);
- switch (err) {
- case SSL_ERROR_SYSCALL:
- break;
-
- case SSL_ERROR_SSL:
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
- break;
- }
- } while (err == SSL_ERROR_WANT_READ);
- xsignal(SIGALRM, SIG_DFL);
- } else {
-#endif
- do {
- n = read(STDIN_FILENO, p, len);
- } while (n == -1 && errno == EINTR);
-#ifdef HAVE_SSL
- }
-#endif
- return n;
-}
-
-READTYPE
-line_read(struct line *line, int timeout, const char **p, size_t *len)
-{
- char *where;
- char *lf = NULL;
- READTYPE r = RTok;
-
- assert(line != NULL);
- assert(line->start != NULL);
- /* shuffle any trailing portion not yet processed to the start of
- * the buffer */
- if (line->remaining != 0) {
- if (line->start != line->where) {
- memmove(line->start, line->where, line->remaining);
- }
- lf = memchr(line->start, '\n', line->remaining);
- }
- where = line->start + line->remaining;
-
- /* if we found a line terminator in the data we have we don't need
- * to ask for any more */
- if (lf == NULL) {
- do {
- fd_set rmask;
- int i;
- ssize_t count;
-
- /* if we've filled the line buffer, double the size,
- * reallocate the buffer and try again */
- if (where == line->start + line->allocated) {
- size_t newsize = line->allocated * 2;
-
- /* don't grow the buffer bigger than the maximum
- * article size we'll accept */
- if (PERMaccessconf->localmaxartsize > NNTP_STRLEN)
- if (newsize > (unsigned)PERMaccessconf->localmaxartsize)
- newsize = PERMaccessconf->localmaxartsize;
-
- /* if we're trying to grow from the same size, to the
- * same size, we must have hit the localmaxartsize
- * buffer for a second (or subsequent) time - the user
- * is likely trying to DOS us, so don't double the
- * size any more, just overwrite characters until they
- * stop, then discard the whole thing */
- if (newsize == line->allocated) {
- warn("%s overflowed our line buffer (%ld), "
- "discarding further input", ClientHost,
- PERMaccessconf->localmaxartsize);
- where = line->start;
- r = RTlong;
- } else {
- line->start = xrealloc(line->start, newsize);
- where = line->start + line->allocated;
- line->allocated = newsize;
- }
- }
-
-#ifdef HAVE_SSL
- /* It seems that the SSL_read cannot be mixed with select()
- * as in the current code. SSL communicates in its own data
- * blocks and hand shaking. The do_readline using SSL_read
- * could return, but still with a partial line in the SSL_read
- * buffer. Then the server SSL routine would sit there waiting
- * for completion of that data block while nnrpd sat at the
- * select() routine waiting for more data from the server.
- *
- * Here, we decide to just bypass the select() wait. Unlike
- * innd with multiple threads, the select on nnrpd is just
- * waiting on a single file descriptor, so it is not really
- * essential with blocked read like SSL_read. Using an alarm
- * signal around SSL_read for non active timeout, SSL works
- * without dead locks. However, without the select() wait,
- * the IDLE timer stat won't be collected...
- */
- if (tls_conn == NULL) {
-#endif
- /* Wait for activity on stdin, updating timer stats as we
- * go. */
- do {
- struct timeval t;
-
- FD_ZERO(&rmask);
- FD_SET(STDIN_FILENO, &rmask);
- t.tv_sec = timeout;
- t.tv_usec = 0;
- TMRstart(TMR_IDLE);
- i = select(STDIN_FILENO + 1, &rmask, NULL, NULL, &t);
- TMRstop(TMR_IDLE);
- if (i == -1 && errno != EINTR) {
- syswarn("%s can't select", ClientHost);
- return RTtimeout;
- }
- } while (i == -1);
-
- /* If stdin didn't select, we must have timed out. */
- if (i == 0 || !FD_ISSET(STDIN_FILENO, &rmask))
- return RTtimeout;
-#ifdef HAVE_SSL
- }
-#endif
- count = line_doread(where,
- line->allocated - (where - line->start),
- timeout);
-
- /* give timeout for read errors */
- if (count < 0) {
- sysnotice("%s can't read", ClientHost);
- return RTtimeout;
- }
- /* if we hit EOF, terminate the string and send it back */
- if (count == 0) {
- assert((where + count) < (line->start + line->allocated));
- where[count] = '\0';
- return RTeof;
- }
- /* search for `\n' in what we just read, if we find it we'll
- * drop out and return the line for processing */
- lf = memchr(where, '\n', count);
- where += count;
- } while (lf == NULL);
- }
-
- /* remember where we've processed up to so we can start off there
- * next time */
- line->where = lf + 1;
- line->remaining = where - line->where;
-
- if (r == RTok) {
- /* if we see a full CRLF pair strip them both off before
- * returning the line to our caller, if we just get an LF
- * we'll accept that too */
- if (lf > line->start && lf[-1] == '\r') {
- --lf;
- }
- *lf = '\0';
- *len = lf - line->start;
- *p = line->start;
- }
- return r;
-}
+++ /dev/null
-/* $Id: list.c 7731 2008-04-06 08:40:29Z iulius $
-**
-** List commands.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "nnrpd.h"
-#include "ov.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-
-typedef struct _LISTINFO {
- const char *method;
- const char * File;
- void (*impl)(struct _LISTINFO *);
- bool Required;
- const char * Items;
- const char * Format;
-} LISTINFO;
-
-static void cmd_list_schema(LISTINFO *lp);
-static void cmd_list_extensions(LISTINFO *lp);
-
-static LISTINFO INFOactive = {
- "active", _PATH_ACTIVE, NULL, true, "active newsgroups",
- "Newsgroups in form \"group high low flags\""
-};
-static LISTINFO INFOactivetimes = {
- "active.times", _PATH_ACTIVETIMES, NULL, false, "creation times",
- "Group creations in form \"name time who\""
-};
-static LISTINFO INFOdistribs = {
- "distributions", _PATH_NNRPDIST, NULL, false, "newsgroup distributions",
- "Distributions in form \"area description\""
-};
-static LISTINFO INFOsubs = {
- "subscriptions", _PATH_NNRPSUBS, NULL, false, "automatic group subscriptions",
- "Subscriptions in form \"group\""
-};
-static LISTINFO INFOdistribpats = {
- "distrib.pats", _PATH_DISTPATS, NULL, false, "distribution patterns",
- "Default distributions in form \"weight:pattern:value\""
-};
-static LISTINFO INFOextensions = {
- "extensions", NULL, cmd_list_extensions, false, "supported extensions",
- "Supported NNTP extensions"
-};
-static LISTINFO INFOgroups = {
- "newsgroups", _PATH_NEWSGROUPS, NULL, false, "newsgroup descriptions",
- "Descriptions in form \"group description\""
-};
-static LISTINFO INFOmoderators = {
- "moderators", _PATH_MODERATORS, NULL, false, "moderator patterns",
- "Newsgroup moderators in form \"group-pattern:mail-address-pattern\""
-};
-static LISTINFO INFOschema = {
- "overview.fmt", NULL, cmd_list_schema, true, "overview format",
- "Order of fields in overview database"
-};
-static LISTINFO INFOmotd = {
- "motd", _PATH_MOTD, NULL, false, "motd",
- "Message of the day text"
-};
-
-static LISTINFO *info[] = {
- &INFOactive,
- &INFOactivetimes,
- &INFOdistribs,
- &INFOsubs,
- &INFOdistribpats,
- &INFOextensions,
- &INFOgroups,
- &INFOmoderators,
- &INFOschema,
- &INFOmotd,
-};
-
-
-/*
-** List the overview schema
-*/
-static void
-cmd_list_schema(LISTINFO *lp)
-{
- const struct cvector *standard;
- unsigned int i;
-
- Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, lp->Format);
- standard = overview_fields();
- for (i = 0; i < standard->count; ++i) {
- Printf("%s:\r\n", standard->strings[i]);
- }
- for (i = 0; i < OVextra->count; ++i) {
- Printf("%s:full\r\n", OVextra->strings[i]);
- }
- Printf(".\r\n");
-}
-
-
-/*
-** List supported extensions
-*/
-static void
-cmd_list_extensions(LISTINFO *lp)
-{
- Reply("%d %s.\r\n", NNTP_SLAVEOK_VAL, lp->Format);
- if (PERMauthorized != true)
- Printf("AUTHINFO USER\r\n");
- Printf("LISTGROUP\r\n");
- Printf(".\r\n");
-}
-
-
-/*
-** List a single newsgroup. Called by LIST ACTIVE with a single argument.
-** This is quicker than parsing the whole active file, but only works with
-** single groups. It also doesn't work for aliased groups, since overview
-** doesn't know what group the group is aliased to (yet). Returns whether we
-** were able to answer the command.
-*/
-static bool
-CMD_list_single(char *group)
-{
- char *grplist[2] = { NULL, NULL };
- int lo, hi, flag;
-
- if (PERMspecified) {
- grplist[0] = group;
- if (!PERMmatch(PERMreadlist, grplist))
- return false;
- }
- if (OVgroupstats(group, &lo, &hi, NULL, &flag) && flag != '=') {
- Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, INFOactive.Format);
- Printf("%s %010u %010u %c\r\n.\r\n", group, hi, lo, flag);
- return true;
- }
- return false;
-}
-
-
-/*
-** List active newsgroups, newsgroup descriptions, and distributions.
-*/
-void
-CMDlist(int ac, char *av[])
-{
- QIOSTATE *qp;
- char *p;
- char *save;
- char *path;
- char *q;
- char *grplist[2];
- LISTINFO *lp;
- char *wildarg = NULL;
- char savec;
- unsigned int i;
-
- p = av[1];
- if (p == NULL) {
- lp = &INFOactive;
- } else {
- lp = NULL;
- for (i = 0; i < ARRAY_SIZE(info); ++i) {
- if (strcasecmp(p, info[i]->method) == 0) {
- lp = info[i];
- break;
- }
- }
- }
- if (lp == NULL) {
- Reply("%s\r\n", NNTP_SYNTAX_USE);
- return;
- }
- if (lp == &INFOactive) {
- if (ac == 3) {
- wildarg = av[2];
- if (CMD_list_single(wildarg))
- return;
- }
- } else if (lp == &INFOgroups || lp == &INFOactivetimes) {
- if (ac == 3)
- wildarg = av[2];
- }
-
- if (ac > 2 && !wildarg) {
- Reply("%s\r\n", NNTP_SYNTAX_USE);
- return;
- }
-
- if (lp->impl != NULL) {
- lp->impl(lp);
- return;
- }
-
- path = innconf->pathetc;
- if ((strstr(lp->File, "active") != NULL) ||
- (strstr(lp->File, "newsgroups") != NULL))
- path = innconf->pathdb;
- if (strchr(lp->File, '/') != NULL)
- path = "";
- path = concatpath(path, lp->File);
- qp = QIOopen(path);
- free(path);
- if (qp == NULL) {
- Reply("%d No list of %s available.\r\n",
- NNTP_TEMPERR_VAL, lp->Items);
- if (lp->Required || errno != ENOENT) {
- syslog(L_ERROR, "%s cant fopen %s %m", ClientHost, lp->File);
- }
- return;
- }
-
- Reply("%d %s.\r\n", NNTP_LIST_FOLLOWS_VAL, lp->Format);
- if (!PERMspecified) {
- /* Optmize for unlikely case of no permissions and false default. */
- QIOclose(qp);
- Printf(".\r\n");
- return;
- }
-
- /* Set up group list terminator. */
- grplist[1] = NULL;
-
- /* Read lines, ignore long ones. */
- while ((p = QIOread(qp)) != NULL) {
- if (lp == &INFOmotd) {
- Printf("%s\r\n", p);
- continue;
- }
- if (p[0] == '.' && p[1] == '\0') {
- syslog(L_ERROR, "%s single dot in %s", ClientHost, lp->File);
- continue;
- }
- /* matching patterns against patterns is not that
- good but it's better than nothing ... */
- if (lp == &INFOdistribpats) {
- if (*p == '\0' || *p == '#' || *p == ';' || *p == ' ')
- continue;
- if (PERMspecified) {
- if ((q = strchr(p, ':')) == NULL)
- continue;
- q++;
- if ((save = strchr(q, ':')) == NULL)
- continue;
- *save = '\0';
- grplist[0] = q;
- if (!PERMmatch(PERMreadlist, grplist))
- continue;
- *save = ':';
- }
- Printf("%s\r\n", p);
- continue;
- }
- if (lp == &INFOdistribs || lp == &INFOmoderators) {
- if (*p != '\0' && *p != '#' && *p != ';' && *p != ' ')
- Printf("%s\r\n", p);
- continue;
- }
- savec = '\0';
- for (save = p; *save != '\0'; save++) {
- if (*save == ' ' || *save == '\t') {
- savec = *save;
- *save = '\0';
- break;
- }
- }
-
- if (PERMspecified) {
- grplist[0] = p;
- if (!PERMmatch(PERMreadlist, grplist))
- continue;
- }
- if (wildarg && !uwildmat(p, wildarg))
- continue;
- if (savec != '\0')
- *save = savec;
- Printf("%s\r\n", p);
- }
- QIOclose(qp);
-
- Printf(".\r\n");
-}
+++ /dev/null
-/* $Id: misc.c 6535 2003-12-10 09:02:22Z rra $
-**
-** Miscellaneous support routines.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "tls.h"
-#include "sasl_config.h"
-
-#ifdef HAVE_SSL
-extern SSL *tls_conn;
-extern int nnrpd_starttls_done;
-#endif
-
-
-/*
-** Parse a string into a NULL-terminated array of words; return number
-** of words. If argvp isn't NULL, it and what it points to will be freed.
-*/
-int
-Argify(line, argvp)
- char *line;
- char ***argvp;
-{
- char **argv;
- char *p;
-
- if (*argvp != NULL) {
- free(*argvp[0]);
- free(*argvp);
- }
-
- /* Copy the line, which we will split up. */
- while (ISWHITE(*line))
- line++;
- p = xstrdup(line);
-
- /* Allocate worst-case amount of space. */
- for (*argvp = argv = xmalloc((strlen(p) + 2) * sizeof(char *)); *p; ) {
- /* Mark start of this word, find its end. */
- for (*argv++ = p; *p && !ISWHITE(*p); )
- p++;
- if (*p == '\0')
- break;
-
- /* Nip off word, skip whitespace. */
- for (*p++ = '\0'; ISWHITE(*p); )
- p++;
- }
- *argv = NULL;
- return argv - *argvp;
-}
-
-
-/*
-** Take a vector which Argify made and glue it back together with
-** spaces between each element. Returns a pointer to dynamic space.
-*/
-char *
-Glom(av)
- char **av;
-{
- char **v;
- int i;
- char *save;
-
- /* Get space. */
- for (i = 0, v = av; *v; v++)
- i += strlen(*v) + 1;
- i++;
-
- save = xmalloc(i);
- save[0] = '\0';
- for (v = av; *v; v++) {
- if (v > av)
- strlcat(save, " ", i);
- strlcat(save, *v, i);
- }
-
- return save;
-}
-
-
-/*
-** Match a list of newsgroup specifiers against a list of newsgroups.
-** func is called to see if there is a match.
-*/
-bool PERMmatch(char **Pats, char **list)
-{
- int i;
- char *p;
- int match = false;
-
- if (Pats == NULL || Pats[0] == NULL)
- return true;
-
- for ( ; *list; list++) {
- for (i = 0; (p = Pats[i]) != NULL; i++) {
- if (p[0] == '!') {
- if (uwildmat(*list, ++p))
- match = false;
- }
- else if (uwildmat(*list, p))
- match = true;
- }
- if (match)
- /* If we can read it in one group, we can read it, period. */
- return true;
- }
-
- return false;
-}
-
-
-/*
-** Check to see if user is allowed to see this article by matching
-** Newsgroups line.
-*/
-bool
-PERMartok(void)
-{
- static char **grplist;
- char *p, **grp;
-
- if (!PERMspecified)
- return false;
-
- if ((p = GetHeader("Xref")) == NULL) {
- /* in case article does not include Xref */
- if ((p = GetHeader("Newsgroups")) != NULL) {
- if (!NGgetlist(&grplist, p))
- /* No newgroups or null entry. */
- return true;
- } else {
- return true;
- }
- } else {
- /* skip path element */
- if ((p = strchr(p, ' ')) == NULL)
- return true;
- for (p++ ; *p == ' ' ; p++);
- if (*p == '\0')
- return true;
- if (!NGgetlist(&grplist, p))
- /* No newgroups or null entry. */
- return true;
- /* chop ':' and article number */
- for (grp = grplist ; *grp != NULL ; grp++) {
- if ((p = strchr(*grp, ':')) == NULL)
- return true;
- *p = '\0';
- }
- }
-
-#ifdef DO_PYTHON
- if (PY_use_dynamic) {
- char *reply;
-
- /* Authorize user at a Python authorization module */
- if (PY_dynamic(PERMuser, p, false, &reply) < 0) {
- syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
- } else {
- if (reply != NULL) {
- syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
- free(reply);
- return false;
- }
- return true;
- }
- }
-#endif /* DO_PYTHON */
-
- return PERMmatch(PERMreadlist, grplist);
-}
-
-
-/*
-** Parse a newsgroups line, return true if there were any.
-*/
-bool
-NGgetlist(argvp, list)
- char ***argvp;
- char *list;
-{
- char *p;
-
- for (p = list; *p; p++)
- if (*p == ',')
- *p = ' ';
-
- return Argify(list, argvp) != 0;
-}
-
-
-/*********************************************************************
- * POSTING RATE LIMITS - The following code implements posting rate
- * limits. News clients are indexed by IP number (or PERMuser, see
- * config file). After a relatively configurable number of posts, the nnrpd
- * process will sleep for a period of time before posting anything.
- *
- * Each time that IP number posts a message, the time of
- * posting and the previous sleep time is stored. The new sleep time
- * is computed based on these values.
- *
- * To compute the new sleep time, the previous sleep time is, for most
- * cases multiplied by a factor (backoff_k).
- *
- * See inn.conf(5) for how this code works
- *
- *********************************************************************/
-
-/* Defaults are pass through, i.e. not enabled
- * NEW for INN 1.8 - Use the inn.conf file to specify the following:
- *
- * backoff_k: <integer>
- * backoff_postfast: <integer>
- * backoff_postslow: <integer>
- * backoff_trigger: <integer>
- * backoff_db: <path>
- * backoff_auth: <on|off>
- *
- * You may also specify posting backoffs on a per user basis. To do this
- * turn on "backoff_auth"
- *
- * Now these are runtime constants. <grin>
- */
-static char postrec_dir[SMBUF]; /* Where is the post record directory? */
-
-void
-InitBackoffConstants()
-{
- struct stat st;
-
- /* Default is not to enable this code */
- BACKOFFenabled = false;
-
- /* Read the runtime config file to get parameters */
-
- if ((PERMaccessconf->backoff_db == NULL) ||
- !(PERMaccessconf->backoff_k >= 0L && PERMaccessconf->backoff_postfast >= 0L && PERMaccessconf->backoff_postslow >= 1L))
- return;
-
- /* Need this database for backing off */
- strlcpy(postrec_dir, PERMaccessconf->backoff_db, sizeof(postrec_dir));
- if (stat(postrec_dir, &st) < 0) {
- if (ENOENT == errno) {
- if (!MakeDirectory(postrec_dir, true)) {
- syslog(L_ERROR, "%s cannot create backoff_db '%s': %s",ClientHost,postrec_dir,strerror(errno));
- return;
- }
- } else {
- syslog(L_ERROR, "%s cannot stat backoff_db '%s': %s",ClientHost,postrec_dir,strerror(errno));
- return;
- }
- }
- if (!S_ISDIR(st.st_mode)) {
- syslog(L_ERROR, "%s backoff_db '%s' is not a directory",ClientHost,postrec_dir);
- return;
- }
-
- BACKOFFenabled = true;
-
- return;
-}
-
-/*
- * PostRecs are stored in individual files. I didn't have a better
- * way offhand, don't want to touch DBZ, and the number of posters is
- * small compared to the number of readers. This is the filename corresponding
- * to an IP number.
- */
-char
-*PostRecFilename(ip,user)
- char *ip;
- char *user;
-{
- static char buff[SPOOLNAMEBUFF];
- char dirbuff[SPOOLNAMEBUFF];
- struct in_addr inaddr;
- unsigned long int addr;
- unsigned char quads[4];
- unsigned int i;
-
- if (PERMaccessconf->backoff_auth) {
- snprintf(buff, sizeof(buff), "%s/%s", postrec_dir, user);
- return(buff);
- }
-
- if (inet_aton(ip, &inaddr) < 1) {
- /* If inet_aton() fails, we'll assume it's an IPv6 address. We'll
- * also assume for now that we're dealing with a limited number of
- * IPv6 clients so we'll place their files all in the same
- * directory for simplicity. Someday we'll need to change this to
- * something more scalable such as DBZ when IPv6 clients become
- * more popular. */
- snprintf(buff, sizeof(buff), "%s/%s", postrec_dir, ip);
- return(buff);
- }
- /* If it's an IPv4 address just fall through. */
-
- addr = ntohl(inaddr.s_addr);
- for (i=0; i<4; i++)
- quads[i] = (unsigned char) (0xff & (addr>>(i*8)));
-
- snprintf(dirbuff, sizeof(dirbuff), "%s/%03d%03d/%03d",
- postrec_dir, quads[3], quads[2], quads[1]);
- if (!MakeDirectory(dirbuff,true)) {
- syslog(L_ERROR, "%s Unable to create postrec directories '%s': %s",
- ClientHost, dirbuff, strerror(errno));
- return NULL;
- }
- snprintf(buff, sizeof(buff), "%s/%03d", dirbuff, quads[0]);
- return(buff);
-}
-
-/*
- * Lock the post rec file. Return 1 on lock, 0 on error
- */
-int
-LockPostRec(path)
- char *path;
-{
- char lockname[SPOOLNAMEBUFF];
- char temp[SPOOLNAMEBUFF];
- int statfailed = 0;
-
- snprintf(lockname, sizeof(lockname), "%s.lock", path);
-
- for (;; sleep(5)) {
- int fd;
- struct stat st;
- time_t now;
-
- fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT, 0600);
- if (fd >= 0) {
- /* We got the lock! */
- snprintf(temp, sizeof(temp), "pid:%ld\n", (unsigned long) getpid());
- write(fd, temp, strlen(temp));
- close(fd);
- return(1);
- }
-
- /* No lock. See if the file is there. */
- if (stat(lockname, &st) < 0) {
- syslog(L_ERROR, "%s cannot stat lock file %s", ClientHost, strerror(errno));
- if (statfailed++ > 5) return(0);
- continue;
- }
-
- /* If lockfile is older than the value of
- PERMaccessconf->backoff_postslow, remove it */
- statfailed = 0;
- time(&now);
- if (now < st.st_ctime + PERMaccessconf->backoff_postslow) continue;
- syslog(L_ERROR, "%s removing stale lock file %s", ClientHost, lockname);
- unlink(lockname);
- }
-}
-
-void
-UnlockPostRec(path)
- char *path;
-{
- char lockname[SPOOLNAMEBUFF];
-
- snprintf(lockname, sizeof(lockname), "%s.lock", path);
- if (unlink(lockname) < 0) {
- syslog(L_ERROR, "%s can't unlink lock file: %s", ClientHost,strerror(errno)) ;
- }
- return;
-}
-
-/*
- * Get the stored postrecord for that IP
- */
-static int
-GetPostRecord(char *path, long *lastpost, long *lastsleep, long *lastn)
-{
- static char buff[SMBUF];
- FILE *fp;
- char *s;
-
- fp = fopen(path,"r");
- if (fp == NULL) {
- if (errno == ENOENT) {
- return 1;
- }
- syslog(L_ERROR, "%s Error opening '%s': %s",
- ClientHost, path, strerror(errno));
- return 0;
- }
-
- if (fgets(buff,SMBUF,fp) == NULL) {
- syslog(L_ERROR, "%s Error reading '%s': %s",
- ClientHost, path, strerror(errno));
- return 0;
- }
- *lastpost = atol(buff);
-
- if ((s = strchr(buff,',')) == NULL) {
- syslog(L_ERROR, "%s bad data in postrec file: '%s'",
- ClientHost, buff);
- return 0;
- }
- s++; *lastsleep = atol(s);
-
- if ((s = strchr(s,',')) == NULL) {
- syslog(L_ERROR, "%s bad data in postrec file: '%s'",
- ClientHost, buff);
- return 0;
- }
- s++; *lastn = atol(s);
-
- fclose(fp);
- return 1;
-}
-
-/*
- * Store the postrecord for that IP
- */
-static int
-StorePostRecord(char *path, time_t lastpost, long lastsleep, long lastn)
-{
- FILE *fp;
-
- fp = fopen(path,"w");
- if (fp == NULL) {
- syslog(L_ERROR, "%s Error opening '%s': %s",
- ClientHost, path, strerror(errno));
- return 0;
- }
-
- fprintf(fp,"%ld,%ld,%ld\n",(long) lastpost,lastsleep,lastn);
- fclose(fp);
- return 1;
-}
-
-/*
- * Return the proper sleeptime. Return false on error.
- */
-int
-RateLimit(sleeptime,path)
- long *sleeptime;
- char *path;
-{
- TIMEINFO Now;
- long prevpost,prevsleep,prevn,n;
-
- if (GetTimeInfo(&Now) < 0)
- return 0;
-
- prevpost = 0L; prevsleep = 0L; prevn = 0L; n = 0L;
- if (!GetPostRecord(path,&prevpost,&prevsleep,&prevn)) {
- syslog(L_ERROR, "%s can't get post record: %s",
- ClientHost, strerror(errno));
- return 0;
- }
- /*
- * Just because yer paranoid doesn't mean they ain't out ta get ya
- * This is called paranoid clipping
- */
- if (prevn < 0L) prevn = 0L;
- if (prevsleep < 0L) prevsleep = 0L;
- if (prevsleep > PERMaccessconf->backoff_postfast) prevsleep = PERMaccessconf->backoff_postfast;
-
- /*
- * Compute the new sleep time
- */
- *sleeptime = 0L;
- if (prevpost <= 0L) {
- prevpost = 0L;
- prevn = 1L;
- } else {
- n = Now.time - prevpost;
- if (n < 0L) {
- syslog(L_NOTICE,"%s previous post was in the future (%ld sec)",
- ClientHost,n);
- n = 0L;
- }
- if (n < PERMaccessconf->backoff_postfast) {
- if (prevn >= PERMaccessconf->backoff_trigger) {
- *sleeptime = 1 + (prevsleep * PERMaccessconf->backoff_k);
- }
- } else if (n < PERMaccessconf->backoff_postslow) {
- if (prevn >= PERMaccessconf->backoff_trigger) {
- *sleeptime = prevsleep;
- }
- } else {
- prevn = 0L;
- }
- prevn++;
- }
-
- *sleeptime = ((*sleeptime) > PERMaccessconf->backoff_postfast) ? PERMaccessconf->backoff_postfast : (*sleeptime);
- /* This ought to trap this bogon */
- if ((*sleeptime) < 0L) {
- syslog(L_ERROR,"%s Negative sleeptime detected: %ld, prevsleep: %ld, N: %ld",ClientHost,*sleeptime,prevsleep,n);
- *sleeptime = 0L;
- }
-
- /* Store the postrecord */
- if (!StorePostRecord(path,Now.time,*sleeptime,prevn)) {
- syslog(L_ERROR, "%s can't store post record: %s", ClientHost, strerror(errno));
- return 0;
- }
-
- return 1;
-}
-
-#ifdef HAVE_SSL
-/*
-** The "STARTTLS" command. RFC2595.
-*/
-/* ARGSUSED0 */
-
-void
-CMDstarttls(ac, av)
- int ac UNUSED;
- char *av[] UNUSED;
-{
- int result;
-
- tls_init();
- if (nnrpd_starttls_done == 1) {
- Reply("%d Already successfully executed STARTTLS\r\n",
- NNTP_STARTTLS_DONE_VAL);
- return;
- }
-
- Reply("%d Begin TLS negotiation now\r\n", NNTP_STARTTLS_NEXT_VAL);
- fflush(stdout);
-
- /* must flush our buffers before starting tls */
-
- result=tls_start_servertls(0, /* read */
- 1); /* write */
- if (result==-1) {
- /* No reply because we have already sent NNTP_STARTTLS_NEXT_VAL. */
- return;
- }
- nnrpd_starttls_done = 1;
-}
-#endif /* HAVE_SSL */
+++ /dev/null
-/* $Revision: 6372 $
-**
-** The newnews command.
-*/
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/wire.h"
-#include "nnrpd.h"
-#include "ov.h"
-#include "cache.h"
-
-#define GROUP_LIST_DELTA 10
-
-static bool FindHeader(ARTHANDLE *art, const char **pp, const char **qp,
- const char* hdr, size_t hdrlen)
-{
- const char *p, *p1, *q;
- bool Nocr = true;
-
- p = wire_findheader(art->data, art->len, hdr);
- if (p == NULL)
- return false;
- q = p;
- for (p1 = NULL; p < art->data + art->len; p++) {
- if (p1 != NULL && *p1 == '\r' && *p == '\n') {
- Nocr = false;
- break;
- }
- if (*p == '\n') {
- Nocr = true;
- break;
- }
- p1 = p;
- }
- if (p >= art->data + art->len)
- return false;
- if (!Nocr)
- p = p1;
-
- *pp = p;
- *qp = q;
- return true;
-}
-
-/*
-** get Xref header
-*/
-static char *GetXref(ARTHANDLE *art) {
- const char *p, *q;
-
- if (!FindHeader(art, &p, &q, "xref", sizeof("xref")))
- return NULL;
- return xstrndup(q, p - q);
-}
-
-/*
-** Split newsgroup list into array of newsgroups. Return static pointer,
-** or NULL if there are no newsgroup.
-*/
-static char **GetGroups(char *p) {
- static int size;
- static char **list;
- int i;
- char *q;
- static char *Xrefbuf = NULL;
- char *Xref = p;
-
- if (size == 0) {
- size = GROUP_LIST_DELTA;
- list = xmalloc((size + 1) * sizeof(char *));
- }
- Xref = p;
- for (Xref++; *Xref == ' '; Xref++);
- if ((Xref = strchr(Xref, ' ')) == NULL)
- return NULL;
- for (Xref++; *Xref == ' '; Xref++);
- if (!Xrefbuf)
- Xrefbuf = xmalloc(BIG_BUFFER);
- strlcpy(Xrefbuf, Xref, BIG_BUFFER);
- if ((q = strchr(Xrefbuf, '\t')) != NULL)
- *q = '\0';
- p = Xrefbuf;
-
- for (i = 0 ; ;i++) {
- while (ISWHITE(*p))
- p++;
- if (*p == '\0' || *p == '\n')
- break;
-
- if (i >= size - 1) {
- size += GROUP_LIST_DELTA;
- list = xrealloc(list, (size + 1) * sizeof(char *));
- }
- for (list[i] = p; *p && *p != '\n' && !ISWHITE(*p); p++) {
- if (*p == ':')
- *p = '\0';
- }
- if (*p) *p++ = '\0';
- }
- list[i] = NULL;
- return i ? list : NULL;
-}
-
-static bool HaveSeen(bool AllGroups, char *group, char **groups, char **xrefs) {
- char *list[2];
-
- list[1] = NULL;
- for ( ; *xrefs; xrefs++) {
- list[0] = *xrefs;
- if ((!AllGroups && PERMmatch(groups, list)) && (!PERMspecified || (PERMspecified && PERMmatch(PERMreadlist, list)))) {
- if (!strcmp(*xrefs, group))
- return false;
- else
- return true;
- }
- }
- return false;
-}
-
-static char **groups;
-
-static void
-process_newnews(char *group, bool AllGroups, time_t date)
-{
- char **xrefs;
- int count;
- void *handle;
- char *p;
- time_t arrived;
- ARTHANDLE *art = NULL;
- TOKEN token;
- char *data;
- int len;
- char *grplist[2];
- time_t now;
-
- grplist[0] = group;
- grplist[1] = NULL;
- if (PERMspecified && !PERMmatch(PERMreadlist, grplist))
- return;
- if (!AllGroups && !PERMmatch(groups, grplist))
- return;
- if (!OVgroupstats(group, &ARTlow, &ARThigh, &count, NULL))
- return;
- if ((handle = OVopensearch(group, ARTlow, ARThigh)) != NULL) {
- ARTNUM artnum;
- unsigned long artcount = 0;
- struct cvector *vector = NULL;
-
- if (innconf->nfsreader) {
- time(&now);
- /* move the start time back nfsreaderdelay seconds */
- if (date >= innconf->nfsreaderdelay)
- date -= innconf->nfsreaderdelay;
- }
- while (OVsearch(handle, &artnum, &data, &len, &token, &arrived)) {
- if (innconf->nfsreader && arrived + innconf->nfsreaderdelay > now)
- continue;
- if (len == 0 || date > arrived)
- continue;
-
- vector = overview_split(data, len, NULL, vector);
- if (overhdr_xref == -1) {
- if ((art = SMretrieve(token, RETR_HEAD)) == NULL)
- continue;
- p = GetXref(art);
- SMfreearticle(art);
- } else {
- if (PERMaccessconf->nnrpdcheckart &&
- !ARTinstorebytoken(token))
- continue;
- /* We only care about the newsgroup list here, virtual
- * hosting isn't relevant */
- p = overview_getheader(vector, overhdr_xref, OVextra);
- }
- if (p == NULL)
- continue;
- xrefs = GetGroups(p);
- free(p);
- if (xrefs == NULL)
- continue;
- if (HaveSeen(AllGroups, group, groups, xrefs))
- continue;
- p = overview_getheader(vector, OVERVIEW_MESSAGE_ID, OVextra);
- if (p == NULL)
- continue;
-
- ++artcount;
- cache_add(HashMessageID(p), token);
- Printf("%s\r\n", p);
- free(p);
- }
- OVclosesearch(handle);
- notice("%s newnews %s %lu", ClientHost, group, artcount);
- if (vector)
- cvector_free(vector);
- }
-}
-
-/*
-** NEWNEWS newsgroups date time ["GMT"]
-** Return the Message-ID of any articles after the specified date
-*/
-void CMDnewnews(int ac, char *av[]) {
- char *p, *q;
- char *path;
- bool AllGroups;
- char line[BIG_BUFFER];
- time_t date;
- QIOSTATE *qp;
- int i;
- bool local;
-
- if (!PERMaccessconf->allownewnews) {
- Reply("%d NEWNEWS command disabled by administrator\r\n", NNTP_ACCESS_VAL);
- return;
- }
-
- if (!PERMcanread) {
- Reply("%s\r\n", NNTP_ACCESS);
- return;
- }
-
- /* Make other processes happier if someone uses NEWNEWS */
- if (innconf->nicenewnews > 0) {
- nice(innconf->nicenewnews);
- innconf->nicenewnews = 0;
- }
-
- snprintf(line, sizeof(line), "%s %s %s %s", av[1], av[2], av[3],
- (ac >= 5 && (*av[4] == 'G' || *av[4] == 'U')) ? "GMT" : "local");
- notice("%s newnews %s", ClientHost, line);
-
- TMRstart(TMR_NEWNEWS);
- /* Optimization in case client asks for !* (no groups) */
- if (strcmp(av[1], "!*") == 0) {
- Reply("%s\r\n", NNTP_NEWNEWSOK);
- Printf(".\r\n");
- TMRstop(TMR_NEWNEWS);
- return;
- }
-
- /* Parse the newsgroups. */
- AllGroups = (strcmp(av[1], "*") == 0);
- if (!AllGroups && !NGgetlist(&groups, av[1])) {
- Reply("%d Bad newsgroup specifier %s\r\n", NNTP_SYNTAX_VAL, av[1]);
- TMRstop(TMR_NEWNEWS);
- return;
- }
-
- /* Parse the date. */
- local = !(ac > 4 && strcasecmp(av[4], "GMT") == 0);
- date = parsedate_nntp(av[2], av[3], local);
- if (date == (time_t) -1) {
- Reply("%d Bad date\r\n", NNTP_SYNTAX_VAL);
- TMRstop(TMR_NEWNEWS);
- return;
- }
-
- if (strcspn(av[1], "\\!*[?]") == strlen(av[1])) {
- /* optimise case - don't need to scan the active file pattern
- * matching */
- Reply("%s\r\n", NNTP_NEWNEWSOK);
- for (i = 0; groups[i]; ++i) {
- process_newnews(groups[i], AllGroups, date);
- }
- } else {
- path = concatpath(innconf->pathdb, _PATH_ACTIVE);
- qp = QIOopen(path);
- if (qp == NULL) {
- if (errno == ENOENT) {
- Reply("%d Can't open active\r\n", NNTP_TEMPERR_VAL);
- } else {
- syswarn("%s cant fopen %s", ClientHost, path);
- Reply("%d Can't open active\r\n", NNTP_TEMPERR_VAL);
- }
- free(path);
- TMRstop(TMR_NEWNEWS);
- return;
- }
- free(path);
-
- Reply("%s\r\n", NNTP_NEWNEWSOK);
-
- while ((p = QIOread(qp)) != NULL) {
- for (q = p; *q != '\0'; q++) {
- if (*q == ' ' || *q == '\t') {
- *q = '\0';
- break;
- }
- }
- process_newnews(p, AllGroups, date);
- }
- QIOclose(qp);
- }
- Printf(".\r\n");
- TMRstop(TMR_NEWNEWS);
-}
+++ /dev/null
-/* $Id: nnrpd.c 7731 2008-04-06 08:40:29Z iulius $
-**
-** NNTP server for readers (NNRP) for InterNetNews.
-**
-** This server doesn't do any real load-limiting, except for what has
-** proven empirically necesary (i.e., look at GRPscandir).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/setproctitle.h"
-#include "portable/wait.h"
-#include <grp.h>
-#include <netdb.h>
-#include <pwd.h>
-#include <signal.h>
-
-#if HAVE_GETSPNAM
-# include <shadow.h>
-#endif
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "ov.h"
-#define MAINLINE
-#include "nnrpd.h"
-
-#include "tls.h"
-#include "sasl_config.h"
-
-#ifdef HAVE_SSL
-extern SSL *tls_conn;
-int nnrpd_starttls_done = 0;
-#endif
-
-#if NEED_HERRNO_DECLARATION
-extern int h_errno;
-#endif
-
-/* If we have getloadavg, include the appropriate header file. Otherwise,
- just assume that we always have a load of 0. */
-#if HAVE_GETLOADAVG
-# if HAVE_SYS_LOADAVG_H
-# include <sys/loadavg.h>
-# endif
-#else
-static int
-getloadavg(double loadavg[], int nelem)
-{
- int i;
-
- for (i = 0; i < nelem && i < 3; i++)
- loadavg[i] = 0;
- return i;
-}
-#endif
-
-
-#define MAXPATTERNDEFINE 10
-
-#define CMDany -1
-
-
-typedef struct _CMDENT {
- const char * Name;
- void (*Function)(int, char **);
- bool Needauth;
- int Minac;
- int Maxac;
- const char * Help;
-} CMDENT;
-
-
-char NOACCESS[] = NNTP_ACCESS;
-char *ACTIVE = NULL;
-char *ACTIVETIMES = NULL;
-char *HISTORY = NULL;
-char *NEWSGROUPS = NULL;
-char *NNRPACCESS = NULL;
-
-static char *LocalLogFileName = NULL;
-static char *LocalLogDirName;
-
-struct history *History;
-static double STATstart;
-static double STATfinish;
-static char *PushedBack;
-static sig_atomic_t ChangeTrace;
-bool DaemonMode = false;
-bool ForeGroundMode = false;
-#if HAVE_GETSPNAM
-static const char *ShadowGroup;
-#endif
-static const char *HostErrorStr;
-bool GetHostByAddr = true; /* formerly DO_NNRP_GETHOSTBYADDR */
-const char *NNRPinstance = "";
-
-#ifdef DO_PERL
-bool PerlLoaded = false;
-#endif /* DO_PERL */
-
-#ifdef DO_PYTHON
-bool PY_use_dynamic = false;
-#endif /* DO_PYTHON */
-
-static char CMDfetchhelp[] = "[MessageID|Number]";
-
-static CMDENT CMDtable[] = {
- { "authinfo", CMDauthinfo, false, 3, CMDany,
- "user Name|pass Password|generic <prog> <args>" },
-#ifdef HAVE_SSL
- { "starttls", CMDstarttls, false, 1, 1,
- NULL },
-#endif
- { "article", CMDfetch, true, 1, 2,
- CMDfetchhelp },
- { "body", CMDfetch, true, 1, 2,
- CMDfetchhelp },
- { "date", CMDdate, false, 1, 1,
- NULL },
- { "group", CMDgroup, true, 2, 2,
- "newsgroup" },
- { "head", CMDfetch, true, 1, 2,
- CMDfetchhelp },
- { "help", CMDhelp, false, 1, CMDany,
- NULL },
- { "ihave", CMDpost, true, 2, 2,
- "MessageID" },
- { "last", CMDnextlast, true, 1, 1,
- NULL },
- { "list", CMDlist, true, 1, 3,
- "[active|active.times|distrib.pats|distributions|extensions|moderators|motd|newsgroups|overview.fmt|subscriptions]" },
- { "listgroup", CMDgroup, true, 1, 2,
- "newsgroup" },
- { "mode", CMDmode, false, 2, 2,
- "reader" },
- { "newgroups", CMDnewgroups, true, 3, 5,
- "[YY]yymmdd hhmmss [\"GMT\"]" },
- { "newnews", CMDnewnews, true, 4, 5,
- "newsgroups [YY]yymmdd hhmmss [\"GMT\"]" },
- { "next", CMDnextlast, true, 1, 1,
- NULL },
- { "post", CMDpost, true, 1, 1,
- NULL },
- { "slave", CMD_unimp, false, 1, 1,
- NULL },
- { "stat", CMDfetch, true, 1, 2,
- CMDfetchhelp },
- { "xgtitle", CMDxgtitle, true, 1, 2,
- "[group_pattern]" },
- { "xhdr", CMDpat, true, 2, 3,
- "header [range|MessageID]" },
- { "xover", CMDxover, true, 1, 2,
- "[range]" },
- { "xpat", CMDpat, true, 4, CMDany,
- "header range|MessageID pat [morepat...]" },
- { "xpath", CMDxpath, true, 2, 2,
- "MessageID" },
- { NULL, CMD_unimp, false, 0, 0,
- NULL }
-};
-
-
-static const char *const timer_name[] = {
- "idle",
- "newnews",
- "readart",
- "checkart",
- "nntpread",
- "nntpwrite",
-};
-
-/*
-** Log a summary status message and exit.
-*/
-void
-ExitWithStats(int x, bool readconf)
-{
- double usertime;
- double systime;
-
- line_free(&NNTPline);
- fflush(stdout);
- STATfinish = TMRnow_double();
- if (GetResourceUsage(&usertime, &systime) < 0) {
- usertime = 0;
- systime = 0;
- }
-
- GRPreport();
- if (ARTcount)
- syslog(L_NOTICE, "%s exit articles %ld groups %ld",
- ClientHost, ARTcount, GRPcount);
- if (POSTreceived || POSTrejected)
- syslog(L_NOTICE, "%s posts received %ld rejected %ld",
- ClientHost, POSTreceived, POSTrejected);
- syslog(L_NOTICE, "%s times user %.3f system %.3f idle %.3f elapsed %.3f",
- ClientHost, usertime, systime, IDLEtime, STATfinish - STATstart);
- /* Tracking code - Make entries in the logfile(s) to show that we have
- finished with this session */
- if (!readconf && PERMaccessconf && PERMaccessconf->readertrack) {
- syslog(L_NOTICE, "%s Tracking Disabled (%s)", ClientHost, Username);
- if (LLOGenable) {
- fprintf(locallog, "%s Tracking Disabled (%s)\n", ClientHost, Username);
- fclose(locallog);
- syslog(L_NOTICE,"%s Local Logging ends (%s) %s",ClientHost, Username, LocalLogFileName);
- }
- }
- if (ARTget)
- syslog(L_NOTICE, "%s artstats get %ld time %ld size %ld", ClientHost,
- ARTget, ARTgettime, ARTgetsize);
- if (!readconf && PERMaccessconf && PERMaccessconf->nnrpdoverstats && OVERcount)
- syslog(L_NOTICE, "%s overstats count %ld hit %ld miss %ld time %ld size %ld dbz %ld seek %ld get %ld artcheck %ld", ClientHost,
- OVERcount, OVERhit, OVERmiss, OVERtime, OVERsize, OVERdbz, OVERseek, OVERget, OVERartcheck);
-
-#ifdef HAVE_SSL
- if (tls_conn) {
- SSL_shutdown(tls_conn);
- SSL_free(tls_conn);
- tls_conn = NULL;
- }
-#endif
-
- if (DaemonMode) {
- shutdown(STDIN_FILENO, 2);
- shutdown(STDOUT_FILENO, 2);
- shutdown(STDERR_FILENO, 2);
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- }
-
- OVclose();
- SMshutdown();
-
-#ifdef DO_PYTHON
- PY_close_python();
-#endif /* DO_PYTHON */
-
- if (History)
- HISclose(History);
-
- if (innconf->timer != 0) {
- TMRsummary(ClientHost, timer_name);
- TMRfree();
- }
-
- if (LocalLogFileName != NULL)
- free(LocalLogFileName);
- closelog();
- exit(x);
-}
-
-
-/*
-** The "help" command.
-*/
-/* ARGSUSED0 */
-void
-CMDhelp(int ac UNUSED, char *av[] UNUSED)
-{
- CMDENT *cp;
- char *p, *q;
- static const char *newsmaster = NEWSMASTER;
-
- Reply("%s\r\n", NNTP_HELP_FOLLOWS);
- for (cp = CMDtable; cp->Name; cp++)
- if (cp->Help == NULL)
- Printf(" %s\r\n", cp->Name);
- else
- Printf(" %s %s\r\n", cp->Name, cp->Help);
- if (PERMaccessconf && (VirtualPathlen > 0)) {
- if (PERMaccessconf->newsmaster) {
- if (strchr(PERMaccessconf->newsmaster, '@') == NULL) {
- Printf("Report problems to <%s@%s>\r\n",
- PERMaccessconf->newsmaster, PERMaccessconf->domain);
- } else {
- Printf("Report problems to <%s>\r\n",
- PERMaccessconf->newsmaster);
- }
- } else {
- /* sigh, pickup from newsmaster anyway */
- if ((p = strchr(newsmaster, '@')) == NULL)
- Printf("Report problems to <%s@%s>\r\n",
- newsmaster, PERMaccessconf->domain);
- else {
- q = xstrndup(newsmaster, p - newsmaster);
- Printf("Report problems to <%s@%s>\r\n",
- q, PERMaccessconf->domain);
- free(q);
- }
- }
- } else {
- if (strchr(newsmaster, '@') == NULL)
- Printf("Report problems to <%s@%s>\r\n",
- newsmaster, innconf->fromhost);
- else
- Printf("Report problems to <%s>\r\n",
- newsmaster);
- }
- Reply(".\r\n");
-}
-
-
-/*
-** Unimplemented catch-all.
-*/
-/* ARGSUSED0 */
-void
-CMD_unimp(ac, av)
- int ac UNUSED;
- char *av[];
-{
- if (strcasecmp(av[0], "slave") == 0)
- /* Somebody sends us this? I don't believe it! */
- Reply("%d Unsupported\r\n", NNTP_SLAVEOK_VAL);
- else
- Reply("%d %s not implemented; try help\r\n",
- NNTP_BAD_COMMAND_VAL, av[0]);
-}
-
-
-#ifndef INADDR_LOOPBACK
-#define INADDR_LOOPBACK 0x7f000001
-#endif /* INADDR_LOOPBACK */
-/*
-** Convert an IP address to a hostname. Don't trust the reverse lookup,
-** since anyone can fake .in-addr.arpa entries.
-*/
-static bool
-Address2Name(INADDR *ap, char *hostname, int i)
-{
- char *p;
- struct hostent *hp;
- static char mismatch_error[] = "reverse lookup validation failed";
- char **pp;
-
- /* Get the official hostname, store it away. */
- if ((hp = gethostbyaddr((char *)ap, sizeof *ap, AF_INET)) == NULL) {
- HostErrorStr = hstrerror(h_errno);
- return false;
- }
- strlcpy(hostname, hp->h_name, i);
-
- /* Get addresses for this host. */
- if ((hp = gethostbyname(hostname)) == NULL) {
- HostErrorStr = hstrerror(h_errno);
- return false;
- }
-
- /* Make sure one of those addresses is the address we got. */
- for (pp = hp->h_addr_list; *pp; pp++)
- if (strncmp((const char *)&ap->s_addr, *pp, hp->h_length) == 0)
- break;
- if (*pp == NULL)
- {
- HostErrorStr = mismatch_error;
- return false;
- }
-
- /* Only needed for misconfigured YP/NIS systems. */
- if (ap->s_addr != INADDR_LOOPBACK && strchr(hostname, '.') == NULL
- && (p = innconf->domain) != NULL) {
- strlcat(hostname, ".", i);
- strlcat(hostname, p, i);
- }
-
- /* Make all lowercase, for wildmat. */
- for (p = hostname; *p; p++)
- if (CTYPE(isupper, (int)*p))
- *p = tolower(*p);
- return true;
-}
-
-/*
-** Convert an IPv6 address to a hostname. Don't trust the reverse lookup,
-** since anyone can fake .ip6.arpa entries.
-*/
-#ifdef HAVE_INET6
-static bool
-Address2Name6(struct sockaddr *sa, char *hostname, int i)
-{
- static char mismatch_error[] = "reverse lookup validation failed";
- int ret;
- bool valid = 0;
- struct addrinfo hints, *res, *res0;
- char *p;
-
- /* Get the official hostname, store it away. */
- ret = getnameinfo( sa, SA_LEN( sa ), hostname, i, NULL, 0, NI_NAMEREQD );
- if( ret != 0 )
- {
- HostErrorStr = gai_strerror( ret );
- return false;
- }
-
- /* Get addresses for this host. */
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = AF_INET6;
- if( ( ret = getaddrinfo( hostname, NULL, &hints, &res0 ) ) != 0 )
- {
- HostErrorStr = gai_strerror( ret );
- return false;
- }
-
- /* Make sure one of those addresses is the address we got. */
- for( res = res0; res; res = res->ai_next )
- {
-#ifdef HAVE_BROKEN_IN6_ARE_ADDR_EQUAL
- if( ! memcmp( &(((struct sockaddr_in6 *)sa)->sin6_addr),
- &(((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr),
- sizeof( struct in6_addr ) ) )
-#else
- if( IN6_ARE_ADDR_EQUAL( &(((struct sockaddr_in6 *)sa)->sin6_addr),
- &(((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr) ) )
-#endif
- {
- valid = 1;
- break;
- }
- }
-
- freeaddrinfo( res0 );
-
- if (valid) {
- /* Make all lowercase for matching. */
- for (p = hostname; *p != '\0'; p++)
- if (CTYPE(isupper, *p))
- *p = tolower(*p);
- return true;
- } else {
- HostErrorStr = mismatch_error;
- return false;
- }
-}
-#endif
-
-
-static bool
-Sock2String( struct sockaddr *sa, char *string, int len, bool lookup )
-{
- struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
-
-#ifdef HAVE_INET6
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
- struct sockaddr_in temp;
-
- if( sa->sa_family == AF_INET6 )
- {
- if( ! IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) )
- {
- if( lookup )
- {
- return Address2Name6(sa, string, len);
- } else {
- strlcpy( string, sprint_sockaddr( sa ), len );
- return true;
- }
- } else {
- temp.sin_family = AF_INET;
- memcpy( &temp.sin_addr, sin6->sin6_addr.s6_addr + 12, 4 );
- temp.sin_port = sin6->sin6_port;
- sin4 = &temp;
- /* fall through to AF_INET case */
- }
- }
-#endif
- if( lookup ) {
- return Address2Name(&sin4->sin_addr, string, len);
- } else {
- strlcpy( string, inet_ntoa(sin4->sin_addr), len );
- return true;
- }
-}
-
-/*
-** Determine access rights of the client.
-*/
-static void StartConnection(void)
-{
- struct sockaddr_storage ssc, sss;
- socklen_t length;
- const char *default_host_error = "unknown error";
-
- ClientIpAddr = 0L;
- ClientHost[0] = '\0';
- ClientIpString[0] = '\0';
- ClientPort = 0;
- ServerHost[0] = '\0';
- ServerIpString[0] = '\0';
- ServerPort = 0;
-
- /* Get the peer's name. */
- length = sizeof ssc;
- if (getpeername(STDIN_FILENO, (struct sockaddr *)&ssc, &length) < 0) {
- if (!isatty(STDIN_FILENO)) {
- syslog(L_TRACE, "%s cant getpeername %m", "?");
- /* so stats generation looks correct. */
- strlcpy(ClientHost, "?", sizeof(ClientHost));
- Printf("%d I can't get your name. Goodbye.\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
- strlcpy(ClientHost, "stdin", sizeof(ClientHost));
- }
-
- else {
-#ifdef HAVE_INET6
- if ( ssc.ss_family != AF_INET && ssc.ss_family != AF_INET6) {
-#else
- if ( ssc.ss_family != AF_INET ) {
-#endif
- syslog(L_ERROR, "%s bad_address_family %ld",
- "?", (long)ssc.ss_family);
- Printf("%d Bad address family. Goodbye.\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- length = sizeof sss;
- if (getsockname(STDIN_FILENO, (struct sockaddr *)&sss, &length) < 0) {
- syslog(L_NOTICE, "%s can't getsockname %m", ClientHost);
- Printf("%d Can't figure out where you connected to. Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* figure out client's IP address/hostname */
- HostErrorStr = default_host_error;
- if( ! Sock2String( (struct sockaddr *)&ssc, ClientIpString,
- sizeof( ClientIpString ), false ) ) {
- syslog(L_NOTICE, "? cant get client numeric address: %s", HostErrorStr);
- ExitWithStats(1, true);
- }
- if(GetHostByAddr) {
- HostErrorStr = default_host_error;
- if( ! Sock2String( (struct sockaddr *)&ssc, ClientHost,
- sizeof( ClientHost ), true ) ) {
- syslog(L_NOTICE,
- "? reverse lookup for %s failed: %s -- using IP address for access",
- ClientIpString, HostErrorStr);
- strlcpy(ClientHost, ClientIpString, sizeof(ClientHost));
- }
- } else {
- strlcpy(ClientHost, ClientIpString, sizeof(ClientHost));
- }
-
- /* figure out server's IP address/hostname */
- HostErrorStr = default_host_error;
- if( ! Sock2String( (struct sockaddr *)&sss, ServerIpString,
- sizeof( ServerIpString ), false ) ) {
- syslog(L_NOTICE, "? cant get server numeric address: %s", HostErrorStr);
- ExitWithStats(1, true);
- }
- if(GetHostByAddr) {
- HostErrorStr = default_host_error;
- if( ! Sock2String( (struct sockaddr *)&sss, ServerHost,
- sizeof( ServerHost ), true ) ) {
- syslog(L_NOTICE,
- "? reverse lookup for %s failed: %s -- using IP address for access",
- ServerIpString, HostErrorStr);
- strlcpy(ServerHost, ServerIpString, sizeof(ServerHost));
- }
- } else {
- strlcpy(ServerHost, ServerIpString, sizeof(ServerHost));
- }
-
- /* get port numbers */
- switch( ssc.ss_family ) {
- case AF_INET:
- ClientPort = ntohs( ((struct sockaddr_in *)&ssc)->sin_port );
- ServerPort = ntohs( ((struct sockaddr_in *)&sss)->sin_port );
- break;
-#ifdef HAVE_INET6
- case AF_INET6:
- ClientPort = ntohs( ((struct sockaddr_in6 *)&ssc)->sin6_port );
- ServerPort = ntohs( ((struct sockaddr_in6 *)&sss)->sin6_port );
- break;
-#endif
- }
- }
-
- strlcpy(LogName, ClientHost, sizeof(LogName));
-
- syslog(L_NOTICE, "%s (%s) connect", ClientHost, ClientIpString);
-
- PERMgetaccess(NNRPACCESS);
- PERMgetpermissions();
-}
-
-
-/*
-** Send a reply, possibly with debugging output.
-*/
-void
-Reply(const char *fmt, ...)
-{
- va_list args;
- int oerrno;
- char * p;
- char buff[2048];
-
-#ifdef HAVE_SSL
- if (tls_conn) {
- int r;
-
- va_start(args, fmt);
- vsnprintf(buff, sizeof(buff), fmt, args);
- va_end(args);
- TMRstart(TMR_NNTPWRITE);
-Again:
- r = SSL_write(tls_conn, buff, strlen(buff));
- switch (SSL_get_error(tls_conn, r)) {
- case SSL_ERROR_NONE:
- case SSL_ERROR_SYSCALL:
- break;
- case SSL_ERROR_WANT_WRITE:
- goto Again;
- break;
- case SSL_ERROR_SSL:
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- }
- TMRstop(TMR_NNTPWRITE);
- } else {
- va_start(args, fmt);
- TMRstart(TMR_NNTPWRITE);
- vprintf(fmt, args);
- TMRstop(TMR_NNTPWRITE);
- va_end(args);
- }
-#else
- va_start(args, fmt);
- TMRstart(TMR_NNTPWRITE);
- vprintf(fmt, args);
- TMRstop(TMR_NNTPWRITE);
- va_end(args);
-#endif
- if (Tracing) {
- oerrno = errno;
- va_start(args, fmt);
-
- /* Copy output, but strip trailing CR-LF. Note we're assuming here
- that no output line can ever be longer than 2045 characters. */
- vsnprintf(buff, sizeof(buff), fmt, args);
- va_end(args);
- p = buff + strlen(buff) - 1;
- while (p >= buff && (*p == '\n' || *p == '\r'))
- *p-- = '\0';
- syslog(L_TRACE, "%s > %s", ClientHost, buff);
-
- errno = oerrno;
- }
-}
-
-void
-Printf(const char *fmt, ...)
-{
- va_list args;
-
-#ifdef HAVE_SSL
- if (tls_conn) {
- int r;
- char buff[2048];
-
- va_start(args, fmt);
- vsnprintf(buff, sizeof(buff), fmt, args);
- va_end(args);
- TMRstart(TMR_NNTPWRITE);
-Again:
- r = SSL_write(tls_conn, buff, strlen(buff));
- switch (SSL_get_error(tls_conn, r)) {
- case SSL_ERROR_NONE:
- case SSL_ERROR_SYSCALL:
- break;
- case SSL_ERROR_WANT_WRITE:
- goto Again;
- break;
- case SSL_ERROR_SSL:
- SSL_shutdown(tls_conn);
- tls_conn = NULL;
- errno = ECONNRESET;
- break;
- case SSL_ERROR_ZERO_RETURN:
- break;
- }
- TMRstop(TMR_NNTPWRITE);
- } else {
-#endif /* HAVE_SSL */
- va_start(args, fmt);
- TMRstart(TMR_NNTPWRITE);
- vprintf(fmt, args);
- TMRstop(TMR_NNTPWRITE);
- va_end(args);
-#ifdef HAVE_SSL
- }
-#endif /* HAVE_SSL */
-}
-
-
-#ifdef HAVE_SIGACTION
-#define NO_SIGACTION_UNUSED UNUSED
-#else
-#define NO_SIGACTION_UNUSED
-#endif
-/*
-** Got a signal; toggle tracing.
-*/
-static RETSIGTYPE
-ToggleTrace(int s NO_SIGACTION_UNUSED)
-{
- ChangeTrace = true;
-#ifndef HAVE_SIGACTION
- xsignal(s, ToggleTrace);
-#endif
-}
-
-/*
-** Got a SIGPIPE; exit cleanly
-*/
-static RETSIGTYPE
-CatchPipe(int s UNUSED)
-{
- ExitWithStats(0, false);
-}
-
-/*
-** Got a signal; wait for children.
-*/
-static RETSIGTYPE
-WaitChild(int s NO_SIGACTION_UNUSED)
-{
- int pid;
-
- for (;;) {
- pid = waitpid(-1, NULL, WNOHANG);
- if (pid <= 0)
- break;
- }
-#ifndef HAVE_SIGACTION
- xsignal(s, WaitChild);
-#endif
-}
-
-static void SetupDaemon(void) {
- bool val;
-
- val = true;
- if (SMsetup(SM_PREOPEN, (void *)&val) && !SMinit()) {
- syslog(L_NOTICE, "cant initialize storage method, %s", SMerrorstr);
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- OVextra = overview_extra_fields();
- if (OVextra == NULL) {
- /* overview_extra_fields should already have logged something
- * useful */
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- overhdr_xref = overview_index("Xref", OVextra);
- if (!OVopen(OV_READ)) {
- /* This shouldn't really happen. */
- syslog(L_NOTICE, "cant open overview %m");
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- if (!OVctl(OVCACHEKEEP, &val)) {
- syslog(L_NOTICE, "cant enable overview cache %m");
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
-}
-
-/*
-** Print a usage message and exit.
-*/
-static void
-Usage(void)
-{
- fprintf(stderr, "Usage error.\n");
- exit(1);
-}
-
-
-/* ARGSUSED0 */
-int
-main(int argc, char *argv[])
-{
- const char *name;
- CMDENT *cp;
- char buff[NNTP_STRLEN];
- char **av;
- int ac;
- READTYPE r;
- int i;
- char *Reject;
- int timeout;
- unsigned int vid=0;
- int count=123456789;
- struct timeval tv;
- unsigned short ListenPort = NNTP_PORT;
-#ifdef HAVE_INET6
- char ListenAddr[INET6_ADDRSTRLEN];
-#else
- char ListenAddr[16];
-#endif
- int lfd, fd;
- socklen_t clen;
-#ifdef HAVE_INET6
- struct sockaddr_storage ssa, csa;
- struct sockaddr_in6 *ssa6 = (struct sockaddr_in6 *) &ssa;
-#else
- struct sockaddr_in ssa, csa;
-#endif
- struct sockaddr_in *ssa4 = (struct sockaddr_in *) &ssa;
- struct stat Sb;
- pid_t pid = -1;
- gid_t NewsGID;
- uid_t NewsUID;
- int one = 1;
- FILE *pidfile;
- struct passwd *pwd;
- int clienttimeout;
- char *ConfFile = NULL;
- char *path;
-#if HAVE_GETSPNAM
- struct group *grp;
- gid_t shadowgid;
-#endif /* HAVE_GETSPNAM */
-
- int respawn = 0;
-
- setproctitle_init(argc, argv);
-
- /* Parse arguments. Must xstrdup() optarg if used because setproctitle may
- clobber it! */
- Reject = NULL;
- LLOGenable = false;
- GRPcur = NULL;
- MaxBytesPerSecond = 0;
- strlcpy(Username, "unknown", sizeof(Username));
-
- /* Set up the pathname, first thing, and teach our error handlers about
- the name of the program. */
- name = argv[0];
- if (name == NULL || *name == '\0')
- name = "nnrpd";
- else {
- const char *p;
-
- p = strrchr(name, '/');
- if (p != NULL)
- name = p + 1;
- }
- message_program_name = xstrdup(name);
- openlog(message_program_name, L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
- message_handlers_die(1, message_log_syslog_crit);
- message_handlers_warn(1, message_log_syslog_warning);
- message_handlers_notice(1, message_log_syslog_notice);
-
- if (!innconf_read(NULL))
- exit(1);
-
-#ifdef HAVE_SSL
- while ((i = getopt(argc, argv, "c:b:Dfi:I:g:nop:P:r:s:tS")) != EOF)
-#else
- while ((i = getopt(argc, argv, "c:b:Dfi:I:g:nop:P:r:s:t")) != EOF)
-#endif /* HAVE_SSL */
- switch (i) {
- default:
- Usage();
- /* NOTREACHED */
- case 'c': /* use alternate readers.conf */
- ConfFile = concatpath(innconf->pathetc, optarg);
- break;
- case 'b': /* bind to a certain address in
- daemon mode */
- strlcpy(ListenAddr, optarg, sizeof(ListenAddr));
- break;
- case 'D': /* standalone daemon mode */
- DaemonMode = true;
- break;
- case 'P': /* prespawn count in daemon mode */
- respawn = atoi(optarg);
- break;
- case 'f': /* Don't fork on daemon mode */
- ForeGroundMode = true;
- break;
-#if HAVE_GETSPNAM
- case 'g':
- ShadowGroup = optarg;
- break;
-#endif /* HAVE_GETSPNAM */
- case 'i': /* Initial command */
- PushedBack = xstrdup(optarg);
- break;
- case 'I': /* Instance */
- NNRPinstance = xstrdup(optarg);
- break;
- case 'n': /* No DNS lookups */
- GetHostByAddr = false;
- break;
- case 'o':
- Offlinepost = true; /* Offline posting only */
- break;
- case 'p': /* tcp port for daemon mode */
- ListenPort = atoi(optarg);
- break;
- case 'r': /* Reject connection message */
- Reject = xstrdup(optarg);
- break;
- case 's': /* Unused title string */
- break;
- case 't': /* Tracing */
- Tracing = true;
- break;
-#ifdef HAVE_SSL
- case 'S': /* SSL negotiation as soon as connected */
- initialSSL = true;
- break;
-#endif /* HAVE_SSL */
- }
- argc -= optind;
- if (argc)
- Usage();
-
- /*
- * Make other processes happier if someone is reading
- * This allows other processes like 'overchan' to keep up when
- * there are lots of readers. Note that this is cumulative with
- * 'nicekids'
- */
- if (innconf->nicennrpd > 0)
- nice(innconf->nicennrpd);
-
- HISTORY = concatpath(innconf->pathdb, _PATH_HISTORY);
- ACTIVE = concatpath(innconf->pathdb, _PATH_ACTIVE);
- ACTIVETIMES = concatpath(innconf->pathdb, _PATH_ACTIVETIMES);
- NEWSGROUPS = concatpath(innconf->pathdb, _PATH_NEWSGROUPS);
- if(ConfFile)
- NNRPACCESS = ConfFile;
- else
- NNRPACCESS = concatpath(innconf->pathetc,_PATH_NNRPACCESS);
- SPOOLlen = strlen(innconf->patharticles);
-
- if (DaemonMode) {
-#ifdef HAVE_INET6
- memset(&ssa, '\0', sizeof(struct sockaddr_in6));
- ssa6->sin6_family = AF_INET6;
- ssa6->sin6_port = htons(ListenPort);
- if (inet_pton(AF_INET6, ListenAddr, ssa6->sin6_addr.s6_addr) > 0) {
- if ( (lfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
- syslog(L_FATAL, "can't open socket (%m)");
- exit(1);
- }
- }
- else {
-#endif
- memset(&ssa, '\0', sizeof(struct sockaddr_in));
- ssa4->sin_family = AF_INET;
- ssa4->sin_port = htons(ListenPort);
- if (inet_aton(ListenAddr, &ssa4->sin_addr) <= 0 )
- ssa4->sin_addr.s_addr = htonl(INADDR_ANY);
- if ( (lfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- syslog(L_FATAL, "can't open socket (%m)");
- exit(1);
- }
-#ifdef HAVE_INET6
- }
-#endif
-
- if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,
- (char *)&one, sizeof(one)) < 0) {
- syslog(L_FATAL, "can't setsockopt(SO_REUSEADDR) (%m)");
- exit(1);
- }
-
- if (bind(lfd, (struct sockaddr *) &ssa, sizeof(ssa)) < 0) {
- fprintf(stderr, "%s: can't bind (%s)\n", argv[0], strerror(errno));
- syslog(L_FATAL, "can't bind local address (%m)");
- exit(1);
- }
-
- /* If started as root, switch to news uid */
- if (getuid() == 0) {
- if (stat(innconf->pathrun, &Sb) < 0 || !S_ISDIR(Sb.st_mode)) {
- syslog(L_FATAL, "nnrpd cant stat %s %m", innconf->pathrun);
- exit(1);
- }
- if (Sb.st_uid == 0) {
- syslog(L_FATAL, "nnrpd %s must not be owned by root", innconf->pathrun);
- exit(1);
- }
- pwd = getpwnam(NEWSUSER);
- if (pwd == (struct passwd *)NULL) {
- syslog(L_FATAL, "nnrpd getpwnam(%s): %s", NEWSUSER, strerror(errno));
- exit(1);
- } else if (pwd->pw_gid != Sb.st_gid) {
- syslog(L_FATAL, "nnrpd %s must have group %s", innconf->pathrun, NEWSGRP);
- exit(1);
- } else if (pwd->pw_uid != Sb.st_uid) {
- syslog(L_FATAL, "nnrpd %s must be owned by %s", innconf->pathrun, NEWSUSER);
- exit(1);
- }
-
-#if HAVE_GETSPNAM
- shadowgid = (gid_t) -1;
- /* Find shadowgroup gid if needed */
- if (ShadowGroup != NULL) {
- if ((grp = getgrnam(ShadowGroup)) == NULL)
- syslog(L_ERROR, "nnrpd cannot find group %s",
- ShadowGroup);
- else
- shadowgid = grp->gr_gid;
- } else if ((grp = getgrnam("shadow")) != NULL) {
- /* found default group "shadow" */
- shadowgid = grp->gr_gid;
- ShadowGroup = "shadow";
- }
- /* If we have a shadowgid, try to set it as an extra group. */
- if (shadowgid != (gid_t) -1) {
- if (setgroups(1, &shadowgid) < 0)
- syslog(L_ERROR, "nnrpd cannot set supplementary group %s %m",
- ShadowGroup);
- else
- syslog(L_NOTICE, "nnrpd added supplementary group %s",
- ShadowGroup);
- }
-#endif /* HAVE_GETSPNAM */
-
- NewsUID = Sb.st_uid;
- NewsGID = Sb.st_gid;
- setgid(NewsGID);
- if (getgid() != NewsGID)
- syslog(L_ERROR, "nnrpd cant setgid to %d %m", NewsGID);
- setuid(NewsUID);
- if (getuid() != NewsUID)
- syslog(L_ERROR, "nnrpd cant setuid to %d %m", NewsUID);
- }
-
- /* Detach */
- if (!ForeGroundMode) {
- daemonize("/");
- }
-
- if (ListenPort == NNTP_PORT)
- strlcpy(buff, "nnrpd.pid", sizeof(buff));
- else
- snprintf(buff, sizeof(buff), "nnrpd-%d.pid", ListenPort);
- path = concatpath(innconf->pathrun, buff);
- pidfile = fopen(path, "w");
- free(path);
- if (pidfile == NULL) {
- syslog(L_ERROR, "cannot write %s %m", buff);
- exit(1);
- }
- fprintf(pidfile,"%lu\n", (unsigned long) getpid());
- fclose(pidfile);
-
- /* Set signal handle to care for dead children */
- if (!respawn)
- xsignal(SIGCHLD, WaitChild);
-
- /* Arrange to toggle tracing. */
- xsignal(SIGHUP, ToggleTrace);
-
- setproctitle("accepting connections");
-
- listen(lfd, 128);
-
- if (respawn) {
- /* pre-forked mode */
- for (;;) {
- if (respawn > 0) {
- --respawn;
- pid = fork();
- if (pid == 0) {
- do {
- clen = sizeof(csa);
- fd = accept(lfd, (struct sockaddr *) &csa, &clen);
- } while (fd < 0);
- break;
- }
- }
- for (;;) {
- if (respawn == 0)
- pid = wait(NULL);
- else
- pid = waitpid(-1, NULL, WNOHANG);
- if (pid <= 0)
- break;
- ++respawn;
- }
- }
- } else {
- /* fork on demand */
- do {
- clen = sizeof(csa);
- fd = accept(lfd, (struct sockaddr *) &csa, &clen);
- if (fd < 0)
- continue;
-
- for (i = 0; i <= innconf->maxforks && (pid = fork()) < 0; i++) {
- if (i == innconf->maxforks) {
- syslog(L_FATAL, "cant fork (dropping connection): %m");
- continue;
- }
- syslog(L_NOTICE, "cant fork (waiting): %m");
- sleep(1);
- }
- if (ChangeTrace) {
- Tracing = Tracing ? false : true;
- syslog(L_TRACE, "trace %sabled", Tracing ? "en" : "dis");
- ChangeTrace = false;
- }
- if (pid != 0)
- close(fd);
- } while (pid != 0);
- }
-
- /* child process starts here */
- setproctitle("connected");
- close(lfd);
- dup2(fd, 0);
- close(fd);
- dup2(0, 1);
- dup2(0, 2);
- if (innconf->timer != 0)
- TMRinit(TMR_MAX);
- STATstart = TMRnow_double();
- SetupDaemon();
-
- /* if we are a daemon innd didn't make us nice, so be nice kids */
- if (innconf->nicekids) {
- if (nice(innconf->nicekids) < 0)
- syslog(L_ERROR, "Could not nice child to %ld: %m", innconf->nicekids);
- }
-
- /* Only automatically reap children in the listening process */
- xsignal(SIGCHLD, SIG_DFL);
-
- } else {
- if (innconf->timer)
- TMRinit(TMR_MAX);
- STATstart = TMRnow_double();
- SetupDaemon();
- /* Arrange to toggle tracing. */
- xsignal(SIGHUP, ToggleTrace);
- }/* DaemonMode */
-
-#ifdef HAVE_SSL
- ClientSSL = false;
- if (initialSSL) {
- tls_init();
- if (tls_start_servertls(0, 1) == -1) {
- Reply("%d SSL connection failed\r\n", NNTP_STARTTLS_BAD_VAL);
- ExitWithStats(1, false);
- }
- nnrpd_starttls_done = 1;
- ClientSSL = true;
- }
-#endif /* HAVE_SSL */
-
- /* If requested, check the load average. */
- if (innconf->nnrpdloadlimit > 0) {
- double load[1];
-
- if (getloadavg(load, 1) < 0)
- warn("cannot obtain system load");
- else {
- if ((int)(load[0] + 0.5) > innconf->nnrpdloadlimit) {
- syslog(L_NOTICE, "load %.2f > %ld", load[0], innconf->nnrpdloadlimit);
- Reply("%d load at %.2f, try later\r\n", NNTP_GOODBYE_VAL,
- load[0]);
- ExitWithStats(1, true);
- }
- }
- }
-
- strlcpy(LogName, "?", sizeof(LogName));
-
- /* Catch SIGPIPE so that we can exit out of long write loops */
- xsignal(SIGPIPE, CatchPipe);
-
- /* Get permissions and see if we can talk to this client */
- StartConnection();
- if (!PERMcanread && !PERMcanpost && !PERMneedauth) {
- syslog(L_NOTICE, "%s no_permission", ClientHost);
- Printf("%d You have no permission to talk. Goodbye.\r\n",
- NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
-
- /* Proceed with initialization. */
- setproctitle("%s connect", ClientHost);
-
- /* Were we told to reject connections? */
- if (Reject) {
- syslog(L_NOTICE, "%s rejected %s", ClientHost, Reject);
- Reply("%s %s\r\n", NNTP_GOODBYE, Reject);
- ExitWithStats(0, false);
- }
-
- if (PERMaccessconf) {
- if (PERMaccessconf->readertrack)
- PERMaccessconf->readertrack=TrackClient(ClientHost,Username);
- } else {
- if (innconf->readertrack)
- innconf->readertrack=TrackClient(ClientHost,Username);
- }
-
- if ((PERMaccessconf && PERMaccessconf->readertrack)
- || (!PERMaccessconf && innconf->readertrack)) {
- int len;
- syslog(L_NOTICE, "%s Tracking Enabled (%s)", ClientHost, Username);
- pid=getpid();
- gettimeofday(&tv,NULL);
- count += pid;
- vid = tv.tv_sec ^ tv.tv_usec ^ pid ^ count;
- len = strlen("innconf->pathlog") + strlen("/tracklogs/log-") + BUFSIZ;
- LocalLogFileName = xmalloc(len);
- sprintf(LocalLogFileName, "%s/tracklogs/log-%d", innconf->pathlog, vid);
- if ((locallog = fopen(LocalLogFileName, "w")) == NULL) {
- LocalLogDirName = concatpath(innconf->pathlog, "tracklogs");
- MakeDirectory(LocalLogDirName, false);
- free(LocalLogDirName);
- }
- if (locallog == NULL && (locallog = fopen(LocalLogFileName, "w")) == NULL) {
- syslog(L_ERROR, "%s Local Logging failed (%s) %s: %m", ClientHost, Username, LocalLogFileName);
- } else {
- syslog(L_NOTICE, "%s Local Logging begins (%s) %s",ClientHost, Username, LocalLogFileName);
- fprintf(locallog, "%s Tracking Enabled (%s)\n", ClientHost, Username);
- fflush(locallog);
- LLOGenable = true;
- }
- }
-
- if (PERMaccessconf) {
- Reply("%d %s InterNetNews NNRP server %s ready (%s).\r\n",
- PERMcanpost ? NNTP_POSTOK_VAL : NNTP_NOPOSTOK_VAL,
- PERMaccessconf->pathhost, inn_version_string,
- PERMcanpost ? "posting ok" : "no posting");
- clienttimeout = PERMaccessconf->clienttimeout;
- } else {
- Reply("%d %s InterNetNews NNRP server %s ready (%s).\r\n",
- PERMcanpost ? NNTP_POSTOK_VAL : NNTP_NOPOSTOK_VAL,
- innconf->pathhost, inn_version_string,
- PERMcanpost ? "posting ok" : "no posting");
- clienttimeout = innconf->clienttimeout;
- }
-
- line_init(&NNTPline);
-
- /* Main dispatch loop. */
- for (timeout = innconf->initialtimeout, av = NULL, ac = 0; ;
- timeout = clienttimeout) {
- TMRstart(TMR_NNTPWRITE);
- fflush(stdout);
- TMRstop(TMR_NNTPWRITE);
- if (ChangeTrace) {
- Tracing = Tracing ? false : true;
- syslog(L_TRACE, "trace %sabled", Tracing ? "en" : "dis");
- ChangeTrace = false;
- }
- if (PushedBack) {
- if (PushedBack[0] == '\0')
- continue;
- if (Tracing)
- syslog(L_TRACE, "%s < %s", ClientHost, PushedBack);
- ac = Argify(PushedBack, &av);
- r = RTok;
- }
- else {
- size_t len;
- const char *p;
-
- r = line_read(&NNTPline, timeout, &p, &len);
- switch (r) {
- default:
- syslog(L_ERROR, "%s internal %d in main", ClientHost, r);
- /* FALLTHROUGH */
- case RTtimeout:
- if (timeout < clienttimeout)
- syslog(L_NOTICE, "%s timeout short", ClientHost);
- else
- syslog(L_NOTICE, "%s timeout", ClientHost);
- ExitWithStats(1, false);
- break;
- case RTok:
- if (len < sizeof(buff)) {
- /* line_read guarantees null termination */
- memcpy(buff, p, len + 1);
- /* Do some input processing, check for blank line. */
- if (Tracing)
- syslog(L_TRACE, "%s < %s", ClientHost, buff);
- if (buff[0] == '\0')
- continue;
- ac = Argify(buff, &av);
- break;
- }
- /* FALLTHROUGH */
- case RTlong:
- Reply("%d Line too long\r\n", NNTP_BAD_COMMAND_VAL);
- continue;
- case RTeof:
- /* Handled below. */
- break;
- }
- }
- /* Client gone? */
- if (r == RTeof)
- break;
- if (ac == 0 || strcasecmp(av[0], "quit") == 0)
- break;
-
- /* Find command. */
- for (cp = CMDtable; cp->Name; cp++)
- if (strcasecmp(cp->Name, av[0]) == 0)
- break;
- if (cp->Name == NULL) {
- if ((int)strlen(buff) > 40)
- syslog(L_NOTICE, "%s unrecognized %.40s...", ClientHost, buff);
- else
- syslog(L_NOTICE, "%s unrecognized %s", ClientHost, buff);
- Reply("%d What?\r\n", NNTP_BAD_COMMAND_VAL);
- continue;
- }
-
- /* Check usage. */
- if ((cp->Minac != CMDany && ac < cp->Minac)
- || (cp->Maxac != CMDany && ac > cp->Maxac)) {
- Reply("%d %s\r\n",
- NNTP_SYNTAX_VAL, cp->Help ? cp->Help : "Usage error");
- continue;
- }
-
- /* Check permissions and dispatch. */
- if (cp->Needauth && PERMneedauth) {
- Reply("%d Authentication required for command\r\n",
- NNTP_AUTH_NEEDED_VAL);
- continue;
- }
- setproctitle("%s %s", ClientHost, av[0]);
- (*cp->Function)(ac, av);
- if (PushedBack)
- break;
- if (PERMaccessconf)
- clienttimeout = PERMaccessconf->clienttimeout;
- else
- clienttimeout = innconf->clienttimeout;
- }
-
- Reply("%s\r\n", NNTP_GOODBYE_ACK);
-
- ExitWithStats(0, false);
- /* NOTREACHED */
- return 1;
-}
+++ /dev/null
-/* $Id: nnrpd.h 7343 2005-06-20 03:23:34Z eagle $
-**
-** Net News Reading Protocol server.
-*/
-
-#include "config.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <sys/stat.h>
-
-#include "inn/qio.h"
-#include "libinn.h"
-#include "nntp.h"
-#include "paths.h"
-#include "storage.h"
-#include "inn/vector.h"
-#include "inn/timer.h"
-
-/*
-** Maximum input line length, sigh.
-*/
-#define ART_LINE_LENGTH 1000
-#define ART_LINE_MALLOC 1024
-#define ART_MAX 1024
-
-
-/*
-** Some convenient shorthands.
-*/
-typedef struct in_addr INADDR;
-
-
-/*
-** A range of article numbers.
-*/
-typedef struct _ARTRANGE {
- int Low;
- int High;
-} ARTRANGE;
-
-/*
-** access configuration for each readers
- */
-typedef struct _ACCESSGROUP {
- char *name;
- char *key;
- char *read;
- char *post;
- char *users;
- char *rejectwith;
- int allownewnews;
- bool allowihave;
- int locpost;
- int allowapproved;
- int used;
- int localtime;
- int strippath;
- int nnrpdperlfilter;
- int nnrpdpythonfilter;
- char *fromhost;
- char *pathhost;
- char *organization;
- char *moderatormailer;
- char *domain;
- char *complaints;
- int spoolfirst;
- int checkincludedtext;
- int clienttimeout;
- long localmaxartsize;
- int readertrack;
- int strippostcc;
- int addnntppostinghost;
- int addnntppostingdate;
- char *nnrpdposthost;
- int nnrpdpostport;
- int nnrpdoverstats;
- int backoff_auth;
- char *backoff_db;
- long backoff_k;
- long backoff_postfast;
- long backoff_postslow;
- long backoff_trigger;
- int nnrpdcheckart;
- int nnrpdauthsender;
- int virtualhost;
- char *newsmaster;
- long maxbytespersecond;
-} ACCESSGROUP;
-
-/*
-** What line_read returns.
-*/
-typedef enum _READTYPE {
- RTeof,
- RTok,
- RTlong,
- RTtimeout
-} READTYPE;
-
-
-/*
-** Structure used by line_read to keep track of what's been read
-*/
-struct line {
- char *start;
- char *where;
- size_t remaining;
- size_t allocated;
-};
-
-/*
-** Information about the schema of the news overview files.
-*/
-typedef struct _ARTOVERFIELD {
- char *Header;
- int Length;
- bool NeedsHeader;
-} ARTOVERFIELD;
-
-/*
-** Supported timers. If you add new timers to this list, also add them to
-** the list of tags in nnrpd.c.
-*/
-enum timer {
- TMR_IDLE = TMR_APPLICATION, /* Server is completely idle. */
- TMR_NEWNEWS, /* Executing NEWNEWS command */
- TMR_READART, /* Reading an article (SMretrieve) */
- TMR_CHECKART, /* Checking an article (ARTinstorebytoken) */
- TMR_NNTPREAD, /* Reading from the peer */
- TMR_NNTPWRITE, /* Writing to the peer */
- TMR_MAX
-};
-
-#if defined(MAINLINE)
-#define EXTERN /* NULL */
-#else
-#define EXTERN extern
-#endif /* defined(MAINLINE) */
-
-EXTERN bool PERMauthorized;
-EXTERN bool PERMcanpost;
-EXTERN bool PERMcanread;
-EXTERN bool PERMneedauth;
-EXTERN bool PERMspecified;
-EXTERN ACCESSGROUP *PERMaccessconf;
-EXTERN bool Tracing;
-EXTERN bool Offlinepost;
-EXTERN bool initialSSL;
-EXTERN char **PERMreadlist;
-EXTERN char **PERMpostlist;
-EXTERN char ClientHost[SMBUF];
-EXTERN char ServerHost[SMBUF];
-EXTERN char Username[SMBUF];
-#ifdef HAVE_INET6
-EXTERN char ClientIpString[INET6_ADDRSTRLEN];
-EXTERN char ServerIpString[INET6_ADDRSTRLEN];
-#else
-EXTERN char ClientIpString[20];
-EXTERN char ServerIpString[20];
-#endif
-EXTERN int ClientPort;
-EXTERN int ServerPort;
-EXTERN char LogName[256] ;
-#ifdef HAVE_SSL
-EXTERN bool ClientSSL;
-#endif
-extern char *ACTIVETIMES;
-extern char *HISTORY;
-extern char *ACTIVE;
-extern char *NEWSGROUPS;
-extern char *NNRPACCESS;
-extern char NOACCESS[];
-EXTERN int SPOOLlen;
-EXTERN char PERMpass[SMBUF];
-EXTERN char PERMuser[SMBUF];
-EXTERN FILE *locallog;
-EXTERN int ARTnumber; /* Current article number */
-EXTERN int ARThigh; /* Current high number for group */
-EXTERN int ARTlow; /* Current low number for group */
-EXTERN long ARTcount; /* Current number of articles in group */
-EXTERN long MaxBytesPerSecond; /* maximum bytes per sec a client can use, defaults to 0 */
-EXTERN long ARTget;
-EXTERN long ARTgettime;
-EXTERN long ARTgetsize;
-EXTERN long OVERcount; /* number of XOVER commands */
-EXTERN long OVERhit; /* number of XOVER records found in .overview */
-EXTERN long OVERmiss; /* number of XOVER records found in articles */
-EXTERN long OVERtime; /* number of ms spent sending XOVER data */
-EXTERN long OVERsize; /* number of bytes of XOVER data sent */
-EXTERN long OVERdbz; /* number of ms spent reading dbz data */
-EXTERN long OVERseek; /* number of ms spent seeking history */
-EXTERN long OVERget; /* number of ms spent reading history */
-EXTERN long OVERartcheck; /* number of ms spent article check */
-EXTERN double IDLEtime;
-EXTERN long GRParticles;
-EXTERN long GRPcount;
-EXTERN char *GRPcur;
-EXTERN long POSTreceived;
-EXTERN long POSTrejected;
-
-EXTERN bool BACKOFFenabled;
-EXTERN long ClientIpAddr;
-EXTERN char *VirtualPath;
-EXTERN int VirtualPathlen;
-EXTERN struct history *History;
-EXTERN struct line NNTPline;
-EXTERN struct vector *OVextra;
-EXTERN int overhdr_xref;
-EXTERN bool LLOGenable;
-
-extern const char *ARTpost(char *article, char *idbuff, bool ihave,
- bool *permanent);
-extern void ARTclose(void);
-extern int TrimSpaces(char *line);
-extern char *Glom(char **av);
-extern int Argify(char *line, char ***argvp);
-extern void InitBackoffConstants(void);
-extern char *PostRecFilename(char *ip, char *user);
-extern int LockPostRec(char *path);
-extern int LockPostRec(char *path);
-extern void UnlockPostRec(char *path);
-extern int RateLimit(long *sleeptime, char *path);
-extern void ExitWithStats(int x, bool readconf);
-extern char *GetHeader(const char *header);
-extern void GRPreport(void);
-extern bool NGgetlist(char ***argvp, char *list);
-extern bool PERMartok(void);
-extern void PERMgetaccess(char *nnrpaccess);
-extern void PERMgetpermissions(void);
-extern void PERMlogin(char *uname, char *pass, char *errorstr);
-extern bool PERMmatch(char **Pats, char **list);
-extern bool ParseDistlist(char ***argvp, char *list);
-extern void SetDefaultAccess(ACCESSGROUP*);
-extern void Reply(const char *fmt, ...);
-extern void Printf(const char *fmt, ...);
-
-extern void CMDauthinfo (int ac, char** av);
-extern void CMDdate (int ac, char** av);
-extern void CMDfetch (int ac, char** av);
-extern void CMDgroup (int ac, char** av);
-extern void CMDhelp (int ac, char** av);
-extern void CMDlist (int ac, char** av);
-extern void CMDmode (int ac, char** av);
-extern void CMDnewgroups (int ac, char** av);
-extern void CMDnewnews (int ac, char** av);
-extern void CMDnextlast (int ac, char** av);
-extern void CMDpost (int ac, char** av);
-extern void CMDxgtitle (int ac, char** av);
-extern void CMDxover (int ac, char** av);
-extern void CMDpat (int ac, char** av);
-extern void CMDxpath (int ac, char** av);
-extern void CMD_unimp (int ac, char** av);
-#ifdef HAVE_SSL
-extern void CMDstarttls (int ac, char** av);
-#endif
-
-
-
-extern char *HandleHeaders(char *article);
-extern bool ARTinstorebytoken(TOKEN token);
-
-extern int TrackClient(char *client, char* user);
-
-#ifdef DO_PERL
-extern void loadPerl(void);
-extern void perlAccess(char *user, struct vector *access_vec);
-extern int perlAuthenticate(char *user, char *passwd, char *errorstring, char*newUser);
-extern void perlAuthInit(void);
-#endif /* DO_PERL */
-
-#ifdef DO_PYTHON
-extern bool PY_use_dynamic;
-
-int PY_authenticate(char *path, char *Username, char *Password, char *errorstring, char *newUser);
-void PY_access(char* path, struct vector *access_vec, char *Username);
-int PY_dynamic(char *Username, char *NewsGroup, int PostFlag, char **reply_message);
-void PY_dynamic_init (char* file);
-#endif /* DO_PYTHON */
-
-void line_free(struct line *);
-void line_init(struct line *);
-READTYPE line_read(struct line *, int, const char **, size_t *);
+++ /dev/null
-/* $Id: perl.c 7815 2008-05-05 08:43:58Z iulius $
-**
-** Embedded Perl support for INN.
-**
-** Originally written by Christophe Wolfhugel <wolf@pasteur.fr> (although
-** he wouldn't recongize it any more, so don't blame him) and modified,
-** expanded, and tweaked by James Brister, Dave Hayes, Andrew Gierth, and
-** Russ Allbery among others.
-**
-** This file should contain all innd-specific Perl linkage. Linkage
-** applicable to both innd and nnrpd should go into lib/perl.c instead.
-**
-** We are assuming Perl 5.004 or later.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "paths.h"
-#include "post.h"
-
-#include "nntp.h"
-
-/* Skip this entire file if DO_PERL (./configure --with-perl) isn't set. */
-#ifdef DO_PERL
-
-#include <EXTERN.h>
-#include <perl.h>
-#include <XSUB.h>
-#include "ppport.h"
-
-#include "innperl.h"
-
-extern HEADER Table[], *EndOfTable;
-extern char LogName[];
-extern char PERMuser[];
-
-extern char **OtherHeaders;
-extern int OtherCount;
-extern bool HeadersModified;
-
-extern bool PerlLoaded;
-
-/* #define DEBUG_MODIFY only if you want to see verbose outout */
-#ifdef DEBUG_MODIFY
-static FILE *flog;
-void dumpTable(char *msg);
-#endif /* DEBUG_MODIFY */
-
-char *HandleHeaders(char *article)
-{
- dSP;
- HEADER *hp;
- HV *hdr;
- SV *body;
- int rc;
- char *p, *q;
- static char buf[256];
- int i;
- char *s,*t;
- HE *scan;
- SV *modswitch;
- int OtherSize;
- char *argv[] = { NULL };
-
- if(!PerlLoaded) {
- loadPerl();
- }
-
- if (!PerlFilterActive)
- return NULL; /* not really necessary */
-
-#ifdef DEBUG_MODIFY
- if ((flog = fopen("/var/news/log/nnrpdperlerrror","a+")) == NULL) {
- syslog(L_ERROR,"Whoops. Can't open error log: %m");
- }
-#endif /* DEBUG_MODIFY */
-
- ENTER ;
- SAVETMPS ;
-
- /* Create the Perl Hash */
- hdr = perl_get_hv("hdr", true);
- for (hp = Table; hp < EndOfTable; hp++) {
- if (hp->Body)
- hv_store(hdr, (char *) hp->Name, strlen(hp->Name), newSVpv(hp->Body, 0), 0);
- }
-
- /* Also store other headers */
- OtherSize = OtherCount;
- for (i = 0; i < OtherCount; i++) {
- p = OtherHeaders[i];
- if (p == NULL) {
- syslog (L_ERROR,"Null header number %d copying headers for Perl",i);
- continue;
- }
- s = strchr(p,':');
- if (s == NULL) {
- syslog (L_ERROR,"Bad header copying headers for Perl: '%s'",p);
- continue;
- }
- s++;
- t = (*s == ' ' ? s + 1 : s);
- hv_store(hdr, p, (s - p) - 1, newSVpv(t, 0), 0);
- }
- /* Store user */
- sv_setpv(perl_get_sv("user",true), PERMuser);
-
- /* Store body */
- body = perl_get_sv("body", true);
- sv_setpv(body, article);
-
- /* Call the filtering function */
- rc = perl_call_argv("filter_post", G_EVAL|G_SCALAR, argv);
-
- SPAGAIN;
-
- /* Restore headers */
- modswitch = perl_get_sv("modify_headers",false);
- HeadersModified = false;
- if (SvTRUE(modswitch)) {
- HeadersModified = true;
- i = 0;
-
-#ifdef DEBUG_MODIFY
- dumpTable("Before mod");
-#endif /* DEBUG_MODIFY */
-
- hv_iterinit(hdr);
- while ((scan = hv_iternext(hdr)) != NULL) {
- /* Get the values */
- p = HePV(scan, PL_na);
- s = SvPV(HeVAL(scan), PL_na);
-#ifdef DEBUG_MODIFY
- fprintf(flog,"Hash iter: '%s','%s'\n",p,s);
-#endif /* DEBUG_MODIFY */
-
- /* See if it's a table header */
- for (hp = Table; hp < EndOfTable; hp++) {
- if (strncasecmp(p, hp->Name, hp->Size) == 0) {
- char *copy = xstrdup(s);
- HDR_SET(hp - Table, copy);
- hp->Len = TrimSpaces(hp->Value);
- for (q = hp->Value ; ISWHITE(*q) || *q == '\n' ; q++)
- continue;
- hp->Body = q;
- if (hp->Len == 0) {
- free(hp->Value);
- hp->Value = hp->Body = NULL;
- }
- break;
- }
- }
- if (hp != EndOfTable) continue;
-
- /* Add to other headers */
- if (i >= OtherSize - 1) {
- OtherSize += 20;
- OtherHeaders = xrealloc(OtherHeaders, OtherSize * sizeof(char *));
- }
- t = concat(p, ": ", s, (char *) 0);
- OtherHeaders[i++] = t;
- }
- OtherCount = i;
-#ifdef DEBUG_MODIFY
- dumpTable("After Mod");
-#endif /* DEBUG_MODIFY */
- }
-
- hv_undef (hdr);
- sv_setsv (body, &PL_sv_undef);
-
- buf [0] = '\0' ;
-
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog (L_ERROR,"Perl function filter_post died: %s",
- SvPV(ERRSV, PL_na)) ;
- (void)POPs ;
- PerlFilter (false) ;
- } else if (rc == 1) {
- p = POPp;
- if (p != NULL && *p != '\0')
- strlcpy(buf, p, sizeof(buf));
- }
-
- FREETMPS ;
- LEAVE ;
-
- if (buf[0] != '\0')
- return buf ;
- return NULL;
-}
-
-void loadPerl(void) {
- char *path;
-
- path = concatpath(innconf->pathfilter, _PATH_PERL_FILTER_NNRPD);
- PERLsetup(NULL, path, "filter_post");
- free(path);
- PerlFilter(true);
- PerlLoaded = true;
-}
-
-void perlAccess(char *user, struct vector *access_vec) {
- dSP;
- HV *attribs;
- SV *sv;
- int rc, i;
- char *key, *val, *buffer;
-
- if (!PerlFilterActive)
- return;
-
- ENTER;
- SAVETMPS;
-
- attribs = perl_get_hv("attributes", true);
- hv_store(attribs, "hostname", 8, newSVpv(ClientHost, 0), 0);
- hv_store(attribs, "ipaddress", 9, newSVpv(ClientIpString, 0), 0);
- hv_store(attribs, "port", 4, newSViv(ClientPort), 0);
- hv_store(attribs, "interface", 9, newSVpv(ServerHost, 0), 0);
- hv_store(attribs, "intipaddr", 9, newSVpv(ServerIpString, 0), 0);
- hv_store(attribs, "intport", 7, newSViv(ServerPort), 0);
- hv_store(attribs, "username", 8, newSVpv(user, 0), 0);
-
- PUSHMARK(SP);
-
- if (perl_get_cv("access", 0) == NULL) {
- syslog(L_ERROR, "Perl function access not defined");
- Reply("%d Internal Error (3). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- rc = perl_call_pv("access", G_EVAL|G_ARRAY);
-
- SPAGAIN;
-
- if (rc == 0 ) { /* Error occured, same as checking $@ */
- syslog(L_ERROR, "Perl function access died: %s",
- SvPV(ERRSV, PL_na));
- Reply("%d Internal Error (1). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- if ((rc % 2) != 0) {
- syslog(L_ERROR, "Perl function access returned an odd number of arguments: %i", rc);
- Reply("%d Internal Error (2). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- vector_resize(access_vec, (rc / 2));
-
- buffer = xmalloc(BIG_BUFFER);
-
- for (i = (rc / 2); i >= 1; i--) {
- sv = POPs;
- val = SvPV(sv, PL_na);
- sv = POPs;
- key = SvPV(sv, PL_na);
-
- strlcpy(buffer, key, BIG_BUFFER);
- strlcat(buffer, ": \"", BIG_BUFFER);
- strlcat(buffer, val, BIG_BUFFER);
- strlcat(buffer, "\"\n", BIG_BUFFER);
-
- vector_add(access_vec, xstrdup(buffer));
- }
-
- free(buffer);
-
- PUTBACK;
- FREETMPS;
- LEAVE;
-
-}
-
-void perlAuthInit(void) {
- dSP;
- int rc;
-
- if (!PerlFilterActive)
- return;
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
-
- if (perl_get_cv("auth_init", 0) == NULL) {
- syslog(L_ERROR, "Perl function auth_init not defined");
- Reply("%d Internal Error (3). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- rc = perl_call_pv("auth_init", G_EVAL|G_DISCARD);
-
- SPAGAIN;
-
-
- if (SvTRUE(ERRSV)) /* check $@ */ {
- syslog(L_ERROR, "Perl function authenticate died: %s",
- SvPV(ERRSV, PL_na));
- Reply("%d Internal Error (1). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- while (rc--) {
- (void)POPs;
- }
-
- PUTBACK;
- FREETMPS;
- LEAVE;
-
-}
-
-int perlAuthenticate(char *user, char *passwd, char *errorstring, char *newUser) {
- dSP;
- HV *attribs;
- int rc;
- char *p;
- int code;
-
- if (!PerlFilterActive)
- return NNTP_ACCESS_VAL;
-
- if (perl_get_cv("authenticate", 0) == NULL) {
- syslog(L_ERROR, "Perl function authenticate not defined");
- Reply("%d Internal Error (3). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- ENTER;
- SAVETMPS;
- attribs = perl_get_hv("attributes", true);
- hv_store(attribs, "hostname", 8, newSVpv(ClientHost, 0), 0);
- hv_store(attribs, "ipaddress", 9, newSVpv(ClientIpString, 0), 0);
- hv_store(attribs, "port", 4, newSViv(ClientPort), 0);
- hv_store(attribs, "interface", 9, newSVpv(ServerHost, 0), 0);
- hv_store(attribs, "intipaddr", 9, newSVpv(ServerIpString, 0), 0);
- hv_store(attribs, "intport", 7, newSViv(ServerPort), 0);
- hv_store(attribs, "username", 8, newSVpv(user, 0), 0);
- hv_store(attribs, "password", 8, newSVpv(passwd, 0), 0);
-
- PUSHMARK(SP);
- rc = perl_call_pv("authenticate", G_EVAL|G_ARRAY);
-
- SPAGAIN;
-
- if (rc == 0 ) { /* Error occured, same as checking $@ */
- syslog(L_ERROR, "Perl function authenticate died: %s",
- SvPV(ERRSV, PL_na));
- Reply("%d Internal Error (1). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
-
- if ((rc != 3) && (rc != 2)) {
- syslog(L_ERROR, "Perl function authenticate returned wrong number of results: %d", rc);
- Reply("%d Internal Error (2). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
-
- if (rc == 3) {
- p = POPp;
- strcpy(newUser, p);
- }
-
- p = POPp;
- strcpy(errorstring, p);
-
- code = POPi;
-
- if ((code == NNTP_POSTOK_VAL) || (code == NNTP_NOPOSTOK_VAL))
- code = PERMcanpost ? NNTP_POSTOK_VAL : NNTP_NOPOSTOK_VAL;
-
- if (code == NNTP_AUTH_NEEDED_VAL)
- PERMneedauth = true;
-
- hv_undef(attribs);
-
- PUTBACK;
- FREETMPS;
- LEAVE;
-
- return code;
-}
-
-#ifdef DEBUG_MODIFY
-void
-dumpTable (msg)
-char *msg;
-{
- HEADER *hp;
- int i;
-
- fprintf(flog,"===BEGIN TABLE DUMP: %s\n",msg);
-
- for (hp = Table; hp < EndOfTable; hp++) {
- fprintf(flog," Name: '%s'",hp->Name); fflush(flog);
- fprintf(flog," Size: '%d'",hp->Size); fflush(flog);
- fprintf(flog," Value: '%s'\n",((hp->Value == NULL) ? "(NULL)" : hp->Value)); fflush(flog);
- }
-
- for (i=0; i<OtherCount; i++) {
- fprintf(flog,"Extra[%02d]: %s\n",i,OtherHeaders[i]);
- }
- fprintf(flog,"===END TABLE DUMP: %s\n",msg);
-}
-#endif /* DEBUG_MODIFY */
-
-#endif /* DO_PERL */
+++ /dev/null
-/* $Id: perm.c 7426 2005-12-11 20:37:27Z eagle $
-**
-** How to figure out where a user comes from, and what that user can do once
-** we know who sie is.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-#include <netdb.h>
-#include <signal.h>
-
-#include "conffile.h"
-#include "inn/innconf.h"
-#include "innperl.h"
-#include "nnrpd.h"
-
-/* Needed on AIX 4.1 to get fd_set and friends. */
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-
-/* data types */
-typedef struct _CONFCHAIN {
- CONFFILE *f;
- struct _CONFCHAIN *parent;
-} CONFCHAIN;
-
-typedef struct _METHOD {
- char *name;
- char *program;
- int type; /* type of auth (perl, python or external) */
- char *users; /* only used for auth_methods, not for res_methods. */
- char **extra_headers;
- char **extra_logs;
-} METHOD;
-
-typedef struct _AUTHGROUP {
- char *name;
- char *key;
-#ifdef HAVE_SSL
- int require_ssl;
-#endif
- char *hosts;
- METHOD **res_methods;
- METHOD **auth_methods;
- char *default_user;
- char *default_domain;
- char *localaddress;
- char *access_script;
- int access_type; /* type of access (perl or python) */
- char *dynamic_script;
- int dynamic_type; /* type of dynamic authorization (python only) */
-} AUTHGROUP;
-
-typedef struct _GROUP {
- char *name;
- struct _GROUP *above;
- AUTHGROUP *auth;
- ACCESSGROUP *access;
-} GROUP;
-
-/* function declarations */
-static void PERMreadfile(char *filename);
-static void authdecl_parse(AUTHGROUP*, CONFFILE*, CONFTOKEN*);
-static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok);
-static void method_parse(METHOD*, CONFFILE*, CONFTOKEN*, int);
-
-static void add_authgroup(AUTHGROUP*);
-static void add_accessgroup(ACCESSGROUP*);
-static void strip_accessgroups(void);
-
-static METHOD *copy_method(METHOD*);
-static void free_method(METHOD*);
-static AUTHGROUP *copy_authgroup(AUTHGROUP*);
-static void free_authgroup(AUTHGROUP*);
-static ACCESSGROUP *copy_accessgroup(ACCESSGROUP*);
-static void free_accessgroup(ACCESSGROUP*);
-
-static void CompressList(char*);
-static bool MatchHost(char*, char*, char*);
-static int MatchUser(char*, char*);
-static char *ResolveUser(AUTHGROUP*);
-static char *AuthenticateUser(AUTHGROUP*, char*, char*, char*);
-
-static void GrowArray(void***, void*);
-static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *acccess_vec);
-
-/* global variables */
-static AUTHGROUP **auth_realms;
-static AUTHGROUP *success_auth;
-static ACCESSGROUP **access_realms;
-
-static char *ConfigBit;
-static int ConfigBitsize;
-
-extern bool PerlLoaded;
-
-#define PERMlbrace 1
-#define PERMrbrace 2
-#define PERMgroup 3
-#define PERMauth 4
-#define PERMaccess 5
-#define PERMhost 6
-#define PERMauthprog 7
-#define PERMresolv 8
-#define PERMresprog 9
-#define PERMdefuser 10
-#define PERMdefdomain 11
-#define PERMusers 12
-#define PERMnewsgroups 13
-#define PERMread 14
-#define PERMpost 15
-#define PERMaccessrp 16
-#define PERMheader 17
-#define PERMalsolog 18
-#define PERMprogram 19
-#define PERMinclude 20
-#define PERMkey 21
-#define PERMlocaltime 22
-#define PERMstrippath 23
-#define PERMnnrpdperlfilter 24
-#define PERMnnrpdpythonfilter 25
-#define PERMfromhost 26
-#define PERMpathhost 27
-#define PERMorganization 28
-#define PERMmoderatormailer 29
-#define PERMdomain 30
-#define PERMcomplaints 31
-#define PERMspoolfirst 32
-#define PERMcheckincludedtext 33
-#define PERMclienttimeout 34
-#define PERMlocalmaxartsize 35
-#define PERMreadertrack 36
-#define PERMstrippostcc 37
-#define PERMaddnntppostinghost 38
-#define PERMaddnntppostingdate 39
-#define PERMnnrpdposthost 40
-#define PERMnnrpdpostport 41
-#define PERMnnrpdoverstats 42
-#define PERMbackoff_auth 43
-#define PERMbackoff_db 44
-#define PERMbackoff_k 45
-#define PERMbackoff_postfast 46
-#define PERMbackoff_postslow 47
-#define PERMbackoff_trigger 48
-#define PERMnnrpdcheckart 49
-#define PERMnnrpdauthsender 50
-#define PERMvirtualhost 51
-#define PERMnewsmaster 52
-#define PERMlocaladdress 53
-#define PERMrejectwith 54
-#define PERMmaxbytespersecond 55
-#define PERMperl_auth 56
-#define PERMpython_auth 57
-#define PERMperl_access 58
-#define PERMpython_access 59
-#define PERMpython_dynamic 60
-#ifdef HAVE_SSL
-#define PERMrequire_ssl 61
-#define PERMMAX 62
-#else
-#define PERMMAX 61
-#endif
-
-#define TEST_CONFIG(a, b) \
- { \
- int byte, offset; \
- offset = a % 8; \
- byte = (a - offset) / 8; \
- b = ((ConfigBit[byte] & (1 << offset)) != 0) ? true : false; \
- }
-#define SET_CONFIG(a) \
- { \
- int byte, offset; \
- offset = a % 8; \
- byte = (a - offset) / 8; \
- ConfigBit[byte] |= (1 << offset); \
- }
-#define CLEAR_CONFIG(a) \
- { \
- int byte, offset; \
- offset = a % 8; \
- byte = (a - offset) / 8; \
- ConfigBit[byte] &= ~(1 << offset); \
- }
-
-static CONFTOKEN PERMtoks[] = {
- { PERMlbrace, "{" },
- { PERMrbrace, "}" },
- { PERMgroup, "group" },
- { PERMauth, "auth" },
- { PERMaccess, "access" },
- { PERMhost, "hosts:" },
- { PERMauthprog, "auth:" },
- { PERMresolv, "res" },
- { PERMresprog, "res:" },
- { PERMdefuser, "default:" },
- { PERMdefdomain, "default-domain:" },
- { PERMusers, "users:" },
- { PERMnewsgroups, "newsgroups:" },
- { PERMread, "read:" },
- { PERMpost, "post:" },
- { PERMaccessrp, "access:" },
- { PERMheader, "header:" },
- { PERMalsolog, "log:" },
- { PERMprogram, "program:" },
- { PERMinclude, "include" },
- { PERMkey, "key:" },
- { PERMlocaltime, "localtime:" },
- { PERMstrippath, "strippath:" },
- { PERMnnrpdperlfilter, "perlfilter:" },
- { PERMnnrpdpythonfilter, "pythonfilter:" },
- { PERMfromhost, "fromhost:" },
- { PERMpathhost, "pathhost:" },
- { PERMorganization, "organization:" },
- { PERMmoderatormailer, "moderatormailer:" },
- { PERMdomain, "domain:" },
- { PERMcomplaints, "complaints:" },
- { PERMspoolfirst, "spoolfirst:" },
- { PERMcheckincludedtext, "checkincludedtext:" },
- { PERMclienttimeout, "clienttimeout:" },
- { PERMlocalmaxartsize, "localmaxartsize:" },
- { PERMreadertrack, "readertrack:" },
- { PERMstrippostcc, "strippostcc:" },
- { PERMaddnntppostinghost, "addnntppostinghost:" },
- { PERMaddnntppostingdate, "addnntppostingdate:" },
- { PERMnnrpdposthost, "nnrpdposthost:" },
- { PERMnnrpdpostport, "nnrpdpostport:" },
- { PERMnnrpdoverstats, "nnrpdoverstats:" },
- { PERMbackoff_auth, "backoff_auth:" },
- { PERMbackoff_db, "backoff_db:" },
- { PERMbackoff_k, "backoff_k:" },
- { PERMbackoff_postfast, "backoff_postfast:" },
- { PERMbackoff_postslow, "backoff_postslow:" },
- { PERMbackoff_trigger, "backoff_trigger:" },
- { PERMnnrpdcheckart, "nnrpdcheckart:" },
- { PERMnnrpdauthsender, "nnrpdauthsender:" },
- { PERMvirtualhost, "virtualhost:" },
- { PERMnewsmaster, "newsmaster:" },
- { PERMlocaladdress, "localaddress:" },
- { PERMrejectwith, "reject_with:" },
- { PERMmaxbytespersecond, "max_rate:" },
- { PERMperl_auth, "perl_auth:" },
- { PERMpython_auth, "python_auth:" },
- { PERMperl_access, "perl_access:" },
- { PERMpython_access, "python_access:" },
- { PERMpython_dynamic, "python_dynamic:" },
-#ifdef HAVE_SSL
- { PERMrequire_ssl, "require_ssl:" },
-#endif
- { 0, 0 }
-};
-
-/* function definitions */
-static void GrowArray(void ***array, void *el)
-{
- int i;
-
- if (!*array) {
- *array = xmalloc(2 * sizeof(void *));
- i = 0;
- } else {
- for (i = 0; (*array)[i]; i++)
- ;
- *array = xrealloc(*array, (i + 2) * sizeof(void *));
- }
- (*array)[i++] = el;
- (*array)[i] = 0;
-}
-
-static METHOD *copy_method(METHOD *orig)
-{
- METHOD *ret;
- int i;
-
- ret = xmalloc(sizeof(METHOD));
- memset(ConfigBit, '\0', ConfigBitsize);
-
- ret->name = xstrdup(orig->name);
- ret->program = xstrdup(orig->program);
- if (orig->users)
- ret->users = xstrdup(orig->users);
- else
- ret->users = 0;
-
- ret->extra_headers = 0;
- if (orig->extra_headers) {
- for (i = 0; orig->extra_headers[i]; i++)
- GrowArray((void***) &ret->extra_headers,
- (void*) xstrdup(orig->extra_headers[i]));
- }
-
- ret->extra_logs = 0;
- if (orig->extra_logs) {
- for (i = 0; orig->extra_logs[i]; i++)
- GrowArray((void***) &ret->extra_logs,
- (void*) xstrdup(orig->extra_logs[i]));
- }
-
- ret->type = orig->type;
-
- return(ret);
-}
-
-static void free_method(METHOD *del)
-{
- int j;
-
- if (del->extra_headers) {
- for (j = 0; del->extra_headers[j]; j++)
- free(del->extra_headers[j]);
- free(del->extra_headers);
- }
- if (del->extra_logs) {
- for (j = 0; del->extra_logs[j]; j++)
- free(del->extra_logs[j]);
- free(del->extra_logs);
- }
- if (del->program)
- free(del->program);
- if (del->users)
- free(del->users);
- free(del->name);
- free(del);
-}
-
-static AUTHGROUP *copy_authgroup(AUTHGROUP *orig)
-{
- AUTHGROUP *ret;
- int i;
-
- if (!orig)
- return(0);
- ret = xmalloc(sizeof(AUTHGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
-
- if (orig->name)
- ret->name = xstrdup(orig->name);
- else
- ret->name = 0;
-
- if (orig->key)
- ret->key = xstrdup(orig->key);
- else
- ret->key = 0;
-
- if (orig->hosts)
- ret->hosts = xstrdup(orig->hosts);
- else
- ret->hosts = 0;
-
-#ifdef HAVE_SSL
- ret->require_ssl = orig->require_ssl;
-#endif
-
- ret->res_methods = 0;
- if (orig->res_methods) {
- for (i = 0; orig->res_methods[i]; i++)
- GrowArray((void***) &ret->res_methods,
- (void*) copy_method(orig->res_methods[i]));;
- }
-
- ret->auth_methods = 0;
- if (orig->auth_methods) {
- for (i = 0; orig->auth_methods[i]; i++)
- GrowArray((void***) &ret->auth_methods,
- (void*) copy_method(orig->auth_methods[i]));
- }
-
- if (orig->default_user)
- ret->default_user = xstrdup(orig->default_user);
- else
- ret->default_user = 0;
-
- if (orig->default_domain)
- ret->default_domain = xstrdup(orig->default_domain);
- else
- ret->default_domain = 0;
-
- if (orig->localaddress)
- ret->localaddress = xstrdup(orig->localaddress);
- else
- ret->localaddress = 0;
-
- if (orig->access_script)
- ret->access_script = xstrdup(orig->access_script);
- else
- ret->access_script = 0;
-
- if (orig->access_type)
- ret->access_type = orig->access_type;
- else
- ret->access_type = 0;
-
- if (orig->dynamic_script)
- ret->dynamic_script = xstrdup(orig->dynamic_script);
- else
- ret->dynamic_script = 0;
-
- if (orig->dynamic_type)
- ret->dynamic_type = orig->dynamic_type;
- else
- ret->dynamic_type = 0;
-
- return(ret);
-}
-
-static ACCESSGROUP *copy_accessgroup(ACCESSGROUP *orig)
-{
- ACCESSGROUP *ret;
-
- if (!orig)
- return(0);
- ret = xmalloc(sizeof(ACCESSGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- /* copy all anyway, and update for local strings */
- *ret = *orig;
-
- if (orig->name)
- ret->name = xstrdup(orig->name);
- if (orig->key)
- ret->key = xstrdup(orig->key);
- if (orig->read)
- ret->read = xstrdup(orig->read);
- if (orig->post)
- ret->post = xstrdup(orig->post);
- if (orig->users)
- ret->users = xstrdup(orig->users);
- if (orig->rejectwith)
- ret->rejectwith = xstrdup(orig->rejectwith);
- if (orig->fromhost)
- ret->fromhost = xstrdup(orig->fromhost);
- if (orig->pathhost)
- ret->pathhost = xstrdup(orig->pathhost);
- if (orig->organization)
- ret->organization = xstrdup(orig->organization);
- if (orig->moderatormailer)
- ret->moderatormailer = xstrdup(orig->moderatormailer);
- if (orig->domain)
- ret->domain = xstrdup(orig->domain);
- if (orig->complaints)
- ret->complaints = xstrdup(orig->complaints);
- if (orig->nnrpdposthost)
- ret->nnrpdposthost = xstrdup(orig->nnrpdposthost);
- if (orig->backoff_db)
- ret->backoff_db = xstrdup(orig->backoff_db);
- if (orig->newsmaster)
- ret->newsmaster = xstrdup(orig->newsmaster);
- return(ret);
-}
-
-static void SetDefaultAuth(AUTHGROUP *curauth UNUSED)
-{
-#ifdef HAVE_SSL
- curauth->require_ssl = false;
-#endif
-}
-
-void SetDefaultAccess(ACCESSGROUP *curaccess)
-{
- curaccess->allownewnews = innconf->allownewnews;;
- curaccess->allowihave = false;
- curaccess->locpost = false;
- curaccess->allowapproved = false;
- curaccess->localtime = false;
- curaccess->strippath = false;
- curaccess->nnrpdperlfilter = true;
- curaccess->nnrpdpythonfilter = true;
- curaccess->fromhost = NULL;
- if (innconf->fromhost)
- curaccess->fromhost = xstrdup(innconf->fromhost);
- curaccess->pathhost = NULL;
- if (innconf->pathhost)
- curaccess->pathhost = xstrdup(innconf->pathhost);
- curaccess->organization = NULL;
- if (innconf->organization)
- curaccess->organization = xstrdup(innconf->organization);
- curaccess->moderatormailer = NULL;
- if (innconf->moderatormailer)
- curaccess->moderatormailer = xstrdup(innconf->moderatormailer);
- curaccess->domain = NULL;
- if (innconf->domain)
- curaccess->domain = xstrdup(innconf->domain);
- curaccess->complaints = NULL;
- if (innconf->complaints)
- curaccess->complaints = xstrdup(innconf->complaints);
- curaccess->spoolfirst = innconf->spoolfirst;
- curaccess->checkincludedtext = innconf->checkincludedtext;
- curaccess->clienttimeout = innconf->clienttimeout;
- curaccess->localmaxartsize = innconf->localmaxartsize;
- curaccess->readertrack = innconf->readertrack;
- curaccess->strippostcc = innconf->strippostcc;
- curaccess->addnntppostinghost = innconf->addnntppostinghost;
- curaccess->addnntppostingdate = innconf->addnntppostingdate;
- curaccess->nnrpdposthost = innconf->nnrpdposthost;
- curaccess->nnrpdpostport = innconf->nnrpdpostport;
- curaccess->nnrpdoverstats = innconf->nnrpdoverstats;
- curaccess->backoff_auth = innconf->backoffauth;
- curaccess->backoff_db = NULL;
- if (innconf->backoffdb && *innconf->backoffdb != '\0')
- curaccess->backoff_db = xstrdup(innconf->backoffdb);
- curaccess->backoff_k = innconf->backoffk;
- curaccess->backoff_postfast = innconf->backoffpostfast;
- curaccess->backoff_postslow = innconf->backoffpostslow;
- curaccess->backoff_trigger = innconf->backofftrigger;
- curaccess->nnrpdcheckart = innconf->nnrpdcheckart;
- curaccess->nnrpdauthsender = innconf->nnrpdauthsender;
- curaccess->virtualhost = false;
- curaccess->newsmaster = NULL;
- curaccess->maxbytespersecond = 0;
-}
-
-static void free_authgroup(AUTHGROUP *del)
-{
- int i;
-
- if (del->name)
- free(del->name);
- if (del->key)
- free(del->key);
- if (del->hosts)
- free(del->hosts);
- if (del->res_methods) {
- for (i = 0; del->res_methods[i]; i++)
- free_method(del->res_methods[i]);
- free(del->res_methods);
- }
- if (del->auth_methods) {
- for (i = 0; del->auth_methods[i]; i++)
- free_method(del->auth_methods[i]);
- free(del->auth_methods);
- }
- if (del->default_user)
- free(del->default_user);
- if (del->default_domain)
- free(del->default_domain);
- if (del->localaddress)
- free(del->localaddress);
- if (del->access_script)
- free(del->access_script);
- if (del->dynamic_script)
- free(del->dynamic_script);
- free(del);
-}
-
-static void free_accessgroup(ACCESSGROUP *del)
-{
- if (del->name)
- free(del->name);
- if (del->key)
- free(del->key);
- if (del->read)
- free(del->read);
- if (del->post)
- free(del->post);
- if (del->users)
- free(del->users);
- if (del->rejectwith)
- free(del->rejectwith);
- if (del->fromhost)
- free(del->fromhost);
- if (del->pathhost)
- free(del->pathhost);
- if (del->organization)
- free(del->organization);
- if (del->moderatormailer)
- free(del->moderatormailer);
- if (del->domain)
- free(del->domain);
- if (del->complaints)
- free(del->complaints);
- if (del->nnrpdposthost)
- free(del->nnrpdposthost);
- if (del->backoff_db)
- free(del->backoff_db);
- if (del->newsmaster)
- free(del->newsmaster);
- free(del);
-}
-
-static void ReportError(CONFFILE *f, const char *err)
-{
- syslog(L_ERROR, "%s syntax error in %s(%d), %s", ClientHost,
- f->filename, f->lineno, err);
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
-}
-
-static void method_parse(METHOD *method, CONFFILE *f, CONFTOKEN *tok, int auth)
-{
- int oldtype;
-
- oldtype = tok->type;
- tok = CONFgettoken(0, f);
-
- if (tok == NULL) {
- ReportError(f, "Expected value.");
- }
-
- switch (oldtype) {
- case PERMheader:
- GrowArray((void***) &method->extra_headers, (void*) xstrdup(tok->name));
- break;
- case PERMalsolog:
- GrowArray((void***) &method->extra_logs, (void*) xstrdup(tok->name));
- break;
- case PERMusers:
-
- if (!auth) {
- ReportError(f, "Unexpected users: directive in file.");
- } else if (method->users) {
- ReportError(f, "Multiple users: directive in file.");
- }
-
- method->users = xstrdup(tok->name);
- break;
- case PERMprogram:
- if (method->program) {
- ReportError(f, "Multiple program: directives in auth/res decl.");
- }
-
- method->program = xstrdup(tok->name);
- break;
- }
-}
-
-static void authdecl_parse(AUTHGROUP *curauth, CONFFILE *f, CONFTOKEN *tok)
-{
- int oldtype,boolval;
- METHOD *m;
- bool bit;
- char buff[SMBUF], *oldname, *p;
-
- oldtype = tok->type;
- oldname = tok->name;
-
- tok = CONFgettoken(PERMtoks, f);
-
- if (tok == NULL) {
- ReportError(f, "Expected value.");
- }
- TEST_CONFIG(oldtype, bit);
- if (bit) {
- snprintf(buff, sizeof(buff), "Duplicated '%s' field in authgroup.",
- oldname);
- ReportError(f, buff);
- }
-
- if (strcasecmp(tok->name, "on") == 0
- || strcasecmp(tok->name, "true") == 0
- || strcasecmp(tok->name, "yes") == 0)
- boolval = true;
- else if (strcasecmp(tok->name, "off") == 0
- || strcasecmp(tok->name, "false") == 0
- || strcasecmp(tok->name, "no") == 0)
- boolval = false;
- else
- boolval = -1;
-
- switch (oldtype) {
- case PERMkey:
- curauth->key = xstrdup(tok->name);
- SET_CONFIG(PERMkey);
- break;
-#ifdef HAVE_SSL
- case PERMrequire_ssl:
- if (boolval != -1) curauth->require_ssl = boolval;
- SET_CONFIG(PERMrequire_ssl);
- break;
-#endif
- case PERMhost:
- curauth->hosts = xstrdup(tok->name);
- CompressList(curauth->hosts);
- SET_CONFIG(PERMhost);
-
- /* nnrpd.c downcases the names of connecting hosts. We should
- therefore also downcase the wildmat patterns to make sure there
- aren't any surprises. DNS is case-insensitive. */
- for (p = curauth->hosts; *p; p++)
- if (CTYPE(isupper, (unsigned char) *p))
- *p = tolower((unsigned char) *p);
-
- break;
- case PERMdefdomain:
- curauth->default_domain = xstrdup(tok->name);
- SET_CONFIG(PERMdefdomain);
- break;
- case PERMdefuser:
- curauth->default_user = xstrdup(tok->name);
- SET_CONFIG(PERMdefuser);
- break;
- case PERMresolv:
- case PERMresprog:
- m = xcalloc(1, sizeof(METHOD));
- memset(ConfigBit, '\0', ConfigBitsize);
- GrowArray((void***) &curauth->res_methods, (void*) m);
-
- if (oldtype == PERMresprog)
- m->program = xstrdup(tok->name);
- else {
- m->name = xstrdup(tok->name);
- tok = CONFgettoken(PERMtoks, f);
- if (tok == NULL || tok->type != PERMlbrace) {
- ReportError(f, "Expected '{' after 'res'");
- }
-
- tok = CONFgettoken(PERMtoks, f);
-
- while (tok != NULL && tok->type != PERMrbrace) {
- method_parse(m, f, tok, 0);
- tok = CONFgettoken(PERMtoks, f);
- }
-
- if (tok == NULL) {
- ReportError(f, "Unexpected EOF.");
- }
- }
- break;
- case PERMauth:
- case PERMperl_auth:
- case PERMpython_auth:
- case PERMauthprog:
- m = xcalloc(1, sizeof(METHOD));
- memset(ConfigBit, '\0', ConfigBitsize);
- GrowArray((void***) &curauth->auth_methods, (void*) m);
- if (oldtype == PERMauthprog) {
- m->type = PERMauthprog;
- m->program = xstrdup(tok->name);
- } else if (oldtype == PERMperl_auth) {
-#ifdef DO_PERL
- m->type = PERMperl_auth;
- m->program = xstrdup(tok->name);
-#else
- ReportError(f, "perl_auth can not be used in readers.conf: inn not compiled with perl support enabled.");
-#endif
- } else if (oldtype == PERMpython_auth) {
-#ifdef DO_PYTHON
- m->type = PERMpython_auth;
- m->program = xstrdup(tok->name);
-#else
- ReportError(f, "python_auth can not be used in readers.conf: inn not compiled with python support enabled.");
-#endif
- } else {
- m->name = xstrdup(tok->name);
- tok = CONFgettoken(PERMtoks, f);
-
- if (tok == NULL || tok->type != PERMlbrace) {
- ReportError(f, "Expected '{' after 'auth'");
- }
-
- tok = CONFgettoken(PERMtoks, f);
-
- while (tok != NULL && tok->type != PERMrbrace) {
- method_parse(m, f, tok, 1);
- tok = CONFgettoken(PERMtoks, f);
- }
-
- if (tok == NULL) {
- ReportError(f, "Unexpected EOF.");
- }
- }
- break;
- case PERMperl_access:
-#ifdef DO_PERL
- curauth->access_script = xstrdup(tok->name);
- curauth->access_type = PERMperl_access;
-#else
- ReportError(f, "perl_access can not be used in readers.conf: inn not compiled with perl support enabled.");
-#endif
- break;
- case PERMpython_access:
-#ifdef DO_PYTHON
- curauth->access_script = xstrdup(tok->name);
- curauth->access_type = PERMpython_access;
-#else
- ReportError(f, "python_access can not be used in readers.conf: inn not compiled with python support enabled.");
-#endif
- break;
- case PERMpython_dynamic:
-#ifdef DO_PYTHON
- curauth->dynamic_script = xstrdup(tok->name);
- curauth->dynamic_type = PERMpython_dynamic;
-#else
- ReportError(f, "python_dynamic can not be used in readers.conf: inn not compiled with python support enabled.");
-#endif
- break;
- case PERMlocaladdress:
- curauth->localaddress = xstrdup(tok->name);
- CompressList(curauth->localaddress);
- SET_CONFIG(PERMlocaladdress);
- break;
- default:
- snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
- ReportError(f, buff);
- break;
- }
-}
-
-static void accessdecl_parse(ACCESSGROUP *curaccess, CONFFILE *f, CONFTOKEN *tok)
-{
- int oldtype, boolval;
- bool bit;
- char buff[SMBUF], *oldname;
-
- oldtype = tok->type;
- oldname = tok->name;
-
- tok = CONFgettoken(0, f);
-
- if (tok == NULL) {
- ReportError(f, "Expected value.");
- }
- TEST_CONFIG(oldtype, bit);
- if (bit) {
- snprintf(buff, sizeof(buff), "Duplicated '%s' field in accessgroup.",
- oldname);
- ReportError(f, buff);
- }
- if (strcasecmp(tok->name, "on") == 0
- || strcasecmp(tok->name, "true") == 0
- || strcasecmp(tok->name, "yes") == 0)
- boolval = true;
- else if (strcasecmp(tok->name, "off") == 0
- || strcasecmp(tok->name, "false") == 0
- || strcasecmp(tok->name, "no") == 0)
- boolval = false;
- else
- boolval = -1;
-
- switch (oldtype) {
- case PERMkey:
- curaccess->key = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMusers:
- curaccess->users = xstrdup(tok->name);
- CompressList(curaccess->users);
- SET_CONFIG(oldtype);
- break;
- case PERMrejectwith:
- curaccess->rejectwith = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMnewsgroups:
- TEST_CONFIG(PERMread, bit);
- if (bit) {
- /* syntax error.. can't set read: or post: _and_ use
- * newsgroups: */
- ReportError(f, "read: newsgroups already set.");
- }
- TEST_CONFIG(PERMpost, bit);
- if (bit) {
- /* syntax error.. can't set read: or post: _and_ use
- * newsgroups: */
- ReportError(f, "post: newsgroups already set.");
- }
-
- curaccess->read = xstrdup(tok->name);
- CompressList(curaccess->read);
- curaccess->post = xstrdup(tok->name);
- CompressList(curaccess->post);
- SET_CONFIG(oldtype);
- SET_CONFIG(PERMread);
- SET_CONFIG(PERMpost);
- break;
- case PERMread:
- curaccess->read = xstrdup(tok->name);
- CompressList(curaccess->read);
- SET_CONFIG(oldtype);
- break;
- case PERMpost:
- curaccess->post = xstrdup(tok->name);
- CompressList(curaccess->post);
- SET_CONFIG(oldtype);
- break;
- case PERMaccessrp:
- TEST_CONFIG(PERMread, bit);
- if (bit && strchr(tok->name, 'R') == NULL) {
- free(curaccess->read);
- curaccess->read = 0;
- CLEAR_CONFIG(PERMread);
- }
- TEST_CONFIG(PERMpost, bit);
- if (bit && strchr(tok->name, 'P') == NULL) {
- free(curaccess->post);
- curaccess->post = 0;
- CLEAR_CONFIG(PERMpost);
- }
- curaccess->allowapproved = (strchr(tok->name, 'A') != NULL);
- curaccess->allownewnews = (strchr(tok->name, 'N') != NULL);
- curaccess->allowihave = (strchr(tok->name, 'I') != NULL);
- curaccess->locpost = (strchr(tok->name, 'L') != NULL);
- SET_CONFIG(oldtype);
- break;
- case PERMlocaltime:
- if (boolval != -1) curaccess->localtime = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMstrippath:
- if (boolval != -1) curaccess->strippath = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdperlfilter:
- if (boolval != -1) curaccess->nnrpdperlfilter = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdpythonfilter:
- if (boolval != -1) curaccess->nnrpdpythonfilter = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMfromhost:
- if (curaccess->fromhost)
- free(curaccess->fromhost);
- curaccess->fromhost = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMpathhost:
- if (curaccess->pathhost)
- free(curaccess->pathhost);
- curaccess->pathhost = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMorganization:
- if (curaccess->organization)
- free(curaccess->organization);
- curaccess->organization = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMmoderatormailer:
- if (curaccess->moderatormailer)
- free(curaccess->moderatormailer);
- curaccess->moderatormailer = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMdomain:
- if (curaccess->domain)
- free(curaccess->domain);
- curaccess->domain = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMcomplaints:
- if (curaccess->complaints)
- free(curaccess->complaints);
- curaccess->complaints = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMspoolfirst:
- if (boolval != -1) curaccess->spoolfirst = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMcheckincludedtext:
- if (boolval != -1) curaccess->checkincludedtext = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMclienttimeout:
- curaccess->clienttimeout = atoi(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMlocalmaxartsize:
- curaccess->localmaxartsize = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMreadertrack:
- if (boolval != -1) curaccess->readertrack = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMstrippostcc:
- if (boolval != -1) curaccess->strippostcc = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMaddnntppostinghost:
- if (boolval != -1) curaccess->addnntppostinghost = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMaddnntppostingdate:
- if (boolval != -1) curaccess->addnntppostingdate = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdposthost:
- if (curaccess->nnrpdposthost)
- free(curaccess->nnrpdposthost);
- curaccess->nnrpdposthost = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdpostport:
- curaccess->nnrpdpostport = atoi(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdoverstats:
- if (boolval != -1) curaccess->nnrpdoverstats = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_auth:
- if (boolval != -1) curaccess->backoff_auth = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_db:
- if (curaccess->backoff_db)
- free(curaccess->backoff_db);
- curaccess->backoff_db = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_k:
- curaccess->backoff_k = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_postfast:
- curaccess->backoff_postfast = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_postslow:
- curaccess->backoff_postslow = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMbackoff_trigger:
- curaccess->backoff_trigger = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdcheckart:
- if (boolval != -1) curaccess->nnrpdcheckart = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMnnrpdauthsender:
- if (boolval != -1) curaccess->nnrpdauthsender = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMvirtualhost:
- if (boolval != -1) curaccess->virtualhost = boolval;
- SET_CONFIG(oldtype);
- break;
- case PERMnewsmaster:
- if (curaccess->newsmaster)
- free(curaccess->newsmaster);
- curaccess->newsmaster = xstrdup(tok->name);
- SET_CONFIG(oldtype);
- break;
- case PERMmaxbytespersecond:
- curaccess->maxbytespersecond = atol(tok->name);
- SET_CONFIG(oldtype);
- break;
- default:
- snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
- ReportError(f, buff);
- break;
- }
-}
-
-static void PERMvectortoaccess(ACCESSGROUP *acc, const char *name, struct vector *access_vec) {
- CONFTOKEN *tok = NULL;
- CONFFILE *file;
- char *str;
- unsigned int i;
-
- file = xcalloc(1, sizeof(CONFFILE));
- file->array = access_vec->strings;
- file->array_len = access_vec->count;
-
- memset(ConfigBit, '\0', ConfigBitsize);
-
- SetDefaultAccess(acc);
- str = xstrdup(name);
- acc->name = str;
-
- for (i = 0; i <= access_vec->count; i++) {
- tok = CONFgettoken(PERMtoks, file);
-
- if (tok != NULL) {
- accessdecl_parse(acc, file, tok);
- }
- }
- free(file);
- return;
-}
-
-static void PERMreadfile(char *filename)
-{
- CONFCHAIN *cf = NULL,
- *hold = NULL;
- CONFTOKEN *tok = NULL;
- int inwhat;
- GROUP *curgroup = NULL,
- *newgroup = NULL;
- ACCESSGROUP *curaccess = NULL;
- AUTHGROUP *curauth = NULL;
- int oldtype;
- char *str = NULL;
- char *path = NULL;
- char buff[SMBUF];
-
- if(filename != NULL) {
- syslog(L_TRACE, "Reading access from %s",
- filename == NULL ? "(NULL)" : filename);
- }
-
- cf = xmalloc(sizeof(CONFCHAIN));
- if ((cf->f = CONFfopen(filename)) == NULL) {
- syslog(L_ERROR, "%s cannot open %s: %m", ClientHost, filename);
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- cf->parent = 0;
-
- /* are we editing an AUTH or ACCESS group? */
-
- inwhat = 0;
- newgroup = curgroup = 0;
-
- tok = CONFgettoken(PERMtoks, cf->f);
-
- while (tok != NULL) {
- if (inwhat == 0) {
- /* top-level parser */
-
- switch (tok->type) {
- /* include a child file */
-
- case PERMinclude:
- tok = CONFgettoken(0, cf->f);
-
- if (tok == NULL) {
- ReportError(cf->f, "Expected filename after 'include'.");
- }
-
- hold = xmalloc(sizeof(CONFCHAIN));
- hold->parent = cf;
-
- /* unless the filename's path is fully qualified, open it
- * relative to /news/etc */
-
- path = concatpath(innconf->pathetc, tok->name);
- hold->f = CONFfopen(path);
- free(path);
-
- if (hold->f == NULL) {
- ReportError(cf->f, "Couldn't open 'include' filename.");
- }
-
- cf = hold;
- goto again;
- break;
-
- /* nested group declaration. */
- case PERMgroup:
- tok = CONFgettoken(PERMtoks, cf->f);
-
- if (tok == NULL) {
- ReportError(cf->f, "Unexpected EOF at group name");
- }
-
- newgroup = xmalloc(sizeof(GROUP));
- newgroup->above = curgroup;
- newgroup->name = xstrdup(tok->name);
- memset(ConfigBit, '\0', ConfigBitsize);
-
- tok = CONFgettoken(PERMtoks, cf->f);
-
- if (tok == NULL || tok->type != PERMlbrace) {
- ReportError(cf->f, "Expected '{' after group name");
- }
-
- /* nested group declaration */
- if (curgroup) {
- newgroup->auth = copy_authgroup(curgroup->auth);
- newgroup->access = copy_accessgroup(curgroup->access);
- } else {
- newgroup->auth = 0;
- newgroup->access = 0;
- }
-
- curgroup = newgroup;
- break;
-
- /* beginning of an auth or access group decl */
- case PERMauth:
- case PERMaccess:
- oldtype = tok->type;
-
- if ((tok = CONFgettoken(PERMtoks, cf->f)) == NULL) {
- ReportError(cf->f, "Expected identifier.");
- }
-
- str = xstrdup(tok->name);
-
- tok = CONFgettoken(PERMtoks, cf->f);
-
- if (tok == NULL || tok->type != PERMlbrace) {
- ReportError(cf->f, "Expected '{'");
- }
-
- switch (oldtype) {
- case PERMauth:
- if (curgroup && curgroup->auth)
- curauth = copy_authgroup(curgroup->auth);
- else {
- curauth = xcalloc(1, sizeof(AUTHGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- SetDefaultAuth(curauth);
- }
-
- curauth->name = str;
- inwhat = 1;
- break;
-
- case PERMaccess:
- if (curgroup && curgroup->access)
- curaccess = copy_accessgroup(curgroup->access);
- else {
- curaccess = xcalloc(1, sizeof(ACCESSGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- SetDefaultAccess(curaccess);
- }
- curaccess->name = str;
- inwhat = 2;
- break;
- }
-
- break;
-
- /* end of a group declaration */
-
- case PERMrbrace:
- if (curgroup == NULL) {
- ReportError(cf->f, "Unmatched '}'");
- }
-
- newgroup = curgroup;
- curgroup = curgroup->above;
- if (newgroup->auth)
- free_authgroup(newgroup->auth);
- if (newgroup->access)
- free_accessgroup(newgroup->access);
- free(newgroup->name);
- free(newgroup);
- break;
-
- /* stuff that belongs in an authgroup */
- case PERMhost:
-#ifdef HAVE_SSL
- case PERMrequire_ssl:
-#endif
- case PERMauthprog:
- case PERMresprog:
- case PERMdefuser:
- case PERMdefdomain:
- if (curgroup == NULL) {
- curgroup = xcalloc(1, sizeof(GROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- }
- if (curgroup->auth == NULL) {
- curgroup->auth = xcalloc(1, sizeof(AUTHGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- SetDefaultAuth(curgroup->auth);
- }
-
- authdecl_parse(curgroup->auth, cf->f, tok);
- break;
-
- /* stuff that belongs in an accessgroup */
- case PERMusers:
- case PERMrejectwith:
- case PERMnewsgroups:
- case PERMread:
- case PERMpost:
- case PERMaccessrp:
- case PERMlocaltime:
- case PERMstrippath:
- case PERMnnrpdperlfilter:
- case PERMnnrpdpythonfilter:
- case PERMfromhost:
- case PERMpathhost:
- case PERMorganization:
- case PERMmoderatormailer:
- case PERMdomain:
- case PERMcomplaints:
- case PERMspoolfirst:
- case PERMcheckincludedtext:
- case PERMclienttimeout:
- case PERMlocalmaxartsize:
- case PERMreadertrack:
- case PERMstrippostcc:
- case PERMaddnntppostinghost:
- case PERMaddnntppostingdate:
- case PERMnnrpdposthost:
- case PERMnnrpdpostport:
- case PERMnnrpdoverstats:
- case PERMbackoff_auth:
- case PERMbackoff_db:
- case PERMbackoff_k:
- case PERMbackoff_postfast:
- case PERMbackoff_postslow:
- case PERMbackoff_trigger:
- case PERMnnrpdcheckart:
- case PERMnnrpdauthsender:
- case PERMvirtualhost:
- case PERMnewsmaster:
- if (!curgroup) {
- curgroup = xcalloc(1, sizeof(GROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- }
- if (!curgroup->access) {
- curgroup->access = xcalloc(1, sizeof(ACCESSGROUP));
- memset(ConfigBit, '\0', ConfigBitsize);
- SetDefaultAccess(curgroup->access);
- }
- accessdecl_parse(curgroup->access, cf->f, tok);
- break;
- default:
- snprintf(buff, sizeof(buff), "Unexpected token: %s", tok->name);
- ReportError(cf->f, buff);
- break;
- }
- } else if (inwhat == 1) {
- /* authgroup parser */
- if (tok->type == PERMrbrace) {
- inwhat = 0;
-
- if (curauth->name
-#ifdef HAVE_SSL
- && ((curauth->require_ssl == false) || (ClientSSL == true))
-#endif
- && MatchHost(curauth->hosts, ClientHost, ClientIpString)) {
- if (!MatchHost(curauth->localaddress, ServerHost, ServerIpString)) {
- syslog(L_TRACE, "Auth strategy '%s' does not match localhost. Removing.",
- curauth->name == NULL ? "(NULL)" : curauth->name);
- free_authgroup(curauth);
- } else
- add_authgroup(curauth);
- } else {
- syslog(L_TRACE, "Auth strategy '%s' does not match client. Removing.",
- curauth->name == NULL ? "(NULL)" : curauth->name);
- free_authgroup(curauth);
- }
- curauth = NULL;
- goto again;
- }
-
- authdecl_parse(curauth, cf->f, tok);
- } else if (inwhat == 2) {
- /* accessgroup parser */
- if (tok->type == PERMrbrace) {
- inwhat = 0;
-
- if (curaccess->name)
- add_accessgroup(curaccess);
- else
- free_accessgroup(curaccess);
- curaccess = NULL;
- goto again;
- }
-
- accessdecl_parse(curaccess, cf->f, tok);
- } else {
- /* should never happen */
- syslog(L_TRACE, "SHOULD NEVER HAPPEN!");
- }
-again:
- /* go back up the 'include' chain. */
- tok = CONFgettoken(PERMtoks, cf->f);
-
- while (tok == NULL && cf) {
- hold = cf;
- cf = hold->parent;
- CONFfclose(hold->f);
- free(hold);
- if (cf) {
- tok = CONFgettoken(PERMtoks, cf->f);
- }
- }
- }
-
- return;
-}
-
-void PERMgetaccess(char *nnrpaccess)
-{
- int i;
- char *uname;
- int canauthenticate;
-
- auth_realms = NULL;
- access_realms = NULL;
- success_auth = NULL;
-
- PERMcanread = PERMcanpost = false;
- PERMreadlist = PERMpostlist = false;
- PERMaccessconf = NULL;
-
- if (ConfigBit == NULL) {
- if (PERMMAX % 8 == 0)
- ConfigBitsize = PERMMAX/8;
- else
- ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
- ConfigBit = xcalloc(ConfigBitsize, 1);
- }
- PERMreadfile(nnrpaccess);
-
- strip_accessgroups();
-
- if (auth_realms == NULL) {
- /* no one can talk, empty file */
- syslog(L_NOTICE, "%s no_permission", ClientHost);
- Printf("%d You have no permission to talk. Goodbye.\r\n",
- NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* auth_realms are all expected to match the user. */
- canauthenticate = 0;
- for (i = 0; auth_realms[i]; i++)
- if (auth_realms[i]->auth_methods)
- canauthenticate = 1;
- uname = 0;
- while (!uname && i--) {
- if ((uname = ResolveUser(auth_realms[i])) != NULL)
- PERMauthorized = true;
- if (!uname && auth_realms[i]->default_user)
- uname = auth_realms[i]->default_user;
- }
- if (uname) {
- strlcpy(PERMuser, uname, sizeof(PERMuser));
- uname = strchr(PERMuser, '@');
- if (!uname && auth_realms[i]->default_domain) {
- /* append the default domain to the username */
- strlcat(PERMuser, "@", sizeof(PERMuser));
- strlcat(PERMuser, auth_realms[i]->default_domain,
- sizeof(PERMuser));
- }
- PERMneedauth = false;
- success_auth = auth_realms[i];
- syslog(L_TRACE, "%s res %s", ClientHost, PERMuser);
- } else if (!canauthenticate) {
- /* couldn't resolve the user. */
- syslog(L_NOTICE, "%s no_user", ClientHost);
- Printf("%d Could not get your access name. Goodbye.\r\n",
- NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- } else {
- PERMneedauth = true;
- }
- /* check maximum allowed permissions for any host that matches (for
- * the greeting string) */
- for (i = 0; access_realms[i]; i++) {
- if (!PERMcanread)
- PERMcanread = (access_realms[i]->read != NULL);
- if (!PERMcanpost)
- PERMcanpost = (access_realms[i]->post != NULL);
- }
- if (!i) {
- /* no applicable access groups. Zeroing all these makes INN
- * return permission denied to client. */
- PERMcanread = PERMcanpost = PERMneedauth = false;
- }
-}
-
-void PERMlogin(char *uname, char *pass, char *errorstr)
-{
- int i = 0;
- char *runame;
-
- if (ConfigBit == NULL) {
- if (PERMMAX % 8 == 0)
- ConfigBitsize = PERMMAX/8;
- else
- ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
- ConfigBit = xcalloc(ConfigBitsize, 1);
- }
- /* The check in CMDauthinfo uses the value of PERMneedauth to know if
- * authentication succeeded or not. By default, authentication doesn't
- * succeed. */
- PERMneedauth = true;
-
- if(auth_realms != NULL) {
- for (i = 0; auth_realms[i]; i++) {
- ;
- }
- }
-
- runame = NULL;
-
- while (runame == NULL && i--)
- runame = AuthenticateUser(auth_realms[i], uname, pass, errorstr);
- if (runame) {
- strlcpy(PERMuser, runame, sizeof(PERMuser));
- uname = strchr(PERMuser, '@');
- if (!uname && auth_realms[i]->default_domain) {
- /* append the default domain to the username */
- strlcat(PERMuser, "@", sizeof(PERMuser));
- strlcat(PERMuser, auth_realms[i]->default_domain,
- sizeof(PERMuser));
- }
- PERMneedauth = false;
- PERMauthorized = true;
- success_auth = auth_realms[i];
- }
-}
-
-static int MatchUser(char *pat, char *user)
-{
- char *cp, **list;
- char *userlist[2];
- int ret;
-
- if (!pat)
- return(1);
- if (!user || !*user)
- return(0);
- cp = xstrdup(pat);
- list = 0;
- NGgetlist(&list, cp);
- userlist[0] = user;
- userlist[1] = 0;
- ret = PERMmatch(list, userlist);
- free(cp);
- free(list[0]);
- free(list);
- return(ret);
-}
-
-void PERMgetpermissions()
-{
- int i;
- char *cp, **list;
- char *user[2];
- static ACCESSGROUP *noaccessconf;
- char *uname;
- char *cpp, *script_path;
- char **args;
- struct vector *access_vec;
-
- if (ConfigBit == NULL) {
- if (PERMMAX % 8 == 0)
- ConfigBitsize = PERMMAX/8;
- else
- ConfigBitsize = (PERMMAX - (PERMMAX % 8))/8 + 1;
- ConfigBit = xcalloc(ConfigBitsize, 1);
- }
- if (!success_auth) {
- /* if we haven't successfully authenticated, we can't do anything. */
- syslog(L_TRACE, "%s no_success_auth", ClientHost);
- if (!noaccessconf)
- noaccessconf = xmalloc(sizeof(ACCESSGROUP));
- PERMaccessconf = noaccessconf;
- SetDefaultAccess(PERMaccessconf);
- return;
-#ifdef DO_PERL
- } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMperl_access)) {
- i = 0;
- cpp = xstrdup(success_auth->access_script);
- args = 0;
- Argify(cpp, &args);
- script_path = concat(args[0], (char *) 0);
- if ((script_path != NULL) && (strlen(script_path) > 0)) {
- if(!PerlLoaded) {
- loadPerl();
- }
- PERLsetup(NULL, script_path, "access");
- free(script_path);
-
- uname = xstrdup(PERMuser);
-
- access_vec = vector_new();
-
- perlAccess(uname, access_vec);
- free(uname);
-
- access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
-
- PERMvectortoaccess(access_realms[0], "perl-dynamic", access_vec);
-
- vector_free(access_vec);
- } else {
- syslog(L_ERROR, "No script specified in perl_access method.\n");
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- free(cpp);
- free(args);
-#endif /* DO_PERL */
-#ifdef DO_PYTHON
- } else if ((success_auth->access_script != NULL) && (success_auth->access_type == PERMpython_access)) {
- i = 0;
- cpp = xstrdup(success_auth->access_script);
- args = 0;
- Argify(cpp, &args);
- script_path = concat(args[0], (char *) 0);
- if ((script_path != NULL) && (strlen(script_path) > 0)) {
- uname = xstrdup(PERMuser);
- access_vec = vector_new();
-
- PY_access(script_path, access_vec, uname);
- free(script_path);
- free(uname);
- free(args);
-
- access_realms[0] = xcalloc(1, sizeof(ACCESSGROUP));
- memset(access_realms[0], 0, sizeof(ACCESSGROUP));
-
- PERMvectortoaccess(access_realms[0], "python-dynamic", access_vec);
-
- vector_free(access_vec);
- } else {
- syslog(L_ERROR, "No script specified in python_access method.\n");
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- free(cpp);
-#endif /* DO_PYTHON */
- } else {
- for (i = 0; access_realms[i]; i++)
- ;
- user[0] = PERMuser;
- user[1] = 0;
- while (i--) {
- if ((!success_auth->key && !access_realms[i]->key) ||
- (access_realms[i]->key && success_auth->key &&
- strcmp(access_realms[i]->key, success_auth->key) == 0)) {
- if (!access_realms[i]->users)
- break;
- else if (!*PERMuser)
- continue;
- cp = xstrdup(access_realms[i]->users);
- list = 0;
- NGgetlist(&list, cp);
- if (PERMmatch(list, user)) {
- syslog(L_TRACE, "%s match_user %s %s", ClientHost,
- PERMuser, access_realms[i]->users);
- free(cp);
- free(list[0]);
- free(list);
- break;
- } else
- syslog(L_TRACE, "%s no_match_user %s %s", ClientHost,
- PERMuser, access_realms[i]->users);
- free(cp);
- free(list[0]);
- free(list);
- }
- }
- }
- if (i >= 0) {
- /* found the right access group */
- if (access_realms[i]->rejectwith) {
- syslog(L_ERROR, "%s rejected by rule (%s)",
- ClientHost, access_realms[i]->rejectwith);
- Reply("%d Permission denied: %s\r\n",
- NNTP_ACCESS_VAL, access_realms[i]->rejectwith);
- ExitWithStats(1, true);
- }
- if (access_realms[i]->read) {
- cp = xstrdup(access_realms[i]->read);
- PERMspecified = NGgetlist(&PERMreadlist, cp);
- free(cp);
- PERMcanread = true;
- } else {
- syslog(L_TRACE, "%s no_read %s", ClientHost, access_realms[i]->name);
- PERMcanread = false;
- }
- if (access_realms[i]->post) {
- cp = xstrdup(access_realms[i]->post);
- NGgetlist(&PERMpostlist, cp);
- free(cp);
- PERMcanpost = true;
- } else {
- syslog(L_TRACE, "%s no_post %s", ClientHost, access_realms[i]->name);
- PERMcanpost = false;
- }
- PERMaccessconf = access_realms[i];
- MaxBytesPerSecond = PERMaccessconf->maxbytespersecond;
- if (PERMaccessconf->virtualhost) {
- if (PERMaccessconf->domain == NULL) {
- syslog(L_ERROR, "%s virtualhost needs domain parameter(%s)",
- ClientHost, PERMaccessconf->name);
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- if (VirtualPath)
- free(VirtualPath);
- if (strcmp(innconf->pathhost, PERMaccessconf->pathhost) == 0) {
- /* use domain, if pathhost in access relm matches one in
- inn.conf to differentiate virtual host */
- if (innconf->domain != NULL && strcmp(innconf->domain, PERMaccessconf->domain) == 0) {
- syslog(L_ERROR, "%s domain parameter(%s) in readers.conf must be different from the one in inn.conf",
- ClientHost, PERMaccessconf->name);
- Reply("%d NNTP server unavailable. Try later.\r\n", NNTP_TEMPERR_VAL);
- ExitWithStats(1, true);
- }
- VirtualPath = concat(PERMaccessconf->domain, "!", (char *) 0);
- } else {
- VirtualPath = concat(PERMaccessconf->pathhost, "!",
- (char *) 0);
- }
- VirtualPathlen = strlen(VirtualPath);
- } else
- VirtualPathlen = 0;
- } else {
- if (!noaccessconf)
- noaccessconf = xmalloc(sizeof(ACCESSGROUP));
- PERMaccessconf = noaccessconf;
- SetDefaultAccess(PERMaccessconf);
- syslog(L_TRACE, "%s no_access_realm", ClientHost);
- }
- /* check if dynamic access control is enabled, if so init it */
-#ifdef DO_PYTHON
- if ((success_auth->dynamic_type == PERMpython_dynamic) && success_auth->dynamic_script) {
- PY_dynamic_init(success_auth->dynamic_script);
- }
-#endif /* DO_PYTHON */
-}
-
-/* strip blanks out of a string */
-static void CompressList(char *list)
-{
- char *cpto;
- bool inword = false;
-
- for (cpto = list; *list; ) {
- if (strchr("\n \t,", *list) != NULL) {
- list++;
- if(inword) {
- *cpto++ = ',';
- inword = false;
- }
- } else {
- *cpto++ = *list++;
- inword = true;
- }
- }
- *cpto = '\0';
-}
-
-static bool MatchHost(char *hostlist, char *host, char *ip)
-{
- char **list;
- bool ret = false;
- char *cp;
- int iter;
- char *pat,
- *p;
-
- /* If no hostlist are specified, by default they match. */
-
- if (hostlist == NULL) {
- return(true);
- }
-
- list = 0;
- cp = xstrdup(hostlist);
-
- NGgetlist(&list, cp);
-
- /* default is no access */
- for (iter = 0; list[iter]; iter++) {
- ;
- }
-
- while (iter-- > 0) {
- pat = list[iter];
- if (*pat == '!')
- pat++;
- ret = uwildmat(host, pat);
- if (!ret && *ip) {
- ret = uwildmat(ip, pat);
- if (!ret && (p = strchr(pat, '/')) != (char *)NULL) {
- unsigned int bits, c;
- struct in_addr ia, net, tmp;
-#ifdef HAVE_INET6
- struct in6_addr ia6, net6;
- unsigned char bits8;
-#endif
- unsigned int mask;
-
- *p = '\0';
- if (inet_aton(ip, &ia) && inet_aton(pat, &net)) {
- if (strchr(p+1, '.') == (char *)NULL) {
- /* string following / is a masklength */
- mask = atoi(p+1);
- for (bits = c = 0; c < mask && c < 32; c++)
- bits |= (1 << (31 - c));
- mask = htonl(bits);
- } else { /* or it may be a dotted quad bitmask */
- if (inet_aton(p+1, &tmp))
- mask = tmp.s_addr;
- else /* otherwise skip it */
- continue;
- }
- if ((ia.s_addr & mask) == (net.s_addr & mask))
- ret = true;
- }
-#ifdef HAVE_INET6
- else if (inet_pton(AF_INET6, ip, &ia6) &&
- inet_pton(AF_INET6, pat, &net6)) {
- mask = atoi(p+1);
- ret = true;
- /* do a prefix match byte by byte */
- for (c = 0; c*8 < mask && c < sizeof(ia6); c++) {
- if ( (c+1)*8 <= mask &&
- ia6.s6_addr[c] != net6.s6_addr[c] ) {
- ret = false;
- break;
- } else if ( (c+1)*8 > mask ) {
- unsigned int b;
-
- for (bits8 = b = 0; b < (mask % 8); b++)
- bits8 |= (1 << (7 - b));
- if ((ia6.s6_addr[c] & bits8) !=
- (net6.s6_addr[c] & bits8) ) {
- ret = false;
- break;
- }
- }
- }
- }
-#endif
- }
- }
- if (ret)
- break;
- }
- if (ret && list[iter][0] == '!')
- ret = false;
- free(list[0]);
- free(list);
- free(cp);
- return(ret);
-}
-
-static void add_authgroup(AUTHGROUP *group)
-{
- int i;
-
- if (auth_realms == NULL) {
- i = 0;
- auth_realms = xmalloc(2 * sizeof(AUTHGROUP *));
- } else {
- for (i = 0; auth_realms[i]; i++)
- ;
- auth_realms = xrealloc(auth_realms, (i + 2) * sizeof(AUTHGROUP *));
- }
- auth_realms[i] = group;
- auth_realms[i+1] = 0;
-}
-
-static void add_accessgroup(ACCESSGROUP *group)
-{
- int i;
-
- if (access_realms == NULL) {
- i = 0;
- access_realms = xmalloc(2 * sizeof(ACCESSGROUP *));
- } else {
- for (i = 0; access_realms[i]; i++)
- ;
- access_realms = xrealloc(access_realms, (i + 2) * sizeof(ACCESSGROUP *));
- }
- access_realms[i] = group;
- access_realms[i+1] = 0;
-}
-
-/* clean out access groups that don't apply to any of our auth groups. */
-
-static void strip_accessgroups(void)
-{
- int i, j;
-
- /* flag the access group as used or not */
-
- if(access_realms != NULL) {
- for (j = 0; access_realms[j] != NULL; j++) {
- access_realms[j]->used = 0;
- }
- } else {
- syslog(L_TRACE, "No access realms to check!");
- }
-
- /* If there are auth realms to check... */
-
- if(auth_realms != NULL) {
- /* ... Then for each auth realm... */
-
- for (i = 0; auth_realms[i] != NULL; i++) {
-
- /* ... for each access realm... */
-
- for (j = 0; access_realms[j] != NULL; j++) {
-
- /* If the access realm isn't already in use... */
-
- if (! access_realms[j]->used) {
- /* Check to see if both the access_realm key and
- auth_realm key are NULL... */
-
- if (!access_realms[j]->key && !auth_realms[i]->key) {
- /* If so, mark the realm in use and continue on... */
-
- access_realms[j]->used = 1;
- } else {
- /* If not, check to see if both the access_realm and
- auth_realm are NOT _both_ NULL, and see if they are
- equal... */
-
- if (access_realms[j]->key && auth_realms[i]->key &&
- strcmp(access_realms[j]->key, auth_realms[i]->key) == 0) {
-
- /* And if so, mark the realm in use. */
-
- access_realms[j]->used = 1;
- }
- }
- }
- }
- }
- } else {
- syslog(L_TRACE, "No auth realms to check!");
- }
-
- /* strip out unused access groups */
- i = j = 0;
-
- while (access_realms[i] != NULL) {
- if (access_realms[i]->used)
- access_realms[j++] = access_realms[i];
- else
- syslog(L_TRACE, "%s removing irrelevant access group %s",
- ClientHost, access_realms[i]->name);
- i++;
- }
- access_realms[j] = 0;
-}
-
-typedef struct _EXECSTUFF {
- pid_t pid;
- int rdfd, errfd, wrfd;
-} EXECSTUFF;
-
-static EXECSTUFF *ExecProg(char *arg0, char **args)
-{
- EXECSTUFF *ret;
- int rdfd[2], errfd[2], wrfd[2];
- pid_t pid;
- struct stat stb;
-
-#if !defined(S_IXUSR) && defined(_S_IXUSR)
-#define S_IXUSR _S_IXUSR
-#endif /* !defined(S_IXUSR) && defined(_S_IXUSR) */
-
-#if !defined(S_IXUSR) && defined(S_IEXEC)
-#define S_IXUSR S_IEXEC
-#endif /* !defined(S_IXUSR) && defined(S_IEXEC) */
-
- if (stat(arg0, &stb) || !(stb.st_mode&S_IXUSR))
- return(0);
-
- pipe(rdfd);
- pipe(errfd);
- pipe(wrfd);
- switch (pid = fork()) {
- case -1:
- close(rdfd[0]);
- close(rdfd[1]);
- close(errfd[0]);
- close(errfd[1]);
- close(wrfd[0]);
- close(wrfd[1]);
- return(0);
- case 0:
- close(rdfd[0]);
- dup2(rdfd[1], 1);
- close(errfd[0]);
- dup2(errfd[1], 2);
- close(wrfd[1]);
- dup2(wrfd[0], 0);
- execv(arg0, args);
- /* if we got here, there was an error */
- syslog(L_ERROR, "%s perm could not exec %s: %m", ClientHost, arg0);
- exit(1);
- }
- close(rdfd[1]);
- close(errfd[1]);
- close(wrfd[0]);
- ret = xmalloc(sizeof(EXECSTUFF));
- ret->pid = pid;
- ret->rdfd = rdfd[0];
- ret->errfd = errfd[0];
- ret->wrfd = wrfd[1];
- return(ret);
-}
-
-static void GetConnInfo(METHOD *method, char *buf)
-{
- int i;
-
- buf[0] = '\0';
- if (*ClientHost)
- sprintf(buf, "ClientHost: %s\r\n", ClientHost);
- if (*ClientIpString)
- sprintf(buf+strlen(buf), "ClientIP: %s\r\n", ClientIpString);
- if (ClientPort)
- sprintf(buf+strlen(buf), "ClientPort: %d\r\n", ClientPort);
- if (*ServerIpString)
- sprintf(buf+strlen(buf), "LocalIP: %s\r\n", ServerIpString);
- if (ServerPort)
- sprintf(buf+strlen(buf), "LocalPort: %d\r\n", ServerPort);
- /* handle this here, since we only get here when we're about to exec
- * something. */
- if (method->extra_headers) {
- for (i = 0; method->extra_headers[i]; i++)
- sprintf(buf+strlen(buf), "%s\r\n", method->extra_headers[i]);
- }
-}
-
-static char ubuf[SMBUF];
-
-typedef void (*LineFunc)(char*);
-
-/* messages from a program's stdout */
-static void HandleProgLine(char *ln)
-{
- if (strncasecmp(ln, "User:", strlen("User:")) == 0)
- strlcpy(ubuf, ln + strlen("User:"), sizeof(ubuf));
-}
-
-/* messages from a programs stderr */
-static void HandleErrorLine(char *ln)
-{
- syslog(L_NOTICE, "%s auth_err %s", ClientHost, ln);
-}
-
-static bool
-HandleProgInput(int fd, char *buf, int buflen, LineFunc f)
-{
- char *nl;
- char *start;
- int curpos, got;
-
- /* read the data */
- curpos = strlen(buf);
- if (curpos >= buflen-1) {
- /* data overflow (on one line!) */
- return false;
- }
- got = read(fd, buf+curpos, buflen-curpos-1);
- if (got <= 0)
- return false;
- buf[curpos+got] = '\0';
-
- /* break what we got up into lines */
- start = nl = buf;
- while ((nl = strchr(nl, '\n')) != NULL) {
- if (nl != buf && *(nl-1) == '\r')
- *(nl-1) = '\0';
- *nl++ = '\0';
- f(start);
- start = nl;
- }
-
- /* delete all the lines we've read from the buffer. */
- /* 'start' points to the end of the last unterminated string */
- nl = start;
- start = buf;
- if (nl == start) {
- return true;
- }
-
- while (*nl) {
- *start++ = *nl++;
- }
-
- *start = '\0';
-
- return true;
-}
-
-static void GetProgInput(EXECSTUFF *prog)
-{
- fd_set rfds, tfds;
- int maxfd;
- int got;
- bool okay;
- struct timeval tmout;
- pid_t tmp;
- int status;
- char rdbuf[BIG_BUFFER], errbuf[BIG_BUFFER];
- double start, end;
-
- FD_ZERO(&rfds);
- FD_SET(prog->rdfd, &rfds);
- FD_SET(prog->errfd, &rfds);
- tfds = rfds;
- maxfd = prog->rdfd > prog->errfd ? prog->rdfd : prog->errfd;
- tmout.tv_sec = 5;
- tmout.tv_usec = 0;
- rdbuf[0] = errbuf[0] = '\0';
- start = TMRnow_double();
- while ((got = select(maxfd+1, &tfds, 0, 0, &tmout)) >= 0) {
- end = TMRnow_double();
- IDLEtime += end - start;
- start = end;
- tmout.tv_sec = 5;
- tmout.tv_usec = 0;
- if (got > 0) {
- if (FD_ISSET(prog->rdfd, &tfds)) {
- okay = HandleProgInput(prog->rdfd, rdbuf, sizeof(rdbuf), HandleProgLine);
- if (!okay) {
- close(prog->rdfd);
- FD_CLR(prog->rdfd, &tfds);
- kill(prog->pid, SIGTERM);
- }
- }
- if (FD_ISSET(prog->errfd, &tfds)) {
- okay = HandleProgInput(prog->errfd, errbuf, sizeof(errbuf), HandleErrorLine);
- if (!okay) {
- close(prog->errfd);
- FD_CLR(prog->errfd, &tfds);
- kill(prog->pid, SIGTERM);
- }
- }
- }
- tfds = rfds;
- }
- end = TMRnow_double();
- IDLEtime += end - start;
- /* wait for it if he's toast. */
- do {
- tmp = waitpid(prog->pid, &status, 0);
- } while ((tmp >= 0 || (tmp < 0 && errno == EINTR)) &&
- !WIFEXITED(status) && !WIFSIGNALED(status));
- if (WIFSIGNALED(status)) {
- ubuf[0] = '\0';
- syslog(L_NOTICE, "%s bad_hook program caught signal %d", ClientHost,
- WTERMSIG(status));
- } else if (WIFEXITED(status)) {
- if (WEXITSTATUS(status) != 0) {
- ubuf[0] = '\0';
- syslog(L_TRACE, "%s bad_hook program exited with status %d",
- ClientHost, WEXITSTATUS(status));
- }
- } else {
- syslog(L_ERROR, "%s bad_hook waitpid failed: %m", ClientHost);
- ubuf[0] = '\0';
- }
-}
-
-/* execute a series of resolvers to get the remote username */
-static char *ResolveUser(AUTHGROUP *auth)
-{
- int i, j;
- char *cp;
- char **args;
- char *arg0;
- char *resdir;
- char *tmp;
- EXECSTUFF *foo;
- int done = 0;
- char buf[BIG_BUFFER];
-
- if (!auth->res_methods)
- return(0);
-
- tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR);
- resdir = concatpath(tmp, _PATH_AUTHDIR_NOPASS);
- free(tmp);
-
- ubuf[0] = '\0';
- for (i = 0; auth->res_methods[i]; i++) {
- /* build the command line */
- syslog(L_TRACE, "%s res starting resolver %s", ClientHost, auth->res_methods[i]->program);
- if (auth->res_methods[i]->extra_logs) {
- for (j = 0; auth->res_methods[i]->extra_logs[j]; j++)
- syslog(L_NOTICE, "%s res also-log: %s", ClientHost,
- auth->res_methods[i]->extra_logs[j]);
- }
- cp = xstrdup(auth->res_methods[i]->program);
- args = 0;
- Argify(cp, &args);
- arg0 = args[0];
- if (args[0][0] != '/')
- arg0 = concat(resdir, "/", arg0, (char *) 0);
- /* exec the resolver */
- foo = ExecProg(arg0, args);
- if (foo) {
- GetConnInfo(auth->res_methods[i], buf);
- strlcat(buf, ".\r\n", sizeof(buf));
- xwrite(foo->wrfd, buf, strlen(buf));
- close(foo->wrfd);
-
- GetProgInput(foo);
- done = (ubuf[0] != '\0');
- if (done)
- syslog(L_TRACE, "%s res resolver successful, user %s", ClientHost, ubuf);
- else
- syslog(L_TRACE, "%s res resolver failed", ClientHost);
- free(foo);
- } else
- syslog(L_ERROR, "%s res couldnt start resolver: %m", ClientHost);
- /* clean up */
- if (args[0][0] != '/') {
- free(arg0);
- }
- free(args);
- free(cp);
- if (done)
- /* this resolver succeeded */
- break;
- }
- free(resdir);
- if (ubuf[0])
- return(ubuf);
- return(0);
-}
-
-/* execute a series of authenticators to get the remote username */
-static char *AuthenticateUser(AUTHGROUP *auth, char *username, char *password, char *errorstr)
-{
- int i, j;
- char *cp;
- char **args;
- char *arg0;
- char *resdir;
- char *tmp;
- char *script_path;
- char newUser[BIG_BUFFER];
- EXECSTUFF *foo;
- int done = 0;
- int code;
- char buf[BIG_BUFFER];
-
- if (!auth->auth_methods)
- return(0);
-
- tmp = concatpath(innconf->pathbin, _PATH_AUTHDIR);
- resdir = concatpath(tmp, _PATH_AUTHDIR_PASSWD);
- free(tmp);
-
- ubuf[0] = '\0';
- newUser[0] = '\0';
- for (i = 0; auth->auth_methods[i]; i++) {
- if (auth->auth_methods[i]->type == PERMperl_auth) {
-#ifdef DO_PERL
- cp = xstrdup(auth->auth_methods[i]->program);
- args = 0;
- Argify(cp, &args);
- script_path = concat(args[0], (char *) 0);
- if ((script_path != NULL) && (strlen(script_path) > 0)) {
- if(!PerlLoaded) {
- loadPerl();
- }
- PERLsetup(NULL, script_path, "authenticate");
- free(script_path);
- perlAuthInit();
-
- code = perlAuthenticate(username, password, errorstr, newUser);
- if (code == NNTP_AUTH_OK_VAL) {
- /* Set the value of ubuf to the right username */
- if (newUser[0] != '\0') {
- strlcpy(ubuf, newUser, sizeof(ubuf));
- } else {
- strlcpy(ubuf, username, sizeof(ubuf));
- }
-
- syslog(L_NOTICE, "%s user %s", ClientHost, ubuf);
- if (LLOGenable) {
- fprintf(locallog, "%s user %s\n", ClientHost, ubuf);
- fflush(locallog);
- }
- break;
- } else {
- syslog(L_NOTICE, "%s bad_auth", ClientHost);
- }
- } else {
- syslog(L_ERROR, "No script specified in auth method.\n");
- }
-#endif /* DO_PERL */
- } else if (auth->auth_methods[i]->type == PERMpython_auth) {
-#ifdef DO_PYTHON
- cp = xstrdup(auth->auth_methods[i]->program);
- args = 0;
- Argify(cp, &args);
- script_path = concat(args[0], (char *) 0);
- if ((script_path != NULL) && (strlen(script_path) > 0)) {
- code = PY_authenticate(script_path, username, password, errorstr, newUser);
- free(script_path);
- if (code < 0) {
- syslog(L_NOTICE, "PY_authenticate(): authentication skipped due to no Python authentication method defined.");
- } else {
- if (code == NNTP_AUTH_OK_VAL) {
- /* Set the value of ubuf to the right username */
- if (newUser[0] != '\0') {
- strlcpy(ubuf, newUser, sizeof(ubuf));
- } else {
- strlcpy(ubuf, username, sizeof(ubuf));
- }
-
- syslog(L_NOTICE, "%s user %s", ClientHost, ubuf);
- if (LLOGenable) {
- fprintf(locallog, "%s user %s\n", ClientHost, ubuf);
- fflush(locallog);
- }
- break;
- } else {
- syslog(L_NOTICE, "%s bad_auth", ClientHost);
- }
- }
- } else {
- syslog(L_ERROR, "No script specified in auth method.\n");
- }
-#endif /* DO_PYTHON */
- } else {
- if (auth->auth_methods[i]->users &&
- !MatchUser(auth->auth_methods[i]->users, username))
- continue;
-
- /* build the command line */
- syslog(L_TRACE, "%s auth starting authenticator %s", ClientHost, auth->auth_methods[i]->program);
- if (auth->auth_methods[i]->extra_logs) {
- for (j = 0; auth->auth_methods[i]->extra_logs[j]; j++)
- syslog(L_NOTICE, "%s auth also-log: %s", ClientHost,
- auth->auth_methods[i]->extra_logs[j]);
- }
- cp = xstrdup(auth->auth_methods[i]->program);
- args = 0;
- Argify(cp, &args);
- arg0 = args[0];
- if (args[0][0] != '/')
- arg0 = concat(resdir, "/", arg0, (char *) 0);
- /* exec the authenticator */
- foo = ExecProg(arg0, args);
- if (foo) {
- GetConnInfo(auth->auth_methods[i], buf);
- snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3,
- "ClientAuthname: %s\r\n", username);
- snprintf(buf+strlen(buf), sizeof(buf) - strlen(buf) - 3,
- "ClientPassword: %s\r\n", password);
- strlcat(buf, ".\r\n", sizeof(buf));
- xwrite(foo->wrfd, buf, strlen(buf));
- close(foo->wrfd);
-
- GetProgInput(foo);
- done = (ubuf[0] != '\0');
- if (done)
- syslog(L_TRACE, "%s auth authenticator successful, user %s", ClientHost, ubuf);
- else
- syslog(L_TRACE, "%s auth authenticator failed", ClientHost);
- free(foo);
- } else
- syslog(L_ERROR, "%s auth couldnt start authenticator: %m", ClientHost);
- /* clean up */
- if (args[0][0] != '/') {
- free(arg0);
- }
- free(args);
- free(cp);
- if (done)
- /* this authenticator succeeded */
- break;
- }
- }
- free(resdir);
- if (ubuf[0])
- return(ubuf);
- return(0);
-}
+++ /dev/null
-/* $Revision: 7450 $
-**
-** Check article, send it to the local server.
-*/
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "ov.h"
-#include "post.h"
-
-#define FLUSH_ERROR(F) (fflush((F)) == EOF || ferror((F)))
-#define HEADER_DELTA 20
-
-static char *tmpPtr ;
-static char Error[SMBUF];
-static char NGSEPS[] = NG_SEPARATOR;
-char **OtherHeaders;
-int OtherCount;
-bool HeadersModified;
-static int OtherSize;
-static const char * const BadDistribs[] = {
- BAD_DISTRIBS
-};
-
-HEADER Table[] = {
- /* Name Canset Type Size Value */
- { "Path", true, HTstd, 0, NULL, NULL, 0 },
- { "From", true, HTreq, 0, NULL, NULL, 0 },
- { "Newsgroups", true, HTreq, 0, NULL, NULL, 0 },
- { "Subject", true, HTreq, 0, NULL, NULL, 0 },
- { "Control", true, HTstd, 0, NULL, NULL, 0 },
- { "Supersedes", true, HTstd, 0, NULL, NULL, 0 },
- { "Followup-To", true, HTstd, 0, NULL, NULL, 0 },
- { "Date", true, HTstd, 0, NULL, NULL, 0 },
- { "Organization", true, HTstd, 0, NULL, NULL, 0 },
- { "Lines", true, HTstd, 0, NULL, NULL, 0 },
- { "Sender", true, HTstd, 0, NULL, NULL, 0 },
- { "Approved", true, HTstd, 0, NULL, NULL, 0 },
- { "Distribution", true, HTstd, 0, NULL, NULL, 0 },
- { "Expires", true, HTstd, 0, NULL, NULL, 0 },
- { "Message-ID", true, HTstd, 0, NULL, NULL, 0 },
- { "References", true, HTstd, 0, NULL, NULL, 0 },
- { "Reply-To", true, HTstd, 0, NULL, NULL, 0 },
- { "NNTP-Posting-Host", false, HTstd, 0, NULL, NULL, 0 },
- { "Mime-Version", true, HTstd, 0, NULL, NULL, 0 },
- { "Content-Type", true, HTstd, 0, NULL, NULL, 0 },
- { "Content-Transfer-Encoding", true, HTstd, 0, NULL, NULL, 0 },
- { "X-Trace", false, HTstd, 0, NULL, NULL, 0 },
- { "X-Complaints-To", false, HTstd, 0, NULL, NULL, 0 },
- { "NNTP-Posting-Date", false, HTstd, 0, NULL, NULL, 0 },
- { "Xref", false, HTstd, 0, NULL, NULL, 0 },
- { "Injector-Info", false, HTstd, 0, NULL, NULL, 0 },
- { "Summary", true, HTstd, 0, NULL, NULL, 0 },
- { "Keywords", true, HTstd, 0, NULL, NULL, 0 },
- { "Date-Received", false, HTobs, 0, NULL, NULL, 0 },
- { "Received", false, HTobs, 0, NULL, NULL, 0 },
- { "Posted", false, HTobs, 0, NULL, NULL, 0 },
- { "Posting-Version", false, HTobs, 0, NULL, NULL, 0 },
- { "Relay-Version", false, HTobs, 0, NULL, NULL, 0 },
- { "Cc", true, HTstd, 0, NULL, NULL, 0 },
- { "Bcc", true, HTstd, 0, NULL, NULL, 0 },
- { "To", true, HTstd, 0, NULL, NULL, 0 },
-};
-
-HEADER *EndOfTable = ARRAY_END(Table);
-
-\f
-
-/* Join() and MaxLength() are taken from innd.c */
-/*
-** Turn any \r or \n in text into spaces. Used to splice back multi-line
-** headers into a single line.
-*/
-static char *
-Join(char *text)
-{
- char *p;
-
- for (p = text; *p; p++)
- if (*p == '\n' || *p == '\r')
- *p = ' ';
- return text;
-}
-
-/*
-** Return a short name that won't overrun our bufer or syslog's buffer.
-** q should either be p, or point into p where the "interesting" part is.
-*/
-static char *
-MaxLength(char *p, char *q)
-{
- static char buff[80];
- unsigned int i;
-
- /* Already short enough? */
- i = strlen(p);
- if (i < sizeof buff - 1)
- return Join(p);
-
- /* Don't want casts to unsigned to go horribly wrong. */
- if (q < p || q > p + i)
- q = p;
-
- /* Simple case of just want the begining? */
- if ((size_t)(q - p) < sizeof(buff) - 4) {
- strlcpy(buff, p, sizeof(buff) - 3);
- strlcat(buff, "...", sizeof(buff));
- } else if ((p + i) - q < 10) {
- /* Is getting last 10 characters good enough? */
- strlcpy(buff, p, sizeof(buff) - 13);
- strlcat(buff, "...", sizeof(buff) - 10);
- strlcat(buff, &p[i - 10], sizeof(buff));
- } else {
- /* Not in last 10 bytes, so use double elipses. */
- strlcpy(buff, p, sizeof(buff) - 16);
- strlcat(buff, "...", sizeof(buff) - 13);
- strlcat(buff, &q[-5], sizeof(buff) - 3);
- strlcat(buff, "...", sizeof(buff));
- }
- return Join(buff);
-}
-/*
-** Trim trailing spaces, return pointer to first non-space char.
-*/
-int
-TrimSpaces(char *p)
-{
- char *start;
-
- for (start = p; ISWHITE(*start) || *start == '\n'; start++)
- continue;
- for (p = start + strlen(start); p > start && CTYPE(isspace, (int)p[-1]); p--)
- continue;
- return (int)(p - start);
-}
-
-
-/*
-** Mark the end of the header starting at p, and return a pointer
-** to the start of the next one or NULL. Handles continuations.
-*/
-static char *
-NextHeader(char *p)
-{
- for ( ; (p = strchr(p, '\n')) != NULL; p++) {
- if (ISWHITE(p[1]))
- continue;
- *p = '\0';
- return p + 1;
- }
- return NULL;
-}
-
-
-/*
-** Strip any headers off the article and dump them into the table.
-** On error, return NULL and fill in Error.
-*/
-static char *
-StripOffHeaders(char *article)
-{
- char *p;
- char *q;
- HEADER *hp;
- char c;
-
- /* Scan through buffer, a header at a time. */
- for (p = article; ; ) {
-
- /* See if it's a known header. */
- c = CTYPE(islower, (int)*p) ? toupper(*p) : *p;
- for (hp = Table; hp < ARRAY_END(Table); hp++) {
- if (c == hp->Name[0]
- && p[hp->Size] == ':'
- && strncasecmp(p, hp->Name, hp->Size) == 0) {
- if (hp->Type == HTobs) {
- snprintf(Error, sizeof(Error), "Obsolete \"%s\" header",
- hp->Name);
- return NULL;
- }
- if (hp->Value) {
- snprintf(Error, sizeof(Error), "Duplicate \"%s\" header",
- hp->Name);
- return NULL;
- }
- hp->Value = &p[hp->Size + 1];
- /* '\r\n' is replaced with '\n', and unnecessary to consider
- '\r' */
- for (q = &p[hp->Size + 1]; ISWHITE(*q) || *q == '\n'; q++)
- continue;
- hp->Body = q;
- break;
- }
- }
-
- /* No; add it to the set of other headers. */
- if (hp == ARRAY_END(Table)) {
- if (OtherCount >= OtherSize - 1) {
- OtherSize += HEADER_DELTA;
- OtherHeaders = xrealloc(OtherHeaders, OtherSize * sizeof(char *));
- }
- OtherHeaders[OtherCount++] = p;
- }
-
- /* Get start of next header; if it's a blank line, we hit the end. */
- if ((p = NextHeader(p)) == NULL) {
- strlcpy(Error, "Article has no body -- just headers",
- sizeof(Error));
- return NULL;
- }
- if (*p == '\n')
- break;
- }
-
- return p + 1;
-}
-
-\f
-
-/*
-** Check the control message, and see if it's legit. Return pointer to
-** error message if not.
-*/
-static const char *
-CheckControl(char *ctrl)
-{
- char *p;
- char *q;
- char save;
-
- /* Snip off the first word. */
- for (p = ctrl; ISWHITE(*p); p++)
- continue;
- for (ctrl = p; *p && !ISWHITE(*p); p++)
- continue;
- if (p == ctrl)
- return "Empty control message";
- save = *p;
- *p = '\0';
-
- if (strcmp(ctrl, "cancel") == 0) {
- for (q = p + 1; ISWHITE(*q); q++)
- continue;
- if (*q == '\0')
- return "Message-ID missing in cancel";
- }
- else if (strcmp(ctrl, "sendsys") == 0
- || strcmp(ctrl, "senduuname") == 0
- || strcmp(ctrl, "version") == 0
- || strcmp(ctrl, "checkgroups") == 0
- || strcmp(ctrl, "ihave") == 0
- || strcmp(ctrl, "sendme") == 0
- || strcmp(ctrl, "newgroup") == 0
- || strcmp(ctrl, "rmgroup") == 0)
- ;
- else {
- snprintf(Error, sizeof(Error),
- "\"%s\" is not a valid control message",
- MaxLength(ctrl,ctrl));
- return Error;
- }
- *p = save;
- return NULL;
-}
-
-
-/*
-** Check the Distribution header, and exit on error.
-*/
-static const char *
-CheckDistribution(char *p)
-{
- static char SEPS[] = " \t,";
- const char * const *dp;
-
- if ((p = strtok(p, SEPS)) == NULL)
- return "Can't parse Distribution line.";
- do {
- for (dp = BadDistribs; *dp; dp++)
- if (uwildmat(p, *dp)) {
- snprintf(Error, sizeof(Error), "Illegal distribution \"%s\"",
- MaxLength(p,p));
- return Error;
- }
- } while ((p = strtok((char *)NULL, SEPS)) != NULL);
- return NULL;
-}
-
-
-/*
-** Process all the headers. FYI, they're done in RFC-order.
-** Return NULL if okay, or an error message.
-*/
-static const char *
-ProcessHeaders(int linecount, char *idbuff, bool ihave)
-{
- static char MONTHS[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
- static char datebuff[40];
- static char localdatebuff[40];
- static char orgbuff[SMBUF];
- static char linebuff[40];
- static char tracebuff[SMBUF];
- static char complaintsbuff[SMBUF];
- static char sendbuff[SMBUF];
- static char *newpath = NULL;
- HEADER *hp;
- char *p;
- time_t t;
- struct tm *gmt;
- TIMEINFO Now;
- const char *error;
- pid_t pid;
- bool addvirtual = false;
-
- /* Various things need Now to be set. */
- if (GetTimeInfo(&Now) < 0) {
- snprintf(Error, sizeof(Error), "Can't get the time, %s",
- strerror(errno));
- return Error;
- }
-
- /* Do some preliminary fix-ups. */
- for (hp = Table; hp < ARRAY_END(Table); hp++) {
- if (!ihave && !hp->CanSet && hp->Value) {
- snprintf(Error, sizeof(Error),
- "Can't set system \"%s\" header", hp->Name);
- return Error;
- }
- if (hp->Value) {
- hp->Len = TrimSpaces(hp->Value);
- if (hp->Len == 0)
- hp->Value = hp->Body = NULL;
- }
- }
-
- /* If authorized, add the header based on our info. If not authorized,
- zap the Sender so we don't put out unauthenticated data. */
- if (PERMaccessconf->nnrpdauthsender) {
- if (PERMauthorized && PERMuser[0] != '\0') {
- p = strchr(PERMuser, '@');
- if (p == NULL) {
- snprintf(sendbuff, sizeof(sendbuff), "%s@%s", PERMuser,
- ClientHost);
- } else {
- snprintf(sendbuff, sizeof(sendbuff), "%s", PERMuser);
- }
- HDR_SET(HDR__SENDER, sendbuff);
- } else {
- HDR_SET(HDR__SENDER, NULL);
- }
- }
-
- /* Set Date. datebuff is used later for NNTP-Posting-Date, so we have
- to set it and it has to be the UTC date. */
- if (!makedate(-1, false, datebuff, sizeof(datebuff)))
- return "Can't generate date header";
- if (HDR(HDR__DATE) == NULL) {
- if (ihave)
- return "Missing \"Date\" header";
- if (PERMaccessconf->localtime) {
- if (!makedate(-1, true, localdatebuff, sizeof(localdatebuff)))
- return "Can't generate local date header";
- HDR_SET(HDR__DATE, localdatebuff);
- } else {
- HDR_SET(HDR__DATE, datebuff);
- }
- } else {
- if ((t = parsedate(HDR(HDR__DATE), &Now)) == -1)
- return "Can't parse \"Date\" header";
- if (t > Now.time + DATE_FUZZ)
- return "Article posted in the future";
- }
-
- /* Newsgroups are checked later. */
-
- if (HDR(HDR__CONTROL)) {
- if ((error = CheckControl(HDR(HDR__CONTROL))) != NULL)
- return error;
- } else {
- p = HDR(HDR__SUBJECT);
- if (p == NULL)
- return "Required \"Subject\" header is missing";
- if (strncmp(p, "cmsg ", 5) == 0) {
- HDR_SET(HDR__CONTROL, p + 5);
- if ((error = CheckControl(HDR(HDR__CONTROL))) != NULL)
- return error;
- }
- }
-
- /* Set Message-ID */
- if (HDR(HDR__MESSAGEID) == NULL) {
- if (ihave)
- return "Missing \"Message-ID\" header";
- HDR_SET(HDR__MESSAGEID, idbuff);
- }
-
- /* Set Path */
- if (HDR(HDR__PATH) == NULL) {
- if (ihave)
- return "Missing \"Path\" header";
- /* Note that innd will put host name here for us. */
- HDR_SET(HDR__PATH, PATHMASTER);
- if (VirtualPathlen > 0)
- addvirtual = true;
- } else if (PERMaccessconf->strippath) {
- /* Here's where to do Path changes for new Posts. */
- if ((p = strrchr(HDR(HDR__PATH), '!')) != NULL) {
- p++;
- if (*p == '\0') {
- HDR_SET(HDR__PATH, PATHMASTER);
- if (VirtualPathlen > 0)
- addvirtual = true;
- } else {
- HDR_SET(HDR__PATH, p);
- if ((VirtualPathlen > 0) &&
- strcmp(p, PERMaccessconf->pathhost) != 0)
- addvirtual = true;
- }
- } else if (VirtualPathlen > 0)
- addvirtual = true;
- } else {
- if ((VirtualPathlen > 0) &&
- (p = strchr(HDR(HDR__PATH), '!')) != NULL) {
- *p = '\0';
- if (strcmp(HDR(HDR__PATH), PERMaccessconf->pathhost) != 0)
- addvirtual = true;
- *p = '!';
- } else if (VirtualPathlen > 0)
- addvirtual = true;
- }
- if (addvirtual) {
- if (newpath != NULL)
- free(newpath);
- newpath = concat(VirtualPath, HDR(HDR__PATH), (char *) 0);
- HDR_SET(HDR__PATH, newpath);
- }
-
-
- /* Reply-To; left alone. */
- /* Sender; set above. */
-
- /* Check Expires. */
- if (HDR(HDR__EXPIRES) && parsedate(HDR(HDR__EXPIRES), &Now) == -1)
- return "Can't parse \"Expires\" header";
-
- /* References; left alone. */
- /* Control; checked above. */
-
- /* Distribution. */
- if ((p = HDR(HDR__DISTRIBUTION)) != NULL) {
- p = xstrdup(p);
- error = CheckDistribution(p);
- free(p);
- if (error != NULL)
- return error;
- }
-
- /* Set Organization */
- if (!ihave && HDR(HDR__ORGANIZATION) == NULL
- && (p = PERMaccessconf->organization) != NULL) {
- strlcpy(orgbuff, p, sizeof(orgbuff));
- HDR_SET(HDR__ORGANIZATION, orgbuff);
- }
-
- /* Keywords; left alone. */
- /* Summary; left alone. */
- /* Approved; left alone. */
-
- /* Set Lines */
- if (!ihave) {
- snprintf(linebuff, sizeof(linebuff), "%d", linecount);
- HDR_SET(HDR__LINES, linebuff);
- }
-
- /* Supersedes; left alone. */
-
- /* NNTP-Posting host; set. */
- if (!ihave && PERMaccessconf->addnntppostinghost)
- HDR_SET(HDR__NNTPPOSTINGHOST, ClientHost);
- /* NNTP-Posting-Date - not in RFC (yet) */
- if (!ihave && PERMaccessconf->addnntppostingdate)
- HDR_SET(HDR__NNTPPOSTINGDATE, datebuff);
-
- /* X-Trace; set */
- t = time((time_t *)NULL) ;
- pid = (long) getpid() ;
- if ((gmt = gmtime(&Now.time)) == NULL)
- return "Can't get the time";
- if (VirtualPathlen > 0)
- p = PERMaccessconf->domain;
- else
- if ((p = GetFQDN(PERMaccessconf->domain)) == NULL)
- p = "unknown";
- snprintf(tracebuff, sizeof(tracebuff),
- "%s %ld %ld %s (%d %3.3s %d %02d:%02d:%02d GMT)",
- p, (long) t, (long) pid, ClientIpString,
- gmt->tm_mday, &MONTHS[3 * gmt->tm_mon], 1900 + gmt->tm_year,
- gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
- HDR_SET(HDR__XTRACE, tracebuff);
-
- /* X-Complaints-To; set */
- if ((p = PERMaccessconf->complaints) != NULL)
- snprintf (complaintsbuff, sizeof(complaintsbuff), "%s", p);
- else {
- static const char newsmaster[] = NEWSMASTER;
-
- if ((p = PERMaccessconf->fromhost) != NULL && strchr(newsmaster, '@') == NULL)
- snprintf (complaintsbuff, sizeof(complaintsbuff), "%s@%s",
- newsmaster, p);
- else
- snprintf (complaintsbuff, sizeof(complaintsbuff), "%s",
- newsmaster);
- }
- HDR_SET(HDR__XCOMPLAINTSTO, complaintsbuff);
-
- /* Clear out some headers that should not be here */
- if (!ihave && PERMaccessconf->strippostcc) {
- HDR_SET(HDR__CC, NULL);
- HDR_SET(HDR__BCC, NULL);
- HDR_SET(HDR__TO, NULL);
- }
- /* Now make sure everything is there. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Type == HTreq && hp->Value == NULL) {
- snprintf(Error, sizeof(Error),
- "Required \"%s\" header is missing", hp->Name);
- return Error;
- }
-
- return NULL;
-}
-
-
-/*
-** See if the user has more included text than new text. Simple-minded,
-** but reasonably effective for catching neophyte's mistakes. Son-of-1036
-** says:
-**
-** NOTE: While encouraging trimming is desirable, the 50% rule imposed
-** by some old posting agents is both inadequate and counterproductive.
-** Posters do not respond to it by being more selective about quoting;
-** they respond by padding short responses, or by using different
-** quoting styles to defeat automatic analysis. The former adds
-** unnecessary noise and volume, while the latter also defeats more
-** useful forms of automatic analysis that reading agents might wish to
-** do.
-**
-** NOTE: At the very least, if a minimum-unquoted quota is being set,
-** article bodies shorter than (say) 20 lines, or perhaps articles
-** which exceed the quota by only a few lines, should be exempt. This
-** avoids the ridiculous situation of complaining about a 5-line
-** response to a 6-line quote.
-**
-** Accordingly, bodies shorter than 20 lines are exempt. A line starting
-** with >, |, or : is included text. Decrement the count on lines starting
-** with < so that we don't reject diff(1) output.
-*/
-static const char *
-CheckIncludedText(const char *p, int lines)
-{
- int i;
-
- if (lines < 20)
- return NULL;
- for (i = 0; ; p++) {
- switch (*p) {
- case '>': i++; break;
- case '|': i++; break;
- case ':': i++; break;
- case '<': i--; break;
- default: break;
- }
- p = strchr(p, '\n');
- if (p == NULL)
- break;
- }
- if (i * 2 > lines)
- return "Article not posted -- more included text than new text";
- return NULL;
-}
-
-\f
-
-/*
-** Try to mail an article to the moderator of the group.
-*/
-static const char *
-MailArticle(char *group, char *article)
-{
- static char CANTSEND[] = "Can't send text to mailer";
- FILE *F;
- HEADER *hp;
- int i;
- char *address;
- char buff[SMBUF];
- char *mta;
-
- /* Try to get the address first. */
- if ((address = GetModeratorAddress(NULL, NULL, group, PERMaccessconf->moderatormailer)) == NULL) {
- snprintf(Error, sizeof(Error), "No mailing address for \"%s\" -- %s",
- group, "ask your news administrator to fix this");
- free(group);
- return Error;
- }
- free(group);
-
- /* Now build up the command (ignore format/argument mismatch errors,
- * in case %s isn't in inconf->mta) and send the headers. */
- if ((mta = innconf->mta) == NULL)
- return "Can't start mailer - mta not set";
- snprintf(buff, sizeof(buff), innconf->mta, address);
- if ((F = popen(buff, "w")) == NULL)
- return "Can't start mailer";
- fprintf(F, "To: %s\n", address);
- if (FLUSH_ERROR(F)) {
- pclose(F);
- return CANTSEND;
- }
-
- /* Write the headers, a blank line, then the article. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value) {
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(F, "%s:%s\n", hp->Name, hp->Value);
- else
- fprintf(F, "%s: %s\n", hp->Name, hp->Value);
- if (FLUSH_ERROR(F)) {
- pclose(F);
- return CANTSEND;
- }
- }
- for (i = 0; i < OtherCount; i++) {
- fprintf(F, "%s\n", OtherHeaders[i]);
- if (FLUSH_ERROR(F)) {
- pclose(F);
- return CANTSEND;
- }
- }
- fprintf(F, "\n");
- i = strlen(article);
- if (fwrite(article, 1, i, F) != (size_t)i)
- return "Can't send article";
- if (FLUSH_ERROR(F)) {
- pclose(F);
- return CANTSEND;
- }
- i = pclose(F);
- if (i) {
- snprintf(Error, sizeof(Error), "Mailer exited with status %d -- %s",
- i, "Article might not have been mailed");
- return Error;
- }
- return NULL;
-}
-
-
-/*
-** Check the newsgroups and make sure they're all valid, that none are
-** moderated, etc.
-*/
-static const char *
-ValidNewsgroups(char *hdr, char **modgroup)
-{
- static char distbuff[SMBUF];
- char *groups;
- char *p;
- bool approved;
- struct _DDHANDLE *h;
- char *grplist[2];
- bool IsNewgroup;
- bool FoundOne;
- int flag;
- bool hookpresent = false;
-
-#ifdef DO_PYTHON
- hookpresent = PY_use_dynamic;
-#endif /* DO_PYTHON */
-
- p = HDR(HDR__CONTROL);
- IsNewgroup = (p && strncmp(p, "newgroup", 8) == 0);
- groups = xstrdup(hdr);
- if ((p = strtok(groups, NGSEPS)) == NULL)
- return "Can't parse newsgroups line";
- Error[0] = '\0';
-
- /* Reject all articles with Approved headers unless the user is allowed to
- add them, even to unmoderated or local groups. We want to reject them
- to unmoderated groups in case there's a disagreement of opinion
- between various sites as to the moderation status. */
- approved = HDR(HDR__APPROVED) != NULL;
- if (approved && !PERMaccessconf->allowapproved) {
- snprintf(Error, sizeof(Error),
- "You are not allowed to approve postings");
- }
-
- FoundOne = false;
- h = DDstart((FILE *)NULL, (FILE *)NULL);
- do {
- if (innconf->mergetogroups && p[0] == 't' && p[1] == 'o' && p[2] == '.')
- p = "to";
- if (!hookpresent && PERMspecified) {
- grplist[0] = p;
- grplist[1] = NULL;
- if (!PERMmatch(PERMpostlist, grplist)) {
- snprintf(Error, sizeof(Error),
- "You are not allowed to post to %s\r\n", p);
- }
- }
- if (!OVgroupstats(p, NULL, NULL, NULL, &flag))
- continue;
- FoundOne = true;
- DDcheck(h, p);
- switch (flag) {
- case NF_FLAG_OK:
-#ifdef DO_PYTHON
- if (PY_use_dynamic) {
- char *reply;
-
- /* Authorize user using Python module method dynamic */
- if (PY_dynamic(PERMuser, p, true, &reply) < 0) {
- syslog(L_NOTICE, "PY_dynamic(): authorization skipped due to no Python dynamic method defined.");
- } else {
- if (reply != NULL) {
- syslog(L_TRACE, "PY_dynamic() returned a refuse string for user %s at %s who wants to read %s: %s", PERMuser, ClientHost, p, reply);
- snprintf(Error, sizeof(Error), "%s\r\n", reply);
- free(reply);
- break;
- }
- }
- }
-#endif /* DO_PYTHON */
- break;
- case NF_FLAG_MODERATED:
- if (!approved && modgroup != NULL && !*modgroup)
- *modgroup = xstrdup(p);
- break;
- case NF_FLAG_IGNORE:
- case NF_FLAG_NOLOCAL:
- if (!PERMaccessconf->locpost)
- snprintf(Error, sizeof(Error),
- "Postings to \"%s\" are not allowed here.", p);
- break;
- case NF_FLAG_EXCLUDED:
- /* Do NOT return an error. */
- break;
- case NF_FLAG_ALIAS:
- snprintf(Error, sizeof(Error),
- "The newsgroup \"%s\" has been renamed.\n", p);
- break;
- }
- } while ((p = strtok((char *)NULL, NGSEPS)) != NULL);
- free(groups);
-
- if (!FoundOne && !IsNewgroup)
- snprintf(Error, sizeof(Error), "No valid newsgroups in \"%s\"",
- MaxLength(hdr,hdr));
- if (Error[0]) {
- tmpPtr = DDend(h);
- free(tmpPtr);
- if (modgroup != NULL && *modgroup != NULL) {
- free(*modgroup);
- *modgroup = NULL;
- }
- return Error;
- }
-
- p = DDend(h);
- if (HDR(HDR__DISTRIBUTION) == NULL && *p) {
- strlcpy(distbuff, p, sizeof(distbuff));
- HDR_SET(HDR__DISTRIBUTION, distbuff);
- }
- free(p);
- return NULL;
-}
-
-
-/*
-** Send a quit message to the server, eat its reply.
-*/
-static void
-SendQuit(FILE *FromServer, FILE *ToServer)
-{
- char buff[NNTP_STRLEN];
-
- fprintf(ToServer, "quit\r\n");
- fflush(ToServer);
- fclose(ToServer);
- fgets(buff, sizeof buff, FromServer);
- fclose(FromServer);
-}
-
-
-/*
-** Offer the article to the server, return its reply.
-*/
-static int
-OfferArticle(char *buff, int buffsize, FILE *FromServer, FILE *ToServer)
-{
- static char CANTSEND[] = "Can't send %s to server, %s";
-
- fprintf(ToServer, "ihave %s\r\n", HDR(HDR__MESSAGEID));
- if (FLUSH_ERROR(ToServer)
- || fgets(buff, buffsize, FromServer) == NULL) {
- snprintf(buff, sizeof(buff), CANTSEND, "IHAVE", strerror(errno));
- return -1;
- }
- return atoi(buff);
-}
-
-
-/*
-** Spool article to temp file.
-*/
-static const char *
-SpoolitTo(char *article, char *err, char *SpoolDir)
-{
- static char CANTSPOOL[NNTP_STRLEN+2];
- HEADER *hp;
- FILE *F = NULL;
- int i, fd;
- char *tmpspool = NULL;
- char *spoolfile = NULL;
- char *q;
-
- /* Initialize the returned error message */
- snprintf(CANTSPOOL, sizeof(CANTSPOOL),
- "%s and can't write text to local spool file", err);
-
- /* Try to write it to the spool dir. */
- tmpspool = concatpath(SpoolDir, ".XXXXXX");
- fd = mkstemp(tmpspool);
- if (fd < 0) {
- syslog(L_FATAL, "cant create temporary spool file %s %m", tmpspool);
- goto fail;
- }
- F = fdopen(fd, "w");
- if (F == NULL) {
- syslog(L_FATAL, "cant open %s %m", tmpspool);
- goto fail;
- }
- fchmod(fileno(F), BATCHFILE_MODE);
-
- /* Write the headers and a blank line. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value) {
- q = xstrndup(hp->Value, hp->Body - hp->Value + hp->Len);
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(F, "%s:%s\n", hp->Name, q);
- else
- fprintf(F, "%s: %s\n", hp->Name, q);
- if (FLUSH_ERROR(F)) {
- fclose(F);
- free(q);
- goto fail;
- }
- free(q);
- }
- for (i = 0; i < OtherCount; i++) {
- fprintf(F, "%s\n", OtherHeaders[i]);
- if (FLUSH_ERROR(F)) {
- fclose(F);
- goto fail;
- }
- }
- fprintf(F, "\n");
-
- /* Write the article body */
- i = strlen(article);
- if (fwrite(article, 1, i, F) != (size_t)i) {
- fclose(F);
- goto fail;
- }
-
- /* Flush and catch any errors */
- if (fclose(F))
- goto fail;
-
- /* Rename the spool file to something rnews will pick up. */
- spoolfile = concatpath(SpoolDir, "XXXXXX");
- fd = mkstemp(spoolfile);
- if (fd < 0) {
- syslog(L_FATAL, "cant create spool file %s %m", spoolfile);
- goto fail;
- }
- close(fd);
- if (rename(tmpspool, spoolfile) < 0) {
- syslog(L_FATAL, "cant rename %s %s %m", tmpspool, spoolfile);
- goto fail;
- }
-
- /* Article has been spooled */
- free(tmpspool);
- free(spoolfile);
- return NULL;
-
- fail:
- if (tmpspool != NULL)
- free(tmpspool);
- if (spoolfile != NULL)
- free(spoolfile);
- return CANTSPOOL;
-}
-
-/*
-** Spool article to temp file.
-*/
-static const char *
-Spoolit(char *article, char *err)
-{
- return SpoolitTo(article, err, innconf->pathincoming);
-}
-
-static char *Towire(char *p) {
- char *q, *r, *s;
- int curlen, len = BIG_BUFFER;
-
- for (r = p, q = s = xmalloc(len); *r != '\0' ;) {
- curlen = q - s;
- if (curlen + 3 > len) {
- len += BIG_BUFFER;
- s = xrealloc(s, len);
- q = s + curlen;
- }
- if (*r == '\n') {
- if (r > p) {
- if (*(r - 1) != '\r')
- *q++ = '\r';
- } else {
- /* this should not happen */
- free(s);
- return NULL;
- }
- }
- *q++ = *r++;
- }
- curlen = q - s;
- if (curlen + 1 > len) {
- len++;
- s = xrealloc(s, len);
- q = s + curlen;
- }
- *q = '\0';
- return s;
-}
-
-const char *
-ARTpost(char *article,
- char *idbuff,
- bool ihave,
- bool *permanent)
-{
- static char CANTSEND[] = "Can't send %s to server, %s";
- int i;
- char *p, *q;
- char *next;
- HEADER *hp;
- FILE *ToServer;
- FILE *FromServer;
- char buff[NNTP_STRLEN + 2], frombuf[SMBUF];
- char *modgroup = NULL;
- const char *error;
- char *TrackID;
- char *DirTrackID;
- FILE *ftd;
- char SDir[255];
-
- /* Assume errors are permanent, until we discover otherwise */
- *permanent = true;
-
- /* Set up the other headers list. */
- if (OtherHeaders == NULL) {
- OtherSize = HEADER_DELTA;
- OtherHeaders = xmalloc(OtherSize * sizeof(char *));
- }
-
- /* Basic processing. */
- OtherCount = 0;
- for (hp = Table; hp < ARRAY_END(Table); hp++) {
- hp->Size = strlen(hp->Name);
- hp->Value = hp->Body = NULL;
- }
- if ((article = StripOffHeaders(article)) == NULL)
- return Error;
- for (i = 0, p = article; p; i++, p = next + 1)
- if ((next = strchr(p, '\n')) == NULL)
- break;
- if (PERMaccessconf->checkincludedtext) {
- if ((error = CheckIncludedText(article, i)) != NULL)
- return error;
- }
- if ((error = ProcessHeaders(i, idbuff, ihave)) != NULL)
- return error;
- if (i == 0 && HDR(HDR__CONTROL) == NULL)
- return "Article is empty";
-
- if ((error = ValidNewsgroups(HDR(HDR__NEWSGROUPS), &modgroup)) != NULL)
- return error;
-
- strlcpy(frombuf, HDR(HDR__FROM), sizeof(frombuf));
- for (i = 0, p = frombuf;p < frombuf + sizeof(frombuf);)
- if ((p = strchr(p, '\n')) == NULL)
- break;
- else
- *p++ = ' ';
- HeaderCleanFrom(frombuf);
- p = strchr(frombuf, '@');
- if (p) {
- strlcpy(frombuf, p+1, sizeof(frombuf));
- p = strrchr(frombuf, '.');
- if (!p) {
- if (modgroup)
- free(modgroup);
- return "From: address not in Internet syntax";
- }
- }
- else {
- if (modgroup)
- free(modgroup);
- return "From: address not in Internet syntax";
- }
- if ((p = HDR(HDR__FOLLOWUPTO)) != NULL
- && strcmp(p, "poster") != 0
- && (error = ValidNewsgroups(p, (char **)NULL)) != NULL) {
- if (modgroup)
- free(modgroup);
- return error;
- }
- if ((PERMaccessconf->localmaxartsize > 0) &&
- (strlen(article) > (unsigned)PERMaccessconf->localmaxartsize)) {
- snprintf(Error, sizeof(Error),
- "Article is bigger then local limit of %ld bytes\n",
- PERMaccessconf->localmaxartsize);
- if (modgroup)
- free(modgroup);
- return Error;
- }
-
-#if defined(DO_PERL)
- /* Calls the Perl subroutine for headers management */
- p = PERMaccessconf->nnrpdperlfilter ? HandleHeaders(article) : NULL;
- if (p != NULL) {
- if (idbuff) {
- if (modgroup)
- sprintf(idbuff, "(mailed to moderator for %s)", modgroup);
- else
- strlcpy(idbuff, HDR(HDR__MESSAGEID), SMBUF);
- }
- if (strncmp(p, "DROP", 4) == 0) {
- syslog(L_NOTICE, "%s post %s", ClientHost, p);
- if (modgroup)
- free(modgroup);
- return NULL;
- }
- else if (strncmp(p, "SPOOL", 5) == 0) {
- syslog(L_NOTICE, "%s post %s", ClientHost, p);
- strlcpy(SDir, innconf->pathincoming, sizeof(SDir));
- if (modgroup) {
- free(modgroup);
- strlcat(SDir, "/spam/mod", sizeof(SDir));
- return SpoolitTo(article, p, SDir);
- }
- else {
- strlcat(SDir, "/spam", sizeof(SDir));
- return SpoolitTo(article, p, SDir);
- }
- }
- else
- {
- if (modgroup)
- free(modgroup);
- return p;
- }
- }
-#endif /* defined(DO_PERL) */
-
- /* handle mailing to moderated groups */
-
- if (modgroup) {
- if (idbuff != NULL) {
- const char *retstr;
- retstr = MailArticle(modgroup, article);
- strcpy (idbuff,"(mailed to moderator)") ;
- return retstr;
- }
- return MailArticle(modgroup, article);
- }
-
- if (idbuff)
- strlcpy(idbuff, HDR(HDR__MESSAGEID), SMBUF);
-
- if (PERMaccessconf->spoolfirst)
- return Spoolit(article, Error);
-
- if (Offlinepost)
- return Spoolit(article,Error);
-
- /* Open a local connection to the server. */
- if (PERMaccessconf->nnrpdposthost != NULL)
- i = NNTPconnect(PERMaccessconf->nnrpdposthost, PERMaccessconf->nnrpdpostport,
- &FromServer, &ToServer, buff);
- else {
-#if defined(HAVE_UNIX_DOMAIN_SOCKETS)
- i = NNTPlocalopen(&FromServer, &ToServer, buff);
-#else
- i = NNTPremoteopen(innconf->port, &FromServer,
- &ToServer, buff);
-#endif /* defined(HAVE_UNIX_DOMAIN_SOCKETS) */
- }
-
- /* If we cannot open the connection, initialize the error message and
- * attempt to recover from this by spooling it locally */
- if (i < 0) {
- if (buff[0])
- strlcpy(Error, buff, sizeof(Error));
- else
- snprintf(Error, sizeof(Error), CANTSEND, "connect request",
- strerror(errno));
- return Spoolit(article,Error);
- }
- if (Tracing)
- syslog(L_TRACE, "%s post_connect %s",
- ClientHost, PERMaccessconf->nnrpdposthost ? PERMaccessconf->nnrpdposthost : "localhost");
-
- /* The code below ignores too many return values for my tastes. At least
- * they are all inside cases that are most likely never going to happen --
- * for example, if the server crashes. */
-
- /* Offer article to server. */
- i = OfferArticle(buff, (int)sizeof buff, FromServer, ToServer);
- if (i == NNTP_AUTH_NEEDED_VAL) {
- /* Send authorization. */
- if (NNTPsendpassword(PERMaccessconf->nnrpdposthost, FromServer, ToServer) < 0) {
- snprintf(Error, sizeof(Error), "Can't authorize with %s",
- PERMaccessconf->nnrpdposthost ? PERMaccessconf->nnrpdposthost : "innd");
- return Spoolit(article,Error);
- }
- i = OfferArticle(buff, (int)sizeof buff, FromServer, ToServer);
- }
- if (i != NNTP_SENDIT_VAL) {
- strlcpy(Error, buff, sizeof(Error));
- SendQuit(FromServer, ToServer);
- if (i != NNTP_HAVEIT_VAL)
- return Spoolit(article, Error);
- if (i == NNTP_REJECTIT_VAL || i == NNTP_RESENDIT_VAL) {
- *permanent = false;
- }
- return Error;
- }
- if (Tracing)
- syslog(L_TRACE, "%s post starting", ClientHost);
-
- /* Write the headers and a blank line. */
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value) {
- q = xstrndup(hp->Value, hp->Body - hp->Value + hp->Len);
- if (strchr(q, '\n') != NULL) {
- if ((p = Towire(q)) != NULL) {
- /* there is no white space, if hp->Value and hp->Body is the same */
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(ToServer, "%s:%s\r\n", hp->Name, p);
- else
- fprintf(ToServer, "%s: %s\r\n", hp->Name, p);
- free(p);
- }
- } else {
- /* there is no white space, if hp->Value and hp->Body is the same */
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(ToServer, "%s:%s\r\n", hp->Name, q);
- else
- fprintf(ToServer, "%s: %s\r\n", hp->Name, q);
- }
- free(q);
- }
- for (i = 0; i < OtherCount; i++) {
- if (strchr(OtherHeaders[i], '\n') != NULL) {
- if ((p = Towire(OtherHeaders[i])) != NULL) {
- fprintf(ToServer, "%s\r\n", p);
- free(p);
- }
- } else {
- fprintf(ToServer, "%s\r\n", OtherHeaders[i]);
- }
- }
- fprintf(ToServer, "\r\n");
- if (FLUSH_ERROR(ToServer)) {
- snprintf(Error, sizeof(Error), CANTSEND, "headers", strerror(errno));
- fclose(FromServer);
- fclose(ToServer);
- return Spoolit(article, Error);
- }
-
- /* Send the article, get the server's reply. */
- if (NNTPsendarticle(article, ToServer, true) < 0
- || fgets(buff, sizeof buff, FromServer) == NULL) {
- snprintf(Error, sizeof(Error), CANTSEND, "article", strerror(errno));
- fclose(FromServer);
- fclose(ToServer);
- return Spoolit(article, Error);
- }
-
- /* Did the server want the article? */
- if ((i = atoi(buff)) != NNTP_TOOKIT_VAL) {
- strlcpy(Error, buff, sizeof(Error));
- SendQuit(FromServer, ToServer);
- syslog(L_TRACE, "%s server rejects %s from %s", ClientHost, HDR(HDR__MESSAGEID), HDR(HDR__PATH));
- if (i != NNTP_REJECTIT_VAL && i != NNTP_HAVEIT_VAL)
- return Spoolit(article, Error);
- if (i == NNTP_REJECTIT_VAL || i == NNTP_RESENDIT_VAL) {
- *permanent = false;
- }
- return Error;
- }
-
- /* Send a quit and close down */
- SendQuit(FromServer, ToServer);
-
- /* Tracking */
- if (PERMaccessconf->readertrack) {
- TrackID = concat(innconf->pathlog, "/trackposts/track.",
- HDR(HDR__MESSAGEID), (char *) 0);
- if ((ftd = fopen(TrackID,"w")) == NULL) {
- DirTrackID = concatpath(innconf->pathlog, "trackposts");
- MakeDirectory(DirTrackID, false);
- free(DirTrackID);
- }
- if (ftd == NULL && (ftd = fopen(TrackID,"w")) == NULL) {
- syslog(L_ERROR, "%s (%s) open %s: %m",
- ClientHost, Username, TrackID);
- free(TrackID);
- return NULL;
- }
- for (hp = Table; hp < ARRAY_END(Table); hp++)
- if (hp->Value) {
- q = xstrndup(hp->Value, hp->Body - hp->Value + hp->Len);
- if (strchr(q, '\n') != NULL) {
- if ((p = Towire(q)) != NULL) {
- /* there is no white space, if hp->Value and hp->Body is the same */
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(ftd, "%s:%s\r\n", hp->Name, p);
- else
- fprintf(ftd, "%s: %s\r\n", hp->Name, p);
- free(p);
- }
- } else {
- /* there is no white space, if hp->Value and hp->Body is the same */
- if (*hp->Value == ' ' || *hp->Value == '\t')
- fprintf(ftd, "%s:%s\r\n", hp->Name, q);
- else
- fprintf(ftd, "%s: %s\r\n", hp->Name, q);
- }
- free(q);
- }
- for (i = 0 ; i < OtherCount ; i++) {
- if (strchr(OtherHeaders[i], '\n') != NULL) {
- if ((p = Towire(OtherHeaders[i])) != NULL) {
- fprintf(ftd, "%s\r\n", p);
- free(p);
- }
- } else {
- fprintf(ftd, "%s\r\n", OtherHeaders[i]);
- }
- }
- fprintf(ftd,"\r\n");
- NNTPsendarticle(article, ftd, true);
- if (fclose(ftd) != EOF) {
- syslog(L_NOTICE, "%s (%s) posttrack ok %s",
- ClientHost, Username, TrackID);
- if (LLOGenable)
- fprintf(locallog, "%s (%s) posttrack ok %s\n",
- ClientHost, Username, TrackID);
- } else {
- syslog(L_ERROR, "%s (%s) posttrack error 2 %s",
- ClientHost, Username, TrackID);
- }
- free(TrackID);
- }
-
- return NULL;
-}
+++ /dev/null
-/* $Id: post.h 6474 2003-09-15 07:32:56Z rra $
-**
-** Net News Reading Protocol server.
-*/
-
-typedef enum _HEADERTYPE {
- HTobs,
- HTreq,
- HTstd
-} HEADERTYPE;
-
-typedef struct _HEADER {
- const char * Name;
- bool CanSet;
- HEADERTYPE Type;
- int Size;
- char * Value; /* just after ':' in header */
- char * Body; /* where actual body begins */
- int Len; /* body length excluding trailing white spaces */
-} HEADER;
-
-#define HDR(_x) (Table[(_x)].Body)
-#define HDR_SET(_x, _y) do { \
- Table[(_x)].Body = Table[(_x)].Value = _y; \
- if (_y == NULL) { \
- Table[(_x)].Len = 0; \
- } else { \
- Table[(_x)].Len = strlen(_y); \
- } \
-} while (0)
-
-#define HDR__PATH 0
-#define HDR__FROM 1
-#define HDR__NEWSGROUPS 2
-#define HDR__SUBJECT 3
-#define HDR__CONTROL 4
-#define HDR__FOLLOWUPTO 6
-#define HDR__DATE 7
-#define HDR__ORGANIZATION 8
-#define HDR__LINES 9
-#define HDR__SENDER 10
-#define HDR__APPROVED 11
-#define HDR__DISTRIBUTION 12
-#define HDR__EXPIRES 13
-#define HDR__MESSAGEID 14
-#define HDR__NNTPPOSTINGHOST 17
-#define HDR__XTRACE 21
-#define HDR__XCOMPLAINTSTO 22
-#define HDR__NNTPPOSTINGDATE 23
-#define HDR__CC 33
-#define HDR__BCC 34
-#define HDR__TO 35
+++ /dev/null
-/* $Id: python.c 7893 2008-06-22 10:24:42Z iulius $
-**
-** python.c: Embed Python in the style of nnrpd's TCL and Perl stuff
-** (authentication and authorization hooks only at this point).
-**
-** Written by Ilya Etingof <ilya@glas.net>, 1999.
-**
-** This code bases on Python work for innd filtering done by
-** G.J. Andruk <meowing@banet.net>. Also it borrows some ideas from
-** TCL/Perl work done by Bob Heiney and Christophe Wolfhugel.
-**
-** A quick note regarding Python exceptions: functions like
-** PyObject_GetAttrString(PyObject *o, const char *attr_name)
-** raise an exception when they fail, even though they return NULL.
-** And as exceptions accumulate from caller to caller and so on,
-** it generates weird issues with Python scripts afterwards. So such
-** uses should be checked before. For instance with:
-** PyObject_HasAttrString(PyObject *o, const char *attr_name).
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "inn/hashtab.h"
-
-#if defined(DO_PYTHON)
-
-#include "Python.h"
-
-/* values relate name of hook to array index */
-#define PYTHONauthen 1
-#define PYTHONaccess 2
-#define PYTHONdynamic 3
-
-#define PYTHONtypes_max 4
-
-/* values relate type of method to array index */
-#define PYTHONmain 1
-#define PYTHONinit 2
-#define PYTHONclose 3
-
-#define PYTHONmethods_max 4
-
-/* key names for attributes dictionary */
-#define PYTHONhostname "hostname"
-#define PYTHONipaddress "ipaddress"
-#define PYTHONport "port"
-#define PYTHONinterface "interface"
-#define PYTHONintipaddr "intipaddr"
-#define PYTHONintport "intport"
-#define PYTHONuser "user"
-#define PYTHONpass "pass"
-#define PYTHONtype "type"
-#define PYTHONnewsgroup "newsgroup"
-
-/* Max number of items in dictionary to pass to auth methods */
-#define _PY_MAX_AUTH_ITEM 10
-
-
-/* Pointers to external Python objects */
-PyObject *PYAuthObject = NULL;
-
-/* Dictionary of params to pass to authentication methods */
-PyObject *PYauthinfo = NULL;
-PyObject **PYauthitem = NULL;
-
-/* Forward declaration */
-static PyObject *PY_set_auth_hook(PyObject *dummy, PyObject *args);
-void PY_load_python(void);
-PyObject* PY_setup(int type, int method, char *file);
-static const void *file_key(const void *p);
-static bool file_equal(const void *k, const void *p);
-static void file_free(void *p);
-static void file_trav(void *data, void* null);
-
-bool PythonLoaded = false;
-
-/* structure for storage of attributes for a module file */
-typedef struct PyFile {
- char *file;
- bool loaded[PYTHONtypes_max];
- PyObject *procs[PYTHONtypes_max][PYTHONmethods_max];
-} PyFile;
-
-/* hash for storing files */
-struct hash *files;
-
-/* for passing the dynamic module filename from perm.c */
-char* dynamic_file;
-
-/*
-** Authenticate connecting host by username&password.
-**
-** Return NNTP reply code as returned by Python method or -1 if method
-** is not defined.
-*/
-int PY_authenticate(char* file, char *Username, char *Password, char *errorstring, char *newUser) {
- PyObject *result, *item, *proc;
- int authnum;
- int code, i;
- char *temp;
-
- PY_load_python();
- proc = PY_setup(PYTHONauthen, PYTHONmain, file);
-
- /* Return if authentication method is not defined */
- if (proc == NULL)
- return -1;
-
- /* Initialize PythonAuthObject with connect method specific items */
- authnum = 0;
-
- /* Client hostname */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientHost, strlen(ClientHost));
- PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
-
- /* Client IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientIpString, strlen(ClientIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
-
- /* Client port number */
- PYauthitem[authnum] = PyInt_FromLong(ClientPort);
- PyDict_SetItemString(PYauthinfo, PYTHONport, PYauthitem[authnum++]);
-
- /* Server interface the connection comes to */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerHost, strlen(ServerHost));
- PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
-
- /* Server IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerIpString, strlen(ServerIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONintipaddr, PYauthitem[authnum++]);
-
- /* Server port number */
- PYauthitem[authnum] = PyInt_FromLong(ServerPort);
- PyDict_SetItemString(PYauthinfo, PYTHONintport, PYauthitem[authnum++]);
-
- /* Username if known */
- if (Username == NULL) {
- PYauthitem[authnum] = Py_None;
- } else {
- PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
- }
- PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
-
- /* Password if known */
- if (Password == NULL) {
- PYauthitem[authnum] = Py_None;
- } else {
- PYauthitem[authnum] = PyBuffer_FromMemory(Password, strlen(Password));
- }
- PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
-
- /* Now invoke authenticate method and see if it likes this user */
- result = PyObject_CallFunction(proc, "O", PYauthinfo);
-
- /* Check the response */
- if (result == NULL || !PyTuple_Check(result)
- || ((PyTuple_Size(result) != 2) && (PyTuple_Size(result) != 3)))
- {
- syslog(L_ERROR, "python authenticate method returned wrong result");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* Get the NNTP response code */
- item = PyTuple_GetItem(result, 0);
-
- /* Check the item */
- if (!PyInt_Check(item))
- {
- syslog(L_ERROR, "python authenticate method returned bad NNTP response code");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* Store the code */
- code = PyInt_AS_LONG(item);
-
- /* Get the error string */
- item = PyTuple_GetItem(result, 1);
-
- /* Check the item */
- if (!PyString_Check(item))
- {
- syslog(L_ERROR, "python authenticate method returned bad error string");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* Store error string */
- temp = PyString_AS_STRING(item);
- errorstring = xstrdup(temp);
-
- if (PyTuple_Size(result) == 3) {
-
- /* Get the username string */
- item = PyTuple_GetItem(result, 2);
-
- /* Check the item */
- if (!PyString_Check(item)) {
- syslog(L_ERROR, "python authenticate method returned bad username string");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* Store error string */
- temp = PyString_AS_STRING(item);
- newUser = xstrdup(temp);
- }
-
- /* Clean up the dictionary object */
- PyDict_Clear(PYauthinfo);
-
- /* Clean up dictionary items */
- for (i = 0; i < authnum; i++) {
- if (PYauthitem[i] != Py_None) {
- Py_DECREF(PYauthitem[i]);
- }
- }
-
- /* Log auth result */
- syslog(L_NOTICE, "python authenticate method succeeded, return code %d, error string %s", code, errorstring);
-
- /* Return response code */
- return code;
-}
-
-/*
-** Create an access group based on the values returned by the script in file
-**
-*/
-void PY_access(char* file, struct vector *access_vec, char *Username) {
- PyObject *result, *key, *value, *proc;
- char *buffer;
- int authnum;
- int i;
-
- PY_load_python();
- proc = PY_setup(PYTHONaccess, PYTHONmain, file);
-
- /* Exit if access method is not defined */
- if (proc == NULL) {
- syslog(L_ERROR, "python access method not defined");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* Initialize PythonAuthObject with group method specific items */
- authnum = 0;
-
- /* Client hostname */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientHost, strlen(ClientHost));
- PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
-
- /* Client IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientIpString, strlen(ClientIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
-
- /* Client port number */
- PYauthitem[authnum] = PyInt_FromLong(ClientPort);
- PyDict_SetItemString(PYauthinfo, PYTHONport, PYauthitem[authnum++]);
-
- /* Server interface the connection comes to */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerHost, strlen(ServerHost));
- PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
-
- /* Server IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerIpString, strlen(ServerIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONintipaddr, PYauthitem[authnum++]);
-
- /* Server port number */
- PYauthitem[authnum] = PyInt_FromLong(ServerPort);
- PyDict_SetItemString(PYauthinfo, PYTHONintport, PYauthitem[authnum++]);
-
- /* Username */
- PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
- PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
-
- /* Password is not known */
- PYauthitem[authnum] = Py_None;
- PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
-
- /*
- * Now invoke newsgroup access method
- */
- result = PyObject_CallFunction(proc, "O", PYauthinfo);
-
- /* Check the response */
- if (result == NULL || result == Py_None || !PyDict_Check(result)) {
- syslog(L_ERROR, "python access method returned wrong result -- expected a dictionary");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, true);
- }
-
- /* resize vector to dictionary length */
- vector_resize(access_vec, PyDict_Size(result) - 1);
-
- /* store dict values in proper format in access vector */
- i = 0;
- buffer = xmalloc(BIG_BUFFER);
-
- while(PyDict_Next(result, &i, &key, &value)) {
- if (!PyString_Check(key)) {
- syslog(L_ERROR, "python access method return dictionary key %i not a string", i);
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
- if (!PyString_Check(value)) {
- syslog(L_ERROR, "python access method return dictionary value %i not a string", i);
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
-
- strlcpy(buffer, PyString_AsString(key), BIG_BUFFER);
- strlcat(buffer, ": \"", BIG_BUFFER);
- strlcat(buffer, PyString_AsString(value), BIG_BUFFER);
- strlcat(buffer, "\"\n", BIG_BUFFER);
-
- vector_add(access_vec, xstrdup(buffer));
- }
-
- free(buffer);
-
- /* Clean up the dictionary object */
- PyDict_Clear(PYauthinfo);
- /* Clean up dictionary items */
- for (i = 0; i < authnum; i++) {
- if (PYauthitem[i] != Py_None) {
- Py_DECREF(PYauthitem[i]);
- }
- }
-
- /* Log auth result */
- syslog(L_NOTICE, "python access method succeeded");
-}
-
-/*
-** Initialize dynamic access control code
-*/
-
-void PY_dynamic_init (char* file) {
- dynamic_file = xstrdup(file);
- PY_use_dynamic = true;
-}
-
-
-/*
-** Determine dynamic user access rights to a given newsgroup.
-**
-** Return 0 if requested privelege is granted or positive value
-** and a reply_message pointer initialized with reply message.
-** Return negative value if dynamic method is not defined.
-*/
-int PY_dynamic(char *Username, char *NewsGroup, int PostFlag, char **reply_message) {
- PyObject *result, *item, *proc;
- char *string, *temp;
- int authnum;
- int i;
-
- PY_load_python();
- proc = PY_setup(PYTHONdynamic, PYTHONmain, dynamic_file);
-
- /* Return if dynamic method is not defined */
- if (proc == NULL)
- return -1;
-
- /* Initialize PythonAuthObject with group method specific items */
- authnum = 0;
-
- /* Client hostname */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientHost, strlen(ClientHost));
- PyDict_SetItemString(PYauthinfo, PYTHONhostname, PYauthitem[authnum++]);
-
- /* Client IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ClientIpString, strlen(ClientIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONipaddress, PYauthitem[authnum++]);
-
- /* Client port number */
- PYauthitem[authnum] = PyInt_FromLong(ClientPort);
- PyDict_SetItemString(PYauthinfo, PYTHONport, PYauthitem[authnum++]);
-
- /* Server interface the connection comes to */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerHost, strlen(ServerHost));
- PyDict_SetItemString(PYauthinfo, PYTHONinterface, PYauthitem[authnum++]);
-
- /* Server IP number */
- PYauthitem[authnum] = PyBuffer_FromMemory(ServerIpString, strlen(ServerIpString));
- PyDict_SetItemString(PYauthinfo, PYTHONintipaddr, PYauthitem[authnum++]);
-
- /* Server port number */
- PYauthitem[authnum] = PyInt_FromLong(ServerPort);
- PyDict_SetItemString(PYauthinfo, PYTHONintport, PYauthitem[authnum++]);
-
- /* Username */
- PYauthitem[authnum] = PyBuffer_FromMemory(Username, strlen(Username));
- PyDict_SetItemString(PYauthinfo, PYTHONuser, PYauthitem[authnum++]);
-
- /* Password is not known */
- PYauthitem[authnum] = Py_None;
- PyDict_SetItemString(PYauthinfo, PYTHONpass, PYauthitem[authnum++]);
-
- /* Assign authentication type */
- PYauthitem[authnum] = PyBuffer_FromMemory(PostFlag ? "post" : "read", 4);
- PyDict_SetItemString(PYauthinfo, PYTHONtype, PYauthitem[authnum++]);
-
- /* Newsgroup user tries to access */
- PYauthitem[authnum] = PyBuffer_FromMemory(NewsGroup, strlen(NewsGroup));
- PyDict_SetItemString(PYauthinfo, PYTHONnewsgroup, PYauthitem[authnum++]);
-
- /*
- * Now invoke newsgroup dynamic access method and see if
- * it likes this user to access this newsgroup.
- */
- result = PyObject_CallFunction(proc, "O", PYauthinfo);
-
- /* Check the response */
- if (result == NULL || (result != Py_None && !PyString_Check(result)))
- {
- syslog(L_ERROR, "python dynamic method (%s access) returned wrong result: %s", PostFlag ? "post" : "read", result);
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- ExitWithStats(1, false);
- }
-
- /* Get the response string */
- if (result == Py_None) {
- string = NULL;
- } else {
- temp = PyString_AS_STRING(result);
- string = xstrdup(temp);
- }
- /* Clean up the dictionary object */
- PyDict_Clear(PYauthinfo);
-
- /* Clean up dictionary items */
- for (i = 0; i < authnum; i++) {
- if (PYauthitem[i] != Py_None) {
- Py_DECREF(PYauthitem[i]);
- }
- }
-
- /* Log auth result */
- syslog(L_NOTICE, "python dynamic method (%s access) succeeded, refusion string: %s", PostFlag ? "post" : "read", string == NULL ? "<empty>" : string);
-
- /* Initialize reply string */
- if (reply_message != NULL)
- *reply_message = string;
-
- /* Return result */
- return string == NULL ? 0 : 1;
-}
-
-
-/*
-** This runs when nnrpd shuts down. If Python is closed and reopened
-** in the same process, files and dynamic_file are reused so they
-** must point to NULL.
-*/
-void
-PY_close_python(void)
-{
- if (files != NULL) {
- hash_traverse(files, file_trav, NULL);
- hash_free(files);
- files = NULL;
- }
- if (dynamic_file != NULL) {
- free(dynamic_file);
- dynamic_file = NULL;
- }
-}
-
-/*
-** Traversal function for PY_close_python
-*/
-void
-file_trav(void *data, void* null UNUSED)
-{
- PyFile *fp = data;
- int j;
- PyObject *result, *func;
-
- for (j = 1; j < PYTHONtypes_max; j++) {
- if (fp->loaded[j] != false) {
- func = fp->procs[j][PYTHONclose];
- if (func != NULL) {
- result = PyObject_CallFunction(func, NULL);
- Py_XDECREF(result);
- }
- }
- }
-}
-
-/*
-** Python's syslog module isn't compiled in by default. It's easier
-** to do it this way, and the switch block looks pretty in a color
-** editor).
-*/
-static PyObject *
-PY_syslog(PyObject *self UNUSED, PyObject *args)
-{
- char *loglevel;
- int levellen;
- char *logmsg;
- int msglen;
- int priority;
-
- /* Get loglevel and message */
- if (!PyArg_ParseTuple(args, "s#s#", &loglevel, &levellen, &logmsg, &msglen))
- return NULL;
-
- /* Assign syslog priority by abbreviated names */
- switch (*loglevel) {
- default: priority = LOG_NOTICE ;
- case 'd': case 'D': priority = LOG_DEBUG ; break;
- case 'i': case 'I': priority = LOG_INFO ; break;
- case 'n': case 'N': priority = LOG_NOTICE ; break;
- case 'w': case 'W': priority = LOG_WARNING ; break;
- case 'e': case 'E': priority = LOG_ERR ; break;
- case 'c': case 'C': priority = LOG_CRIT ; break;
- case 'a': case 'A': priority = LOG_ALERT ; break;
- }
-
- /* Log the message */
- syslog(priority, "python: %s", logmsg);
-
- /* Return None */
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-
-/*
-** Make the internal nnrpd module's functions visible to Python.
-*/
-static PyMethodDef nnrpdPyMethods[] = {
- {"set_auth_hook", PY_set_auth_hook, METH_VARARGS},
- {"syslog", PY_syslog, METH_VARARGS},
- {NULL, NULL}
-};
-
-
-/*
-** Called by the external module so it can register itself with nnrpd.
-*/
-static PyObject *
-PY_set_auth_hook(PyObject *dummy UNUSED, PyObject *args)
-{
- PyObject *result = NULL;
- PyObject *temp;
-
- /* set_auth_hook method should return a pointer to nnrpd auth object */
- if (PyArg_ParseTuple(args, "O:set_auth_hook", &temp)) {
- Py_XINCREF(temp);
- Py_XDECREF(PYAuthObject);
- PYAuthObject = temp;
- Py_INCREF(Py_None);
- result = Py_None;
- }
-
- /* Return a pointer to nnrpd auth method */
- return result;
-}
-
-/*
-** Load the Python interpreter
-*/
-void PY_load_python() {
- if (!PythonLoaded) {
- /* add path for nnrpd module */
- setenv("PYTHONPATH", innconf->pathfilter, 1);
-
- /* Load up the interpreter ;-O */
- Py_Initialize();
-
- /* It makes Python sad when its stdout and stderr are closed. */
- if ((fileno(stdout) == -1) || (fileno(stderr) == -1))
- PyRun_SimpleString("import sys; sys.stdout=sys.stderr=open('/dev/null', 'a')");
-
- /* See if Python initialized OK */
- if (!Py_IsInitialized ()) {
- syslog(L_ERROR, "python interpreter NOT initialized");
- return;
- }
-
-
- /* Build a module interface to certain nnrpd functions */
- (void) Py_InitModule("nnrpd", nnrpdPyMethods);
-
- /*
- ** Grab space for authinfo dictionary so we aren't forever
- ** recreating them.
- */
- PYauthinfo = PyDict_New();
- PYauthitem = xcalloc(_PY_MAX_AUTH_ITEM, sizeof(PyObject *));
-
- /* create hash to store file attributes */
-
- files = hash_create(4, hash_string, file_key,
- file_equal, file_free);
-
- PythonLoaded = true;
-
- syslog(L_NOTICE, "python interpreter initialized OK");
- }
-}
-
-/*
-** Check that a method exists and is callable. Set up a pointer to
-** the corresponding PyObject, or NULL if not found.
-*/
-void
-PYdefonemethod(PyFile *fp, int type, int method, char *methname, int realtype) {
- PyObject **methptr;
-
- methptr = &fp->procs[type][method];
- /* There is no need to check the existence of methods useless for our realtype. */
- if (type == realtype) {
- /*
- ** We check with HasAttrString() the existence of the method because
- ** otherwise, in case it does not exist, an exception is raised by Python,
- ** although the result of the function is NULL.
- */
- if (PyObject_HasAttrString(PYAuthObject, (char *) methname) == 1) {
- /* Get a pointer to given method. */
- *methptr = PyObject_GetAttrString(PYAuthObject, (char *) methname);
- } else {
- *methptr = NULL;
- }
-
- /* See if such method is defined */
- if (*methptr == NULL)
- syslog(L_NOTICE, "python method %s not found", methname);
- else {
- /* See if it is callable */
- if (PyCallable_Check(*methptr) == 0) {
- syslog(L_ERROR, "python object %s found but not a function", methname);
- Py_DECREF(*methptr);
- *methptr = NULL;
- }
- }
- } else {
- *methptr = NULL;
- }
-}
-
-
-/*
-** Look up all the known python methods and set up
-** pointers to them so that we could call them from nnrpd.
-*/
-void
-PYdefmethods(PyFile *fp, int realtype)
-{
- /* Get a reference to authenticate() method */
- PYdefonemethod(fp, PYTHONauthen, PYTHONmain, "authenticate", realtype);
-
- /* Get a reference to authen_init() method */
- PYdefonemethod(fp, PYTHONauthen, PYTHONinit, "authen_init", realtype);
-
- /* Get a reference to authen_close() method */
- PYdefonemethod(fp, PYTHONauthen, PYTHONclose, "authen_close", realtype);
-
- /* Get a reference to access() method */
- PYdefonemethod(fp, PYTHONaccess, PYTHONmain, "access", realtype);
-
- /* Get a reference to access_init() method */
- PYdefonemethod(fp, PYTHONaccess, PYTHONinit, "access_init", realtype);
-
- /* Get a reference to access_close() method */
- PYdefonemethod(fp, PYTHONaccess, PYTHONclose, "access_close", realtype);
-
- /* Get a reference to dynamic() method */
- PYdefonemethod(fp, PYTHONdynamic, PYTHONmain, "dynamic", realtype);
-
- /* Get a reference to dynamic_init() method */
- PYdefonemethod(fp, PYTHONdynamic, PYTHONinit, "dynamic_init", realtype);
-
- /* Get a reference to dynamic_close() method */
- PYdefonemethod(fp, PYTHONdynamic, PYTHONclose, "dynamic_close", realtype);
-}
-
-
-/*
-** Called when a python hook is needed -- this gets the scripts hooked in.
-*/
-PyObject*
-PY_setup(int type, int method, char *file)
-{
- int i;
- PyFile *fp;
- PyObject *result;
-
- /* check to see if this file is in files */
- if (!(hash_lookup(files, file))) {
- fp = xmalloc(sizeof(PyFile));
- fp->file = xstrdup(file);
-
- for (i = 1; i < PYTHONtypes_max; i++) {
- fp->loaded[i] = false;
- }
-
- /* Load up external module */
- (void) PyImport_ImportModule(file);
-
- /* See if nnrpd auth object is defined in auth module */
- if (PYAuthObject == NULL) {
- syslog(L_ERROR, "python auth object is not defined");
- Reply("%d Internal Error (7). Goodbye\r\n", NNTP_ACCESS_VAL);
- PY_close_python();
- ExitWithStats(1, false);
- } else {
- /* Set up pointers to known Python methods */
- PYdefmethods(fp, type);
- }
- hash_insert(files, file, fp);
-
- if ((!fp->loaded[type]) && (fp->procs[type][PYTHONinit] != NULL)) {
- result = PyObject_CallFunction(fp->procs[type][PYTHONinit], NULL);
- if (result != NULL) {
- Py_XDECREF(result);
- }
- fp->loaded[type] = true;
- }
- return fp->procs[type][method];
- }
- return NULL;
-}
-
-/*
-** Return the key (filename) from a file struct, used by the hash table.
-*/
-static const void *
-file_key(const void *p)
-{
- const struct PyFile *f = p;
-
- return f->file;
-}
-
-/*
-** Check to see if a provided key matches the key of a PyFile struct,
-** used by the hash table.
-*/
-static bool
-file_equal(const void *k, const void *p)
-{
- const char *key = k;
- const struct PyFile *f = p;
-
- return strcmp(key, f->file) == 0;
-}
-
-/*
-** Free a file, used by the hash table.
-*/
-static void
-file_free(void *p)
-{
- struct PyFile *fp = p;
- int i, j;
-
- free(fp->file);
-
- for (i = 1; i < PYTHONtypes_max; i++) {
- for (j = 1; j < PYTHONmethods_max; j++) {
- if (fp->procs[i][j] != NULL) {
- Py_DECREF(fp->procs[i][j]);
- }
- }
- }
-
- free(fp);
-}
-
-#endif /* defined(DO_PYTHON) */
+++ /dev/null
-/* sasl_config.c -- Configuration routines
- Copyright (C) 2000 Kenichi Okada <okada@opaopa.org>
-
- Author: Kenichi Okada <okada@opaopa.org>
- Created: 2000-03-04
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-#include "paths.h"
-#include "sasl_config.h"
-
-#ifdef HAVE_SSL
-
-struct configlist {
- char *key;
- char *value;
-};
-
-static struct configlist *configlist;
-static int nconfiglist;
-
-const char *sasl_config_getstring(key, def)
-const char *key;
-const char *def;
-{
- int opt;
-
- for (opt = 0; opt < nconfiglist; opt++) {
- if (*key == configlist[opt].key[0] &&
- !strcmp(key, configlist[opt].key))
- return configlist[opt].value;
- }
- return def;
-}
-
-int sasl_config_getint(key, def)
-const char *key;
-int def;
-{
- const char *val = sasl_config_getstring(key, (char *)0);
-
- if (!val) return def;
- if (!isdigit(*val) && (*val != '-' || !isdigit(val[1]))) return def;
- return atoi(val);
-}
-
-int sasl_config_getswitch(key, def)
-const char *key;
-int def;
-{
- const char *val = sasl_config_getstring(key, (char *)0);
-
- if (!val) return def;
-
- if (*val == '0' || *val == 'n' ||
- (*val == 'o' && val[1] == 'f') || *val == 'f') {
- return 0;
- }
- else if (*val == '1' || *val == 'y' ||
- (*val == 'o' && val[1] == 'n') || *val == 't') {
- return 1;
- }
- return def;
-}
-
-const char *sasl_config_partitiondir(partition)
-const char *partition;
-{
- char buf[80];
-
- if (strlen(partition) > 70) return 0;
- snprintf(buf, sizeof(buf), "partition-%s", partition);
-
- return sasl_config_getstring(buf, (char *)0);
-}
-
-#define CONFIGLISTGROWSIZE 10 /* 100 */
-void
-sasl_config_read()
-{
- FILE *infile;
- int lineno = 0;
- int alloced = 0;
- char buf[4096];
- char *p, *key;
- static char *SASL_CONFIG = NULL;
-
- if (!SASL_CONFIG)
- SASL_CONFIG = concatpath(innconf->pathetc, _PATH_SASL_CONFIG);
- infile = fopen(SASL_CONFIG, "r");
- if (!infile) {
- fprintf(stderr, "can't open configuration file %s\n", SASL_CONFIG);
- exit(1);
- }
-
- while (fgets(buf, sizeof(buf), infile)) {
- lineno++;
-
- if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
- for (p = buf; *p && isspace(*p); p++);
- if (!*p || *p == '#') continue;
-
- key = p;
- while (*p && (isalnum(*p) || *p == '-' || *p == '_')) {
- if (isupper(*p)) *p = tolower(*p);
- p++;
- }
- if (*p != ':') {
- fprintf(stderr,
- "invalid option name on line %d of configuration file\n",
- lineno);
- exit(1);
- }
- *p++ = '\0';
-
- while (*p && isspace(*p)) p++;
-
- if (!*p) {
- fprintf(stderr, "empty option value on line %d of configuration file\n",
- lineno);
- exit(1);
- }
-
- if (nconfiglist == alloced) {
- alloced += CONFIGLISTGROWSIZE;
- configlist = xrealloc(configlist, alloced * sizeof(struct configlist));
- }
-
- configlist[nconfiglist].key = xstrdup(key);
- configlist[nconfiglist].value = xstrdup(p);
- nconfiglist++;
- }
- fclose(infile);
-}
-
-#endif /* HAVE_SSL */
+++ /dev/null
-/* sasl_config.h
- Copyright (C) 2000 Kenichi Okada <okada@opaopa.org>
-
- Author: Kenichi Okada <okada@opaopa.org>
- Created: 2000-03-04
-*/
-
-#ifndef SASL_CONFIG_H
-#define SASL_CONFIG_H
-
-#ifndef P
-#ifdef __STDC__
-#define P(x) x
-#else
-#define P(x) ()
-#endif
-#endif
-
-extern void sasl_config_read P((void));
-extern const char *sasl_config_getstring P((const char *key, const char *def));
-extern int sasl_config_getint P((const char *key, int def));
-extern int sasl_config_getswitch P((const char *key, int def));
-extern const char *sasl_config_partitiondir P((const char *partition));
-
-#endif /* SASL_SASL_CONFIG_H */
+++ /dev/null
-/* tls.c --- TLSv1 functions
- Copyright (C) 2000 Kenichi Okada <okada@opaopa.org>
-
- Author: Kenichi Okada <okada@opaopa.org>
- Created: 2000-02-22
-
- Keywords: TLS, OpenSSL
-
- Commentary:
-
- [RFC 2246] "The TLS Protocol Version 1.0"
- by Christopher Allen <callen@certicom.com> and
- Tim Dierks <tdierks@certicom.com> (1999/01)
-
- [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
- by Chris Newman <chris.newman@innosoft.com> (1999/06)
-
-*/
-
-#include <sys/types.h>
-#include "config.h"
-#include "nnrpd.h"
-
-#ifdef HAVE_SSL
-
-/* System library. */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#endif
-
-/* outside the ifdef so `make depend` works even ifndef HAVE_SSL */
-#include "tls.h"
-#include "sasl_config.h"
-
-#ifdef HAVE_SSL
-
-/* We must keep some of the info available */
-static const char hexcodes[] = "0123456789ABCDEF";
-
-static bool tls_initialized = false;
-
-static int verify_depth;
-static int verify_error = X509_V_OK;
-static int do_dump = 0;
-static SSL_CTX *CTX = NULL;
-SSL *tls_conn = NULL;
-
-#define CCERT_BUFSIZ 256
-
-int tls_serverengine = 0;
-int tls_serveractive = 0; /* available or not */
-char *tls_peer_subject = NULL;
-char *tls_peer_issuer = NULL;
-char *tls_peer_fingerprint = NULL;
-
-int tls_clientactive = 0; /* available or not */
-char *tls_peer_CN = NULL;
-char *tls_issuer_CN = NULL;
-
-const char *tls_protocol = NULL;
-const char *tls_cipher_name = NULL;
-int tls_cipher_usebits = 0;
-int tls_cipher_algbits = 0;
-
-
-int tls_loglevel = 0;
-
-
-/* taken from OpenSSL apps/s_cb.c
- * tim - this seems to just be giving logging messages
- */
-
-static void apps_ssl_info_callback(SSL * s, int where, int ret)
-{
- const char *str;
- int w;
-
- if (tls_loglevel==0) return;
-
- w = where & ~SSL_ST_MASK;
-
- if (w & SSL_ST_CONNECT)
- str = "SSL_connect";
- else if (w & SSL_ST_ACCEPT)
- str = "SSL_accept";
- else
- str = "undefined";
-
- if (where & SSL_CB_LOOP) {
- if (tls_serverengine && (tls_loglevel >= 2))
- Printf("%s:%s", str, SSL_state_string_long(s));
- } else if (where & SSL_CB_ALERT) {
- str = (where & SSL_CB_READ) ? "read" : "write";
- if ((tls_serverengine && (tls_loglevel >= 2)) ||
- ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY))
- Printf("SSL3 alert %s:%s:%s", str,
- SSL_alert_type_string_long(ret),
- SSL_alert_desc_string_long(ret));
- } else if (where & SSL_CB_EXIT) {
- if (ret == 0)
- Printf("%s:failed in %s",
- str, SSL_state_string_long(s));
- else if (ret < 0) {
- Printf("%s:error in %s",
- str, SSL_state_string_long(s));
- }
- }
-}
-
-
-/*
- * Hardcoded DH parameter files, from OpenSSL.
- * For information on how these files were generated, see
- * "Assigned Number for SKIP Protocols"
- * (http://www.skip-vpn.org/spec/numbers.html.
- */
-static const char file_dh512[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh1024[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
-jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
-ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh2048[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
-89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\
-T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\
-zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\
-Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
-CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh4096[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
-l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
-Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
-Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
-VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
-alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
-sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
-ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
-OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
-AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
-KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
------END DH PARAMETERS-----\n";
-
-/*
- * Load hardcoded DH parameters.
- */
-static DH *
-load_dh_buffer (const char *buffer, size_t len)
-{
- BIO *bio;
- DH *dh = NULL;
-
- bio = BIO_new_mem_buf((char *) buffer, len);
- if (bio == NULL)
- return NULL;
- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-/* if (dh == NULL) log error */
- BIO_free(bio);
-
- return dh;
-}
-
-/*
- * Generate empheral DH key. Because this can take a long
- * time to compute, we use precomputed parameters of the
- * common key sizes.
- *
- * These values can be static (once loaded or computed) since
- * the OpenSSL library can effectively generate random keys
- * from the information provided.
- *
- * EDH keying is slightly less efficient than static RSA keying,
- * but it offers Perfect Forward Secrecy (PFS).
- *
- * FIXME: support user-specified files, to eliminate risk of
- * "small group" attacks.
- */
-static DH *tmp_dh_cb(SSL *s UNUSED, int export UNUSED, int keylength)
-{
- DH *r = NULL;
- static DH *dh = NULL;
- static DH *dh512 = NULL;
- static DH *dh1024 = NULL;
- static DH *dh2048 = NULL;
- static DH *dh4096 = NULL;
-
- switch (keylength)
- {
- case 512:
- if (dh512 == NULL)
- dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);
- r = dh512;
- break;
- case 1024:
- if (dh1024 == NULL)
- dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);
- r = dh1024;
- break;
- case 2048:
- if (dh2048 == NULL)
- dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);
- r = dh2048;
- break;
- case 4096:
- if (dh4096 == NULL)
- dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);
- r = dh4096;
- break;
- default:
- /* we should check current keylength vs. requested keylength */
- /* also, this is an extremely expensive operation! */
- dh = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);
- r = dh;
- }
-
- return r;
-}
-
-/* taken from OpenSSL apps/s_cb.c */
-
-static int verify_callback(int ok, X509_STORE_CTX * ctx)
-{
- char buf[256];
- X509 *err_cert;
- int err;
- int depth;
-
- syslog(L_NOTICE,"Doing a peer verify");
-
- err_cert = X509_STORE_CTX_get_current_cert(ctx);
- err = X509_STORE_CTX_get_error(ctx);
- depth = X509_STORE_CTX_get_error_depth(ctx);
-
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
- if ((tls_serveractive) && (tls_loglevel >= 1))
- Printf("Peer cert verify depth=%d %s", depth, buf);
- if (ok==0)
- {
- syslog(L_NOTICE, "verify error:num=%d:%s", err,
- X509_verify_cert_error_string(err));
-
- if (verify_depth >= depth) {
- ok = 1;
- verify_error = X509_V_OK;
- } else {
- ok = 0;
- verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
- }
- }
- switch (ctx->error) {
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
- syslog(L_NOTICE, "issuer= %s", buf);
- break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- syslog(L_NOTICE, "cert not yet valid");
- break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- syslog(L_NOTICE, "cert has expired");
- break;
- }
- if ((tls_serveractive) && (tls_loglevel >= 1))
- Printf("verify return:%d", ok);
-
- return (ok);
-}
-
-
-/*
- * taken from OpenSSL crypto/bio/b_dump.c, modified to save a lot of strcpy
- * and strcat by Matti Aarnio.
- */
-
-#define TRUNCATE
-#define DUMP_WIDTH 16
-
-static int tls_dump(const char *s, int len)
-{
- int ret = 0;
- char buf[160 + 1];
- char *ss;
- int i;
- int j;
- int rows;
- int trunc;
- unsigned char ch;
-
- trunc = 0;
-
-
-#ifdef TRUNCATE
- for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--)
- trunc++;
-#endif
-
- rows = (len / DUMP_WIDTH);
- if ((rows * DUMP_WIDTH) < len)
- rows++;
-
- for (i = 0; i < rows; i++) {
- buf[0] = '\0'; /* start with empty string */
- ss = buf;
-
- sprintf(ss, "%04x ", i * DUMP_WIDTH);
- ss += strlen(ss);
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len) {
- strcpy(ss, " ");
- } else {
- ch = ((unsigned char) *((const char *)(s) + i * DUMP_WIDTH + j))
- & 0xff;
- sprintf(ss, "%02x%c", ch, j == 7 ? '|' : ' ');
- ss += 3;
- }
- }
- ss += strlen(ss);
- *ss+= ' ';
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len)
- break;
- ch = ((unsigned char) *((const char *)(s) + i * DUMP_WIDTH + j))
- & 0xff;
- *ss+= (((ch >= ' ') && (ch <= '~')) ? ch : '.');
- if (j == 7) *ss+= ' ';
- }
- *ss = 0;
- /*
- * if this is the last call then update the ddt_dump thing so that
- * we will move the selection point in the debug window
- */
- if (tls_loglevel>0)
- Printf("%s", buf);
- ret += strlen(buf);
- }
-#ifdef TRUNCATE
- if (trunc > 0) {
- snprintf(buf, sizeof(buf), "%04x - <SPACES/NULS>\n", len+ trunc);
- if (tls_loglevel>0)
- Printf("%s", buf);
- ret += strlen(buf);
- }
-#endif
- return (ret);
-}
-
- /*
- * Set up the cert things on the server side. We do need both the
- * private key (in key_file) and the cert (in cert_file).
- * Both files may be identical.
- *
- * This function is taken from OpenSSL apps/s_cb.c
- */
-
-static int set_cert_stuff(SSL_CTX * ctx, char *cert_file, char *key_file)
-{
- struct stat buf;
-
- if (cert_file != NULL) {
- if (SSL_CTX_use_certificate_file(ctx, cert_file,
- SSL_FILETYPE_PEM) <= 0) {
- syslog(L_ERROR, "unable to get certificate from '%s'", cert_file);
- return (0);
- }
- if (key_file == NULL)
- key_file = cert_file;
-
- /* check ownership and permissions of key file */
- if (lstat(key_file, &buf) == -1) {
- syslog(L_ERROR, "unable to stat private key '%s'", key_file);
- return (0);
- }
- if (!S_ISREG(buf.st_mode) || (buf.st_mode & 0077) != 0 ||
- buf.st_uid != getuid()) {
- syslog(L_ERROR, "bad ownership or permissions on private key"
- " '%s': private key must be mode 600 and owned by "
- NEWSUSER, cert_file);
- return (0);
- }
-
- if (SSL_CTX_use_PrivateKey_file(ctx, key_file,
- SSL_FILETYPE_PEM) <= 0) {
- syslog(L_ERROR, "unable to get private key from '%s'", key_file);
- return (0);
- }
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if (!SSL_CTX_check_private_key(ctx)) {
- syslog(L_ERROR, "Private key does not match the certificate public key");
- return (0);
- }
- }
- return (1);
-}
-
-
-
- /*
- * This is the setup routine for the SSL server. As smtpd might be called
- * more than once, we only want to do the initialization one time.
- *
- * The skeleton of this function is taken from OpenSSL apps/s_server.c.
-
- * returns -1 on error
- */
-
-int tls_init_serverengine(int verifydepth,
- int askcert,
- int requirecert,
- char *tls_CAfile,
- char *tls_CApath,
- char *tls_cert_file,
- char *tls_key_file
- )
-{
- int off = 0;
- int verify_flags = SSL_VERIFY_NONE;
- char *CApath;
- char *CAfile;
- char *s_cert_file;
- char *s_key_file;
- struct stat buf;
-
- if (tls_serverengine)
- return (0); /* already running */
-
- if (tls_loglevel >= 2)
- Printf("starting TLS engine");
-
- SSL_load_error_strings();
- SSLeay_add_ssl_algorithms();
-
- CTX = SSL_CTX_new(SSLv23_server_method());
- if (CTX == NULL) {
- return (-1);
- };
-
- off |= SSL_OP_ALL; /* Work around all known bugs */
- SSL_CTX_set_options(CTX, off);
- SSL_CTX_set_info_callback(CTX, apps_ssl_info_callback);
- SSL_CTX_sess_set_cache_size(CTX, 128);
-
- if (strlen(tls_CAfile) == 0)
- CAfile = NULL;
- else
- CAfile = tls_CAfile;
- if (strlen(tls_CApath) == 0)
- CApath = NULL;
- else
- CApath = tls_CApath;
-
- if ((!SSL_CTX_load_verify_locations(CTX, CAfile, CApath)) ||
- (!SSL_CTX_set_default_verify_paths(CTX))) {
- if (tls_loglevel >= 2)
- Printf("TLS engine: cannot load CA data\n");
- return (-1);
- }
-
- if (strlen(tls_cert_file) == 0)
- s_cert_file = NULL;
- else
- s_cert_file = tls_cert_file;
- if (strlen(tls_key_file) == 0)
- s_key_file = NULL;
- else
- s_key_file = tls_key_file;
-
- if (!set_cert_stuff(CTX, s_cert_file, s_key_file)) {
- if (tls_loglevel >= 2)
- Printf("TLS engine: cannot load cert/key data\n");
- return (-1);
- }
-
- /* load some randomization data from /dev/urandom, if it exists */
- /* FIXME: should also check for ".rand" file, update it on exit */
- if (stat("/dev/urandom", &buf) == 0)
- RAND_load_file("/dev/urandom", 16 * 1024);
-
- SSL_CTX_set_tmp_dh_callback(CTX, tmp_dh_cb);
- SSL_CTX_set_options(CTX, SSL_OP_SINGLE_DH_USE);
-
- verify_depth = verifydepth;
- if (askcert!=0)
- verify_flags |= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
- if (requirecert)
- verify_flags |= SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
- | SSL_VERIFY_CLIENT_ONCE;
- SSL_CTX_set_verify(CTX, verify_flags, verify_callback);
-
- SSL_CTX_set_client_CA_list(CTX, SSL_load_client_CA_file(CAfile));
-
- tls_serverengine = 1;
- return (0);
-}
-
-
-/*
-** The function called by nnrpd to initialize the TLS support. Calls
-** tls_init_server_engine and checks the result. On any sort of failure,
-** nnrpd will exit.
-*/
-void
-tls_init(void)
-{
- int ssl_result;
-
- if (tls_initialized)
- return;
- sasl_config_read();
- ssl_result = tls_init_serverengine(5, /* depth to verify */
- 0, /* can client auth? */
- 0, /* required client to auth? */
- (char *)sasl_config_getstring("tls_ca_file", ""),
- (char *)sasl_config_getstring("tls_ca_path", ""),
- (char *)sasl_config_getstring("tls_cert_file", ""),
- (char *)sasl_config_getstring("tls_key_file", ""));
- if (ssl_result == -1) {
- Reply("%d Error initializing TLS\r\n", NNTP_STARTTLS_BAD_VAL);
- syslog(L_ERROR, "error initializing TLS: "
- "[CA_file: %s] [CA_path: %s] [cert_file: %s] [key_file: %s]",
- sasl_config_getstring("tls_ca_file", ""),
- sasl_config_getstring("tls_ca_path", ""),
- sasl_config_getstring("tls_cert_file", ""),
- sasl_config_getstring("tls_key_file", ""));
- ExitWithStats(1, false);
- }
- tls_initialized = true;
-}
-
-
-/* taken from OpenSSL apps/s_cb.c */
-
-static long bio_dump_cb(BIO * bio, int cmd, const char *argp, int argi,
- long argl UNUSED, long ret)
-{
- if (!do_dump)
- return (ret);
-
- if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) {
- Printf("read from %08X [%08lX] (%d bytes => %ld (0x%X))", (unsigned int) bio, (long unsigned int) argp,
- argi, ret, (unsigned int) ret);
- tls_dump(argp, (int) ret);
- return (ret);
- } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) {
- Printf("write to %08X [%08lX] (%d bytes => %ld (0x%X))", (unsigned int) bio, (long unsigned int)argp,
- argi, ret, (unsigned int) ret);
- tls_dump(argp, (int) ret);
- }
- return (ret);
-}
-
- /*
- * This is the actual startup routine for the connection. We expect
- * that the buffers are flushed and the "220 Ready to start TLS" was
- * send to the client, so that we can immediately can start the TLS
- * handshake process.
- *
- * layerbits and authid are filled in on sucess. authid is only
- * filled in if the client authenticated
- *
- */
-int tls_start_servertls(int readfd, int writefd)
-{
- int sts;
- int keepalive;
- SSL_SESSION *session;
- SSL_CIPHER *cipher;
-
- if (!tls_serverengine)
- {
- /* should never happen */
- syslog(L_ERROR, "tls_engine not running");
- return (-1);
- }
- if (tls_loglevel >= 1)
- Printf("setting up TLS connection");
-
- if (tls_conn == NULL)
- {
- tls_conn = (SSL *) SSL_new(CTX);
- }
- if (tls_conn == NULL)
- {
- return (-1);
- }
- SSL_clear(tls_conn);
-
-#if defined(SOL_SOCKET) && defined(SO_KEEPALIVE)
- /* Set KEEPALIVE to catch broken socket connections. */
- keepalive = 1;
- if (setsockopt(readfd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0)
- syslog(L_ERROR, "fd %d can't setsockopt(KEEPALIVE) %m", readfd);
- if (setsockopt(writefd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)) < 0)
- syslog(L_ERROR, "fd %d can't setsockopt(KEEPALIVE) %m", writefd);
-#endif /* SOL_SOCKET && SO_KEEPALIVE */
-
- /* set the file descriptors for SSL to use */
- if (SSL_set_rfd(tls_conn, readfd)==0)
- {
- return (-1);
- }
-
- if (SSL_set_wfd(tls_conn, writefd)==0)
- {
- return (-1);
- }
-
- /*
- * This is the actual handshake routine. It will do all the negotiations
- * and will check the client cert etc.
- */
- SSL_set_accept_state(tls_conn);
-
- /*
- * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
- * Well there is a BIO below the SSL routines that is automatically
- * created for us, so we can use it for debugging purposes.
- */
- if (tls_loglevel >= 3)
- BIO_set_callback(SSL_get_rbio(tls_conn), bio_dump_cb);
-
- /* Dump the negotiation for loglevels 3 and 4*/
- if (tls_loglevel >= 3)
- do_dump = 1;
-
- if ((sts = SSL_accept(tls_conn)) <= 0) { /* xxx <= 0 */
- session = SSL_get_session(tls_conn);
-
- if (session) {
- SSL_CTX_remove_session(CTX, session);
- }
- if (tls_conn)
- SSL_free(tls_conn);
- tls_conn = NULL;
- return (-1);
- }
- /* Only loglevel==4 dumps everything */
- if (tls_loglevel < 4)
- do_dump = 0;
-
- tls_protocol = SSL_get_version(tls_conn);
- cipher = SSL_get_current_cipher(tls_conn);
-
- tls_cipher_name = SSL_CIPHER_get_name(cipher);
- tls_cipher_usebits = SSL_CIPHER_get_bits(cipher,
- &tls_cipher_algbits);
- tls_serveractive = 1;
-
- syslog(L_NOTICE, "starttls: %s with cipher %s (%d/%d bits) no authentication", tls_protocol, tls_cipher_name,
- tls_cipher_usebits, tls_cipher_algbits);
-
- return (0);
-}
-
-ssize_t
-SSL_writev (ssl, vector, count)
- SSL *ssl;
- const struct iovec *vector;
- int count;
-{
- static char *buffer = NULL;
- static size_t allocsize = 0;
- char *bp;
- size_t bytes, to_copy;
- int i;
- /* Find the total number of bytes to be written. */
- bytes = 0;
- for (i = 0; i < count; ++i)
- bytes += vector[i].iov_len;
- /* Allocate a buffer to hold the data. */
- if (NULL == buffer) {
- buffer = (char *) xmalloc(bytes);
- allocsize = bytes;
- } else if (bytes > allocsize) {
- buffer = (char *) xrealloc (buffer, bytes);
- allocsize = bytes;
- }
- /* Copy the data into BUFFER. */
- to_copy = bytes;
- bp = buffer;
- for (i = 0; i < count; ++i)
- {
-#define min(a, b) ((a) > (b) ? (b) : (a))
- size_t copy = min (vector[i].iov_len, to_copy);
- memcpy (bp, vector[i].iov_base, copy);
- bp += copy;
- to_copy -= copy;
- if (to_copy == 0)
- break;
- }
- return SSL_write (ssl, buffer, bytes);
-}
-
-
-#endif /* HAVE_SSL */
+++ /dev/null
-/* tls.h --- TLSv1 functions
- Copyright (C) 2000 Kenichi Okada <okada@opaopa.org>
-
- Author: Kenichi Okada <okada@opaopa.org>
- Created: 2000-02-22
-
- Keywords: TLS, OpenSSL
-
- Commentary:
-
- [RFC 2246] "The TLS Protocol Version 1.0"
- by Christopher Allen <callen@certicom.com> and
- Tim Dierks <tdierks@certicom.com> (1999/01)
-
- [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
- by Chris Newman <chris.newman@innosoft.com> (1999/06)
-
-*/
-
-#ifdef HAVE_SSL
-
-#ifndef TLS_H
-#define TLS_H
-
-#include <openssl/lhash.h>
-#include <openssl/bn.h>
-#include <openssl/err.h>
-#include <openssl/pem.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-#include <openssl/ssl.h>
-
-/* init tls engine */
-int tls_init_serverengine(int verifydepth, /* depth to verify */
- int askcert, /* 1 = verify client */
- int requirecert, /* 1 = another client verify? */
- char *tls_CAfile,
- char *tls_CApath,
- char *tls_cert_file,
- char *tls_key_file);
-
-/* init tls */
-void tls_init(void);
-
-/* start tls negotiation */
-int tls_start_servertls(int readfd, int writefd);
-
-ssize_t SSL_writev (SSL *ssl, const struct iovec *vector, int count);
-
-#endif /* CYRUSTLS_H */
-
-#endif /* HAVE_SSL */
+++ /dev/null
-/* $Revision: 6124 $
-**
-** User and post tracking database.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "nnrpd.h"
-
-#define MAX_LEN 180
-
-/* TrackClient determines whether or not
- we are interested in tracking the activities
- of the currently connected host. We have to
- rely on an external process to set up the
- entries in the database though which makes
- this only as reliable as the process that
- sets this up...
-*/
-
-/* Format of the input line is <host>:<username>
-*/
-
-int TrackClient(char *client, char *user)
-{
- int RARTon;
- FILE *fd;
- char line[MAX_LEN],*p,*pp,*lp;
- char *dbfile;
-
- dbfile = concatpath(innconf->pathetc, "nnrpd.track");
-
- RARTon=false;
- strcpy(user, "unknown");
-
- if ((fd=fopen(dbfile,"r"))!=NULL) {
- while((fgets(line,(MAX_LEN - 1),fd))!=NULL) {
- if (line[0] == '#' || line[0] == '\n') continue;
- if ((p=strchr(line,' ')) != NULL) *p='\0';
- if ((p=strchr(line,'\n')) != NULL) *p='\0';
- if ((p=strchr(line,':')) != NULL) {
- *p++='\0';
- } else {
- p=NULL;
- }
- pp=line;
- if ((lp=strchr(pp,'*')) != NULL) {
- pp=++lp;
- }
- if (strstr(client,pp)!=NULL) {
- RARTon=true;
- if (p != NULL)
- strcpy(user,p);
- break;
- }
- }
- fclose(fd);
- } else {
- RARTon=false;
- syslog(L_NOTICE, "%s No logging - can't read %s", ClientHost, dbfile);
- }
-
- free(dbfile);
- return RARTon;
-}
+++ /dev/null
-## $Id: INN.py 7897 2008-06-22 18:04:31Z iulius $
-##
-## This module supplies stub Python functions corresponding to the ones
-## provided by innd. It is not used by the server; it is only here so
-## that you can test your filter scripts before loading.
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-
-from types import *
-
-def set_filter_hook(anObject):
- if type(anObject) == InstanceType:
- print "** set_filter_hook for " + repr(anObject)
- else:
- print "** <Your object is not a class instance.>"
-
-def addhist(messageid):
- print "** addhist Message-ID: " + messageid
-
-def havehist(messageid):
- print "** havehist Message-ID: " + messageid
-
-def cancel(messageid):
- print "** cancel Message-ID: " + messageid
-
-def newsgroup(groupname):
- print "** newsgroup: " + groupname
-
-def head(messageid):
- print "** head Message-ID: " + messageid
-
-def article(messageid):
- print "** article Message-ID: " + messageid
-
-def hashstring(mystring):
- print "** hash: " + mystring
-
-def syslog(level, message):
- print "-- syslog level: %s message: %s" % (level, message)
+++ /dev/null
-## $Id: Makefile 6299 2003-04-20 19:04:14Z vinocur $
-##
-## All the actual installation work of any files in the samples directory
-## is done via the site directory, so that one can maintain one's news
-## configuration in the site directory and use make commands to update the
-## server automatically. All this Makefile does is run fixscript on a few
-## files that don't need the full power of configure (and clean up after
-## them on make clean).
-
-include ../Makefile.global
-
-top = ..
-
-ALL = nnrpd_auth.pl nnrpd_access.pl \
- nnrpd_auth_wrapper.pl nnrpd_access_wrapper.pl
-
-EXTRA = inn.conf innreport.conf newsfeeds sasl.conf
-
-all: $(ALL) $(EXTRA)
-
-clean:
- rm -f $(ALL)
-
-clobber distclean: clean
- rm -f $(EXTRA)
-
-install:
-depend:
-
-profiled: all
-
-$(EXTRA) $(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Build rules.
-
-FIX = $(FIXSCRIPT)
-
-nnrpd_auth.pl: nnrpd_auth.pl.in $(FIX) ; $(FIX) $@.in
-nnrpd_access.pl: nnrpd_access.pl.in $(FIX) ; $(FIX) $@.in
-nnrpd_auth_wrapper.pl: nnrpd_auth_wrapper.pl.in $(FIX) ; $(FIX) $@.in
-nnrpd_access_wrapper.pl: nnrpd_access_wrapper.pl.in $(FIX) ; $(FIX) $@.in
+++ /dev/null
-control 0000000000 0000000001 n
-control.cancel 0000000000 0000000001 n
-control.checkgroups 0000000000 0000000001 n
-control.newgroup 0000000000 0000000001 n
-control.rmgroup 0000000000 0000000001 n
-junk 0000000000 0000000001 n
+++ /dev/null
-# $Id: actsync.cfg 7081 2004-12-22 04:20:47Z rra $
-
-host=ftp.isc.org
-ftppath=/pub/usenet/CONFIG/active.gz
-flags=-v 0 -p 80
-ignore_file=actsync.ign
+++ /dev/null
-# $Id: actsync.ign 7079 2004-12-22 04:20:14Z rra $
-#
-# Sample actsync ignore_file.
-
-# For now by default do not sync
-#
-i *
-
-# sync on the 8 majors
-#
-c comp.*
-c humanities.*
-c misc.*
-c news.*
-c rec.*
-c sci.*
-c soc.*
-c talk.*
-
-# don't compare to.* groups as they will differ
-#
-i to.*
-
-# we always want our special top level groups
-#
-i control
-i general
-i junk
-i test
-i to
+++ /dev/null
-#
-# overview buffer configuration file
-#
-# The order in this items appear in this file is not important
-
-# Format:
-# index(0-65535) : path to buffer file :
-# length of buffer in kilobytes in decimal (1KB = 1024 bytes)
-
-0:/var/spool/news/overview/OV1:1536000
-1:/var/spool/news/overview/OV2:1536000
+++ /dev/null
-## control.ctl - Access control for control messages.
-## Last modified: 2008-03-05
-##
-## Based on rone's unified control.ctl file.
-##
-## For a web presentation of the information recorded here, as well as
-## other useful information about Usenet hierarchies, please see:
-##
-## <http://usenet.trigofacile.com/hierarchies/>
-##
-## Please copy usenet-config@isc.org on any updates to this file so that
-## it can be updated in the INN CVS repository and on ftp.isc.org. For
-## changes to a public hierarchy, please also post the changes to
-## news.admin.hierarchies.
-##
-## The canonical version of this file can be found in the latest INN
-## release and at <ftp://ftp.isc.org/pub/usenet/CONFIG/control.ctl>; these
-## two files will be kept in sync. Please refer to the latest version of
-## this file for the most up-to-date hierarchy control information and
-## please use the latest version if you intend to carry all hierarchies.
-##
-## You may wish to review and change the policy for alt.*, free.*,
-## it-alt.*, and oesterreich.* below before using this file on your
-## server.
-##
-## Format:
-## <message>:<from>:<newsgroups>:<action>
-##
-## <message> Control message or "all" if it applies to all control
-## messages.
-## <from> Pattern that must match the From line.
-## <newsgroups> Pattern that must match the newsgroup being newgroup'd
-## or rmgroup'd (ignored for other messages).
-## <action> What to do:
-## doit Perform action
-## drop Ignore message
-## log One line to error log
-## mail Send mail to admin
-## verify-pgp_userid Do PGP verification on user.
-## All actions except drop and mail can be given a log
-## location by following the action with an = and the
-## log ("mail" says to mail the admin, an empty location
-## tosses the log information, and a relative path xxx
-## logs to $LOG/xxx.log).
-##
-## The *last* matching entry is used. See the expire.ctl(5) man page for
-## complete information.
-##
-## This file follows the following policies:
-##
-## * Most unknown or invalid control messages no longer result in mail.
-## This is due to the proliferation of forged control messages filling
-## up mailboxes. Some news servers even get overwhelmed with trying to
-## log failure, so unsigned control messages for hierarchies that use
-## PGP are simply dropped.
-##
-## * The assumption is that you now have PGP on your system. If you
-## don't, you should get it to help protect yourself against all the
-## control message forgeries. See <ftp://ftp.isc.org/pub/pgpcontrol/>.
-## PGP control message verification comes with all versions of INN since
-## 1.5, but you will need to install either PGP or GnuPG; see the
-## installation instructions for your news server.
-##
-## If for some reason you can't use PGP, search for the *PGP* comments
-## and modify the control lines to change "verify-..." in the action
-## field to "mail" or "doit=mail" or "doit=<log file>" or whatever you
-## prefer (replacing <log file> with the name of an appropriate log
-## file).
-##
-## * A number of hierarchies are for local use only but have leaked out
-## into the general stream. In this config file, they are set so that
-## the groups will be easy to remove, and are marked with a comment of
-## *LOCAL* (for use by that organization only, not generally
-## distributed), *DEFUNCT* (a hierarchy that's no longer used), or
-## *PRIVATE* (should only be carried after making arrangements with the
-## given contact address). Please delete all groups in those
-## hierarchies from your server if you carry them, unless you've
-## contacted the listed contact address and arranged a feed.
-##
-## If you have permission to carry any of the hierarchies so listed in
-## this file, you should change the entries for those hierarchies below.
-##
-## The comments of this file aren't in any formal or well-defined syntax,
-## but they are meant to use a consistent syntax to allow eventual parsing
-## by scripts into a better database format. Please follow the syntax of
-## existing entries when providing new ones. The recognized "fields" are
-## Contact (contact e-mail address), Admin group (the administrative group
-## for the hierarchy), URL, Key URL (URL for PGP key), Key fingerprint, Key
-## mail (address to mail for PGP key), and Syncable server (for actsync or
-## a similar tool).
-##
-## Names used in this file that cannot be encoded in 7bit ASCII are in
-## UTF-8. The only non-7bit-ASCII content is in comments.
-
-## -------------------------------------------------------------------------
-## DEFAULT
-## -------------------------------------------------------------------------
-
-# Default to dropping control messages that aren't recognized to allow
-# people to experiment without inadvertently mailbombing news admins.
-all:*:*:drop
-
-## -------------------------------------------------------------------------
-## CHECKGROUPS MESSAGES
-## -------------------------------------------------------------------------
-
-# Default to mailing all checkgroups messages to the administrator.
-checkgroups:*:*:mail
-
-## -------------------------------------------------------------------------
-## MISCELLANEOUS CONTROL MESSAGES
-## -------------------------------------------------------------------------
-
-# Mostly only used for UUCP feeds, very rarely used these days.
-ihave:*:*:drop
-sendme:*:*:drop
-
-# Request to send a copy of the newsfeeds file, intended for mapping
-# projects. Almost never used for anything other than mailbombing now.
-sendsys:*:*:log=sendsys
-
-# Request to send the server's path entry. Not particularly useful.
-senduuname:*:*:log=senduuname
-
-# Request to send the server's version number.
-version:*:*:log=version
-
-## -------------------------------------------------------------------------
-## NEWGROUP/RMGROUP MESSAGES
-## -------------------------------------------------------------------------
-
-## Default (for any group)
-newgroup:*:*:mail
-rmgroup:*:*:mail
-
-## A.BSU (*DEFUNCT* -- Ball State University, USA)
-# This hierarchy is defunct. Please remove it.
-newgroup:*:a.bsu.*:mail
-rmgroup:*:a.bsu.*:doit
-
-## ACS & OSU (*LOCAL* -- Ohio State University, USA)
-# Contact: Albert J. School <school.1@osu.edu>
-# Contact: Harpal Chohan <chohan+@osu.edu>
-# For local use only, contact the above address for information.
-newgroup:*:acs.*|osu.*:mail
-rmgroup:*:acs.*|osu.*:doit
-
-## ADASS (Astronomical Data Analysis Software and Systems)
-# URL: http://iraf.noao.edu/iraf/web/adass_news.html
-checkgroups:news@iraf.noao.edu:adass.*:doit
-newgroup:news@iraf.noao.edu:adass.*:doit
-rmgroup:news@iraf.noao.edu:adass.*:doit
-
-## AHN (Athens-Clarke County, Georgia, USA)
-checkgroups:greg@*.ucns.uga.edu:ahn.*:doit
-newgroup:greg@*.ucns.uga.edu:ahn.*:doit
-rmgroup:greg@*.ucns.uga.edu:ahn.*:doit
-
-## AIOE (Aioe.org)
-# Contact: usenet@aioe.org
-# URL: http://news.aioe.org/hierarchy/
-# Admin group: aioe.system
-# Key URL: http://news.aioe.org/hierarchy/aioe.txt
-# Key fingerprint = 2203 1AAC 51E7 C7FD 664F 1D80 90DF 6C71 2322 A7F8
-# Syncable server: nntp.aioe.org
-# *PGP* See comment at top of file.
-newgroup:*:aioe.*:drop
-rmgroup:*:aioe.*:drop
-checkgroups:usenet@aioe.org:aioe.*:verify-usenet@aioe.org
-newgroup:usenet@aioe.org:aioe.*:verify-usenet@aioe.org
-rmgroup:usenet@aioe.org:aioe.*:verify-usenet@aioe.org
-
-## AIR (*DEFUNCT* -- Stanford University, USA)
-# Contact: news@news.stanford.edu
-# This hierarchy is defunct. Please remove it.
-newgroup:*:air.*:mail
-rmgroup:*:air.*:doit
-
-## AKR (Akron, Ohio, USA)
-checkgroups:red@redpoll.mrfs.oh.us:akr.*:doit
-newgroup:red@redpoll.mrfs.oh.us:akr.*:doit
-rmgroup:red@redpoll.mrfs.oh.us:akr.*:doit
-
-## ALABAMA & HSV (Huntsville, Alabama, USA)
-# Contact: jpc@suespammers.org
-# Admin group: alabama.config
-# *PGP* See comment at top of file.
-newgroup:*:alabama.*|hsv.*:drop
-rmgroup:*:alabama.*|hsv.*:drop
-checkgroups:jpc@suespammers.org:alabama.*|hsv.*:verify-alabama-group-admin
-newgroup:jpc@suespammers.org:alabama.*|hsv.*:verify-alabama-group-admin
-rmgroup:jpc@suespammers.org:alabama.*|hsv.*:verify-alabama-group-admin
-
-## ALIVE (*DEFUNCT* -- ?)
-# Contact: thijs@kink.xs4all.nl
-# This hierarchy is defunct. Please remove it.
-newgroup:*:alive.*:mail
-rmgroup:*:alive.*:doit
-
-## ALT
-#
-# Accept all newgroups (except ones forged from Big 8 newgroup issuers,
-# who never issue alt.* control messages) and silently ignore all
-# rmgroups.
-#
-# What policy to use for alt.* groups varies widely from site to site.
-# For a small site, it is strongly recommended that this policy be changed
-# to drop all newgroups and rmgroups for alt.*. The local news admin can
-# then add new alt.* groups only on user request. Tons of alt.* newgroups
-# are sent out regularly with the intent more to create nonsense entries
-# in active files than to actually create a useable newsgroup. The admin
-# may still want to check the control message archive, as described below.
-#
-# Quality, user-desirable new groups can often be discovered by a quick
-# perusal of recent alt.* newgroup messages after discarding obvious junk
-# groups. One good initial filter is to check the archive of control
-# messages for a requested group to see if a syntactically valid newgroup
-# message was issued. Many of the junk control messages are invalid and
-# won't be archived, and many sites will only add alt.* groups with valid
-# control messages. To check the archive, see if:
-#
-# ftp://ftp.isc.org/pub/usenet/control/alt/<group-name>.gz
-#
-# exists (replacing <group-name> with the name of the group) and read the
-# first and last few control messages to see if the newsgroup should be
-# moderated. (Some alt.* groups that should be moderated are created
-# unmoderated by hijackers to try to damage the newsgroup.)
-#
-# Be aware that there is no official, generally accepted alt.* policy and
-# all information about alt.* groups available is essentially someone's
-# opinion, including these comments. There are nearly as many different
-# policies with regard to alt.* groups as there are Usenet sites.
-#
-newgroup:*:alt.*:doit
-newgroup:group-admin@isc.org:alt.*:drop
-newgroup:tale@*uu.net:alt.*:drop
-rmgroup:*:alt.*:drop
-
-## AR (Argentina)
-checkgroups:jorge_f@nodens.fisica.unlp.edu.ar:ar.*:doit
-newgroup:jorge_f@nodens.fisica.unlp.edu.ar:ar.*:doit
-rmgroup:jorge_f@nodens.fisica.unlp.edu.ar:ar.*:doit
-
-## ARC (*LOCAL* -- NASA Ames Research Center, USA)
-# Contact: news@arc.nasa.gov
-# For local use only, contact the above address for information.
-newgroup:*:arc.*:mail
-rmgroup:*:arc.*:doit
-
-## ARKANE (Arkane Systems, UK)
-# Contact: newsbastard@arkane.demon.co.uk
-checkgroups:newsbastard@arkane.demon.co.uk:arkane.*:doit
-newgroup:newsbastard@arkane.demon.co.uk:arkane.*:doit
-rmgroup:newsbastard@arkane.demon.co.uk:arkane.*:doit
-
-## AT (Austria)
-# URL: http://www.usenet.at/
-# Admin group: at.usenet.gruppen
-# Key URL: http://www.usenet.at/pgpkey.asc
-# *PGP* See comment at top of file.
-newgroup:*:at.*:drop
-rmgroup:*:at.*:drop
-checkgroups:control@usenet.backbone.at:at.*:verify-control@usenet.backbone.at
-newgroup:control@usenet.backbone.at:at.*:verify-control@usenet.backbone.at
-rmgroup:control@usenet.backbone.at:at.*:verify-control@usenet.backbone.at
-
-## AUS (Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://aus.news-admin.org/
-# Admin group: aus.net.news
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:aus.*:drop
-rmgroup:*:aus.*:drop
-checkgroups:ausadmin@aus.news-admin.org:aus.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:aus.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:aus.*:verify-ausadmin@aus.news-admin.org
-
-## AUSTIN (Austin, Texas, USA)
-# URL: http://frenzy.austin.tx.us/austin/
-# Admin group: austin.usenet.config
-checkgroups:chip@unicom.com:austin.*:doit
-checkgroups:fletcher@cs.utexas.edu:austin.*:doit
-checkgroups:pug@pug.net:austin.*:doit
-newgroup:chip@unicom.com:austin.*:doit
-newgroup:fletcher@cs.utexas.edu:austin.*:doit
-newgroup:pug@pug.net:austin.*:doit
-rmgroup:chip@unicom.com:austin.*:doit
-rmgroup:fletcher@cs.utexas.edu:austin.*:doit
-rmgroup:pug@pug.net:austin.*:doit
-
-## AZ (Arizona, USA)
-checkgroups:system@asuvax.eas.asu.edu:az.*:doit
-newgroup:system@asuvax.eas.asu.edu:az.*:doit
-rmgroup:system@asuvax.eas.asu.edu:az.*:doit
-
-## BA (San Francisco Bay Area, USA)
-# Contact: ba-mod@nas.nasa.gov
-# URL: http://ennui.org/ba/
-# Admin group: ba.news.config
-# Key URL: http://ennui.org/ba/ba-mod.asc
-# *PGP* See comment at top of file.
-newgroup:*:ba.*:drop
-rmgroup:*:ba.*:drop
-checkgroups:ba-mod@nas.nasa.gov:ba.*:verify-ba.news.config
-newgroup:ba-mod@nas.nasa.gov:ba.*:verify-ba.news.config
-rmgroup:ba-mod@nas.nasa.gov:ba.*:verify-ba.news.config
-
-## BACKBONE (*LOCAL* -- ruhr.de/ruhrgebiet.individual.net in Germany)
-# Contact: admin@ruhr.de
-# For local use only, contact the above address for information.
-newgroup:*:backbone.*:mail
-rmgroup:*:backbone.*:doit
-
-## BC (British Columbia, Canada)
-checkgroups:bc_van_usenet@fastmail.ca:bc.*:doit
-newgroup:bc_van_usenet@fastmail.ca:bc.*:doit
-rmgroup:bc_van_usenet@fastmail.ca:bc.*:doit
-
-## BDA (German groups?)
-checkgroups:news@*netuse.de:bda.*:doit
-newgroup:news@*netuse.de:bda.*:doit
-rmgroup:news@*netuse.de:bda.*:doit
-
-## BE (Belgique/Belgie/Belgien/Belgium)
-# Contact: be-hierarchy-admin@usenet.be
-# URL: http://usenet.be/
-# Admin group: be.announce
-# Key URL: http://usenet.be/be.announce.newgroups.asc
-# Key fingerprint = 30 2A 45 94 70 DE 1F D5 81 8C 58 64 D2 F7 08 71
-# *PGP* See comment at top of file.
-newgroup:*:be.*:drop
-rmgroup:*:be.*:drop
-checkgroups:group-admin@usenet.be:be.*:verify-be.announce.newgroups
-newgroup:group-admin@usenet.be:be.*:verify-be.announce.newgroups
-rmgroup:group-admin@usenet.be:be.*:verify-be.announce.newgroups
-
-## BELWUE (Baden-Wuerttemberg, Germany)
-# Admin group: belwue.infos
-# *PGP* See comment at top of file.
-newgroup:*:belwue.*:drop
-rmgroup:*:belwue.*:drop
-checkgroups:news@news.belwue.de:belwue.*:verify-belwue-hir-control
-newgroup:news@news.belwue.de:belwue.*:verify-belwue-hir-control
-rmgroup:news@news.belwue.de:belwue.*:verify-belwue-hir-control
-
-## BERMUDA (Bermuda)
-checkgroups:news@*ibl.bm:bermuda.*:doit
-newgroup:news@*ibl.bm:bermuda.*:doit
-rmgroup:news@*ibl.bm:bermuda.*:doit
-
-## BES (*PRIVATE* -- Beijing Electron Spectrometer)
-# Contact: news@news.stanford.edu
-# For private use only, contact the above address for information.
-newgroup:news@news.stanford.edu:bes.*:mail
-rmgroup:news@news.stanford.edu:bes.*:doit
-
-## BEST (*LOCAL* -- Best Internet Communications, Inc.)
-# Contact: news@best.net
-# For local use only, contact the above address for information.
-newgroup:*:best.*:mail
-rmgroup:*:best.*:doit
-
-## BIONET (Biology Network)
-# URL: http://www.bio.net/
-# Admin group: bionet.general
-# Key fingerprint = EB C0 F1 BA 26 0B C6 D6 FB 8D ED C4 AE 5D 10 54
-# *PGP* See comment at top of file.
-newgroup:*:bionet.*:drop
-rmgroup:*:bionet.*:drop
-checkgroups:Biosci-control-key@net.bio.net:bionet.*:verify-Biosci-control-key@net.bio.net
-newgroup:Biosci-control-key@net.bio.net:bionet.*:verify-Biosci-control-key@net.bio.net
-rmgroup:Biosci-control-key@net.bio.net:bionet.*:verify-Biosci-control-key@net.bio.net
-
-## BIRK (*LOCAL* -- University of Oslo, Norway)
-# Contact: birk-admin@ping.uio.no
-# For local use only, contact the above address for information.
-newgroup:*:birk.*:mail
-rmgroup:*:birk.*:doit
-
-## BIT (Gatewayed Mailing lists)
-# URL: http://www.newsadmin.com/bit/bit.htm
-# Admin group: bit.admin
-# *PGP* See comment at top of file.
-newgroup:*:bit.*:drop
-rmgroup:*:bit.*:drop
-checkgroups:bit@newsadmin.com:bit.*:verify-bit@newsadmin.com
-newgroup:bit@newsadmin.com:bit.*:verify-bit@newsadmin.com
-rmgroup:bit@newsadmin.com:bit.*:verify-bit@newsadmin.com
-
-## BIZ (Business Groups)
-checkgroups:edhew@xenitec.on.ca:biz.*:doit
-newgroup:edhew@xenitec.on.ca:biz.*:doit
-rmgroup:edhew@xenitec.on.ca:biz.*:doit
-
-## BLGTN (Bloomington, In, USA)
-checkgroups:control@news.bloomington.in.us:blgtn.*:doit
-newgroup:control@news.bloomington.in.us:blgtn.*:doit
-rmgroup:control@news.bloomington.in.us:blgtn.*:doit
-
-## BLN (Berlin, Germany)
-checkgroups:news@*fu-berlin.de:bln.*:doit
-newgroup:news@*fu-berlin.de:bln.*:doit
-rmgroup:news@*fu-berlin.de:bln.*:doit
-
-## BNE (Brisbane, Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://bne.news-admin.org/
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:bne.*:drop
-rmgroup:*:bne.*:drop
-checkgroups:ausadmin@aus.news-admin.org:bne.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:bne.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:bne.*:verify-ausadmin@aus.news-admin.org
-
-## BOFH (*PRIVATE* -- Bastard Operator From Hell)
-# Contact: myname@myhost.mydomain.com
-# For private use only, contact the above address for information.
-newgroup:*:bofh.*:mail
-rmgroup:*:bofh.*:doit
-
-## CA (California, USA)
-# Contact: ikluft@thunder.sbay.org
-# URL: http://www.sbay.org/ca/
-checkgroups:ikluft@thunder.sbay.org:ca.*:doit
-newgroup:ikluft@thunder.sbay.org:ca.*:doit
-rmgroup:ikluft@thunder.sbay.org:ca.*:doit
-
-## CAIS (*LOCAL* -- Capital Area Internet Services)
-# Contact: news@cais.com
-# For local use only, contact the above address for information.
-newgroup:*:cais.*:mail
-rmgroup:*:cais.*:doit
-
-## CALSTATE (California State University)
-checkgroups:*@*calstate.edu:calstate.*:doit
-newgroup:*@*calstate.edu:calstate.*:doit
-rmgroup:*@*calstate.edu:calstate.*:doit
-
-## CANB (Canberra, Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://canb.news-admin.org/
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:canb.*:drop
-rmgroup:*:canb.*:drop
-checkgroups:ausadmin@aus.news-admin.org:canb.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:canb.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:canb.*:verify-ausadmin@aus.news-admin.org
-
-## CAPDIST (Albany, The Capital District, New York, USA)
-checkgroups:danorton@albany.net:capdist.*:doit
-newgroup:danorton@albany.net:capdist.*:doit
-rmgroup:danorton@albany.net:capdist.*:doit
-
-## CARLETON (Carleton University, Canada)
-newgroup:news@cunews.carleton.ca:carleton.*:doit
-newgroup:news@cunews.carleton.ca:carleton*class.*:mail
-rmgroup:news@cunews.carleton.ca:carleton.*:doit
-
-## CD-ONLINE (*LOCAL* -- ?)
-# Contact: newsmaster@worldonline.nl
-# For local use only, contact the above address for information.
-newgroup:*:cd-online.*:mail
-rmgroup:*:cd-online.*:doit
-
-## CENTRAL (*LOCAL* -- The Internet Company of New Zealand, Wellington, NZ)
-# Contact: usenet@iconz.co.nz
-# For local use only, contact the above address for information.
-newgroup:*:central.*:mail
-rmgroup:*:central.*:doit
-
-## CERN (*PRIVATE* -- CERN European Laboratory for Particle Physics)
-# Contact: Dietrich Wiegandt <News.Support@cern.ch>
-# For private use only, contact the above address for information.
-newgroup:News.Support@cern.ch:cern.*:mail
-rmgroup:News.Support@cern.ch:cern.*:doit
-
-## CH (Switzerland)
-# Contact: ch-news-admin@use-net.ch
-# URL: http://www.use-net.ch/Usenet/
-# Key URL: http://www.use-net.ch/Usenet/adminkey.html
-# Key fingerprint = 71 80 D6 8C A7 DE 2C 70 62 4A 48 6E D9 96 02 DF
-# *PGP* See comment at top of file.
-newgroup:*:ch.*:drop
-rmgroup:*:ch.*:drop
-checkgroups:felix.rauch@nice.ch:ch.*:verify-ch-news-admin@use-net.ch
-newgroup:felix.rauch@nice.ch:ch.*:verify-ch-news-admin@use-net.ch
-rmgroup:felix.rauch@nice.ch:ch.*:verify-ch-news-admin@use-net.ch
-
-## CHAVEN (*LOCAL* -- Celestian Haven ISP, Midwest, USA)
-# Contact: news@chaven.com
-# For local use only, contact the above address for information.
-newgroup:*:chaven.*:mail
-rmgroup:*:chaven.*:doit
-
-## CHI (Chicago, USA)
-# URL: http://lull.org/pub/chi-newsgroup-faq
-checkgroups:lisbon@*chi.il.us:chi.*:doit
-newgroup:lisbon@*chi.il.us:chi.*:doit
-rmgroup:lisbon@*chi.il.us:chi.*:doit
-
-## CHILE (Chile and Chilean affairs)
-# Contact: mod-cga@usenet.cl
-# URL: http://www.usenet.cl/
-# Admin group: chile.grupos.anuncios
-checkgroups:mod-cga@*lj.cl:chile.*:doit
-newgroup:mod-cga@*lj.cl:chile.*:doit
-rmgroup:mod-cga@*lj.cl:chile.*:doit
-
-## CHINESE (China and Chinese language groups)
-checkgroups:pinghua@stat.berkeley.edu:chinese.*:doit
-newgroup:pinghua@stat.berkeley.edu:chinese.*:doit
-rmgroup:pinghua@stat.berkeley.edu:chinese.*:doit
-
-## CHRISTNET (Christian Discussion)
-checkgroups:news@fdma.com:christnet.*:doit
-newgroup:news@fdma.com:christnet.*:doit
-rmgroup:news@fdma.com:christnet.*:doit
-
-## CL (*PRIVATE* -- CL-Netz, German)
-# Contact: koordination@cl-netz.de
-# URL: http://www.cl-netz.de/
-# Key URL: http://www.cl-netz.de/control.txt
-# For private use only, contact above address for questions.
-# *PGP* See comment at top of file.
-newgroup:*:cl.*:drop
-rmgroup:*:cl.*:doit
-# The following three lines are only for authorized cl.* sites.
-#checkgroups:koordination@cl-netz.de:cl.*:verify-cl.netz.infos
-#newgroup:koordination@cl-netz.de:cl.*:verify-cl.netz.infos
-#rmgroup:koordination@cl-netz.de:cl.*:verify-cl.netz.infos
-
-## CLARI (*PRIVATE* -- Features and News, available on a commercial basis)
-# Contact: support@clari.net
-# Admin group: clari.net.admin
-# Key URL: http://www.clari.net/tech/clarikey.txt
-# For private use only, contact the above address for information.
-# *PGP* See comment at top of file.
-newgroup:*:clari.*:drop
-rmgroup:*:clari.*:drop
-newgroup:cl*@clarinet.com:clari.*:mail
-rmgroup:cl*@clarinet.com:clari.*:verify-ClariNet.Group
-
-## CMI (*LOCAL* -- Champaign County, IL, USA)
-# Contact: news@ks.uiuc.edu
-# For local use only, contact the above address for information.
-newgroup:*:cmi.*:mail
-rmgroup:*:cmi.*:doit
-
-## CMU (*LOCAL* -- Carnegie-Mellon University, Pennsylvania, USA)
-# Contact: Daniel Edward Lovinger <del+@CMU.EDU>
-# For local use only, contact the above address for information.
-newgroup:*:cmu.*:mail
-rmgroup:*:cmu.*:doit
-
-## CN (China)
-# URL: http://news.yaako.com/
-# Admin group: cn.announce
-# Key fingerprint = 62 97 EE 33 F7 16 25 C1 A4 9E 47 BA C5 3E 5E 9E
-# *PGP* See comment at top of file.
-newgroup:*:cn.*:drop
-rmgroup:*:cn.*:drop
-checkgroups:control@bentium.com:cn.*:verify-cn.admin.news.announce
-newgroup:control@bentium.com:cn.*:verify-cn.admin.news.announce
-rmgroup:control@bentium.com:cn.*:verify-cn.admin.news.announce
-
-## CN.BBS (China)
-# URL: http://bbs.cn.news-admin.org/
-# Admin group: cn.bbs.admin.announce
-# *PGP* See comment at top of file.
-newgroup:*:cn.bbs.*:drop
-rmgroup:*:cn.bbs.*:drop
-checkgroups:control@cn-bbs.org:cn.bbs.*:verify-cn.bbs.admin.announce
-newgroup:control@cn-bbs.org:cn.bbs.*:verify-cn.bbs.admin.announce
-rmgroup:control@cn-bbs.org:cn.bbs.*:verify-cn.bbs.admin.announce
-
-## CO (Colorado, USA)
-# Contact: coadmin@boyznoyz.com (Bill of Denver)
-checkgroups:coadmin@boyznoyz.com:co.*:doit
-newgroup:coadmin@boyznoyz.com:co.*:doit
-rmgroup:coadmin@boyznoyz.com:co.*:doit
-
-## CODEWARRIOR (CodeWarrior discussion)
-checkgroups:news@supernews.net:codewarrior.*:doit
-newgroup:news@supernews.net:codewarrior.*:doit
-rmgroup:news@supernews.net:codewarrior.*:doit
-
-## COMP, HUMANITIES, MISC, NEWS, REC, SCI, SOC, TALK (The Big Eight)
-# Contact: board@big-8.org
-# URL: http://www.big-8.org/
-# Admin group: news.announce.newgroups
-# Key fingerprint = F5 35 58 D3 55 64 10 14 07 C6 95 53 13 6F D4 07
-# *PGP* See comment at top of file.
-newgroup:*:comp.*|humanities.*|misc.*|news.*|rec.*|sci.*|soc.*|talk.*:drop
-rmgroup:*:comp.*|humanities.*|misc.*|news.*|rec.*|sci.*|soc.*|talk.*:drop
-checkgroups:group-admin@isc.org:comp.*|humanities.*|misc.*|news.*|rec.*|sci.*|soc.*|talk.*:verify-news.announce.newgroups
-newgroup:group-admin@isc.org:comp.*|humanities.*|misc.*|news.*|rec.*|sci.*|soc.*|talk.*:verify-news.announce.newgroups
-rmgroup:group-admin@isc.org:comp.*|humanities.*|misc.*|news.*|rec.*|sci.*|soc.*|talk.*:verify-news.announce.newgroups
-
-## COMPUTER42 (Computer 42, Germany)
-# Contact: Dirk Schmitt <news@computer42.org>
-checkgroups:news@computer42.org:computer42.*:doit
-newgroup:news@computer42.org:computer42.*:doit
-rmgroup:news@computer42.org:computer42.*:doit
-
-## CONCORDIA (Concordia University, Montreal, Canada)
-# Contact: newsmaster@concordia.ca
-# URL: General University info at http://www.concordia.ca/
-checkgroups:news@newsflash.concordia.ca:concordia.*:doit
-newgroup:news@newsflash.concordia.ca:concordia.*:doit
-rmgroup:news@newsflash.concordia.ca:concordia.*:doit
-
-## COURTS (*DEFUNCT* -- Court discussion)
-# Contact: trier@ins.cwru.edu
-# This hierarchy is defunct. Please remove it.
-newgroup:*:courts.*:mail
-rmgroup:*:courts.*:doit
-
-## CPCUIIA (Chartered Prop. Casulty Underwriter/Insurance Institute of America)
-# Contact: miller@cpcuiia.org
-# URL: http://www.aicpcu.org/
-checkgroups:miller@cpcuiia.org:cpcuiia.*:doit
-newgroup:miller@cpcuiia.org:cpcuiia.*:doit
-rmgroup:miller@cpcuiia.org:cpcuiia.*:doit
-
-## CU (*LOCAL* -- University of Colorado)
-# Contact: Doreen Petersen <news@colorado.edu>
-# For local use only, contact the above address for information.
-newgroup:*:cu.*:mail
-rmgroup:*:cu.*:doit
-
-## CUHK (*LOCAL* -- Chinese University of Hong Kong)
-# Contact: shlam@ie.cuhk.edu.hk (Alan S H Lam)
-# For local use only, contact the above address for information.
-newgroup:*:cuhk.*:mail
-rmgroup:*:cuhk.*:doit
-
-## CZ (Czech Republic)
-# URL: ftp://ftp.vslib.cz/pub/news/config/cz/newsgroups (text)
-checkgroups:petr.kolar@vslib.cz:cz.*:doit
-newgroup:petr.kolar@vslib.cz:cz.*:doit
-rmgroup:petr.kolar@vslib.cz:cz.*:doit
-
-## DC (Washington, D.C., USA)
-checkgroups:news@mattress.atww.org:dc.*:doit
-newgroup:news@mattress.atww.org:dc.*:doit
-rmgroup:news@mattress.atww.org:dc.*:doit
-
-## DE (German language)
-# Contact: moderator@dana.de
-# URL: http://www.dana.de/mod/
-# Admin group: de.admin.news.announce
-# Key URL: http://www.dana.de/mod/pgp/dana.asc
-# Key fingerprint = 5B B0 52 88 BF 55 19 4F 66 7D C2 AE 16 26 28 25
-# *PGP* See comment at top of file.
-newgroup:*:de.*:drop
-rmgroup:*:de.*:drop
-checkgroups:moderator@dana.de:de.*:verify-de.admin.news.announce
-newgroup:moderator@dana.de:de.*:verify-de.admin.news.announce
-rmgroup:moderator@dana.de:de.*:verify-de.admin.news.announce
-
-## DE.ALT (German language alternative hierarchy)
-# *PGP* See comment at top of file.
-newgroup:*:de.alt.*:doit
-rmgroup:moderator@dana.de:de.alt.*:verify-de.admin.news.announce
-
-## DFW (Dallas/Fort Worth, Texas, USA)
-# URL: http://www.cirr.com/dfw/
-# Admin group: dfw.usenet.config
-checkgroups:eric@*cirr.com:dfw.*:doit
-newgroup:eric@*cirr.com:dfw.*:doit
-rmgroup:eric@*cirr.com:dfw.*:doit
-
-## DK (Denmark)
-# URL: http://www.usenet.dk/dk-admin/
-# Key URL: http://www.usenet.dk/dk-admin/pubkey.html
-# Key fingerprint = 7C B2 C7 50 F3 7D 5D 73 8C EE 2E 3F 55 80 72 FF
-# *PGP* See comment at top of file.
-newgroup:*:dk.*:drop
-rmgroup:*:dk.*:drop
-checkgroups:news@news.dknet.dk:dk.*:verify-news@news.dknet.dk
-newgroup:news@news.dknet.dk:dk.*:verify-news@news.dknet.dk
-rmgroup:news@news.dknet.dk:dk.*:verify-news@news.dknet.dk
-
-## DUKE (*LOCAL* -- Duke University, USA)
-# Contact: news@newsgate.duke.edu
-# For local use only, contact the above address for information.
-newgroup:*:duke.*:mail
-rmgroup:*:duke.*:doit
-
-## EASYNET (Easynet PLC, UK)
-# Contact: Christiaan Keet <newsmaster@easynet.net>
-# Admin group: easynet.support
-# *PGP* See comment at top of file.
-newgroup:*:easynet.*:drop
-rmgroup:*:easynet.*:drop
-checkgroups:newsmaster@easynet.net:easynet.*:verify-easynet.news
-newgroup:newsmaster@easynet.net:easynet.*:verify-easynet.news
-rmgroup:newsmaster@easynet.net:easynet.*:verify-easynet.news
-
-## EE (Estonia)
-# Contact: usenet@news.ut.ee
-# URL: http://news.ut.ee/
-# Key URL: http://news.ut.ee/pubkey.asc
-# *PGP* See comment at top of file.
-newgroup:*:ee.*:drop
-rmgroup:*:ee.*:drop
-checkgroups:news@news.ut.ee:ee.*:verify-ee.news
-newgroup:news@news.ut.ee:ee.*:verify-ee.news
-rmgroup:news@news.ut.ee:ee.*:verify-ee.news
-
-## EFN & EUG (Eugene Free Computer Network, Eugene/Springfield, Oregon, USA)
-# Admin group: eug.config
-# *PGP* See comment at top of file.
-newgroup:*:efn.*|eug.*:drop
-rmgroup:*:efn.*|eug.*:drop
-checkgroups:newsadmin@efn.org:efn.*|eug.*:verify-eug.config
-newgroup:newsadmin@efn.org:efn.*|eug.*:verify-eug.config
-rmgroup:newsadmin@efn.org:efn.*|eug.*:verify-eug.config
-
-## EHIME-U (? University, Japan ?)
-checkgroups:news@cc.nias.ac.jp:ehime-u.*:doit
-checkgroups:news@doc.dpc.ehime-u.ac.jp:ehime-u.*:doit
-newgroup:news@cc.nias.ac.jp:ehime-u.*:doit
-newgroup:news@doc.dpc.ehime-u.ac.jp:ehime-u.*:doit
-rmgroup:news@cc.nias.ac.jp:ehime-u.*:doit
-rmgroup:news@doc.dpc.ehime-u.ac.jp:ehime-u.*:doit
-
-## ENGLAND (England)
-# Contact: admin@england.news-admin.org
-# Admin group: england.news.policy
-# Key fingerprint = DA 3E C2 01 46 E5 61 CB A2 43 09 CA 13 6D 31 1F
-# *PGP* See comment at top of file.
-newgroup:*:england.*:drop
-rmgroup:*:england.*:drop
-checkgroups:admin@england.news-admin.org:england.*:verify-england-usenet
-newgroup:admin@england.news-admin.org:england.*:verify-england-usenet
-rmgroup:admin@england.news-admin.org:england.*:verify-england-usenet
-
-## ES (Spain)
-# Contact: moderador@corus-es.org
-# URL: http://www.corus-es.org/docs/es_newsadmins_faq.txt
-# Admin group: es.news.anuncios
-# Key URL: http://www.corus-es.org/docs/esnews.asc
-# *PGP* See comment at top of file.
-newgroup:*:es.*:drop
-rmgroup:*:es.*:drop
-checkgroups:moderador@corus-es.org:es.*:verify-es.news
-newgroup:moderador@corus-es.org:es.*:verify-es.news
-rmgroup:moderador@corus-es.org:es.*:verify-es.news
-
-## ESP (Spanish-language newsgroups)
-# Contact: <mod-ena@ennui.org>
-# URL: http://ennui.org/esp/
-# Key URL: http://ennui.org/esp/mod-ena.asc
-# *PGP* See comment at top of file.
-newgroup:*:esp.*:drop
-rmgroup:*:esp.*:drop
-checkgroups:mod-ena@ennui.org:esp.*:verify-esp.news.administracion
-newgroup:mod-ena@ennui.org:esp.*:verify-esp.news.administracion
-rmgroup:mod-ena@ennui.org:esp.*:verify-esp.news.administracion
-
-## EUNET (Europe)
-checkgroups:news@noc.eu.net:eunet.*:doit
-newgroup:news@noc.eu.net:eunet.*:doit
-rmgroup:news@noc.eu.net:eunet.*:doit
-
-## EUROPA (Europe)
-# URL: http://www.europa.usenet.eu.org/
-# Admin group: europa.usenet.admin
-# Key URL: http://www.europa.usenet.eu.org/pgp/index.html
-# Key fingerprint = 3A 05 A8 49 FB 16 29 25 75 E3 DE BB 69 E0 1D B4
-# *PGP* See comment at top of file.
-newgroup:*:europa.*:drop
-rmgroup:*:europa.*:drop
-checkgroups:group-admin@usenet.eu.org:europa.*:verify-group-admin@usenet.eu.org
-newgroup:group-admin@usenet.eu.org:europa.*:verify-group-admin@usenet.eu.org
-rmgroup:group-admin@usenet.eu.org:europa.*:verify-group-admin@usenet.eu.org
-
-## EXAMPLE (Bogus hierarchy reserved for standards documents)
-newgroup:*:example.*:mail
-rmgroup:*:example.*:doit
-
-## FA (Gated mailing lists)
-# This hierarchy was removed in the "Great Renaming" of 1988.
-#
-# A site in Norway is currently (as of 2002) gatewaying various mailing
-# lists into fa.* newsgroups, but that site does not appear to be issuing
-# any control messages for those groups.
-#
-newgroup:*:fa.*:mail
-rmgroup:*:fa.*:doit
-
-## FFM (Frankfurt/M., Germany)
-# URL: http://ffm.arcornews.de/
-# Key URL: ftp://ftp.arcor-online.net/pub/news/PGPKEY.FFM
-# *PGP* See comment at top of file.
-newgroup:*:ffm.*:drop
-rmgroup:*:ffm.*:drop
-checkgroups:ffm.admin@arcor.de:ffm.*:verify-ffm.admin
-newgroup:ffm.admin@arcor.de:ffm.*:verify-ffm.admin
-rmgroup:ffm.admin@arcor.de:ffm.*:verify-ffm.admin
-
-## FIDO (FidoNet)
-checkgroups:root@mbh.org:fido.*:doit
-newgroup:root@mbh.org:fido.*:doit
-rmgroup:root@mbh.org:fido.*:doit
-
-## FIDO.BELG (Belgian FidoNet)
-# Admin group: fido.belg.news
-# *PGP* See comment at top of file.
-newgroup:*:fido.belg.*:drop
-rmgroup:*:fido.belg.*:drop
-checkgroups:fidobelg@mail.z2.fidonet.org:fido.belg.*:verify-fido.belg.news
-newgroup:fidobelg@mail.z2.fidonet.org:fido.belg.*:verify-fido.belg.news
-rmgroup:fidobelg@mail.z2.fidonet.org:fido.belg.*:verify-fido.belg.news
-
-## FIDO.GER (German FIDO Net Echos)
-# URL: ftp://ftp.fu-berlin.de/doc/news/fido.ger/fido.ger-info.english
-# Key URL: ftp://ftp.fu-berlin.de/doc/news/fido.ger/PGP-Key
-# *PGP* See comment at top of file.
-newgroup:*:fido.ger.*:drop
-rmgroup:*:fido.ger.*:drop
-checkgroups:fido.ger@news.fu-berlin.de:fido.ger.*:verify-fido.ger@news.fu-berlin.de
-newgroup:fido.ger@news.fu-berlin.de:fido.ger.*:verify-fido.ger@news.fu-berlin.de
-rmgroup:fido.ger@news.fu-berlin.de:fido.ger.*:verify-fido.ger@news.fu-berlin.de
-
-## FIDO7 (Russian FidoNet)
-# URL: http://www.fido7.ru/
-# Admin group: fido7.postmasters
-# Key URL: http://www.fido7.ru/pgpcontrol.html
-# *PGP* See comment at top of file.
-newgroup:*:fido7.*:drop
-rmgroup:*:fido7.*:drop
-checkgroups:newgroups-request@fido7.ru:fido7.*:verify-fido7.announce.newgroups
-newgroup:newgroups-request@fido7.ru:fido7.*:verify-fido7.announce.newgroups
-rmgroup:newgroups-request@fido7.ru:fido7.*:verify-fido7.announce.newgroups
-
-## FINET (Finland and Finnish language alternative newsgroups)
-checkgroups:*@*.fi:finet.*:doit
-newgroup:*@*.fi:finet.*:doit
-rmgroup:*@*.fi:finet.*:doit
-
-## FJ (Japan and Japanese language)
-# Contact: committee@fj-news.org
-# URL: http://www.fj-news.org/index.html.en
-# Admin group: fj.news.announce
-# Key URL: http://www.is.tsukuba.ac.jp/~yas/fj/fj.asc
-# *PGP* See comment at top of file.
-newgroup:*:fj.*:drop
-rmgroup:*:fj.*:drop
-checkgroups:committee@fj-news.org:fj.*:verify-fj.news.announce
-newgroup:committee@fj-news.org:fj.*:verify-fj.news.announce
-rmgroup:committee@fj-news.org:fj.*:verify-fj.news.announce
-
-## FL (Florida, USA)
-checkgroups:hgoldste@news1.mpcs.com:fl.*:doit
-checkgroups:scheidell@fdma.fdma.com:fl.*:doit
-newgroup:hgoldste@news1.mpcs.com:fl.*:doit
-newgroup:scheidell@fdma.fdma.com:fl.*:doit
-rmgroup:hgoldste@news1.mpcs.com:fl.*:doit
-rmgroup:scheidell@fdma.fdma.com:fl.*:doit
-
-## FLORA (FLORA Community WEB, Canada)
-# Contact: russell@flora.org
-# Admin group: flora.general
-# *PGP* See comment at top of file.
-newgroup:*:flora.*:drop
-rmgroup:*:flora.*:drop
-checkgroups:news@flora.ottawa.on.ca:flora.*:verify-flora-news
-newgroup:news@flora.ottawa.on.ca:flora.*:verify-flora-news
-rmgroup:news@flora.ottawa.on.ca:flora.*:verify-flora-news
-
-## FR (French language)
-# URL: http://www.usenet-fr.news.eu.org/
-# Admin group: fr.usenet.forums.annonces
-# Key URL: http://www.usenet-fr.news.eu.org/fur/usenet/presentation-fr.html
-# *PGP* See comment at top of file.
-newgroup:*:fr.*:drop
-rmgroup:*:fr.*:drop
-checkgroups:control@usenet-fr.news.eu.org:fr.*:verify-control@usenet-fr.news.eu.org
-newgroup:control@usenet-fr.news.eu.org:fr.*:verify-control@usenet-fr.news.eu.org
-rmgroup:control@usenet-fr.news.eu.org:fr.*:verify-control@usenet-fr.news.eu.org
-
-## FRANCE (France)
-# Contact: control@usenet-france.news.eu.org
-# Admin group: france.admin.evolutions
-# *PGP* See comment at top of file.
-newgroup:*:france.*:drop
-rmgroup:*:france.*:drop
-checkgroups:control@usenet-france.news.eu.org:france.*:verify-control@usenet-france.news.eu.org
-newgroup:control@usenet-france.news.eu.org:france.*:verify-control@usenet-france.news.eu.org
-rmgroup:control@usenet-france.news.eu.org:france.*:verify-control@usenet-france.news.eu.org
-
-## FREE (Open Hierarchy where anyone can create a group)
-newgroup:*:free.*:doit
-newgroup:group-admin@isc.org:free.*:drop
-newgroup:tale@*uu.net:free.*:drop
-rmgroup:*:free.*:drop
-
-## FUDAI (Japanese ?)
-checkgroups:news@picard.cs.osakafu-u.ac.jp:fudai.*:doit
-newgroup:news@picard.cs.osakafu-u.ac.jp:fudai.*:doit
-rmgroup:news@picard.cs.osakafu-u.ac.jp:fudai.*:doit
-
-## FUR (*PRIVATE* -- furrynet)
-# Contact: fur-config@news.furry.net
-# For private use only, contact the above address for information.
-newgroup:*:fur.*:mail
-rmgroup:*:fur.*:doit
-
-## GER & HANNET & HANNOVER & HILDESHEIM & HISS (Hannover, Germany)
-checkgroups:fifi@hiss.han.de:ger.*|hannover.*|hannet.*|hildesheim.*|hiss.*:doit
-newgroup:fifi@hiss.han.de:ger.*|hannover.*|hannet.*|hildesheim.*|hiss.*:doit
-rmgroup:fifi@hiss.han.de:ger.*|hannover.*|hannet.*|hildesheim.*|hiss.*:doit
-
-## GIT (Georgia Institute of Technology, USA)
-newgroup:news@news.gatech.edu:git.*:doit
-newgroup:news@news.gatech.edu:git*class.*:mail
-rmgroup:news@news.gatech.edu:git.*:doit
-
-## GNU (Free Software Foundation)
-# URL: http://www.gnu.org/usenet/usenet.html
-# Admin group: gnu.gnusenet.config
-# Key URL: http://www.gnu.org/usenet/usenet-pgp-key.txt
-# *PGP* See comment at top of file.
-newgroup:*:gnu.*:drop
-rmgroup:*:gnu.*:drop
-checkgroups:usenet@gnu.org:gnu.*:verify-usenet@gnu.org
-newgroup:usenet@gnu.org:gnu.*:verify-usenet@gnu.org
-rmgroup:usenet@gnu.org:gnu.*:verify-usenet@gnu.org
-
-## GNUU (*PRIVATE* -- GNUU e.V., Oberursel, Germany)
-# Contact: news@gnuu.de
-# For private use only, contact the above address for information.
-newgroup:*:gnuu.*:mail
-rmgroup:*:gnuu.*:doit
-
-## GOV (Government Information)
-# Admin group: gov.usenet.announce
-# *PGP* See comment at top of file.
-newgroup:*:gov.*:drop
-rmgroup:*:gov.*:drop
-checkgroups:gov-usenet-announce-moderator@govnews.org:gov.*:verify-gov.usenet.announce
-newgroup:gov-usenet-announce-moderator@govnews.org:gov.*:verify-gov.usenet.announce
-rmgroup:gov-usenet-announce-moderator@govnews.org:gov.*:verify-gov.usenet.announce
-
-## GWU (George Washington University, Washington, DC)
-# Contact: Sweth Chandramouli <news@nit.gwu.edu>
-checkgroups:news@nit.gwu.edu:gwu.*:doit
-newgroup:news@nit.gwu.edu:gwu.*:doit
-rmgroup:news@nit.gwu.edu:gwu.*:doit
-
-## HAMBURG (City of Hamburg, Germany)
-# Contact: hamburg@steering-group.net
-# URL: http://www.steering-group.net/hamburg/
-# Admin group: hamburg.koordination
-# Key URL: http://www.steering-group.net/hamburg/hamburg.koordination.txt
-# Key fingerprint = 3E E7 0C BB 6E 01 94 EE 45 6F C5 57 F4 B9 54 8E
-# *PGP* See comment at top of file.
-newgroup:*:hamburg.*:drop
-rmgroup:*:hamburg.*:drop
-checkgroups:hamburg@steering-group.net:hamburg.*:verify-hamburg.koordination
-newgroup:hamburg@steering-group.net:hamburg.*:verify-hamburg.koordination
-rmgroup:hamburg@steering-group.net:hamburg.*:verify-hamburg.koordination
-
-## HAMILTON (Canadian)
-checkgroups:news@*dcss.mcmaster.ca:hamilton.*:doit
-newgroup:news@*dcss.mcmaster.ca:hamilton.*:doit
-rmgroup:news@*dcss.mcmaster.ca:hamilton.*:doit
-
-## HAMSTER (Hamster, a Win32 news and mail proxy server)
-# Contact: hamster-contact@snafu.de
-# Admin group: hamster.de.config
-# Key fingerprint = 12 75 A9 42 8A D6 1F 77 6A CF B4 0C 79 15 5F 93
-# *PGP* See comment at top of file.
-newgroup:*:hamster.*:drop
-rmgroup:*:hamster.*:drop
-checkgroups:hamster-control@snafu.de:hamster.*:verify-hamster-control@snafu.de
-newgroup:hamster-control@snafu.de:hamster.*:verify-hamster-control@snafu.de
-rmgroup:hamster-control@snafu.de:hamster.*:verify-hamster-control@snafu.de
-
-## HAN (Korean Hangul)
-# Contact: newgroups-request@usenet.or.kr
-# Admin group: han.news.admin
-# Key URL: ftp://ftp.usenet.or.kr/pub/korea/usenet/pgp/PGPKEY.han
-# *PGP* See comment at top of file.
-newgroup:*:han.*:drop
-rmgroup:*:han.*:drop
-checkgroups:newgroups-request@usenet.or.kr:han.*:verify-han.news.admin
-newgroup:newgroups-request@usenet.or.kr:han.*:verify-han.news.admin
-rmgroup:newgroups-request@usenet.or.kr:han.*:verify-han.news.admin
-
-## HARVARD (*LOCAL* -- Harvard University, Cambridge, MA)
-# For local use only.
-newgroup:*@*.harvard.edu:harvard.*:mail
-rmgroup:*@*.harvard.edu:harvard.*:doit
-
-## HAWAII (Hawaii, USA)
-checkgroups:news@lava.net:hawaii.*:doit
-newgroup:news@lava.net:hawaii.*:doit
-rmgroup:news@lava.net:hawaii.*:doit
-
-## HFX (Halifax, Nova Scotia)
-checkgroups:stevemackie@gmail.com:hfx.*:doit
-newgroup:stevemackie@gmail.com:hfx.*:doit
-rmgroup:stevemackie@gmail.com:hfx.*:doit
-
-## HIV (HIVNET Foundation, for HIV+/AIDS information)
-# Contact: news@hivnet.org
-# Admin group: hiv.config
-# Key fingerprint = 5D D6 0E DC 1E 2D EA 0B B0 56 4D D6 52 53 D7 A4
-# *PGP* See comment at top of file.
-newgroup:*:hiv.*:drop
-rmgroup:*:hiv.*:drop
-checkgroups:news@hivnet.org:hiv.*:verify-news@hivnet.org
-newgroup:news@hivnet.org:hiv.*:verify-news@hivnet.org
-rmgroup:news@hivnet.org:hiv.*:verify-news@hivnet.org
-
-## HK (Hong Kong)
-checkgroups:hknews@comp.hkbu.edu.hk:hk.*:doit
-newgroup:hknews@comp.hkbu.edu.hk:hk.*:doit
-rmgroup:hknews@comp.hkbu.edu.hk:hk.*:doit
-
-## HOUSTON (Houston, Texas, USA)
-# Admin group: houston.usenet.config
-# *PGP* See comment at top of file.
-newgroup:*:houston.*:drop
-rmgroup:*:houston.*:drop
-checkgroups:news@academ.com:houston.*:verify-houston.usenet.config
-newgroup:news@academ.com:houston.*:verify-houston.usenet.config
-rmgroup:news@academ.com:houston.*:verify-houston.usenet.config
-
-## HR (Croatian language)
-# Contact: newsmaster@carnet.hr
-# URL: http://newsfeed.carnet.hr/control/
-# Admin group: hr.news.admin
-# Key URL: http://newsfeed.carnet.hr/control/key.txt
-# Key fingerprint = 0EE5 74FB 1C40 7ADB 0AAC A52F 7192 1BA3 ED63 AD9A
-# Syncable server: news.carnet.hr
-# *PGP* See comment at top of file.
-newgroup:*:hr.*:drop
-rmgroup:*:hr.*:drop
-checkgroups:newsmaster@carnet.hr:hr.*:verify-newsmaster@carnet.hr
-newgroup:newsmaster@carnet.hr:hr.*:verify-newsmaster@carnet.hr
-rmgroup:newsmaster@carnet.hr:hr.*:verify-newsmaster@carnet.hr
-
-## HUMANITYQUEST (Humanities discussion)
-# Contact: news-admin@humanityquest.com
-# URL: http://www.humanityquest.com/projects/newsgroups/
-# Key URL: http://www.humanityquest.com/projects/newsgroups/PGP.htm
-# Key fingerprint = BA3D B306 B6F5 52AA BA8F 32F0 8C4F 5040 16F9 C046
-# *PGP* See comment at top of file.
-newgroup:*:humanityquest.*:drop
-rmgroup:*:humanityquest.*:drop
-checkgroups:news-admin@humanityquest.com:humanityquest.*:verify-humanityquest.admin.config
-newgroup:news-admin@humanityquest.com:humanityquest.*:verify-humanityquest.admin.config
-rmgroup:news-admin@humanityquest.com:humanityquest.*:verify-humanityquest.admin.config
-
-## HUN (Hungary)
-# URL: http://www.sztaki.hu/~kissg/news/hiteles.html
-# Admin group: hun.admin.news
-# Key URL: http://gatling.ikk.sztaki.hu/~kissg/news/hun.admin.news.asc
-# *PGP* See comment at top of file.
-newgroup:*:hun.*:drop
-rmgroup:*:hun.*:drop
-checkgroups:hun-mnt@news.sztaki.hu:hun.*:verify-hun.admin.news
-newgroup:hun-mnt@news.sztaki.hu:hun.*:verify-hun.admin.news
-rmgroup:hun-mnt@news.sztaki.hu:hun.*:verify-hun.admin.news
-
-## IA (Iowa, USA)
-checkgroups:skunz@iastate.edu:ia.*:doit
-newgroup:skunz@iastate.edu:ia.*:doit
-rmgroup:skunz@iastate.edu:ia.*:doit
-
-## IBMNET (*LOCAL* -- ?)
-# Contact: news@ibm.net
-# For local use only, contact the above address for information.
-newgroup:*:ibmnet.*:mail
-rmgroup:*:ibmnet.*:doit
-
-## ICONZ (*LOCAL* -- The Internet Company of New Zealand, New Zealand)
-# Contact: usenet@iconz.co.nz
-# For local use only, contact the above address for information.
-newgroup:*:iconz.*:mail
-rmgroup:*:iconz.*:doit
-
-## IDOCTRA (Idoctra Translation Software, Translation Discussion)
-# Contact: support@idoctra.com
-checkgroups:support@idoctra.com:idoctra.*:doit
-newgroup:support@idoctra.com:idoctra.*:doit
-rmgroup:support@idoctra.com:idoctra.*:doit
-
-## IE (Ireland)
-# Contact: control@usenet.ie
-# Admin group: ie.news.group
-# *PGP* See comment at top of file.
-newgroup:*:ie.*:drop
-rmgroup:*:ie.*:drop
-checkgroups:control@usenet.ie:ie.*:verify-control@usenet.ie
-newgroup:control@usenet.ie:ie.*:verify-control@usenet.ie
-rmgroup:control@usenet.ie:ie.*:verify-control@usenet.ie
-
-## IEEE (*DEFUNCT* -- Institute of Electrical and Electronic Engineers)
-# Contact: postoffice@ieee.org
-# This hierarchy is defunct. Please remove it.
-newgroup:*:ieee.*:mail
-rmgroup:*:ieee.*:doit
-
-## INFO (Gatewayed mailing lists)
-checkgroups:rjoyner@uiuc.edu:info.*:doit
-newgroup:rjoyner@uiuc.edu:info.*:doit
-rmgroup:rjoyner@uiuc.edu:info.*:doit
-
-## IS (Iceland)
-# Contact: IS Group Admins <group-admin@usenet.is>
-# URL: http://www.usenet.is/
-# Admin group: is.isnet
-# Key URL: http://www.usenet.is/group-admin.asc
-# Key fingerprint = 33 32 8D 46 1E 5E 1C 7F 48 60 8E 72 E5 3E CA EA
-# *PGP* See comment at top of file.
-newgroup:*:is.*:drop
-rmgroup:*:is.*:drop
-checkgroups:group-admin@usenet.is:is.*:verify-group-admin@usenet.is
-newgroup:group-admin@usenet.is:is.*:verify-group-admin@usenet.is
-rmgroup:group-admin@usenet.is:is.*:verify-group-admin@usenet.is
-
-## ISC (Japanese ?)
-checkgroups:news@sally.isc.chubu.ac.jp:isc.*:doit
-newgroup:news@sally.isc.chubu.ac.jp:isc.*:doit
-rmgroup:news@sally.isc.chubu.ac.jp:isc.*:doit
-
-## ISRAEL & IL (Israel)
-newgroup:news@news.biu.ac.il:israel.*:doit
-rmgroup:news@news.biu.ac.il:israel.*|il.*:doit
-
-## ISU (I-Shou University, Taiwan)
-# Contact: news@news.isu.edu.tw
-# URL: http://news.isu.edu.tw/
-# Admin group: isu.newgroups
-# Key URL: http://news.isu.edu.tw/isu.asc
-# *PGP* See comment at top of file.
-newgroup:*:isu.*:drop
-rmgroup:*:isu.*:drop
-checkgroups:news@news.isu.edu.tw:isu.*:verify-news@news.isu.edu.tw
-newgroup:news@news.isu.edu.tw:isu.*:verify-news@news.isu.edu.tw
-rmgroup:news@news.isu.edu.tw:isu.*:verify-news@news.isu.edu.tw
-
-## IT (Italian)
-# Contact: gcn@news.nic.it
-# URL: http://www.news.nic.it/
-# Admin group: it.news.annunci
-# Key URL: http://www.news.nic.it/pgp.txt
-# Key fingerprint = 94 A4 F7 B5 46 96 D6 C7 A6 73 F2 98 C4 8C D0 E0
-# *PGP* See comment at top of file.
-newgroup:*:it.*:drop
-rmgroup:*:it.*:drop
-checkgroups:gcn@news.nic.it:it.*:verify-gcn@news.nic.it
-newgroup:gcn@news.nic.it:it.*:verify-gcn@news.nic.it
-rmgroup:gcn@news.nic.it:it.*:verify-gcn@news.nic.it
-
-## IT-ALT (Alternate Italian)
-#
-# There is no one official control message issuer for the it-alt.*
-# hierarchy, so this file doesn't choose any particular one. Several
-# different people issue control messages for this hierarchy, which may
-# or may not agree, and sites carrying this hierarchy are encouraged to
-# pick one and add it below.
-#
-# Newgroup and removal requests are to be posted to it-alt.config. A list
-# of people issuing PGP/GPG signed control messages is available in a
-# periodic posting to news.admin.hierarchies and it-alt.config.
-#
-newgroup:*:it-alt.*:drop
-rmgroup:*:it-alt.*:drop
-
-## ITALIA (Italy)
-# Contact: news@news.cineca.it
-# URL: http://news.cineca.it/italia/
-# Admin group: italia.announce.newgroups
-# Key URL: http://news.cineca.it/italia/italia-pgp.txt
-# Key fingerprint = 0F BB 71 62 DA 5D 5D B8 D5 86 FC 28 02 67 1A 6B
-# *PGP* See comment at top of file.
-newgroup:*:italia.*:drop
-rmgroup:*:italia.*:drop
-checkgroups:news@news.cineca.it:italia.*:verify-italia.announce.newgroups
-newgroup:news@news.cineca.it:italia.*:verify-italia.announce.newgroups
-rmgroup:news@news.cineca.it:italia.*:verify-italia.announce.newgroups
-
-## IU (Indiana University)
-newgroup:news@usenet.ucs.indiana.edu:iu.*:doit
-newgroup:root@usenet.ucs.indiana.edu:iu.*:doit
-newgroup:*@usenet.ucs.indiana.edu:iu*class.*:mail
-rmgroup:news@usenet.ucs.indiana.edu:iu.*:doit
-rmgroup:root@usenet.ucs.indiana.edu:iu.*:doit
-
-## JAPAN (Japan)
-# Contact: Tsuneo Tanaka <tt+null@efnet.com>
-# URL: http://www.asahi-net.or.jp/~AE5T-KSN/japan-e.html
-# Admin group: japan.admin.announce
-# Key URL: http://grex.cyberspace.org/~tt/japan.admin.announce.asc
-# Key fingerprint = 6A FA 19 47 69 1B 10 74 38 53 4B 1B D8 BA 3E 85
-# *PGP* See comment at top of file.
-newgroup:*:japan.*:drop
-rmgroup:*:japan.*:drop
-checkgroups:japan.admin.announce@news.efnet.com:japan.*:verify-japan.admin.announce@news.efnet.com
-newgroup:japan.admin.announce@news.efnet.com:japan.*:verify-japan.admin.announce@news.efnet.com
-rmgroup:japan.admin.announce@news.efnet.com:japan.*:verify-japan.admin.announce@news.efnet.com
-
-## JLUG (Japan Linux Users Group)
-# Contact: news@linux.or.jp
-# URL: http://www.linux.or.jp/community/news/index.html
-# Admin group: jlug.config
-# Key URL: http://www.linux.or.jp/pgpkey/news
-# *PGP* See comment at top of file.
-newgroup:*:jlug.*:drop
-rmgroup:*:jlug.*:drop
-checkgroups:news@linux.or.jp:jlug.*:verify-news@linux.or.jp
-newgroup:news@linux.or.jp:jlug.*:verify-news@linux.or.jp
-rmgroup:news@linux.or.jp:jlug.*:verify-news@linux.or.jp
-
-## K12 (US Educational Network)
-# URL: http://www.k12groups.org/
-checkgroups:braultr@*csmanoirs.qc.ca:k12.*:doit
-newgroup:braultr@*csmanoirs.qc.ca:k12.*:doit
-rmgroup:braultr@*csmanoirs.qc.ca:k12.*:doit
-
-## KA (*PRIVATE* -- Karlsruhe, Germany)
-# Contact: usenet@karlsruhe.org
-# URL: http://www.karlsruhe.org/
-# Key URL: http://www.karlsruhe.org/pubkey-news.karlsruhe.org.asc
-# Key fingerprint = DE 19 BB 25 76 19 81 17 F0 67 D2 23 E8 C8 7C 90
-# For private use only, contact the above address for information.
-# *PGP* See comment at top of file.
-newgroup:*:ka.*:drop
-rmgroup:*:ka.*:drop
-# The following three lines are only for authorized ka.* sites.
-#checkgroups:usenet@karlsruhe.org:ka.*:verify-usenet@karlsruhe.org
-#newgroup:usenet@karlsruhe.org:ka.*:verify-usenet@karlsruhe.org
-#rmgroup:usenet@karlsruhe.org:ka.*:verify-usenet@karlsruhe.org
-
-## KANTO (?)
-# *PGP* See comment at top of file.
-rmgroup:*:kanto.*:drop
-checkgroups:ty@kamoi.imasy.or.jp:kanto.*:verify-kanto.news.network
-# NOTE: newgroups aren't verified...
-newgroup:*@*.jp:kanto.*:doit
-rmgroup:ty@kamoi.imasy.or.jp:kanto.*:verify-kanto.news.network
-
-## KASSEL (Kassel, Germany)
-# *PGP* See comment at top of file.
-newgroup:*:kassel.*:drop
-rmgroup:*:kassel.*:drop
-checkgroups:dirk.meyer@dinoex.sub.org:kassel.*:verify-kassel-admin
-newgroup:dirk.meyer@dinoex.sub.org:kassel.*:verify-kassel-admin
-rmgroup:dirk.meyer@dinoex.sub.org:kassel.*:verify-kassel-admin
-
-## KC (Kansas City, Kansas/Missouri, USA)
-checkgroups:dan@sky.net:kc.*:doit
-newgroup:dan@sky.net:kc.*:doit
-rmgroup:dan@sky.net:kc.*:doit
-
-## KGK (Administered by KGK, Japan)
-# Contact: Keiji KOSAKA <kgk@film.rlss.okayama-u.ac.jp>
-# URL: http://film.rlss.okayama-u.ac.jp/~kgk/kgk/index.html
-# Admin group: kgk.admin
-checkgroups:usenet@film.rlss.okayama-u.ac.jp:kgk.*:doit
-newgroup:usenet@film.rlss.okayama-u.ac.jp:kgk.*:doit
-rmgroup:usenet@film.rlss.okayama-u.ac.jp:kgk.*:doit
-
-## KIEL (Kiel, Germany)
-# URL: http://news.koehntopp.de/kiel/
-checkgroups:kris@koehntopp.de:kiel.*:doit
-newgroup:kris@koehntopp.de:kiel.*:doit
-rmgroup:kris@koehntopp.de:kiel.*:doit
-
-## KRST (*LOCAL* -- University of Oslo, Norway)
-# Contact: jani@ifi.uio.no
-# For local use only, contact the above address for information.
-newgroup:*:krst.*:mail
-rmgroup:*:krst.*:doit
-
-## KWNET (*LOCAL* -- Kitchener-Waterloo?)
-# Contact: Ed Hew <edhew@xenitec.on.ca>
-# For local use only, contact the above address for information.
-newgroup:*:kwnet.*:mail
-rmgroup:*:kwnet.*:doit
-
-## LAW (?)
-# Contact: Jim Burke <jburke@kentlaw.edu>
-checkgroups:*@*.kentlaw.edu:law.*:doit
-checkgroups:*@*.law.vill.edu:law.*:doit
-newgroup:*@*.kentlaw.edu:law.*:doit
-newgroup:*@*.law.vill.edu:law.*:doit
-rmgroup:*@*.kentlaw.edu:law.*:doit
-rmgroup:*@*.law.vill.edu:law.*:doit
-
-## LINUX (Gated Linux mailing lists)
-# Contact: Marco d'Itri <md@linux.it>
-# Admin group: linux.admin.news
-# Key fingerprint = 81 B3 27 99 4F CE 32 D1 1B C9 01 0D BB B3 2E 41
-# *PGP* See comment at top of file.
-newgroup:*:linux.*:drop
-rmgroup:*:linux.*:drop
-checkgroups:linux-admin@bofh.it:linux.*:verify-linux-admin@bofh.it
-newgroup:linux-admin@bofh.it:linux.*:verify-linux-admin@bofh.it
-rmgroup:linux-admin@bofh.it:linux.*:verify-linux-admin@bofh.it
-
-## LOCAL (Local-only groups)
-# It is not really a good idea for sites to use these since they may occur
-# on many unconnected sites.
-newgroup:*:local.*:mail
-rmgroup:*:local.*:drop
-
-## LUEBECK (Luebeck, Germany)
-# Contact: usenet@zybrkat.org
-# Admin group: luebeck.admin
-checkgroups:usenet@zybrkat.org:luebeck.*:doit
-newgroup:usenet@zybrkat.org:luebeck.*:doit
-rmgroup:usenet@zybrkat.org:luebeck.*:doit
-
-## MALTA (Nation of Malta)
-# Contact: cmeli@cis.um.edu.mt
-# URL: http://www.malta.news-admin.org/
-# Admin group: malta.config
-# Key URL: http://www.cis.um.edu.mt/news-malta/PGP.PUBLICKEY
-# Key fingerprint = 20 17 01 5C F0 D0 1A 42 E4 13 30 58 0B 14 48 A6
-# *PGP* See comment at top of file.
-newgroup:*:malta.*:drop
-rmgroup:*:malta.*:drop
-checkgroups:cmeli@cis.um.edu.mt:malta.*:verify-malta.config
-newgroup:cmeli@cis.um.edu.mt:malta.*:verify-malta.config
-rmgroup:cmeli@cis.um.edu.mt:malta.*:verify-malta.config
-
-## MANAWATU (*LOCAL* -- Manawatu district, New Zealand)
-# Contact: alan@manawatu.gen.nz or news@manawatu.gen.nz
-# For local use only, contact the above address for information.
-newgroup:*:manawatu.*:mail
-rmgroup:*:manawatu.*:doit
-
-## MAUS (MausNet, Germany)
-# Admin group: maus.info
-# Key fingerprint = 82 52 C7 70 26 B9 72 A1 37 98 55 98 3F 26 62 3E
-# *PGP* See comment at top of file.
-newgroup:*:maus.*:drop
-rmgroup:*:maus.*:drop
-checkgroups:guenter@gst0hb.hb.provi.de:maus.*:verify-maus-info
-checkgroups:guenter@gst0hb.north.de:maus.*:verify-maus-info
-newgroup:guenter@gst0hb.hb.provi.de:maus.*:verify-maus-info
-newgroup:guenter@gst0hb.north.de:maus.*:verify-maus-info
-rmgroup:guenter@gst0hb.hb.provi.de:maus.*:verify-maus-info
-rmgroup:guenter@gst0hb.north.de:maus.*:verify-maus-info
-
-## MCMASTER (*LOCAL* -- McMaster University, Ontario)
-# Contact: Brian Beckberger <news@informer1.cis.mcmaster.ca>
-# For local use only, contact the above address for information.
-newgroup:*:mcmaster.*:mail
-rmgroup:*:mcmaster.*:doit
-
-## MCOM (*LOCAL* -- Netscape Inc, USA)
-# For local use only.
-newgroup:*:mcom.*:mail
-rmgroup:*:mcom.*:doit
-
-## ME (Maine, USA)
-checkgroups:kerry@maine.maine.edu:me.*:doit
-newgroup:kerry@maine.maine.edu:me.*:doit
-rmgroup:kerry@maine.maine.edu:me.*:doit
-
-## MEDLUX (All-Russia medical teleconferences)
-# URL: ftp://ftp.medlux.ru/pub/news/medlux.grp
-checkgroups:neil@new*.medlux.ru:medlux.*:doit
-newgroup:neil@new*.medlux.ru:medlux.*:doit
-rmgroup:neil@new*.medlux.ru:medlux.*:doit
-
-## MELB (Melbourne, Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://melb.news-admin.org/
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:melb.*:drop
-rmgroup:*:melb.*:drop
-checkgroups:ausadmin@aus.news-admin.org:melb.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:melb.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:melb.*:verify-ausadmin@aus.news-admin.org
-
-## MENSA (The Mensa Organisation)
-# Contact: usenet@newsgate.mensa.org
-# Admin group: mensa.config
-# Key fingerprint = 52B9 3963 85D9 0806 8E19 7344 973C 5005 DC7D B7A7
-# *PGP* See comment at top of file.
-newgroup:*:mensa.*:drop
-rmgroup:*:mensa.*:drop
-checkgroups:usenet@newsgate.mensa.org:mensa.*:verify-mensa.config
-newgroup:usenet@newsgate.mensa.org:mensa.*:verify-mensa.config
-rmgroup:usenet@newsgate.mensa.org:mensa.*:verify-mensa.config
-
-## METOCEAN (ISP in Japan)
-checkgroups:fwataru@*.metocean.co.jp:metocean.*:doit
-newgroup:fwataru@*.metocean.co.jp:metocean.*:doit
-rmgroup:fwataru@*.metocean.co.jp:metocean.*:doit
-
-## METROPOLIS (*LOCAL* -- ?)
-# Contact: newsmaster@worldonline.nl
-# For local use only, contact the above address for information.
-newgroup:*:metropolis.*:mail
-rmgroup:*:metropolis.*:doit
-
-## MI (Michigan, USA)
-# Contact: Steve Simmons <scs@lokkur.dexter.mi.us>
-checkgroups:scs@lokkur.dexter.mi.us:mi.*:doit
-newgroup:scs@lokkur.dexter.mi.us:mi.*:doit
-rmgroup:scs@lokkur.dexter.mi.us:mi.*:doit
-
-## MICROSOFT (Microsoft Corporation, USA)
-#
-# Control articles for that hierarchy are not issued by Microsoft itself
-# but by a Usenet active participant in order to improve the quality of
-# the propagation of Microsoft newsgroups. Their official URL is:
-# http://www.microsoft.com/communities/newsgroups/list/en-us/default.aspx
-#
-# Contact: control-microsoft@trigofacile.com
-# URL: http://www.trigofacile.com/divers/usenet/clefs/index.htm
-# Admin group: microsoft.public.news.server
-# Key URL: http://www.trigofacile.com/divers/usenet/clefs/pgpkey-microsoft.asc
-# Key fingerprint = DF70 5FC9 F615 D52E 02DB A3CB 63A9 8D13 E60E 2FAA
-# Syncable server: msnews.microsoft.com
-# *PGP* See comment at top of file.
-newgroup:*:microsoft.*:drop
-rmgroup:*:microsoft.*:drop
-checkgroups:control-microsoft@trigofacile.com:microsoft.*:verify-control-microsoft@trigofacile.com
-newgroup:control-microsoft@trigofacile.com:microsoft.*:verify-control-microsoft@trigofacile.com
-rmgroup:control-microsoft@trigofacile.com:microsoft.*:verify-control-microsoft@trigofacile.com
-
-## MILW (Milwaukee, Wisconsin, USA)
-# Contact: milw@usenet.mil.wi.us
-# URL: http://usenet.mil.wi.us/
-# Admin group: milw.config
-# Key URL: http://usenet.mil.wi.us/pgpkey
-# Key fingerprint = 6E 9B 9F 70 98 AB 9C E5 C3 C0 05 82 21 5B F4 9E
-# *PGP* See comment at top of file.
-newgroup:*:milw.*:drop
-rmgroup:*:milw.*:drop
-checkgroups:milw@usenet.mil.wi.us:milw.*:verify-milw.config
-newgroup:milw@usenet.mil.wi.us:milw.*:verify-milw.config
-rmgroup:milw@usenet.mil.wi.us:milw.*:verify-milw.config
-
-## MOD (*DEFUNCT* -- Original top level moderated hierarchy)
-# This hierarchy is defunct. Please remove it.
-newgroup:*:mod.*:mail
-rmgroup:*:mod.*:doit
-
-## MUC (Munchen [Munich], Germany)
-# Admin group: muc.admin
-# Key fingerprint = 43 C7 0E 7C 45 C7 06 E0 BD 6F 76 CE 07 39 5E 66
-# *PGP* See comment at top of file.
-newgroup:*:muc.*:drop
-rmgroup:*:muc.*:drop
-checkgroups:muc-cmsg@muenchen.pro-bahn.org:muc.*:verify-muc.admin
-newgroup:muc-cmsg@muenchen.pro-bahn.org:muc.*:verify-muc.admin
-rmgroup:muc-cmsg@muenchen.pro-bahn.org:muc.*:verify-muc.admin
-
-## NAGASAKI-U (Nagasaki University, Japan ?)
-checkgroups:root@*nagasaki-u.ac.jp:nagasaki-u.*:doit
-newgroup:root@*nagasaki-u.ac.jp:nagasaki-u.*:doit
-rmgroup:root@*nagasaki-u.ac.jp:nagasaki-u.*:doit
-
-## NAS (*LOCAL* -- NAS, NASA Ames Research Center, USA)
-# Contact: news@nas.nasa.gov
-# For local use only, contact the above address for information.
-newgroup:*:nas.*:mail
-rmgroup:*:nas.*:doit
-
-## NASA (*LOCAL* -- National Aeronautics and Space Administration, USA)
-# Contact: news@nas.nasa.gov
-# For local use only, contact the above address for information.
-newgroup:*:nasa.*:mail
-rmgroup:*:nasa.*:doit
-
-## NC (North Carolina, USA)
-#
-# Tim Seaver <tas@bellsouth.net> says he hasn't had any dealings with nc.*
-# for over two years and the hierarchy is basically "open to anyone who
-# wants it."
-#
-# newgroup:tas@ncren.net:nc.*:doit
-# rmgroup:tas@ncren.net:nc.*:doit
-
-## NCF (*LOCAL* -- National Capital Freenet, Ottawa, Ontario, Canada)
-# Contact: news@freenet.carleton.ca
-# For local use only, contact the above address for information.
-newgroup:*:ncf.*:mail
-rmgroup:*:ncf.*:doit
-
-## NCTU (Taiwan)
-checkgroups:chen@cc.nctu.edu.tw:nctu.*:doit
-newgroup:chen@cc.nctu.edu.tw:nctu.*:doit
-rmgroup:chen@cc.nctu.edu.tw:nctu.*:doit
-
-## NCU (*LOCAL* -- National Central University, Taiwan)
-# Contact: Ying-Hao Chang <aqlott@db.csie.ncu.edu.tw>
-# Contact: <runn@news.ncu.edu.tw>
-# For local use only, contact the above address for information.
-newgroup:*:ncu.*:mail
-rmgroup:*:ncu.*:doit
-
-## NERSC (National Energy Research Scientific Computing Center)
-# Contact: <usenet@nersc.gov>
-# newgroup:*:nersc.*:mail
-# rmgroup:*:nersc.*:doit
-
-## NET (Usenet 2)
-#
-# This was a failed experiment in a different newsgroup creation policy and
-# administrative policy which has now been almost entirely abandoned. The
-# information is retained here for the few sites still using it, but sites
-# not already carrying the groups probably won't be interested.
-#
-# (This was also the original unmoderated Usenet hierarchy from before the
-# Great Renaming. The groups that used to be in net.* in the 1980s are now
-# in the Big Eight hierarchies.)
-#
-# URL: http://www.usenet2.org
-# Admin group: net.config
-# Key URL: http://www.usenet2.org/control@usenet2.org.asc
-# Key fingerprint = D7 D3 5C DB 18 6A 29 79 BF 74 D4 58 A3 78 9D 22
-# *PGP* See comment at top of file.
-newgroup:*:net.*:drop
-rmgroup:*:net.*:drop
-#checkgroups:control@usenet2.org:net.*:verify-control@usenet2.org
-#newgroup:control@usenet2.org:net.*:verify-control@usenet2.org
-#rmgroup:control@usenet2.org:net.*:verify-control@usenet2.org
-
-## NETINS (*LOCAL* -- netINS, Inc)
-# Contact: news@netins.net
-# For local use only, contact the above address for information.
-newgroup:*:netins.*:mail
-rmgroup:*:netins.*:doit
-
-## NETSCAPE (Netscape Communications Corp)
-# Contact: news@netscape.com
-# URL: http://www.mozilla.org/community.html
-# Admin group: netscape.public.admin
-# Key URL: http://www.mozilla.org/newsfeeds.html
-# Key fingerprint = B7 80 55 12 1F 9C 17 0B 86 66 AD 3B DB 68 35 EC
-# *PGP* See comment at top of file.
-newgroup:*:netscape.*:drop
-rmgroup:*:netscape.*:drop
-checkgroups:news@netscape.com:netscape.*:verify-netscape.public.admin
-newgroup:news@netscape.com:netscape.*:verify-netscape.public.admin
-rmgroup:news@netscape.com:netscape.*:verify-netscape.public.admin
-
-## NF (Newfoundland and Labrador, Canada)
-# Contact: randy@mun.ca
-checkgroups:randy@mun.ca:nf.*:doit
-newgroup:randy@mun.ca:nf.*:doit
-rmgroup:randy@mun.ca:nf.*:doit
-
-## NIAGARA (Niagara Peninsula, USA/Canada)
-checkgroups:news@niagara.com:niagara.*:doit
-newgroup:news@niagara.com:niagara.*:doit
-rmgroup:news@niagara.com:niagara.*:doit
-
-## NIAS (Japanese ?)
-checkgroups:news@cc.nias.ac.jp:nias.*:doit
-newgroup:news@cc.nias.ac.jp:nias.*:doit
-rmgroup:news@cc.nias.ac.jp:nias.*:doit
-
-## NIGERIA (Nigeria)
-checkgroups:news@easnet.net:nigeria.*:doit
-newgroup:news@easnet.net:nigeria.*:doit
-rmgroup:news@easnet.net:nigeria.*:doit
-
-## NIHON (Japan)
-checkgroups:ktomita@jade.dti.ne.jp:nihon.*:doit
-newgroup:ktomita@jade.dti.ne.jp:nihon.*:doit
-rmgroup:ktomita@jade.dti.ne.jp:nihon.*:doit
-
-## NIPPON (*PRIVATE* -- Japan)
-# URL: http://www.gcd.org/news/nippon/
-# Admin group: nippon.news.group
-# Key URL: http://www.gcd.org/news/nippon/
-# Key fingerprint = BC CF 15 CD B1 3C DF B3 C3 DE 35 6F 2F F7 46 DB
-# For private use only.
-# *PGP* See comment at top of file.
-newgroup:*:nippon.*:drop
-rmgroup:*:nippon.*:drop
-newgroup:news@gcd.org:nippon.*:mail
-rmgroup:news@gcd.org:nippon.*:verify-nippon.news.group
-
-## NJ (New Jersey, USA)
-# Contact: nj-admin@gunslinger.net
-# URL: http://www.exit109.com/~jeremy/nj/
-checkgroups:nj-admin@gunslinger.net:nj.*:doit
-newgroup:nj-admin@gunslinger.net:nj.*:doit
-rmgroup:nj-admin@gunslinger.net:nj.*:doit
-
-## NL (Netherlands)
-# Contact: nl-admin@nic.surfnet.nl
-# URL: http://nl.news-admin.org/info/nladmin.html
-# Admin group: nl.newsgroups
-# Key fingerprint = 45 20 0B D5 A1 21 EA 7C EF B2 95 6C 25 75 4D 27
-# *PGP* See comment at top of file.
-newgroup:*:nl.*:drop
-rmgroup:*:nl.*:drop
-checkgroups:nl-admin@nic.surfnet.nl:nl.*:verify-nl.newsgroups
-newgroup:nl-admin@nic.surfnet.nl:nl.*:verify-nl.newsgroups
-rmgroup:nl-admin@nic.surfnet.nl:nl.*:verify-nl.newsgroups
-
-## NL-ALT (Alternative Netherlands groups)
-# Key fingerprint = 6B 62 EB 53 4D 5D 2F 96 35 D9 C8 9C B0 65 0E 4C
-# *PGP* See comment at top of file.
-checkgroups:nl-alt-janitor@surfer.xs4all.nl:nl-alt.*:verify-nl-alt.config.admin
-newgroup:*:nl-alt.*:doit
-rmgroup:nl-alt-janitor@surfer.xs4all.nl:nl-alt.*:verify-nl-alt.config.admin
-rmgroup:news@kink.xs4all.nl:nl-alt.*:verify-nl-alt.config.admin
-
-## NLO (Open Source / Free Software, hosted by nl.linux.org)
-# URL: http://news.nl.linux.org/doc/nlo.html
-# Key URL: http://news.nl.linux.org/doc/nlo-3.html#ss3.1
-# Key fingerprint = 63 DC B2 51 0A F3 DD 72 C2 BD C6 FD C1 C5 44 CF
-# *PGP* See comment at top of file.
-newgroup:*:nlo.*:drop
-rmgroup:*:nlo.*:drop
-checkgroups:news@nl.linux.org:nlo.*:verify-nlo.newsgroups
-newgroup:news@nl.linux.org:nlo.*:verify-nlo.newsgroups
-rmgroup:news@nl.linux.org:nlo.*:verify-nlo.newsgroups
-
-## NM (New Mexico, USA)
-checkgroups:news@tesuque.cs.sandia.gov:nm.*:doit
-newgroup:news@tesuque.cs.sandia.gov:nm.*:doit
-rmgroup:news@tesuque.cs.sandia.gov:nm.*:doit
-
-## NO (Norway)
-# URL: http://www.usenet.no/
-# Admin group: no.usenet.admin
-# Key URL: http://www.usenet.no/pgp-key.txt
-# *PGP* See comment at top of file.
-newgroup:*:no.*:drop
-rmgroup:*:no.*:drop
-checkgroups:control@usenet.no:no.*:verify-no-hir-control
-newgroup:control@usenet.no:no.*:verify-no-hir-control
-rmgroup:control@usenet.no:no.*:verify-no-hir-control
-
-## NO.ALT (Norway alternative hierarchy)
-# *PGP* See comment at top of file.
-newgroup:*:no.alt.*:drop
-rmgroup:*:no.alt.*:drop
-newgroup:*@*.no:no.alt.*:doit
-rmgroup:control@usenet.no:no.alt.*:verify-no-hir-control
-
-## NORD (Northern Germany)
-# thilo@own.deceiver.org no longer a valid address
-# newgroup:thilo@own.deceiver.org:nord.*:doit
-# rmgroup:thilo@own.deceiver.org:nord.*:doit
-
-## NRW (Northrine-Westfalia, Germany)
-# Contact: moderator@nrw.usenetverwaltung.de
-# URL: http://nrw.usenetverwaltung.de/
-# Admin group: nrw.admin.announce
-# Key URL: http://nrw.usenetverwaltung.de/pgp/nrw.asc
-# Key fingerprint = 13 4A 80 FE D6 34 B4 64 AF 32 08 3F 62 0E B1 E2
-# *PGP* See comment at top of file.
-newgroup:*:nrw.*:drop
-rmgroup:*:nrw.*:drop
-checkgroups:moderator@nrw.usenetverwaltung.de:nrw.*:verify-moderator@nrw.usenetverwaltung.de
-newgroup:moderator@nrw.usenetverwaltung.de:nrw.*:verify-moderator@nrw.usenetverwaltung.de
-rmgroup:moderator@nrw.usenetverwaltung.de:nrw.*:verify-moderator@nrw.usenetverwaltung.de
-
-## NV (Nevada)
-checkgroups:cshapiro@netcom.com:nv.*:doit
-checkgroups:doctor@netcom.com:nv.*:doit
-newgroup:cshapiro@netcom.com:nv.*:doit
-newgroup:doctor@netcom.com:nv.*:doit
-rmgroup:cshapiro@netcom.com:nv.*:doit
-rmgroup:doctor@netcom.com:nv.*:doit
-
-## NY (New York State, USA)
-checkgroups:root@ny.psca.com:ny.*:doit
-newgroup:root@ny.psca.com:ny.*:doit
-rmgroup:root@ny.psca.com:ny.*:doit
-
-## NYC (New York City)
-# Contact: Perry E. Metzger <perry@piermont.com>
-checkgroups:perry@piermont.com:nyc.*:doit
-newgroup:perry@piermont.com:nyc.*:doit
-rmgroup:perry@piermont.com:nyc.*:doit
-
-## NZ (New Zealand)
-# Contact: root@usenet.net.nz
-# URL: http://www.faqs.org/faqs/usenet/nz-news-hierarchy
-# Admin group: nz.net.announce
-# Key fingerprint = 07 DF 48 AA D0 ED AA 88 16 70 C5 91 65 3D 1A 28
-# *PGP* See comment at top of file.
-newgroup:*:nz.*:drop
-rmgroup:*:nz.*:drop
-checkgroups:root@usenet.net.nz:nz.*:verify-nz-hir-control
-newgroup:root@usenet.net.nz:nz.*:verify-nz-hir-control
-rmgroup:root@usenet.net.nz:nz.*:verify-nz-hir-control
-
-## OC (Orange County, California, USA)
-checkgroups:bob@tsunami.sugarland.unocal.com:oc.*:doit
-newgroup:bob@tsunami.sugarland.unocal.com:oc.*:doit
-rmgroup:bob@tsunami.sugarland.unocal.com:oc.*:doit
-
-## OESTERREICH (Free Austria)
-#
-# This is apparently another alt.* or free.* but specific to Austria.
-# Currently, the ftp.isc.org list doesn't honor newgroup messages in the
-# hierarchy due to lack of requests, but here is the information in case
-# any news admin wishes to carry it.
-#
-# URL: http://www.tahina.priv.at/~cm/oe/index.en.html
-#newgroup:*:oesterreich.*:doit
-#newgroup:group-admin@isc.org:oesterreich.*:drop
-#newgroup:tale@*uu.net:oesterreich.*:drop
-#rmgroup:*:oesterreich.*:drop
-
-## OH (Ohio, USA)
-checkgroups:trier@ins.cwru.edu:oh.*:doit
-newgroup:trier@ins.cwru.edu:oh.*:doit
-rmgroup:trier@ins.cwru.edu:oh.*:doit
-
-## OK (Oklahoma, USA)
-checkgroups:quentin@*qns.com:ok.*:doit
-newgroup:quentin@*qns.com:ok.*:doit
-rmgroup:quentin@*qns.com:ok.*:doit
-
-## OKINAWA (Okinawa, Japan)
-checkgroups:news@opus.or.jp:okinawa.*:doit
-newgroup:news@opus.or.jp:okinawa.*:doit
-rmgroup:news@opus.or.jp:okinawa.*:doit
-
-## ONT (Ontario, Canada)
-checkgroups:pkern@gpu.utcc.utoronto.ca:ont.*:doit
-newgroup:pkern@gpu.utcc.utoronto.ca:ont.*:doit
-rmgroup:pkern@gpu.utcc.utoronto.ca:ont.*:doit
-
-## OPENNEWS (Open News Network)
-# URL: http://www.open-news-network.org/
-# *PGP* See comment at top of file.
-newgroup:*:opennews.*:drop
-rmgroup:*:opennews.*:drop
-checkgroups:schiller@babsi.de:opennews.*:verify-news@news2.open-news-network.org
-newgroup:schiller@babsi.de:opennews.*:verify-news@news2.open-news-network.org
-rmgroup:schiller@babsi.de:opennews.*:verify-news@news2.open-news-network.org
-
-## OPENWATCOM (Open Watcom compilers)
-# Contact: admin@openwatcom.news-admin.org
-# URL: http://www.openwatcom.org/
-# Admin group: openwatcom.contributors
-# Key URL: http://cmeerw.org/files/openwatcom/pgp-openwatcom.asc
-# Syncable server: news.openwatcom.org
-# *PGP* See comment at top of file.
-newgroup:*:openwatcom.*:drop
-rmgroup:*:openwatcom.*:drop
-checkgroups:admin@openwatcom.news-admin.org:openwatcom.*:verify-admin@openwatcom.news-admin.org
-newgroup:admin@openwatcom.news-admin.org:openwatcom.*:verify-admin@openwatcom.news-admin.org
-rmgroup:admin@openwatcom.news-admin.org:openwatcom.*:verify-admin@openwatcom.news-admin.org
-
-## OPERA (Opera Software, Oslo, Norway)
-# Contact: usenet@opera.com
-# Syncable server: news.opera.com
-# *PGP* See comment at top of file.
-newgroup:*:opera.*:drop
-rmgroup:*:opera.*:drop
-checkgroups:*@opera.com:opera.*:verify-opera-group-admin
-newgroup:*@opera.com:opera.*:verify-opera-group-admin
-rmgroup:*@opera.com:opera.*:verify-opera-group-admin
-
-## OTT (Ottawa, Ontario, Canada)
-# Contact: onag@pinetree.org
-# URL: http://www.pinetree.org/ONAG/
-checkgroups:clewis@ferret.ocunix.on.ca:ott.*:doit
-checkgroups:dave@revcan.ca:ott.*:doit
-checkgroups:gordon@*pinetree.org:ott.*:doit
-checkgroups:news@*pinetree.org:ott.*:doit
-checkgroups:news@bnr.ca:ott.*:doit
-checkgroups:news@ferret.ocunix.on.ca:ott.*:doit
-checkgroups:news@nortel.ca:ott.*:doit
-newgroup:clewis@ferret.ocunix.on.ca:ott.*:doit
-newgroup:dave@revcan.ca:ott.*:doit
-newgroup:gordon@*pinetree.org:ott.*:doit
-newgroup:news@*pinetree.org:ott.*:doit
-newgroup:news@bnr.ca:ott.*:doit
-newgroup:news@ferret.ocunix.on.ca:ott.*:doit
-newgroup:news@nortel.ca:ott.*:doit
-rmgroup:clewis@ferret.ocunix.on.ca:ott.*:doit
-rmgroup:dave@revcan.ca:ott.*:doit
-rmgroup:gordon@*pinetree.org:ott.*:doit
-rmgroup:news@*pinetree.org:ott.*:doit
-rmgroup:news@bnr.ca:ott.*:doit
-rmgroup:news@ferret.ocunix.on.ca:ott.*:doit
-rmgroup:news@nortel.ca:ott.*:doit
-
-## PA (Pennsylvania, USA)
-# URL: http://www.netcom.com/~rb1000/pa_hierarchy/
-checkgroups:fxp@epix.net:pa.*:doit
-newgroup:fxp@epix.net:pa.*:doit
-rmgroup:fxp@epix.net:pa.*:doit
-
-## PBINFO (Paderborn, Germany)
-# Contact: news@uni-paderborn.de
-# *PGP* See comment at top of file.
-newgroup:*:pbinfo.*:drop
-rmgroup:*:pbinfo.*:drop
-checkgroups:postmaster@upb.de:pbinfo.*:verify-news@uni-paderborn.de
-newgroup:postmaster@upb.de:pbinfo.*:verify-news@uni-paderborn.de
-rmgroup:postmaster@upb.de:pbinfo.*:verify-news@uni-paderborn.de
-
-## PERL (Perl Programming Language)
-# Contact: newsadmin@perl.org
-# URL: http://www.nntp.perl.org/about/
-# Key URL: http://www.nntp.perl.org/about/newsadmin@perl.org.pgp
-# Key fingerprint = 438F D1BA 4DCC 3B1A BED8 2BCC 3298 8A7D 8B2A CFBB
-# *PGP* See comment at top of file.
-newgroup:*:perl.*:drop
-rmgroup:*:perl.*:drop
-checkgroups:newsadmin@perl.org:perl.*:verify-newsadmin@perl.org
-newgroup:newsadmin@perl.org:perl.*:verify-newsadmin@perl.org
-rmgroup:newsadmin@perl.org:perl.*:verify-newsadmin@perl.org
-
-## PGH (Pittsburgh, Pennsylvania, USA)
-# Admin group: pgh.config
-# *PGP* See comment at top of file.
-newgroup:*:pgh.*:drop
-rmgroup:*:pgh.*:drop
-checkgroups:pgh-config@psc.edu:pgh.*:verify-pgh.config
-newgroup:pgh-config@psc.edu:pgh.*:verify-pgh.config
-rmgroup:pgh-config@psc.edu:pgh.*:verify-pgh.config
-
-## PGSQL (Gated PostgreSQL mailing lists)
-# Contact: news@postgresql.org
-# URL: http://news.hub.org/gpg_public_keys.html
-# Key URL: http://news.hub.org/gpg_public_keys.html
-# *PGP* See comment at top of file.
-newgroup:*:pgsql.*:drop
-rmgroup:*:pgsql.*:drop
-checkgroups:news@postgresql.org:pgsql.*:verify-news@postgresql.org
-newgroup:news@postgresql.org:pgsql.*:verify-news@postgresql.org
-rmgroup:news@postgresql.org:pgsql.*:verify-news@postgresql.org
-
-## PHL (Philadelphia, Pennsylvania, USA)
-checkgroups:news@vfl.paramax.com:phl.*:doit
-newgroup:news@vfl.paramax.com:phl.*:doit
-rmgroup:news@vfl.paramax.com:phl.*:doit
-
-## PIN (Personal Internauts' NetNews)
-checkgroups:pin-admin@forus.or.jp:pin.*:doit
-newgroup:pin-admin@forus.or.jp:pin.*:doit
-rmgroup:pin-admin@forus.or.jp:pin.*:doit
-
-## PIPEX (UUNET WorldCom UK)
-# Contact: Russell Vincent <news-control@ops.pipex.net>
-checkgroups:news-control@ops.pipex.net:pipex.*:doit
-newgroup:news-control@ops.pipex.net:pipex.*:doit
-rmgroup:news-control@ops.pipex.net:pipex.*:doit
-
-## PITT (University of Pittsburgh, PA)
-checkgroups:news+@pitt.edu:pitt.*:doit
-checkgroups:news@toads.pgh.pa.us:pitt.*:doit
-newgroup:news+@pitt.edu:pitt.*:doit
-newgroup:news@toads.pgh.pa.us:pitt.*:doit
-rmgroup:news+@pitt.edu:pitt.*:doit
-rmgroup:news@toads.pgh.pa.us:pitt.*:doit
-
-## PL (Poland and Polish language)
-# URL: http://www.usenet.pl/doc/news-pl-new-site-faq.html
-# Admin group: pl.news.admin
-# Key URL: http://www.usenet.pl/doc/news-pl-new-site-faq.html#pgp
-# *PGP* See comment at top of file.
-newgroup:*:pl.*:drop
-rmgroup:*:pl.*:drop
-checkgroups:michalj@*fuw.edu.pl:pl.*:verify-pl.announce.newgroups
-checkgroups:newgroup@usenet.pl:pl.*:verify-pl.announce.newgroups
-newgroup:michalj@*fuw.edu.pl:pl.*:verify-pl.announce.newgroups
-newgroup:newgroup@usenet.pl:pl.*:verify-pl.announce.newgroups
-rmgroup:michalj@*fuw.edu.pl:pl.*:verify-pl.announce.newgroups
-rmgroup:newgroup@usenet.pl:pl.*:verify-pl.announce.newgroups
-
-## PLANET (*LOCAL* -- PlaNet FreeNZ co-operative, New Zealand)
-# Contact: office@pl.net
-# For local use only, contact the above address for information.
-newgroup:*:planet.*:mail
-rmgroup:*:planet.*:doit
-
-## PRIMA (*LOCAL* -- prima.ruhr.de/Prima e.V. in Germany)
-# Contact: admin@prima.ruhr.de
-# For local use only, contact the above address for information.
-newgroup:*:prima.*:mail
-rmgroup:*:prima.*:doit
-
-## PSU (*LOCAL* -- Penn State University, USA)
-# Contact: Dave Barr (barr@math.psu.edu)
-# For local use only, contact the above address for information.
-newgroup:*:psu.*:mail
-rmgroup:*:psu.*:doit
-
-## PT (Portugal and Portuguese language)
-# URL: http://www.usenet-pt.org/
-# Admin group: pt.internet.usenet
-# Key URL: http://www.usenet-pt.org/control@usenet-pt.org.asc
-# *PGP* See comment at top of file.
-newgroup:*:pt.*:drop
-rmgroup:*:pt.*:drop
-checkgroups:pmelo@*.inescc.pt:pt.*:verify-control@usenet-pt.org
-newgroup:pmelo@*.inescc.pt:pt.*:verify-control@usenet-pt.org
-rmgroup:pmelo@*.inescc.pt:pt.*:verify-control@usenet-pt.org
-
-## PUBNET (*DEFUNCT* -- ?)
-# URL: ftp://ftp.isc.org/pub/usenet/control/pubnet/pubnet.config.Z
-# This hierarchy is defunct. Please remove it.
-newgroup:*:pubnet.*:mail
-rmgroup:*:pubnet.*:doit
-
-## RELCOM (Commonwealth of Independent States)
-# URL: ftp://ftp.relcom.ru/pub/relcom/netinfo/
-# Admin group: relcom.netnews
-# Key URL: ftp://ftp.relcom.ru/pub/relcom/netinfo/coordpubkey.txt
-# *PGP* See comment at top of file.
-newgroup:*:relcom.*:drop
-rmgroup:*:relcom.*:drop
-checkgroups:coord@*.relcom.ru:relcom.*:verify-relcom.newsgroups
-newgroup:coord@*.relcom.ru:relcom.*:verify-relcom.newsgroups
-rmgroup:coord@*.relcom.ru:relcom.*:verify-relcom.newsgroups
-
-## RPI (*LOCAL* -- Rensselaer Polytechnic Institute, Troy, NY, USA)
-# Contact: sofkam@rpi.edu
-# For local use only, contact the above address for information.
-newgroup:*:rpi.*:mail
-rmgroup:*:rpi.*:doit
-
-## SAAR (Saarland Region, Germany)
-# URL: http://www.saar-admin-news.de/
-# Admin group: saar.admin.news
-# Key URL: http://www.saar-admin-news.de/saar-control.asc
-# *PGP* See comment at top of file.
-newgroup:*:saar.*:drop
-rmgroup:*:saar.*:drop
-checkgroups:control@saar-admin-news.de:saar.*:verify-saar-control
-newgroup:control@saar-admin-news.de:saar.*:verify-saar-control
-rmgroup:control@saar-admin-news.de:saar.*:verify-saar-control
-
-## SACHSNET (German)
-checkgroups:root@lusatia.de:sachsnet.*:doit
-newgroup:root@lusatia.de:sachsnet.*:doit
-rmgroup:root@lusatia.de:sachsnet.*:doit
-
-## SAT (San Antonio, Texas, USA)
-# Contact: satgroup@endicor.com
-# Admin group: sat.usenet.config
-# *PGP* See comment at top of file.
-newgroup:*:sat.*:drop
-rmgroup:*:sat.*:drop
-checkgroups:satgroup@endicor.com:sat.*:verify-satgroup@endicor.com
-newgroup:satgroup@endicor.com:sat.*:verify-satgroup@endicor.com
-rmgroup:satgroup@endicor.com:sat.*:verify-satgroup@endicor.com
-
-## SBAY (South Bay/Silicon Valley, California)
-# URL: http://www.sbay.org/sbay-newsgroups.html
-checkgroups:ikluft@thunder.sbay.org:sbay.*:doit
-checkgroups:steveh@grafex.sbay.org:sbay.*:doit
-newgroup:ikluft@thunder.sbay.org:sbay.*:doit
-newgroup:steveh@grafex.sbay.org:sbay.*:doit
-rmgroup:ikluft@thunder.sbay.org:sbay.*:doit
-rmgroup:steveh@grafex.sbay.org:sbay.*:doit
-
-## SCHULE (?)
-# Contact: schule-admin@roxel.ms.sub.org
-# URL: http://home.pages.de/~schule-admin/
-# Admin group: schule.admin
-# Key URL: http://www.afaik.de/usenet/admin/schule/control/schule.asc
-# Key fingerprint = 64 06 F0 AE E1 46 85 0C BD CA 0E 53 8B 1E 73 D2
-# *PGP* See comment at top of file.
-newgroup:*:schule.*:drop
-rmgroup:*:schule.*:drop
-checkgroups:newsctrl@schule.de:schule.*:verify-schule.konfig
-newgroup:newsctrl@schule.de:schule.*:verify-schule.konfig
-rmgroup:newsctrl@schule.de:schule.*:verify-schule.konfig
-
-## SCOT (Scotland)
-# URL: http://scot.news-admin.org/
-# Admin group: scot.newsgroups.discuss
-# Key URL: http://scot.news-admin.org/signature.html
-# *PGP* See comment at top of file.
-newgroup:*:scot.*:drop
-rmgroup:*:scot.*:drop
-checkgroups:control@scot.news-admin.org:scot.*:verify-control@scot.news-admin.org
-newgroup:control@scot.news-admin.org:scot.*:verify-control@scot.news-admin.org
-rmgroup:control@scot.news-admin.org:scot.*:verify-control@scot.news-admin.org
-
-## SCOUT (Scouts and guides)
-# URL: http://news.scoutnet.org/
-# Admin group: scout.admin
-# Key URL: http://news.scoutnet.org/scout-pgpkey.asc
-# *PGP* See comment at top of file.
-newgroup:*:scout.*:drop
-rmgroup:*:scout.*:drop
-checkgroups:control@news.scoutnet.org:scout.*:verify-control@news.scoutnet.org
-newgroup:control@news.scoutnet.org:scout.*:verify-control@news.scoutnet.org
-rmgroup:control@news.scoutnet.org:scout.*:verify-control@news.scoutnet.org
-
-## SDNET (Greater San Diego Area, California, USA)
-# URL: http://www-rohan.sdsu.edu/~wk/sdnet/sdnet.html
-checkgroups:wkronert@sunstroke.sdsu.edu:sdnet.*:doit
-newgroup:wkronert@sunstroke.sdsu.edu:sdnet.*:doit
-rmgroup:wkronert@sunstroke.sdsu.edu:sdnet.*:doit
-
-## SDSU (*LOCAL* -- San Diego State University, CA)
-# Contact: Craig R. Sadler <usenet@sdsu.edu>
-# For local use only, contact the above address for information.
-newgroup:*:sdsu.*:mail
-rmgroup:*:sdsu.*:doit
-
-## SE (Sweden)
-# Contact: usenet@usenet-se.net
-# Admin group: se.internet.news.meddelanden
-# Key fingerprint = 68 03 F0 FD 0C C3 4E 69 6F 0D 0C 60 3C 58 63 96
-# *PGP* See comment at top of file.
-newgroup:*:se.*:drop
-rmgroup:*:se.*:drop
-checkgroups:usenet@usenet-se.net:se.*:verify-usenet-se
-newgroup:usenet@usenet-se.net:se.*:verify-usenet-se
-rmgroup:usenet@usenet-se.net:se.*:verify-usenet-se
-
-## SEATTLE (Seattle, Washington, USA)
-checkgroups:billmcc@akita.com:seattle.*:doit
-checkgroups:graham@ee.washington.edu:seattle.*:doit
-newgroup:billmcc@akita.com:seattle.*:doit
-newgroup:graham@ee.washington.edu:seattle.*:doit
-rmgroup:billmcc@akita.com:seattle.*:doit
-rmgroup:graham@ee.washington.edu:seattle.*:doit
-
-## SFNET (Finland)
-# Contact: sfnet@cs.tut.fi
-# URL: http://www.cs.tut.fi/sfnet/
-# Admin group: sfnet.ryhmat+listat
-# Key fingerprint = DE79 33C2 D359 D128 44E5 6A0C B6E3 0E53 6933 A636
-# *PGP* See comment at top of file.
-newgroup:*:sfnet.*:drop
-rmgroup:*:sfnet.*:drop
-checkgroups:sfnet@*cs.tut.fi:sfnet.*:verify-sfnet@cs.tut.fi
-newgroup:sfnet@*cs.tut.fi:sfnet.*:verify-sfnet@cs.tut.fi
-rmgroup:sfnet@*cs.tut.fi:sfnet.*:verify-sfnet@cs.tut.fi
-
-## SHAMASH (Jewish)
-checkgroups:archives@israel.nysernet.org:shamash.*:doit
-newgroup:archives@israel.nysernet.org:shamash.*:doit
-rmgroup:archives@israel.nysernet.org:shamash.*:doit
-
-## SI (The Republic of Slovenia)
-# URL: http://www.arnes.si/news/config/
-# Admin group: si.news.announce.newsgroups
-# Key URL: http://www.arnes.si/news/config/
-# *PGP* See comment at top of file.
-newgroup:*:si.*:drop
-rmgroup:*:si.*:drop
-checkgroups:news-admin@arnes.si:si.*:verify-si.news.announce.newsgroups
-newgroup:news-admin@arnes.si:si.*:verify-si.news.announce.newsgroups
-rmgroup:news-admin@arnes.si:si.*:verify-si.news.announce.newsgroups
-
-## SJ (St. John's, Newfoundland and Labrador, Canada)
-# Contact: randy@mun.ca
-checkgroups:randy@mun.ca:sj.*:doit
-newgroup:randy@mun.ca:sj.*:doit
-rmgroup:randy@mun.ca:sj.*:doit
-
-## SK (Slovakia)
-checkgroups:uhlar@ccnews.ke.sanet.sk:sk.*:doit
-newgroup:uhlar@ccnews.ke.sanet.sk:sk.*:doit
-rmgroup:uhlar@ccnews.ke.sanet.sk:sk.*:doit
-
-## SLAC (*PRIVATE* -- Stanford Linear Accelerator Center, Stanford, USA)
-# Contact: news@news.stanford.edu
-# For private use only, contact the above address for information.
-newgroup:news@news.stanford.edu:slac.*:mail
-rmgroup:news@news.stanford.edu:slac.*:doit
-
-## SLO (San Luis Obispo, CA)
-checkgroups:news@punk.net:slo.*:doit
-newgroup:news@punk.net:slo.*:doit
-rmgroup:news@punk.net:slo.*:doit
-
-## SOLENT (Solent region, England)
-checkgroups:news@tcp.co.uk:solent.*:doit
-newgroup:news@tcp.co.uk:solent.*:doit
-rmgroup:news@tcp.co.uk:solent.*:doit
-
-## SPOKANE (Spokane, Washington, USA)
-checkgroups:usenet@news.spokane.wa.us:spokane.*:doit
-newgroup:usenet@news.spokane.wa.us:spokane.*:doit
-rmgroup:usenet@news.spokane.wa.us:spokane.*:doit
-
-## SSLUG (*PRIVATE* -- Skåne Sjælland Linux User Group)
-# URL: http://en.sslug.dk/
-# For private use only.
-newgroup:sparre@sslug.se:sslug.*:mail
-rmgroup:sparre@sslug.se:sslug.*:doit
-
-## STAROFFICE (StarOffice business suite, Sun Microsystems, Inc.)
-# Contact: news@starnews.sun.com
-# Admin group: staroffice.admin
-# Key fingerprint = C6 3E 81 6F 2A 19 D3 84 72 51 F9 1B E3 B9 B2 C9
-# Syncable server: starnews.sun.com
-# *PGP* See comment at top of file.
-newgroup:*:staroffice.*:drop
-rmgroup:*:staroffice.*:drop
-checkgroups:news@stardivision.de:staroffice.*:verify-staroffice.admin
-newgroup:news@stardivision.de:staroffice.*:verify-staroffice.admin
-rmgroup:news@stardivision.de:staroffice.*:verify-staroffice.admin
-
-## STGT (Stuttgart, Germany)
-# URL: http://news.uni-stuttgart.de/hierarchie/stgt/
-# Key URL: http://news.uni-stuttgart.de/hierarchie/stgt/stgt-control.txt
-# *PGP* See comment at top of file.
-newgroup:*:stgt.*:drop
-rmgroup:*:stgt.*:drop
-checkgroups:stgt-control@news.uni-stuttgart.de:stgt.*:verify-stgt-control
-newgroup:stgt-control@news.uni-stuttgart.de:stgt.*:verify-stgt-control
-rmgroup:stgt-control@news.uni-stuttgart.de:stgt.*:verify-stgt-control
-
-## STL (Saint Louis, Missouri, USA)
-checkgroups:news@icon-stl.net:stl.*:doit
-newgroup:news@icon-stl.net:stl.*:doit
-rmgroup:news@icon-stl.net:stl.*:doit
-
-## SU (*LOCAL* -- Stanford University, USA)
-# Contact: news@news.stanford.edu
-# For local use only, contact the above address for information.
-newgroup:*:su.*:mail
-rmgroup:*:su.*:doit
-
-## SUNET (Swedish University Network)
-checkgroups:ber@*.sunet.se:sunet.*:doit
-newgroup:ber@*.sunet.se:sunet.*:doit
-rmgroup:ber@*.sunet.se:sunet.*:doit
-
-## SURFNET (Dutch Universities network)
-checkgroups:news@info.nic.surfnet.nl:surfnet.*:doit
-newgroup:news@info.nic.surfnet.nl:surfnet.*:doit
-rmgroup:news@info.nic.surfnet.nl:surfnet.*:doit
-
-## SWNET (Sverige, Sweden)
-checkgroups:ber@sunic.sunet.se:swnet.*:doit
-newgroup:ber@sunic.sunet.se:swnet.*:doit
-rmgroup:ber@sunic.sunet.se:swnet.*:doit
-
-## SYD (Sydney, Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://syd.news-admin.org/
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:syd.*:drop
-rmgroup:*:syd.*:drop
-checkgroups:ausadmin@aus.news-admin.org:syd.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:syd.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:syd.*:verify-ausadmin@aus.news-admin.org
-
-## T-NETZ (*DEFUNCT* -- Germany)
-# This hierarchy is defunct. Please remove it.
-newgroup:*:t-netz.*:mail
-rmgroup:*:t-netz.*:doit
-
-## TAMU (Texas A&M University)
-# Contact: Philip Kizer <news@tamu.edu>
-checkgroups:news@tamsun.tamu.edu:tamu.*:doit
-newgroup:news@tamsun.tamu.edu:tamu.*:doit
-rmgroup:news@tamsun.tamu.edu:tamu.*:doit
-
-## TAOS (Taos, New Mexico, USA)
-# Contact: Chris Gunn <cgunn@laplaza.org>
-checkgroups:cgunn@laplaza.org:taos.*:doit
-newgroup:cgunn@laplaza.org:taos.*:doit
-rmgroup:cgunn@laplaza.org:taos.*:doit
-
-## TCFN (Toronto Free Community Network, Canada)
-checkgroups:news@t-fcn.net:tcfn.*:doit
-newgroup:news@t-fcn.net:tcfn.*:doit
-rmgroup:news@t-fcn.net:tcfn.*:doit
-
-## TELE (*LOCAL* -- Tele Danmark Internet)
-# Contact: usenet@tdk.net
-# For local use only, contact the above address for information.
-newgroup:*:tele.*:mail
-rmgroup:*:tele.*:doit
-
-## TERMVAKT (*LOCAL* -- University of Oslo, Norway)
-# Contact: jani@ifi.uio.no
-# For local use only, contact the above address for information.
-newgroup:*:termvakt.*:mail
-rmgroup:*:termvakt.*:doit
-
-## TEST (Local test hierarchy)
-# It is not really a good idea for sites to use these since they may occur
-# on many unconnected sites.
-newgroup:*:test.*:mail
-rmgroup:*:test.*:mail
-
-## THUR (Thuringia, Germany)
-# Key fingerprint = 7E 3D 73 13 93 D4 CA 78 39 DE 3C E7 37 EE 22 F1
-# *PGP* See comment at top of file.
-newgroup:*:thur.*:drop
-rmgroup:*:thur.*:drop
-checkgroups:usenet@thur.de:thur.*:verify-thur.net.news.groups
-newgroup:usenet@thur.de:thur.*:verify-thur.net.news.groups
-rmgroup:usenet@thur.de:thur.*:verify-thur.net.news.groups
-
-## TNN (*DEFUNCT* -- The Network News, Japan)
-# This hierarchy is defunct. Please remove it.
-newgroup:netnews@news.iij.ad.jp:tnn.*:mail
-newgroup:tnn@iij-mc.co.jp:tnn.*:mail
-rmgroup:netnews@news.iij.ad.jp:tnn.*:doit
-rmgroup:tnn@iij-mc.co.jp:tnn.*:doit
-
-## TRIANGLE (Research Triangle, Central North Carolina, USA)
-checkgroups:jfurr@acpub.duke.edu:triangle.*:doit
-checkgroups:news@news.duke.edu:triangle.*:doit
-checkgroups:tas@concert.net:triangle.*:doit
-newgroup:jfurr@acpub.duke.edu:triangle.*:doit
-newgroup:news@news.duke.edu:triangle.*:doit
-newgroup:tas@concert.net:triangle.*:doit
-rmgroup:jfurr@acpub.duke.edu:triangle.*:doit
-rmgroup:news@news.duke.edu:triangle.*:doit
-rmgroup:tas@concert.net:triangle.*:doit
-
-## TUM (Technische Universitaet Muenchen)
-checkgroups:news@informatik.tu-muenchen.de:tum.*:doit
-newgroup:news@informatik.tu-muenchen.de:tum.*:doit
-rmgroup:news@informatik.tu-muenchen.de:tum.*:doit
-
-## TW (Taiwan)
-checkgroups:ltc@news.cc.nctu.edu.tw:tw.*:doit
-newgroup:ltc@news.cc.nctu.edu.tw:tw.*:doit
-rmgroup:ltc@news.cc.nctu.edu.tw:tw.*:doit
-
-## TW.K-12 (Taiwan K-12 Discussion)
-checkgroups:k-12@news.nchu.edu.tw:tw.k-12.*:doit
-newgroup:k-12@news.nchu.edu.tw:tw.k-12.*:doit
-rmgroup:k-12@news.nchu.edu.tw:tw.k-12.*:doit
-
-## TX (Texas, USA)
-checkgroups:eric@cirr.com:tx.*:doit
-checkgroups:fletcher@cs.utexas.edu:tx.*:doit
-checkgroups:usenet@academ.com:tx.*:doit
-newgroup:eric@cirr.com:tx.*:doit
-newgroup:fletcher@cs.utexas.edu:tx.*:doit
-newgroup:usenet@academ.com:tx.*:doit
-rmgroup:eric@cirr.com:tx.*:doit
-rmgroup:fletcher@cs.utexas.edu:tx.*:doit
-rmgroup:usenet@academ.com:tx.*:doit
-
-## UCB (University of California Berkeley, USA)
-# Contact: Chris van den Berg <usenet@agate.berkeley.edu>
-# URL: http://www.net.berkeley.edu/usenet/
-# Key URL: http://www.net.berkeley.edu/usenet/usenet.asc
-# Key fingerprint = 96 B8 8E 9A 98 09 37 7D 0E EC 81 88 DB 90 29 BF
-# *PGP* See comment at top of file.
-newgroup:*:ucb.*:drop
-rmgroup:*:ucb.*:drop
-checkgroups:usenet@agate.berkeley.edu:ucb.*:verify-ucb.news
-newgroup:usenet@agate.berkeley.edu:ucb.*:verify-ucb.news
-rmgroup:usenet@agate.berkeley.edu:ucb.*:verify-ucb.news
-
-## UCD (University of California Davis, USA)
-checkgroups:usenet@mark.ucdavis.edu:ucd.*:doit
-checkgroups:usenet@rocky.ucdavis.edu:ucd.*:doit
-newgroup:usenet@mark.ucdavis.edu:ucd.*:doit
-newgroup:usenet@rocky.ucdavis.edu:ucd.*:doit
-rmgroup:usenet@mark.ucdavis.edu:ucd.*:doit
-rmgroup:usenet@rocky.ucdavis.edu:ucd.*:doit
-
-## UFRA (Unterfranken, Deutschland)
-# Contact: news@mayn.de
-# URL: http://www.mayn.de/users/news/
-# Admin group: ufra.admin
-# Key fingerprint = F7 AD 96 D8 7A 3F 7E 84 02 0C 83 9A DB 8F EB B8
-# Syncable server: news.mayn.de (contact news@mayn.de if permission denied)
-# *PGP* See comment at top of file.
-newgroup:*:ufra.*:drop
-rmgroup:*:ufra.*:drop
-checkgroups:news@mayn.de:ufra.*:verify-news.mayn.de
-newgroup:news@mayn.de:ufra.*:verify-news.mayn.de
-rmgroup:news@mayn.de:ufra.*:verify-news.mayn.de
-
-## UIUC (*LOCAL* -- University of Illinois at Urbana-Champaign, USA)
-# Contact: news@ks.uiuc.edu
-# For local use only, contact the above address for information.
-newgroup:*:uiuc.*:mail
-rmgroup:*:uiuc.*:doit
-
-## UK (United Kingdom of Great Britain and Northern Ireland)
-# URL: http://www.usenet.org.uk/
-# Admin group: uk.net.news.announce
-# Key URL: http://www.usenet.org.uk/newsadmins.html
-# *PGP* See comment at top of file.
-newgroup:*:uk.*:drop
-rmgroup:*:uk.*:drop
-checkgroups:control@usenet.org.uk:uk.*:verify-uk.net.news.announce
-newgroup:control@usenet.org.uk:uk.*:verify-uk.net.news.announce
-rmgroup:control@usenet.org.uk:uk.*:verify-uk.net.news.announce
-
-## UKR (Ukraine)
-checkgroups:ay@sita.kiev.ua:ukr.*:doit
-newgroup:ay@sita.kiev.ua:ukr.*:doit
-rmgroup:ay@sita.kiev.ua:ukr.*:doit
-
-## UMICH (University of Michigan, USA)
-checkgroups:*@*.umich.edu:umich.*:doit
-newgroup:*@*.umich.edu:umich.*:doit
-rmgroup:*@*.umich.edu:umich.*:doit
-
-## UMN (University of Minnesota, USA)
-newgroup:edh@*.tc.umn.edu:umn.*:doit
-newgroup:news@*.tc.umn.edu:umn.*:doit
-newgroup:Michael.E.Hedman-1@umn.edu:umn.*:doit
-newgroup:edh@*.tc.umn.edu:umn*class.*:mail
-newgroup:news@*.tc.umn.edu:umn*class.*:mail
-newgroup:Michael.E.Hedman-1@umn.edu:umn*class.*:mail
-rmgroup:news@*.tc.umn.edu:umn.*:doit
-rmgroup:edh@*.tc.umn.edu:umn.*:doit
-rmgroup:Michael.E.Hedman-1@umn.edu:umn.*:doit
-
-## UN (The United Nations)
-# Admin group: un.public.usenet.admin
-# *PGP* See comment at top of file.
-newgroup:*:un.*:drop
-rmgroup:*:un.*:drop
-checkgroups:news@news.itu.int:un.*:verify-ungroups@news.itu.int
-newgroup:news@news.itu.int:un.*:verify-ungroups@news.itu.int
-rmgroup:news@news.itu.int:un.*:verify-ungroups@news.itu.int
-
-## UO (University of Oregon, Eugene, Oregon, USA)
-checkgroups:newsadmin@news.uoregon.edu:uo.*:doit
-newgroup:newsadmin@news.uoregon.edu:uo.*:doit
-rmgroup:newsadmin@news.uoregon.edu:uo.*:doit
-
-## US (United States of America)
-# Contact: admin@usenetnews.us
-# URL: http://www.usenetnews.us/
-# Admin group: us.config
-checkgroups:control@usenetnews.us:us.*:doit
-newgroup:control@usenetnews.us:us.*:doit
-rmgroup:control@usenetnews.us:us.*:doit
-
-## UT (*LOCAL* -- University of Toronto, Canada)
-# URL: http://www.utoronto.ca/ns/utornews/
-#newgroup:news@ecf.toronto.edu:ut.*:doit
-#newgroup:news@ecf.toronto.edu:ut.class.*:mail
-#rmgroup:news@ecf.toronto.edu:ut.*:doit
-
-## UTA (Finnish)
-checkgroups:news@news.cc.tut.fi:uta.*:doit
-newgroup:news@news.cc.tut.fi:uta.*:doit
-rmgroup:news@news.cc.tut.fi:uta.*:doit
-
-## UTEXAS (*LOCAL* -- University of Texas, USA)
-# URL: http://www.utexas.edu/its/usenet/index.php
-newgroup:fletcher@cs.utexas.edu:utexas.*:doit
-newgroup:news@geraldo.cc.utexas.edu:utexas.*:doit
-newgroup:fletcher@cs.utexas.edu:utexas*class.*:mail
-newgroup:news@geraldo.cc.utexas.edu:utexas*class.*:mail
-rmgroup:fletcher@cs.utexas.edu:utexas.*:doit
-rmgroup:news@geraldo.cc.utexas.edu:utexas.*:doit
-
-## UTWENTE (*LOCAL* -- University of Twente, Netherlands)
-# Contact: newsmaster@utwente.nl
-# For local use only, contact the above address for information.
-newgroup:*:utwente.*:mail
-rmgroup:*:utwente.*:doit
-
-## UVA (*LOCAL* -- University of Virginia, USA)
-# Contact: usenet@virginia.edu
-# For local use only, contact the above address for information.
-newgroup:*:uva.*:mail
-rmgroup:*:uva.*:doit
-
-## UW (University of Waterloo, Canada)
-# Admin group: uw.newsgroups
-# Syncable server: news.uwaterloo.ca
-# *PGP* See comment at top of file.
-newgroup:*:uw.*:drop
-rmgroup:*:uw.*:drop
-checkgroups:newsgroups@news.uwaterloo.ca:uw.*:verify-uw.newsgroups
-newgroup:newsgroups@news.uwaterloo.ca:uw.*:verify-uw.newsgroups
-rmgroup:newsgroups@news.uwaterloo.ca:uw.*:verify-uw.newsgroups
-
-## UWARWICK (*LOCAL* -- University of Warwick, UK)
-# Contact: Jon Harley <news@csv.warwick.ac.uk>
-# For local use only, contact the above address for information.
-newgroup:*:uwarwick.*:mail
-rmgroup:*:uwarwick.*:doit
-
-## UWO (University of Western Ontario, London, Canada)
-# URL: http://www.uwo.ca/its/news/groups.uwo.html
-checkgroups:reggers@julian.uwo.ca:uwo.*:doit
-newgroup:reggers@julian.uwo.ca:uwo.*:doit
-rmgroup:reggers@julian.uwo.ca:uwo.*:doit
-
-## VAN (Vancouver, British Columbia, Canada)
-checkgroups:bc_van_usenet@fastmail.ca:van.*:doit
-newgroup:bc_van_usenet@fastmail.ca:van.*:doit
-rmgroup:bc_van_usenet@fastmail.ca:van.*:doit
-
-## VEGAS (Las Vegas, Nevada, USA)
-checkgroups:cshapiro@netcom.com:vegas.*:doit
-checkgroups:doctor@netcom.com:vegas.*:doit
-newgroup:cshapiro@netcom.com:vegas.*:doit
-newgroup:doctor@netcom.com:vegas.*:doit
-rmgroup:cshapiro@netcom.com:vegas.*:doit
-rmgroup:doctor@netcom.com:vegas.*:doit
-
-## VGC (Japan groups?)
-checkgroups:news@isl.melco.co.jp:vgc.*:doit
-newgroup:news@isl.melco.co.jp:vgc.*:doit
-rmgroup:news@isl.melco.co.jp:vgc.*:doit
-
-## VMSNET (VMS Operating System)
-checkgroups:cts@dragon.com:vmsnet.*:doit
-newgroup:cts@dragon.com:vmsnet.*:doit
-rmgroup:cts@dragon.com:vmsnet.*:doit
-
-## WA (Western Australia)
-# Contact: ausadmin@aus.news-admin.org
-# URL: http://wa.news-admin.org/
-# Key URL: http://aus.news-admin.org/ausadmin.asc
-# *PGP* See comment at top of file.
-newgroup:*:wa.*:drop
-rmgroup:*:wa.*:drop
-checkgroups:ausadmin@aus.news-admin.org:wa.*:verify-ausadmin@aus.news-admin.org
-newgroup:ausadmin@aus.news-admin.org:wa.*:verify-ausadmin@aus.news-admin.org
-rmgroup:ausadmin@aus.news-admin.org:wa.*:verify-ausadmin@aus.news-admin.org
-
-## WADAI (Japanese ?)
-checkgroups:kohe-t@*wakayama-u.ac.jp:wadai.*:doit
-newgroup:kohe-t@*wakayama-u.ac.jp:wadai.*:doit
-rmgroup:kohe-t@*wakayama-u.ac.jp:wadai.*:doit
-
-## WALES (Wales)
-# Contact: committee@wales-usenet.org
-# URL: http://www.wales-usenet.org/
-# Admin group: wales.usenet.config
-# Key URL: http://www.wales-usenet.org/english/newsadmin.txt
-# Key fingerprint = 2D 9E DE DF 12 DA 34 5C 49 E1 EE 28 E3 AB 0D AD
-# *PGP* See comment at top of file.
-newgroup:*:wales.*:drop
-rmgroup:*:wales.*:drop
-checkgroups:control@wales-usenet.org:wales.*:verify-wales-usenet
-newgroup:control@wales-usenet.org:wales.*:verify-wales-usenet
-rmgroup:control@wales-usenet.org:wales.*:verify-wales-usenet
-
-## WASH (Washington State, USA)
-checkgroups:graham@ee.washington.edu:wash.*:doit
-newgroup:graham@ee.washington.edu:wash.*:doit
-rmgroup:graham@ee.washington.edu:wash.*:doit
-
-## WEST-VIRGINIA (West Virginia, USA)
-# Note: checkgroups only by bryan27, not mark.
-checkgroups:bryan27@hgo.net:west-virginia.*:doit
-newgroup:mark@bluefield.net:west-virginia.*:doit
-newgroup:bryan27@hgo.net:west-virginia.*:doit
-rmgroup:mark@bluefield.net:west-virginia.*:doit
-rmgroup:bryan27@hgo.net:west-virginia.*:doit
-
-## WORLDONLINE (*LOCAL* -- ?)
-# Contact: newsmaster@worldonline.nl
-# For local use only, contact the above address for information.
-newgroup:*:worldonline.*:mail
-rmgroup:*:worldonline.*:doit
-
-## WPG (Winnipeg, Manitoba, Canada)
-# Contact: Gary Mills <mills@cc.umanitoba.ca>
-checkgroups:mills@cc.umanitoba.ca:wpg.*:doit
-newgroup:mills@cc.umanitoba.ca:wpg.*:doit
-rmgroup:mills@cc.umanitoba.ca:wpg.*:doit
-
-## WPI (*LOCAL* -- Worcester Polytechnic Institute, Worcester, MA)
-# For local use only.
-newgroup:aej@*.wpi.edu:wpi.*:mail
-rmgroup:aej@*.wpi.edu:wpi.*:doit
-
-## WU (Washington University at St. Louis, MO)
-checkgroups:*@*.wustl.edu:wu.*:doit
-newgroup:*@*.wustl.edu:wu.*:doit
-rmgroup:*@*.wustl.edu:wu.*:doit
-
-## X-PRIVAT (Italian)
-# Contact: dmitry@x-privat.org
-# URL: http://www.x-privat.org/
-# Admin group: x-privat.info
-# Key URL: http://www.x-privat.org/dmitry.asc
-# Key fingerprint = 9B 0A 7E 68 27 80 C7 96 47 6B 03 90 51 05 68 43
-# *PGP* See comment at top of file.
-newgroup:*:x-privat.*:drop
-rmgroup:*:x-privat.*:drop
-checkgroups:dmitry@x-privat.org:x-privat.*:verify-dmitry@x-privat.org
-newgroup:dmitry@x-privat.org:x-privat.*:verify-dmitry@x-privat.org
-rmgroup:dmitry@x-privat.org:x-privat.*:verify-dmitry@x-privat.org
-
-## XS4ALL (XS4ALL, Netherlands)
-# Contact: Cor Bosman <news@xs4all.nl>
-checkgroups:news@*xs4all.nl:xs4all.*:doit
-newgroup:news@*xs4all.nl:xs4all.*:doit
-rmgroup:news@*xs4all.nl:xs4all.*:doit
-
-## YORK (*LOCAL* -- York University, Toronto, ON)
-# Contact: Peter Marques <news@yorku.ca>
-# For local use only, contact the above address for information.
-newgroup:*:york.*:mail
-rmgroup:*:york.*:doit
-
-## Z-NETZ (German non-Internet based network)
-# Contact: teko@dinoex.sub.org
-# Admin group: z-netz.koordination.user+sysops
-# Key URL: ftp://ftp.dinoex.de/pub/keys/z-netz.koordination.user+sysops.asc
-# *PGP* See comment at top of file.
-newgroup:*:z-netz.*:drop
-rmgroup:*:z-netz.*:drop
-checkgroups:teko@dinoex.sub.org:z-netz.*:verify-z-netz.koordination.user+sysops
-newgroup:teko@dinoex.sub.org:z-netz.*:verify-z-netz.koordination.user+sysops
-rmgroup:teko@dinoex.sub.org:z-netz.*:verify-z-netz.koordination.user+sysops
-
-## ZA (South Africa)
-checkgroups:ccfj@hippo.ru.ac.za:za.*:doit
-checkgroups:root@duvi.eskom.co.za:za.*:doit
-newgroup:ccfj@hippo.ru.ac.za:za.*:doit
-newgroup:root@duvi.eskom.co.za:za.*:doit
-rmgroup:ccfj@hippo.ru.ac.za:za.*:doit
-rmgroup:root@duvi.eskom.co.za:za.*:doit
-
-## ZER (*DEFUNCT* -- Germany)
-# This hierarchy is defunct. Please remove it.
-newgroup:*:zer.*:mail
-rmgroup:*:zer.*:doit
+++ /dev/null
-#
-# Meta cnfs cyclic buffer configuration file (and assignments of newsgroups to
-# metacyclic buffers)
-#
-# The order of lines in this file is not important among the same item.
-# But all cycbuff item should be presented before any metacycbuff item.
-
-# 1. Cyclic buffers
-# Format:
-# "cycbuff" (literally) : symbolic buffer name : path to buffer file :
-# length of symbolic buffer in kilobytes in decimal (1KB = 1024 bytes)
-
-cycbuff:ONE:/export/cycbuffs/one:512000
-cycbuff:TWO:/export/cycbuffs/two:512000
-cycbuff:THREE:/export/cycbuffs/three:512000
-
-# 2. Meta-cyclic buffers
-# Format:
-# "metacycbuff" (literally) : symbolic meta-cyclic buffer name :
-# comma separated list of cyclic buffer symbolic names
-#
-# symbolic meta-cyclic buffer names are used in storage.conf in the
-# options field
-
-metacycbuff:BIGAREA:ONE,TWO
-metacycbuff:SMALLAREA:THREE
+++ /dev/null
-## $Revision: 6312 $
-## distrib.pats -- specify default Distribution header for newsgroups
-## Format:
-## <weight>:<pattern>:<value>
-## All articles are matched against all patterns, value to be used is the
-## one with the highest weight.
-## <weight> The weight assigned to this match, integer
-## <pattern> Newsgroup name or single wildmat(3) pattern
-## <value> Value of Distribution header.
-##
-##
-## Uncomment to default all local.* groups to a distribution of local.
-#10:local.*:local
+++ /dev/null
-## $Revision: 7143 $
-## expire.ctl - expire control file
-## Format:
-## /remember/:<keep>
-## <class>:<min>:<default>:<max>
-## <wildmat>:<flag>:<min>:<default>:<max>
-## First line gives history retention; second line specifies expiration
-## for classes; third line specifies expiration for group if groupbaseexpiry
-## is true
-## <class> class specified in storage.conf
-## <wildmat> wildmat-style patterns for the newsgroups
-## <min> Mininum number of days to keep article
-## <default> Default number of days to keep the article
-## <max> Flush article after this many days
-## <min>, <default>, and <max> can be floating-point numbers or the
-## word "never." Times are based on when received unless -p is used;
-## see expire.8
-
-## If article expires before 10 days, we still remember it for 10 days in
-## case we get offered it again. Depending on what you use for the innd
-## -c flag and how paranoid you are about old news, you might want to
-## make this 28, 30, etc, but it's probably safe to reduce it to 7 in most
-## cases if you want to keep your history file smaller.
-/remember/:10
-
-## Keep for 1-10 days, allow Expires headers to work. This entry uses
-## the syntax appropriate when groupbaseexpiry is true in inn.conf.
-*:A:1:10:never
-
-## Keep for 1-10 days, allow Expires headers to work. This is an entry
-## based on storage class, used when groupbaseexpiry is false.
-#0:1:10:never
+++ /dev/null
-# -*- tcl -*-
-#
-# $Revision: 4171 $
-#
-# A TCL procedure that will be run over every article. See doc/hook-tcl
-# for more details.
-
-proc filter_news {} {
-# global o Headers
-# set sum [checksum_article]
-# puts $o "$Headers(Message-ID) $sum"
-# set newsgroups [split $Headers(Newsgroups) ,]
-# foreach i $newsgroups {
-# if {$i=="alt.test" && [string match "*heiney@pa.dec.com*" $Headers(From)]} {
-# return "dont like alt.test from heiney"
-# }
-# }
- return "accept"
-}
+++ /dev/null
-#
-# $Id: filter_innd.pl 7860 2008-06-07 12:46:49Z iulius $
-#
-# Sample Perl filtering file for the innd hooks.
-#
-
-# This file gets loaded at innd process startup, and everytime a
-# "ctlinnd reload filter.perl 'reason'" or a
-# "ctlinnd reload all 'reason'" is done.
-#
-# Before this file is loaded, the perl routine `filter_before_reload' is
-# called, and after it's finished loading, the perl routine
-# `filter_after_reload' is called. See startup_innd.pl for more details.
-#
-# The following routines can be defined here for use by innd:
-#
-# sub filter_art { ... }
-#
-# This routine is called before every article is accepted for
-# posting. Is is called with no arguments, but has access to
-# all the non-empty standard headers of the article via the
-# global associative array `%hdr.' If it returns the empty
-# string ("") then the article is accepted. If it returns any
-# non-null string value, then the article is rejected and the
-# returned string value is logged as the reason why.
-#
-# The standard headers are:
-#
-# Approved, Control, Date, Distribution, Expires,
-# From, Lines, Message-ID, Newsgroups, Path,
-# Reply-To, Sender, Subject, Supersedes, Bytes,
-# Also-Control, References
-#
-# sub filter_mode { ... }
-#
-# This routine is called every time `go', `pause', or
-# `throttle' is called. It is called with no arguments and
-# returns no value. The global associative array `%mode' has
-# three keyed values stored in it:
-#
-# 'Mode' The current mode
-# ("running", "paused", "throttled")
-# 'NewMode" The new mode
-# 'reason' The reason given.
-#
-# For example: %mode = ('Mode', 'running',
-# 'NewMode', 'throttled',
-# 'reason', 'doing nightly backups')
-#
-# If filter_art is not defined when this file is done loading, then
-# filtering is disabled. If any syntax error occurs when loading the file,
-# then filtering is disabled.
-#
-# sub filter_messageid { ... }
-#
-# This routine is called when each article (in streaming
-# mode only) is checked to see if INN wants to accept the
-# article. If it returns the empty string, the article
-# is accepted. If it returns a non-empty value, the
-# article is refused. It is called with one argument,
-# the message-id to check.
-
-
-
-#
-# Called on each article innd receives from a peer. Return "" to accept,
-# and any other non-null string to reject. If rejecting the string returned
-# will be part of the logged reason.
-#
-
-sub filter_art {
- my $rval = "" ; # Assume we'll accept. Cannot be `0'
-
-### Remove two leading '##' from the following section (and then
-### "ctlinnd reload filter.perl 'reason'" and the filter will reject articles that
-### have "make money" in the subject, or are posted to more than 10
-### newsgroups.
-
-## my ($maxgroups) = 10 ;
-##
-### Normally this output would be lost, but if you run innd with '-d -f' you
-### can see what's going on.
-###
-### foreach $key (sort keys %hdr) {
-### print "Header:\t$key Value:\t $hdr{$key}\n" ;
-### }
-##
-## if ($hdr{"Subject"} =~ /\$*make.*money.*\$*/i ) {
-## $rval = "no money requests here"
-## } elsif ( ( @_ = split(",",$hdr{'Newsgroups'}) ) > $maxgroups ) {
-## $rval = "too many groups" ;
-### Kill article with "Re: " but no References:
-## } elsif ($hdr{'Subject'} =~ /^Re: /o and $hdr{'References'} eq "") {
-## $rval = "Followup without References:";
-### Kill article with invalid From:
-## } elsif ($hdr{'From'} =~ /^\w*$/o or
-## $hdr{'From'} !~ /^(.+?)\@([-\w\d]+\.)*([-\w\d]+)\.([-\w\d]{2,})$/o) {
-## $rval = "From: is invalid, must be user\@[host.]domain.tld";
-## }
-###
-### print "Accepting\n" if ! $rval ;
-
- $rval ;
-}
-
-sub filter_mode {
- if ($mode{'NewMode'} eq "throttled" || $mode{'NewMode'} eq "paused") {
-# print "Closing spam database\n" ; # won't kill server.
-# &close_spam_database ;
- } else {
-# print "Opening spam database\n" ; # won't kill server
-# &open_spam_database ;
- }
-}
-
-sub filter_messageid {
- my ($messageid) = @_;
- $rval = '';
-# $rval = 'No' if ($messageid =~ /a\.spam\.domain>?/i);
- $rval;
-}
-
-
-
-
-
-###########################################################################
-##
-## Another sample. More elaborate, but cleaner... from Christophe
-## Wolfhugel <wolf@pasteur.fr>.
-##
-
-
-#### Regular expressions we reject.
-#### Format : Header => regexp => reason
-##%reject = (
-## 'Subject' => {
-## 'make.*money.*fast' => 'MMF rejected',
-## 'cash.*cash.*cash' => 'Cash rejected'
-## },
-##);
-##
-##sub filter_art {
-## my($rval) = '';
-## my(@ng, $i, $j, $k, $l);
-##
-## if ($hdr{'From'} !~ /\@/o) {
-## $rval = 'Invalid From';
-## } else {
-## while (($i, $j) = each %reject) {
-## while (($k, $l) = each %{$j}) {
-## if ($hdr{$i} =~ /$k/i) {
-## $rval = $l;
-## goto the_end;
-## }
-## }
-## }
-## }
-## @ng = split(/,/, $hdr{'Newsgroups'});
-## if ($#ng > 10) {
-## $rval = 'ECP rejected';
-## }
-##the_end:
-## undef %hdr;
-## return $rval
-##}
-##
-##sub filter_mode {
-##}
-##
-###%hdr = (
-### 'Subject' => 'Make money fast',
-### 'From' => 'bozo@gov.org'
-###);
-###&filter_art;
-
-
-
-###########################################################################
-##
-## From Chrisophe Wolfhugel again (wolf@pasteur.fr). This is not
-## standalone code.
-##
-
-##Just for the fun, I've added following code to filter_innd.pl :
-##
-## ## Keep track of the From and subject.
-## $i = "$hdr{'From'} $hdr{'Subject'}";
-## push(@history, $i);
-## $history{$i}++;
-##
-## ## Reject the EMP.
-## if ($history{$i} > 10) {
-## $rval = "EMP rejected (appeared $history{$i} times): $i";
-## }
-##
-## ## Remove too old things.
-## while ($#history > 1000) {
-## delete($history{shift(@history)});
-## }
-##
-##It is pretty successfull in detecting and refusing excessive multi-posting.
-##Same sender, same subject, appearing more than 10 times without the last
-##1000 articles gets junked.
-##
-##Already catched a few hundreds :
-##
-##Nov 20 08:27:23.175 - vishnu.jussieu.fr <3292ac9a.4064710@nntp.cts.com> 437 EMP rejected (btr@trenet.com Be a Beta Tester!)
-##
-##That was just for the pleasure. It is still sucking a non significant CPU
-##time on my slow Alpha.
-
+++ /dev/null
-## $Id: filter_innd.py 7903 2008-06-22 20:41:59Z iulius $
-##
-## This is a sample filter for the Python innd hook.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-##
-## You have access to the following methods from the module INN:
-## - addhist(message-id)
-## - article(message-id)
-## - cancel(message-id)
-## - havehist(message-id)
-## - hashstring(string)
-## - head(message-id)
-## - newsgroup(groupname)
-## - set_filter_hook(instance)
-## - syslog(level, message)
-
-import re
-from string import *
-
-## This looks weird, but creating and interning these strings should
-## let us get faster access to header keys (which innd also interns) by
-## losing some strcmps under the covers.
-Also_Control = intern("Also-Control")
-Approved = intern("Approved")
-Bytes = intern("Bytes")
-Cancel_Key = intern("Cancel-Key")
-Cancel_Lock = intern("Cancel-Lock")
-Content_Base = intern("Content-Base")
-Content_Disposition = intern("Content-Disposition")
-Content_Transfer_Encoding = intern("Content-Transfer-Encoding")
-Content_Type = intern("Content-Type")
-Control = intern("Control")
-Date = intern("Date")
-Date_Received = intern("Date-Received")
-Distribution = intern("Distribution")
-Expires = intern("Expires")
-Face = intern("Face")
-Followup_To = intern("Followup-To")
-From = intern("From")
-In_Reply_To = intern("In-Reply-To")
-Injection_Date = intern("Injection-Date")
-Injection_Info = intern("Injection-Info")
-Keywords = intern("Keywords")
-Lines = intern("Lines")
-List_ID = intern("List-ID")
-Message_ID = intern("Message-ID")
-MIME_Version = intern("MIME-Version")
-Newsgroups = intern("Newsgroups")
-NNTP_Posting_Date = intern("NNTP-Posting-Date")
-NNTP_Posting_Host = intern("NNTP-Posting-Host")
-Organization = intern("Organization")
-Originator = intern("Originator")
-Path = intern("Path")
-Posted = intern("Posted")
-Posting_Version = intern("Posting-Version")
-Received = intern("Received")
-References = intern("References")
-Relay_Version = intern("Relay-Version")
-Reply_To = intern("Reply-To")
-Sender = intern("Sender")
-Subject = intern("Subject")
-Supersedes = intern("Supersedes")
-User_Agent = intern("User-Agent")
-X_Auth = intern("X-Auth")
-X_Canceled_By = intern("X-Canceled-By")
-X_Cancelled_By = intern("X-Cancelled-By")
-X_Complaints_To = intern("X-Complaints-To")
-X_Face = intern("X-Face")
-X_HTTP_UserAgent = intern("X-HTTP-UserAgent")
-X_HTTP_Via = intern("X-HTTP-Via")
-X_Mailer = intern("X-Mailer")
-X_Modbot = intern("X-Modbot")
-X_Modtrace = intern("X-Modtrace")
-X_Newsposter = intern("X-Newsposter")
-X_Newsreader = intern("X-Newsreader")
-X_No_Archive = intern("X-No-Archive")
-X_Original_Message_ID = intern("X-Original-Message-ID")
-X_Original_Trace = intern("X-Original-Trace")
-X_Originating_IP = intern("X-Originating-IP")
-X_PGP_Key = intern("X-PGP-Key")
-X_PGP_Sig = intern("X-PGP-Sig")
-X_Poster_Trace = intern("X-Poster-Trace")
-X_Postfilter = intern("X-Postfilter")
-X_Proxy_User = intern("X-Proxy-User")
-X_Submissions_To = intern("X-Submissions-To")
-X_Trace = intern("X-Trace")
-X_Usenet_Provider = intern("X-Usenet-Provider")
-Xref = intern("Xref")
-__BODY__ = intern("__BODY__")
-_LINES__ = intern("__LINES__")
-
-
-class InndFilter:
- """Provide filtering callbacks to innd."""
-
- def __init__(self):
- """This runs every time the filter is loaded or reloaded.
- This is a good place to initialize variables and precompile
- regular expressions, or maybe reload stats from disk.
- """
- self.re_newrmgroup = re.compile('(?:new|rm)group\s')
- self.re_obsctl = re.compile('(?:sendsys|version|uuname)')
- # Message-ID pattern from a once-common spambot.
- self.re_none44 = re.compile('none\d+\.yet>')
- # There is a mad newgrouper who likes to meow.
- self.re_meow = re.compile("^Meow\!", re.M)
- # One of my silly addresses.
- self.re_fluffymorph = re.compile("andruQ@myremarQ.coM", re.I)
-
- def filter_before_reload(self):
- """Runs just before the filter gets reloaded.
-
- You can use this method to save state information to be
- restored by the __init__() method or down in the main module.
- """
- syslog('notice', "filter_before_reload executing...")
-
- def filter_close(self):
- """Runs when innd exits.
-
- You can use this method to save state information to be
- restored by the __init__() method or down in the main module.
- """
- syslog('notice', "filter_close running, bye!")
-
- def filter_messageid(self, msgid):
- """Filter articles just by their Message-IDs.
-
- This method interacts with the IHAVE and CHECK NNTP commands.
- If you return a non-empty string here, the offered article
- will be refused before you ever have to waste any bandwidth
- looking at it. This is not foolproof, so you should do your
- ID checks both here and in filter_art. (TAKETHIS does not
- offer the ID for examination, and a TAKETHIS isn't always
- preceded by a CHECK.)
- """
- return "" # Deactivate the samples.
-
- if self.re_none44.search(msgid):
- return "But I don't like spam!"
- if msgid[0:8] == '<cancel.':
- return "I don't do cybercancels."
-
- def filter_art(self, art):
- """Decide whether to keep offered articles.
-
- art is a dictionary with a bunch of headers, the article's
- body, and innd's reckoning of the line count. Items not
- in the article will have a value of None.
-
- The available headers are the ones listed near the top of
- innd/art.c. At this writing, they are:
-
- Also-Control, Approved, Bytes, Cancel-Key, Cancel-Lock,
- Content-Base, Content-Disposition, Content-Transfer-Encoding,
- Content-Type, Control, Date, Date-Received, Distribution, Expires,
- Face, Followup-To, From, In-Reply-To, Injection-Date, Injection-Info,
- Keywords, Lines, List-ID, Message-ID, MIME-Version, Newsgroups,
- NNTP-Posting-Date, NNTP-Posting-Host, Organization, Originator,
- Path, Posted, Posting-Version, Received, References, Relay-Version,
- Reply-To, Sender, Subject, Supersedes, User-Agent,
- X-Auth, X-Canceled-By, X-Cancelled-By, X-Complaints-To, X-Face,
- X-HTTP-UserAgent, X-HTTP-Via, X-Mailer, X-Modbot, X-Modtrace,
- X-Newsposter, X-Newsreader, X-No-Archive, X-Original-Message-ID,
- X-Original-Trace, X-Originating-IP, X-PGP-Key, X-PGP-Sig,
- X-Poster-Trace, X-Postfilter, X-Proxy-User, X-Submissions-To,
- X-Trace, X-Usenet-Provider, Xref.
-
- The body is the buffer in art['__BODY__'] and the INN-reckoned
- line count is held as an integer in art['__LINES__']. (The
- Lines: header is often generated by the poster, and large
- differences can be a good indication of a corrupt article.)
-
- If you want to keep an article, return None or "". If you
- want to reject, return a non-empty string. The rejection
- string will appear in transfer and posting response banners,
- and local posters will see them if their messages are
- rejected.
- """
- return "" # Deactivate the samples.
-
- # Catch bad Message-IDs from articles fed with TAKETHIS but no CHECK.
- idcheck = self.filter_messageid(art[Message_ID])
- if idcheck:
- return idcheck
-
- # There are some control messages we don't want to process or
- # forward to other sites.
- try:
- if art[Control] is not None:
- if self.re_newrmgroup.match(art[Control]):
- if self.re_meow.search(art[__BODY__]):
- return "The fake tale meows again."
- if art[Distribution] == buffer('mxyzptlk'):
- return "Evil control message from the 10th dimension"
- if self.re_obsctl.match(art[Control]):
- return "Obsolete control message"
-
- # If you don't know, you don't want to know.
- if self.re_fluffymorph.search(art[From]):
- return "No, you may NOT meow."
- except:
- syslog('n', str(sys.exc_info[1]))
-
- def filter_mode(self, oldmode, newmode, reason):
- """Capture server events and do something useful.
-
- When the admin throttles or pauses innd (and lets it go
- again), this method will be called. oldmode is the state we
- just left, and newmode is where we are going. reason is
- usually just a comment string.
-
- The possible values of newmode and oldmode are the five
- strings 'running', 'paused', 'throttled', 'shutdown' and
- 'unknown'. Actually 'unknown' shouldn't happen; it's there
- in case feeping creatures invade innd.
- """
- syslog('notice', 'state change from %s to %s - %s'
- % (oldmode, newmode, reason))
-
-
-"""
-Okay, that's the end of our class definition. What follows is the
-stuff you need to do to get it all working inside innd.
-"""
-
-## This import must succeed, or your filter won't work. I'll repeat
-## that: You MUST import INN.
-from INN import *
-
-## Some of the stuff below is gratuitous, just demonstrating how the
-## INN.syslog call works. That first thingy tells the Unix syslogger
-## what severity to use; you can abbreviate down to one letter and
-## it's case insensitive. Available levels are (in increasing levels
-## of seriousness) Debug, Info, Notice, Warning, Err, Crit, and
-## Alert. If you provide any other string, it will be defaulted to
-## Notice. You'll find the entries in the same log files innd itself
-## uses, with an 'innd: python:' prefix.
-##
-## The native Python syslog module seems to clash with INN, so use
-## INN's. Oh yeah -- you may notice that stdout and stderr have been
-## redirected to /dev/null -- if you want to print stuff, open your
-## own files.
-
-try:
- import sys
-except Exception, errmsg:
- syslog('Error', "import boo-boo: " + errmsg[0])
-
-
-## If you want to do something special when the server first starts
-## up, this is how to find out when it's time.
-
-if 'spamfilter' not in dir():
- syslog('n', "First load, so I can do initialization stuff.")
- # You could unpickle a saved hash here, so that your hard-earned
- # spam scores aren't lost whenever you shut down innd.
-else:
- syslog('NoTicE', "I'm just reloading, so skip the formalities.")
-
-
-## Finally, here is how we get our class on speaking terms with innd.
-## The hook is refreshed on every reload, so that you can change the
-## methods on a running server. Don't forget to test your changes
-## before reloading!
-spamfilter = InndFilter()
-try:
- set_filter_hook(spamfilter)
- syslog('n', "spamfilter successfully hooked into INN")
-except Exception, errmsg:
- syslog('e', "Cannot obtain INN hook for spamfilter: %s" % errmsg[0])
-
+++ /dev/null
-#
-# $Id: filter_nnrpd.pl 5981 2002-12-12 05:01:42Z vinocur $
-#
-# Sample perl filtering code for nnrpd hook.
-#
-
-#
-# This file is loaded when nnrpd starts up. If it defines a sub named
-# `filter_post', then that function will be called during processing of a
-# posting. It has access to the headers of the article via the associative
-# array `%hdr'. If it returns a null string then the article is accepted
-# for posting. A non-null string rejects it, and the value returned is used
-# in the rejection message.
-#
-
-#
-# Do any initialization steps.
-#
-my %config = (checkincludedtext => 0,
- includedcutoff => 40,
- includedratio => 0.6,
- quotere => '^[>:]',
- antiquotere => '^[<]', # so as not to reject dict(1) output
- );
-
-
-#
-# Sample filter
-#
-sub filter_post {
- my $rval = "" ; # assume we'll accept.
-
-### Uncomment this next block to reject articles that have 'make money'
-### in their subject, or which have a "Re: " subject, but no References:
-### header, or which have an invalid From.
-
-## if ($hdr{"Subject"} =~ /make.*money/i) {
-## $rval = "Spam is not acceptable here..." ;
-## } elsif ($hdr{'Subject'} =~ /^Re: /o and $hdr{'References'} eq "") {
-## $rval = "Followup without References:";
-## } elsif ($hdr{'From'} =~ /^\w*$/o or
-## $hdr{'From'} !~ /^(.+?)\@([-\w\d]+\.)*([-\w\d]+)\.([-\w\d]{2,})$/o) {
-## $rval = "From: is invalid, must be user\@[host.]domain.tld";
-## }
-
-
-### The next block rejects articles with too much quoted text, if the
-### config hash directs it to.
-
- if ($config{checkincludedtext}) {
- my ($lines, $quoted, $antiquoted) = analyze($body);
- if ($lines > $config{includedcutoff}
- && $quoted - $antiquoted > $lines * $config{includedratio}) {
- $rval = "Article contains too much quoted text";
- }
- }
-
- return $rval;
-}
-
-sub analyze {
- my ($lines, $quoted, $antiquoted) = (0, 0, 0);
- local $_ = shift;
-
- do {
- if ( /\G$config{quotere}/mgc ) {
- $quoted++;
- } elsif ( /\G$config{antiquotere}/mgc ) {
- $antiquoted++;
- }
- } while ( /\G(.*)\n/gc && ++$lines );
-
- return ($lines, $quoted, $antiquoted);
-}
+++ /dev/null
-## $Revision: 2372 $
-## incoming.conf - names and addresses that feed us news
-##
-## This file consists of three types of entries: key/value, peer and group.
-## Comments are taken from the hash character ``#'' to the end of the line.
-## Blank lines are ignored.
-##
-## Key/value entries are a keyword immediatly followed by a colon, at least
-## one blank and a value. For example:
-##
-## max-connections: 10
-##
-## A legal key contains nor blanks, nor colon, nor ``#''.
-## There are 5 different type of values: integers, booleans, and strings.
-## Integers are as to be expected. A boolean value is either ``true'' or
-## ``false'' (case is significant). A string value is any other sequence of
-## characters. If the string needs to contain whitespace, then it must be
-## quoted with double quotes.
-##
-## Peer entries look like:
-##
-## peer <name> {
-## # body
-## }
-##
-## The word ``peer'' is required. <name> is a label for this peer. It is
-## any string valid as a key. The body of a peer entry contains some number
-## of key/value entries.
-##
-## Group entries look like:
-##
-## group <name> {
-## # body
-## }
-##
-## The word ``group'' is required. The ``<name>'' is any string valid as a
-## key. The body of a group entry contains any number of the three types of
-## entries. So key/value pairs can be defined inside a group, and peers can
-## be nested inside a group, and other groups can be nested inside a group.
-##
-## Key/value entries that are defined outside of all peer and group entries
-## are said to be at ``global scope''. Global key/value entries act as
-## defaults for peers. When innd looks for a specific value in a peer entry
-## (for example, the maximum number of connections to allow), if the value
-## is not defined in the peer entry, then the enclosing groups are examined
-## for the entry (starting at the closest enclosing group). If there are no
-## enclosing groups, or the enclosing groups don't define the key/value,
-## then the value at global scope is used.
-##
-## A small example could be:
-##
-## # Global value applied to all peers that have no value of their own.
-## max-connections: 5
-##
-## # A peer definition.
-## peer uunet {
-## hostname: usenet1.uu.net
-## }
-##
-## peer vixie {
-## hostname: gw.home.vix.com
-## max-connections: 10 # override global value.
-## }
-##
-## # A group of two peers who can open more connections than normal
-## group fast-sites {
-## max-connections: 15
-##
-## # Another peer. The ``max-connections'' value from the
-## # ``fast-sites'' group scope is used.
-## peer data.ramona.vix.com {
-## hostname: data.ramona.vix.com
-## }
-##
-## peer bb.home.vix.com {
-## hostname: bb.home.vix.com
-## max-connections: 20 # he can really cook.
-## }
-## }
-##
-## Given the above configuration file, the defined peers would have the
-## following values for the ``max-connections'' key.
-##
-## uunet 5
-## vixie 10
-## data.ramona.vix.com 15
-## bb.home.vix.com 20
-##
-## Height keys are allowed:
-##
-## hostname:
-## This key is mandatory in a peer block. The value is a string representing
-## a list of hostnames separated by a comma. A hostname is the host's FQDN,
-## or the dotted quad ip-address of the peer.
-##
-## streaming:
-## This key requires a boolean value. It defines whether streaming commands
-## are allowed from this peer. (default=true)
-##
-## max-connections:
-## This key requires positive integer value. It defines the maximum number
-## of connections allowed. A value of zero specifies an unlimited number
-## of maximum connections (``unlimited'' or ``none'' can be used as synonym).
-## (default=0)
-##
-## hold-time:
-## This key requires positive integer value. It defines the hold time before
-## close, if the connection is over max-connections. A value of zero
-## specifies immediate close. (default=0)
-##
-## password:
-## This key requires a string value. It is used if you wish to require a peer
-## to supply a password. (default=no password)
-##
-## patterns:
-## This key requires a string value. It is a list of newsfeeds(5)-style list
-## of newsgroups which are to be accepted from this host. (default="*")
-##
-## email:
-## This key requires a string value. Reserved for future use. (default=empty)
-##
-## comment:
-## This key requires a string value. Reserved for future use. (default=empty)
-##
-## skip:
-## This key requires a boolean value. Setting this entry causes this peer
-## to be skipped. Reserved for future use. (default=false)
-##
-## noresendid:
-## This key requires a boolean value. It defines whether innd should send
-## "431 RESENDID" (stream mode) or "436 Retry later" (non-stream mode)
-## responses if a message is offered that is already received from another
-## peer. This can be useful for peers that resend messages right away,
-## as innfeed does. (default=false)
-##
-
-streaming: true # streaming allowed by default
-max-connections: 8 # per feed
-
-peer ME {
- hostname: "localhost, 127.0.0.1"
-}
+++ /dev/null
-## $Id: inn.conf.in 7751 2008-04-06 14:35:40Z iulius $
-##
-## inn.conf -- INN configuration data
-##
-## Format:
-## <parameter>:<whitespace><value>
-##
-## Blank values are allowed for certain parameters.
-##
-## See the inn.conf(5) man page for a full description of each of these
-## options. This sample file is divided into two sections; first, there
-## are the parameters that must be set (or should be set in nearly all
-## cases), and then all parameters are given with their defaults for
-## reference in the same order and with the same organization as the
-## inn.conf(5) documentation.
-
-# The following parameters are most likely to need setting, although the
-# defaults generated by configure may be reasonable.
-
-mta: "@SENDMAIL@ -oi -oem %s"
-organization: "A poorly-installed InterNetNews site"
-ovmethod: tradindexed
-hismethod: hisv6
-pathhost: @HOSTNAME@
-pathnews: @prefix@
-
-# General Settings
-
-#domain:
-#innflags:
-mailcmd: @prefix@/bin/innmail
-#server:
-
-# Feed Configuration
-
-artcutoff: 10
-#bindaddress:
-#bindaddress6:
-dontrejectfiltered: false
-hiscachesize: 0
-ignorenewsgroups: false
-immediatecancel: false
-linecountfuzz: 0
-maxartsize: 1000000
-maxconnections: 50
-#pathalias:
-#pathcluster:
-pgpverify: @pgpverify@
-port: 119
-refusecybercancels: false
-remembertrash: true
-#sourceaddress:
-#sourceaddress6:
-verifycancels: false
-wanttrash: false
-wipcheck: 5
-wipexpire: 10
-
-# Article Storage
-
-cnfscheckfudgesize: 0
-enableoverview: true
-groupbaseexpiry: true
-mergetogroups: false
-overcachesize: 15
-#ovgrouppat:
-storeonxref: true
-useoverchan: false
-wireformat: false
-xrefslave: false
-nfswriter: false
-
-# Reading
-
-allownewnews: true
-articlemmap: false
-clienttimeout: 600
-initialtimeout: 10
-msgidcachesize: 10000
-nnrpdcheckart: true
-nnrpdflags: ""
-noreader: false
-readerswhenstopped: false
-readertrack: false
-nfsreader: false
-nfsreaderdelay: 60
-tradindexedmmap: true
-nnrpdloadlimit: 16
-
-# Reading -- Keyword Support
-#
-# Enabling this without stopping innd and deleting the existing overview
-# database and adding will probably confuse a lot of things. You must
-# have compiled this support in too.
-
-keywords: false
-keyartlimit: 100000
-keylimit: 512
-keymaxwords: 250
-
-# Posting
-
-addnntppostingdate: true
-addnntppostinghost: true
-checkincludedtext: false
-#complaints:
-#fromhost:
-localmaxartsize: 1000000
-#moderatormailer:
-nnrpdauthsender: false
-#nnrpdposthost:
-nnrpdpostport: 119
-spoolfirst: false
-strippostcc: false
-
-# Posting -- Exponential Backoff
-
-backoffauth: false
-#backoffdb:
-backoffk: 1
-backoffpostfast: 0
-backoffpostslow: 1
-backofftrigger: 10000
-
-# Monitoring
-
-doinnwatch: true
-innwatchbatchspace: 800
-innwatchlibspace: 25000
-innwatchloload: 1000
-innwatchhiload: 2000
-innwatchpauseload: 1500
-innwatchsleeptime: 600
-innwatchspoolnodes: 200
-innwatchspoolspace: 8000
-
-# Logging
-
-docnfsstat: false
-logartsize: true
-logcancelcomm: false
-logcycles: 3
-logipaddr: true
-logsitename: true
-nnrpdoverstats: false
-nntpactsync: 200
-nntplinklog: false
-status: 0
-timer: 0
-
-# System Tuning
-
-badiocount: 5
-blockbackoff: 120
-chaninacttime: 600
-chanretrytime: 300
-datamovethreshold: 8192
-icdsynccount: 10
-keepmmappedthreshold: 1024
-#maxcmdreadsize:
-maxforks: 10
-nicekids: 4
-nicenewnews: 0
-nicennrpd: 0
-pauseretrytime: 300
-peertimeout: 3600
-rlimitnofile: -1
-
-# Paths
-
-patharchive: @SPOOLDIR@/archive
-patharticles: @SPOOLDIR@/articles
-pathbin: @prefix@/bin
-pathcontrol: @CONTROLDIR@
-pathdb: @DBDIR@
-pathetc: @ETCDIR@
-pathfilter: @FILTERDIR@
-pathhttp: @LOGDIR@
-pathincoming: @SPOOLDIR@/incoming
-pathlog: @LOGDIR@
-pathoutgoing: @SPOOLDIR@/outgoing
-pathoverview: @SPOOLDIR@/overview
-pathrun: @RUNDIR@
-pathspool: @SPOOLDIR@
-pathtmp: @tmpdir@
+++ /dev/null
-# $Revision: 7559 $
-#
-# Sample innfeed config file. See the comment block at the
-# end for a fuller description of the format, and innfeed.conf(5) for a
-# description of the entries.
-#
-
-##
-## Global values. Not specific to any peer. These are optional, but if
-## used will override the compiled in values.
-##
-
-pid-file: innfeed.pid # relative to pathrun
-debug-level: 0
-use-mmap: false
-log-file: innfeed.log # relative to pathlog
-stdio-fdmax: 0
-
-## Uncomment the next line to include the contents
-## of ``testfile'' at this point.
-
-#$INCLUDE testfile
-
-backlog-directory: innfeed # relative to pathspool
-backlog-rotate-period: 60
-backlog-ckpt-period: 30
-backlog-newfile-period: 600
-
-dns-retry: 900
-dns-expire: 86400
-close-period: 86400
-gen-html: false
-status-file: innfeed.status # relative to pathlog
-connection-stats: false
-host-queue-highwater: 200
-stats-period: 600
-stats-reset: 43200
-
-max-reconnect-time: 3600
-initial-reconnect-time: 30
-
-
-##
-## Defaults for all peers. These must all exist at
-## global scope. Any of them can be redefined
-## inside a peer or group definition.
-##
-
-article-timeout: 600
-response-timeout: 300
-initial-connections: 1
-max-connections: 5
-max-queue-size: 5
-streaming: true
-no-check-high: 95.0
-no-check-low: 90.0
-no-check-filter: 50.0
-port-number: 119
-force-ipv4: false
-drop-deferred: false
-min-queue-connection: false
-backlog-limit: 0
-backlog-factor: 1.10
-backlog-limit-highwater: 0
-dynamic-method: 3
-dynamic-backlog-filter: 0.7
-dynamic-backlog-low: 25.0
-dynamic-backlog-high: 50.0
-no-backlog: false
-backlog-feed-first: false
-
-##
-## Peers.
-##
-#peer decwrl {
-# ip-name: news1.pa.dec.com
-#}
-
-#peer uunet {
-# ip-name: news.uunet.uu.net
-# max-connections: 10
-#}
-
-
-##
-## Group peers together to give second level defaults.
-##
-#group fast-sites {
-# max-connections: 7
-#
-# peer data.ramona.vix.com {
-# # ip-name defaults to data.ramona.vix.com
-# streaming: false
-# }
-#
-# peer bb.home.vix.com {
-# ip-name: 192.5.5.33
-# }
-#}
-
-
-
-# Blank lines are ignored. Exerything after a '#'
-# is ignored too.
-#
-# Format is:
-# key : value
-#
-# See innfeed.conf(5) for a description of
-# necessary & useful keys. Unknown keys and their
-# values are ignored.
-#
-# Values may be a integer, floating-point, c-style
-# single-quoted characters, boolean, and strings.
-#
-# If a string value contains whitespace, or
-# embedded quotes, or the comment character
-# (``#''), then the whole string must be quoted
-# with double quotes. Inside the quotes, you may
-# use the standard c-escape sequence
-# (\t,\n,\r,\f,\v,\",\').
-#
-# Examples:
-# eg-string: "New\tConfig\tfile\n"
-# eg-long-string: "A long string that goes
-# over multiple lines. The
-# newline is kept in the
-# string except when quoted
-# with a backslash \
-# as here."
-# eg-simple-string: A-no-quote-string
-# eg-integer: 10
-# eg-boolean: true
-# eg-char: 'a'
-# eg-ctrl-g: '\007'
+++ /dev/null
-##########################################################
-# Configuration file for innreport (3.*).
-#
-# Sample file for INN.
-# Tested with INN 2.3, 2.1, 1.7.2 and 1.5.1.
-#
-# (c) 1997, 1998, 1999 by Fabien Tassin <fta@sofaraway.org>
-# version 3.0.2
-##########################################################
-
-# Default parameters
-section default {
- libpath "@LIBDIR@";
- logpath "@LOGDIR@";
- unknown true; # want unknown entries.
- max_unknown 50; # max unknown entries to display.
- casesensitive true;
- module "innreport_inn"; # ${libpath}/${module}.pm
- unwanted_log "unwanted.log"; # ${logpath}/${unwanted_log}
- text true;
- html false;
- graph true; # need 'html'
- archive true; # use false to keep only the latest HTML report.
- index "index.html"; # name of the HTML index file.
- # html_dir "/var/www/News/stats"; # default to pathhttp in inn.conf
- img_dir "pics"; # images will go to ${html_dir}/${img_dir}
- cycle none; # use a number or 'none'.
- separator "."; # use a valid filename character.
- title "Daily Usenet report";
- # title "Daily Usenet report for <A HREF=\"/News/stats/\">news.y.z</A>";
- # footer "Local contact: <A HREF=\"mailto:x@y.z\">x@y.z</A>";
- # html_body "BGCOLOR=\"#FFFFFF\" TEXT=\"#000000\"";
- # html_header_file "header.html"; # ${html_dir}/${html_header_file}
- # html_footer_file "footer.html"; # ${html_dir}/${html_footer_file}
- graph_width 550; # graph width (in pixels)
- transparent true; # graph background transparent ?
- graph_fg "#000000"; # graph foreground color.
- graph_bg "#FFFFFF"; # graph background color.
-};
-
-###########################################################################
-# Index page
-section index {
- column {
- title "Dates";
- value "date";
- };
- column {
- title "Incoming feeds";
- name "Offered|Accepted|Volume";
- value "total(%innd_offered) | total(%innd_accepted) |
- bytes(total(%inn_flow_size))";
- };
- column {
- title "Outgoing feeds";
- name "Offered|Accepted|Volume";
- value "total(%innfeed_offered) + total(%nntplink_offered) +
- total(%innxmit_offered) | total(%innfeed_accepted) +
- total(%nntplink_accepted) + total(%innxmit_accepted) |
- bytes(total(%innfeed_accepted_size) +
- total(%innfeed_rejected_size) +
- total(%innxmit_bytes) +
- total(%innxmit_accepted_size) +
- total(%innxmit_rejected_size))";
- };
- graph {
- title "Incoming feeds";
- value val1;
- color "#FFFFCE";
- unit "art";
- data {
- name "Offered";
- color "#50A0D0";
- value "val2"; # Incoming feeds: Offered
- };
- data {
- name "Accepted";
- color "#0000FF";
- value "val3"; # Incoming feeds: Accepted
- };
- };
- graph {
- title "Outgoing feeds";
- value val1;
- color "#FFFFCE";
- unit "art";
- data {
- name "Offered";
- color "#50A0D0";
- value "val5"; # Outgoing feeds: Offered
- };
- data {
- name "Accepted";
- color "#0000FF";
- value "val6"; # Outgoing feeds: Accepted
- };
- };
- graph {
- title "Bandwidth";
- value val1;
- color "#FFFFCE";
- unit "Kb";
- data {
- name "Incoming";
- color "#50A0D0";
- value "byte(val4)"; # Incoming feeds: Volume
- };
- data {
- name "Outgoing";
- color "#0000FF";
- value "byte(val7)"; # Outgoing feeds: Volume
- };
- };
-};
-
-###########################################################################
-# Report
-
-section prog_type {
- # skip true; # used to skip a section.
- title "Log entries by program:";
- data "%prog_type";
- sort "$prog_type{$b} <=> $prog_type{$a}";
- # text false; # to skip this section in the text report
- # html false; # to skip this section in the HTML report
- column {
- name "Program name";
- format "%-46.46s";
- value "$key";
- format_total "TOTAL: %-39.39s";
- total "$num";
- };
- column {
- name "Lines";
- format_name "%7s";
- format "%7d";
- # text false; # to skip this column in the text report
- value "$prog_type{$key}";
- total "total(%prog_type)";
- };
- column {
- name "%Lines";
- format_name "%7s";
- format "%6.1f%%";
- # html false; # to skip this column in the HTML report
- value "$prog_type{$key} / total(%prog_type) * 100";
- total "100";
- };
- column {
- name "Size";
- format "%9s";
- value "bytes($prog_size{$key})";
- total "bytes(total(%prog_size))";
- };
- column {
- name "%Size";
- format_name "%6s";
- format "%5.1f%%";
- value "$prog_size{$key} / total(%prog_size) * 100";
- total "100";
- };
-};
-
-# INN 2.*
-section innd_his {
- title "History cache:";
- data "%innd_his";
- sort "$innd_his{$b} <=> $innd_his{$a}";
- column {
- name "Reason";
- format "%-57.57s";
- value "$key";
- format_total "TOTAL: %-50.50s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%10s";
- format "%10d";
- value "$innd_his{$key}";
- total "total(%innd_his)";
- };
- column {
- name "%Count";
- format_name "%10s";
- format "%9.1f%%";
- value "100 * $innd_his{$key} / total(%innd_his)";
- total "100";
- };
-};
-
-# INN 1.*
-section innd_cache {
- title "History cache:";
- data "%innd_cache";
- sort "$innd_cache{$b} <=> $innd_cache{$a}";
- column {
- name "Reason";
- format "%-57.57s";
- value "$key";
- format_total "TOTAL: %-50.50s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%10s";
- format "%10d";
- value "$innd_cache{$key}";
- total "total(%innd_cache)";
- };
- column {
- name "%Count";
- format_name "%10s";
- format "%9.1f%%";
- value "100 * $innd_cache{$key} / total(%innd_cache)";
- total "100";
- };
-};
-
-section innd_timer {
- title "INND timer:";
- data "%innd_time_time";
- column {
- name "Code region";
- format "%-15.15s";
- value "$key";
- format_total "TOTAL: %-8.8s";
- total "time_ms($innd_time_times)";
- };
- column {
- name "Time";
- format "%13s";
- value "time_ms($innd_time_time{$key})";
- total "time_ms(total(%innd_time_time))";
- };
- column {
- name "Pct";
- format_name "%6s";
- format "%5.1f%%";
- value "100 * $innd_time_time{$key} / $innd_time_times";
- total "100 * total(%innd_time_time) /
- $innd_time_times";
- };
- column {
- name "Invoked";
- format "%10s";
- value "$innd_time_num{$key}";
- format_total "%9s-";
- total "";
- };
- column {
- name "Min(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$innd_time_min{$key}";
- format_total "%8s-";
- total "";
- };
- column {
- name "Avg(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$innd_time_time{$key} /
- ($innd_time_num{$key} ? $innd_time_num{$key} : 1)";
- format_total "%9s-";
- total "";
- };
- column {
- name "Max(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$innd_time_max{$key}";
- format_total "%9s-";
- total "";
- };
-};
-
-section innfeed_timer {
- title "INNfeed timer:";
- data "%innfeed_time_time";
- column {
- name "Code region";
- format "%-15.15s";
- value "$key";
- format_total "TOTAL: %-8.8s";
- total "time_ms($innfeed_time_times)";
- };
- column {
- name "Time";
- format "%13s";
- value "time_ms($innfeed_time_time{$key})";
- total "time_ms(total(%innfeed_time_time))";
- };
- column {
- name "Pct";
- format_name "%6s";
- format "%5.1f%%";
- value "100 * $innfeed_time_time{$key} / $innfeed_time_times";
- total "100 * total(%innfeed_time_time) /
- $innfeed_time_times";
- };
- column {
- name "Invoked";
- format "%10s";
- value "$innfeed_time_num{$key}";
- format_total "%9s-";
- total "";
- };
- column {
- name "Min(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$innfeed_time_min{$key}";
- format_total "%8s-";
- total "";
- };
- column {
- name "Avg(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$innfeed_time_time{$key} /
- ($innfeed_time_num{$key} ? $innfeed_time_num{$key} : 1)";
- format_total "%9s-";
- total "";
- };
- column {
- name "Max(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$innfeed_time_max{$key}";
- format_total "%9s-";
- total "";
- };
-};
-
-section nnrpd_timer {
- title "nnrpd timer:";
- data "%nnrpd_time_time";
- column {
- name "Code region";
- format "%-15.15s";
- value "$key";
- format_total "TOTAL: %-8.8s";
- total "time_ms($nnrpd_time_times)";
- };
- column {
- name "Time";
- format "%13s";
- value "time_ms($nnrpd_time_time{$key})";
- total "time_ms(total(%nnrpd_time_time))";
- };
- column {
- name "Pct";
- format_name "%6s";
- format "%5.1f%%";
- value "100 * $nnrpd_time_time{$key} / $nnrpd_time_times";
- total "100 * total(%nnrpd_time_time) /
- $nnrpd_time_times";
- };
- column {
- name "Invoked";
- format "%10s";
- value "$nnrpd_time_num{$key}";
- format_total "%9s-";
- total "";
- };
- column {
- name "Min(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$nnrpd_time_min{$key}";
- format_total "%8s-";
- total "";
- };
- column {
- name "Avg(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$nnrpd_time_time{$key} /
- ($nnrpd_time_num{$key} ? $nnrpd_time_num{$key} : 1)";
- format_total "%9s-";
- total "";
- };
- column {
- name "Max(ms)";
- format_name "%10s";
- format "%10.3f";
- value "$nnrpd_time_max{$key}";
- format_total "%9s-";
- total "";
- };
-};
-
-section innd_control {
- title "Control commands to INND:";
- data "%innd_control";
- column {
- name "Command";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Number";
- format_name "%7s";
- value "$innd_control{$key}";
- format "%7d";
- total "total(%innd_control)";
- };
-};
-
-section innd_newgroup {
- title "Newsgroups created:";
- data "%innd_newgroup";
- column {
- name "Group";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL%-66.66s";
- total "";
- };
- column {
- name "Mode";
- value "$innd_newgroup{$key}";
- format "%7s";
- total "$num";
- };
-};
-
-section innd_changegroup {
- title "Newsgroups changed:";
- data "%innd_changegroup";
- column {
- name "Group";
- format "%-68.68s";
- value "$key";
- format_total "TOTAL%-63.63s";
- total "";
- };
- column {
- name "New mode";
- format "%10s";
- value "$innd_changegroup{$key}";
- total "$num";
- };
-};
-
-section innd_rmgroup {
- title "Newsgroups removed:";
- data "%innd_rmgroup";
- column {
- name "Group";
- format "%-78.78s";
- value "$key";
- format_total "TOTAL: %-71.71s";
- total "$num";
- };
-};
-
-section controlchan {
- title "Control Channel:";
- data "%controlchan_who";
- column {
- name "Sender";
- format "%-25.25s";
- value "$key";
- format_total "TOTAL%-20.20s";
- total "";
- };
- column {
- name "newgroup";
- value "$controlchan_new{$key}";
- format "%8s";
- total "total(%controlchan_new)";
- };
- column {
- name "rmgroup";
- value "$controlchan_rm{$key}";
- format "%8s";
- total "total(%controlchan_rm)";
- };
- column {
- name "Other";
- value "$controlchan_other{$key}";
- format "%8s";
- total "total(%controlchan_other)";
- };
- column {
- name "Bad PGP";
- value "$controlchan_skippgp{$key}";
- format "%8s";
- total "total(%controlchan_skippgp)";
- };
- column {
- name "DoIt";
- value "$controlchan_doit{$key}";
- format "%8s";
- total "total(%controlchan_doit)";
- };
- column {
- name "OK";
- value "$controlchan_ok{$key}";
- format "%8s";
- total "total(%controlchan_ok)";
- };
-};
-
-section innd_connect {
- title "Incoming Feeds (INN):";
- data "%innd_seconds";
- sort "$innd_accepted{$b} <=> $innd_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format_name "%-21.21s";
- format "%-24.24s";
- value "$key";
- format_total "TOTAL: %-17.17s";
- total "$num";
- };
- column {
- name "Connects";
- format_name "%5s";
- format "%5d";
- value "$innd_connect{$key}";
- total "total(%innd_connect)";
- };
- column {
- name "Offered";
- format_name "%8s";
- format "%8d";
- value "$innd_offered{$key}";
- total "total(%innd_offered)";
- };
- column {
- name "Taken";
- format_name "%7s";
- format "%7d";
- value "$innd_accepted{$key}";
- total "total(%innd_accepted)";
- };
- column {
- name "Refused";
- format_name "%7s";
- format "%7d";
- value "$innd_refused{$key}";
- total "total(%innd_refused)";
- };
- column {
- name "Reject";
- format_name "%7s";
- format "%7d";
- value "$innd_rejected{$key}";
- total "total(%innd_rejected)";
- };
- column {
- name "%Accpt";
- format_name "%6s";
- format "%4d%%";
- value "$innd_offered{$key} == 0 ? 0 :
- $innd_accepted{$key} / $innd_offered{$key} * 100";
- total "total(%innd_offered) == 0 ? 0 :
- total(%innd_accepted) / total(%innd_offered) * 100";
- };
- column {
- name "Elapsed";
- format_name "%8s";
- format "%9s";
- value "time($innd_seconds{$key})";
- total "time(total(%innd_seconds))";
- };
- graph {
- title "Articles received by server";
- type histo3d;
- sort "%innd_accepted";
- data {
- name "Articles accepted";
- color "#0000FF";
- value "%innd_accepted";
- };
- data {
- name "Articles refused";
- color "#FFAF00";
- value "%innd_refused";
- };
- data {
- name "Articles rejected";
- color "#FF0000";
- value "%innd_rejected";
- };
- };
-};
-
-section innd_incoming_vol {
- title "Incoming Volume (INN):";
- data "%innd_seconds";
- sort "$innd_stored_size{$b} <=> $innd_stored_size{$a}";
- numbering true;
- column {
- name "Server";
- format "%-24.24s";
- value "$key";
- format_total "TOTAL: %-17.17s";
- total "$num";
- };
- column {
- name "AcceptVol";
- format "%9s";
- value "bytes($innd_stored_size{$key})";
- total "bytes(total(%innd_stored_size))";
- };
- column {
- name "DupVol";
- format "%9s";
- value "bytes($innd_duplicated_size{$key})";
- total "bytes(total(%innd_duplicated_size))";
- };
- column {
- name "TotalVol";
- format "%9s";
- value "bytes($innd_stored_size{$key} +
- $innd_duplicated_size{$key})";
- total "bytes(total(%innd_stored_size) +
- total(%innd_duplicated_size))";
- };
- column {
- name "%Acc";
- format_name "%4s";
- format "%3d%%";
- value "$innd_offered_size{$key} == 0 ? 0 :
- $innd_stored_size{$key} / $innd_offered_size{$key} * 100";
- total "total(%innd_offered_size) == 0 ? 0 :
- total(%innd_stored_size) / total(%innd_offered_size) * 100";
- };
- column {
- name "Vol/Art";
- format "%9s";
- value "bytes(($innd_stored_size{$key} +
- $innd_duplicated_size{$key}) /
- ($innd_accepted{$key} +
- $innd_rejected{$key}))";
- total "bytes((total(%innd_stored_size) +
- total(%innd_duplicated_size)) /
- (total(%innd_accepted) +
- total(%innd_rejected)))";
- };
- column {
- name "Elapsed";
- format "%9s";
- value "time($innd_seconds{$key})";
- total "time(total(%innd_seconds))";
- };
- graph {
- title "Incoming Volume received by server";
- type histo3d;
- sort "%innd_stored_size";
- data {
- name "Accepted Volume";
- color "#0000FF";
- value "%innd_stored_size";
- };
- data {
- name "Duplicated Volume";
- color "#FFAF00";
- value "%innd_duplicated_size";
- };
- };
-};
-
-section inn_flow {
- title "Incoming articles:";
- data "%inn_flow";
- sort "&DateCompare";
- column {
- name "Date";
- format "%-27.27s";
- value "$key";
- format_total "TOTAL: %-20.20s";
- total "time(total(%inn_flow_time))";
- };
- column {
- name "Articles";
- format_name "%8s";
- value "$inn_flow{$key}";
- format "%8d";
- total "total(%inn_flow)";
- };
- column {
- name "%Arts";
- format_name "%8s";
- value "$inn_flow{$key} / $inn_flow_total * 100";
- format "%7.1f%%";
- total "100";
- };
- column {
- name "Art/sec";
- format_name "%7s";
- value "$inn_flow{$key} / $inn_flow_time{$key}";
- format "%7.2f";
- total "total(%inn_flow) / total(%inn_flow_time)";
- };
- column {
- name "Size";
- value "bytes($inn_flow_size{$key})";
- format "%9s";
- total "bytes(total(%inn_flow_size))";
- };
- column {
- name "%Size";
- format_name "%7s";
- value "$inn_flow_size{$key} /
- total(%inn_flow_size) * 100";
- format "%6.1f%%";
- total "100";
- };
- column {
- name "KB/sec";
- format_name "%7s";
- value "$inn_flow_size{$key} /
- $inn_flow_time{$key} / 1024";
- format "%7.2f";
- total "total(%inn_flow_size) /
- total(%inn_flow_time) / 1024";
- };
- graph {
- title "Incoming articles";
- type histo;
- data {
- name "Hours";
- value "%inn_flow_labels";
- };
- data {
- name "Art/sec";
- factor 3600;
- value "%inn_flow";
- };
- };
- graph {
- title "Incoming articles (size)";
- type histo;
- data {
- name "Hours";
- value "%inn_flow_labels";
- };
- data {
- name "Kb/sec";
- factor 3686400; # 3600 * 1024
- value "%inn_flow_size";
- };
- };
-};
-
-section cnfsstat {
- title "CNFS buffer status:";
- data "%cnfsstat";
- column {
- name "Buffer";
- format "%-13.13s";
- value "$key";
- format_total "TOTAL: %-6.6s";
- total "$num";
- };
- column {
- name "Class";
- format "%-13.13s";
- value "$cnfsstat{$key}";
- format_total "-%12s";
- total "";
- };
- column {
- name "Size";
- format "%9s";
- value "bytes($cnfsstat_size{$key})";
- total "bytes(total(%cnfsstat_size))";
- };
- column {
- name "Used";
- format "%9s";
- value "bytes($cnfsstat_used{$key})";
- total "bytes(total(%cnfsstat_used))";
- };
- column {
- name "%Used";
- format_name "%7s";
- value "$cnfsstat_used{$key} /
- $cnfsstat_size{$key} * 100";
- format "%6.1f%%";
- total "total(%cnfsstat_used) /
- total(%cnfsstat_size) * 100";
- };
- column {
- name "Cycles";
- format_name "%6s";
- format "%6d";
- value "$cnfsstat_cycles{$key}";
- total "total(%cnfsstat_cycles)";
- };
- column {
- name "KB/sec";
- format_name "%7s";
- value "$cnfsstat_rate{$key} /
- $cnfsstat_samples{$key} / 1024";
- format "%7.2f";
- total "total(%cnfsstat_rate) /
- total(%cnfsstat_samples) / 1024";
- };
- column {
- name "Days";
- format_name "%8s";
- value "$cnfsstat_size{$key} /
- ($cnfsstat_rate{$key} /
- $cnfsstat_samples{$key}) / 86400";
- format "%8.2f";
- format_total "%7s-";
- total "";
- };
-};
-
-section inn_unwanted {
- title "Sites sending bad articles:";
- data "%inn_badart";
- sort "$inn_badart{$b} <=> $inn_badart{$a}";
- numbering true;
- column {
- name "Server";
- format "%-23.23s";
- value "$key";
- format_total "TOTAL: %-16.16s";
- total "$num";
- };
- column {
- name "Total";
- format_name "%6s";
- format "%6d";
- value "$inn_badart{$key}";
- total "total(%inn_badart)";
- };
- column {
- name "Group";
- format_name "%6s";
- format "%6d";
- value "$inn_uw_ng_s{$key}";
- total "total(%inn_uw_ng_s)";
- };
- column {
- name "Dist";
- format_name "%5s";
- format "%5d";
- value "$inn_uw_dist_s{$key}";
- total "total(%inn_uw_dist_s)";
- };
- column {
- name "Duplic";
- format_name "%6s";
- format "%6d";
- value "$inn_duplicate{$key}";
- total "total(%inn_duplicate)";
- };
- column {
- name "Unapp";
- format_name "%5s";
- format "%5d";
- value "$inn_unapproved{$key}";
- total "total(%inn_unapproved)";
- };
- column {
- name "TooOld";
- format_name "%6s";
- format "%6d";
- value "$inn_tooold{$key}";
- total "total(%inn_tooold)";
- };
- column {
- name "Site";
- format_name "%4s";
- format "%4d";
- value "$inn_uw_site{$key}";
- total "total(%inn_uw_site)";
- };
- column {
- name "Line";
- format_name "%4s";
- format "%4d";
- value "$inn_linecount{$key}";
- total "total(%inn_linecount)";
- };
- column {
- name "Other";
- format_name "%5s";
- format "%5d";
- value "$innd_others{$key}";
- total "total(%innd_others)";
- };
-};
-
-section inn_unwanted_group {
- title "Unwanted newsgroups:";
- top 20; # default 'top' value or use 'top_text' and 'top_html'
- # to specify different values for text and HTML reports.
- data "%inn_uw_ng";
- sort "$inn_uw_ng{$b} <=> $inn_uw_ng{$a}";
- column {
- name "Newsgroup";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$inn_uw_ng{$key}";
- total "total(%inn_uw_ng)";
- };
-};
-
-section inn_unwanted_dist {
- title "Unwanted distributions:";
- top 20;
- data "%inn_uw_dist";
- sort "$inn_uw_dist{$b} <=> $inn_uw_dist{$a}";
- column {
- name "Distribution";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$inn_uw_dist{$key}";
- total "total(%inn_uw_dist)";
- };
-};
-
-section inn_unwanted_unapp {
- title "Supposedly-moderated groups with unmoderated postings:";
- top 20;
- data "%inn_unapproved_g";
- sort "$inn_unapproved_g{$b} <=> $inn_unapproved_g{$a}";
- column {
- name "Groups";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$inn_unapproved_g{$key}";
- total "total(%inn_unapproved_g)";
- };
-};
-
-section inn_unwanted_path {
- title "Unwanted sites in Path:";
- top 20;
- data "%inn_site_path";
- sort "$inn_site_path{$b} <=> $inn_site_path{$a}";
- column {
- name "Site";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$inn_site_path{$key}";
- total "total(%inn_site_path)";
- };
-};
-
-section innd_perl {
- title "INND Perl filter:";
- top 20;
- data "%innd_filter_perl";
- sort "$innd_filter_perl{$b} <=> $innd_filter_perl{$a}";
- column {
- name "Reason";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$innd_filter_perl{$key}";
- total "total(%innd_filter_perl)";
- };
-};
-
-section innd_python {
- title "INND Python filter:";
- top 20;
- data "%innd_filter_python";
- sort "$innd_filter_python{$b} <=> $innd_filter_python{$a}";
- column {
- name "Reason";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$innd_filter_python{$key}";
- total "total(%innd_filter_python)";
- };
-};
-
-section nocem {
- title "NoCeM on Spool:";
- data "%nocem_goodsigs";
- sort "$nocem_goodsigs{$b} <=> $nocem_goodsigs{$a}";
- column {
- name "Id";
- format "%-47.47s";
- value "$key";
- format_total "TOTAL: %-40.40s";
- total "$num";
- };
- column {
- name "Good";
- format "%7s";
- value "$nocem_goodsigs{$key}";
- total "total(%nocem_goodsigs)";
- };
- column {
- name "Bad";
- format "%7s";
- value "$nocem_badsigs{$key}";
- total "total(%nocem_badsigs)";
- };
- column {
- name "Unique";
- format "%7s";
- value "$nocem_newids{$key}";
- total "total(%nocem_newids)";
- };
- column {
- name "Total";
- format "%7s";
- value "$nocem_totalids{$key}";
- total "total(%nocem_totalids)";
- };
-};
-
-section innd_no_permission {
- title "INND no permission servers:";
- data "%innd_no_permission";
- sort "$innd_no_permission{$b} <=> $innd_no_permission{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$innd_no_permission{$key}";
- total "total(%innd_no_permission)";
- };
-};
-
-section innd_max_conn {
- title "Too many incoming connections (innd):";
- data "%innd_max_conn";
- sort "$innd_max_conn{$b} <=> $innd_max_conn{$a}";
- column {
- name "Server";
- format "%-70.70s";
- value "$key";
- format_total "TOTAL: %-63.63s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%8s";
- format "%8d";
- value "$innd_max_conn{$key}";
- total "total(%innd_max_conn)";
- };
-};
-
-section innd_too_many_connects_per_minute {
- title "INND too many connects per minute:";
- data "%innd_too_many_connects_per_minute";
- sort "$innd_too_many_connects_per_minute{$b} <=>
- $innd_too_many_connects_per_minute{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$innd_too_many_connects_per_minute{$key}";
- total "total(%innd_too_many_connects_per_minute)";
- };
-};
-
-section innd_misc {
- title "INND misc events:";
- data "%innd_misc";
- sort "$innd_misc{$b} <=> $innd_misc{$a}";
- column {
- name "Events";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$innd_misc{$key}";
- total "total(%innd_misc)";
- };
-};
-
-section innd_misc_stat {
- title "Miscellaneous innd statistics:";
- data "%innd_misc_stat";
- sort "$innd_misc_stat{$b} <=> $innd_misc_stat{$a}";
- double true;
- top 10;
- #numbering true;
- column {
- primary true;
- name "Event";
- format "%-69.69s";
- value "$key1";
- format_total "TOTAL: %-62.62s";
- total "$num";
- };
- column {
- name "Server";
- format " %-67.67s";
- value "$key2";
- total "$num";
- format_total "TOTAL: %-60.60s";
- };
- column {
- name "Number";
- format_name "%9s";
- format "%9d";
- value "$innd_misc_stat{$key1}{$key2}";
- total "total(%innd_misc_stat)";
- };
-};
-
-section innfeed_connect {
- title "Outgoing Feeds (innfeed) by Articles:";
- data "%innfeed_offered";
- sort "$innfeed_accepted{$b} <=> $innfeed_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format "%-18.18s";
- value "$key";
- format_total "TOTAL: %-11.11s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$innfeed_offered{$key}";
- total "total(%innfeed_offered)";
- };
- column {
- name "Taken";
- format_name "%7s";
- format "%7d";
- value "$innfeed_accepted{$key}";
- total "total(%innfeed_accepted)";
- };
- column {
- name "Refused";
- format_name "%7s";
- format "%7d";
- value "$innfeed_refused{$key}";
- total "total(%innfeed_refused)";
- };
- column {
- name "Reject";
- format_name "%6s";
- format "%6d";
- value "$innfeed_rejected{$key}";
- total "total(%innfeed_rejected)";
- };
- column {
- name "Miss";
- format_name "%6s";
- format "%6d";
- value "$innfeed_missing{$key}";
- total "total(%innfeed_missing)";
- };
- column {
- name "Spool";
- format_name "%7s";
- format "%7d";
- value "$innfeed_spooled{$key}";
- total "total(%innfeed_spooled)";
- };
- column {
- name "%Took";
- format_name "%5s";
- format "%3d%%";
- value "$innfeed_offered{$key} == 0 ? 0 :
- $innfeed_accepted{$key} / $innfeed_offered{$key} * 100";
- total "total(%innfeed_offered) == 0 ? 0 :
- total(%innfeed_accepted) / total(%innfeed_offered) * 100";
- };
- column {
- name "Elapsed";
- format_name "%8s";
- format "%9s";
- value "time($innfeed_seconds{$key})";
- total "time(total(%innfeed_seconds))";
- };
- graph {
- title "Outgoing feeds (innfeed) by Articles";
- type histo3d;
- sort "%innfeed_accepted";
- data {
- name "Accepted";
- color "#0000FF";
- value "%innfeed_accepted";
- };
- data {
- name "Refused";
- color "#FFAF00";
- value "%innfeed_refused";
- };
- data {
- name "Rejected";
- color "#FF0000";
- value "%innfeed_rejected";
- };
- data {
- name "Missing";
- color "#00FF00";
- value "%innfeed_missing";
- };
- data {
- name "Spooled";
- color "#AF00FF";
- value "%innfeed_spooled";
- };
- };
-};
-
-section innfeed_volume {
- title "Outgoing Feeds (innfeed) by Volume:";
- data "%innfeed_offered";
- sort "$innfeed_accepted_size{$b} <=> $innfeed_accepted_size{$a}";
- numbering true;
- column {
- name "Server";
- format "%-17.17s";
- value "$key";
- format_total "TOTAL: %-10.10s";
- total "$num";
- };
- column {
- name "AcceptVol";
- format "%9s";
- value "bytes($innfeed_accepted_size{$key})";
- total "bytes(total(%innfeed_accepted_size))";
- };
- column {
- name "RejectVol";
- format "%9s";
- value "bytes($innfeed_rejected_size{$key})";
- total "bytes(total(%innfeed_rejected_size))";
- };
- column {
- name "TotalVol";
- format "%9s";
- value "bytes($innfeed_accepted_size{$key} +
- $innfeed_rejected_size{$key})";
- total "bytes(total(%innfeed_accepted_size) +
- total(%innfeed_rejected_size))";
- };
- column {
- name "Volume/sec";
- format_name "%11s";
- format "%9s/s";
- value "bytes(($innfeed_accepted_size{$key} +
- $innfeed_rejected_size{$key}) /
- $innfeed_seconds{$key})";
- total "bytes((total(%innfeed_accepted_size) +
- total(%innfeed_rejected_size)) /
- total(%innfeed_seconds))";
- };
- column {
- name "Vol/Art";
- format "%9s";
- value "bytes(($innfeed_accepted_size{$key} +
- $innfeed_rejected_size{$key}) /
- ($innfeed_accepted{$key} +
- $innfeed_rejected{$key}))";
- total "bytes((total(%innfeed_accepted_size) +
- total(%innfeed_rejected_size)) /
- (total(%innfeed_accepted) +
- total(%innfeed_rejected)))";
- };
- column {
- name "Elapsed";
- format "%9s";
- value "time($innfeed_seconds{$key})";
- total "time(total(%innfeed_seconds))";
- };
- graph {
- title "Outgoing feeds (innfeed) by Volume";
- type histo3d;
- sort "%innfeed_accepted_size";
- data {
- name "Accepted";
- color "#0000FF";
- value "%innfeed_accepted_size";
- };
- data {
- name "Rejected";
- color "#FFAF00";
- value "%innfeed_rejected_size";
- };
- };
-};
-
-section innfeed_shrunk {
- title "Backlog files shrunk by innfeed:";
- data "%innfeed_shrunk";
- sort "$innfeed_shrunk{$b} <=> $innfeed_shrunk{$a}";
- column {
- name "Server";
- format "%-70.70s";
- value "$key";
- format_total "TOTAL: %-63.63s";
- total "$num";
- };
- column {
- name "Size";
- format "%8s";
- value "bytes($innfeed_shrunk{$key})";
- total "bytes(total(%innfeed_shrunk))";
- };
-};
-
-section nntplink_connect {
- title "Outgoing Feeds (nntplink):";
- data "%nntplink_site";
- sort "$nntplink_accepted{$b} <=> $nntplink_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format "%-25.25s";
- value "$key";
- format_total "TOTAL: %-18.18s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%8s";
- format "%8d";
- value "$nntplink_offered{$key}";
- total "total(%nntplink_offered)";
- };
- column {
- name "Taken";
- format_name "%8s";
- format "%8d";
- value "$nntplink_accepted{$key}";
- total "total(%nntplink_accepted)";
- };
- column {
- name "Rejected";
- format_name "%8s";
- format "%8d";
- value "$nntplink_rejected{$key}";
- total "total(%nntplink_rejected)";
- };
- column {
- name "Failed";
- format_name "%8s";
- format "%8d";
- value "$nntplink_failed{$key}";
- total "total(%nntplink_failed)";
- };
- column {
- name "%Accpt";
- format_name "%6s";
- format "%5d%%";
- value "$nntplink_offered{$key} == 0 ? 0 :
- $nntplink_accepted{$key} / $nntplink_offered{$key} * 100";
- total "total(%nntplink_offered) == 0 ? 0 :
- total(%nntplink_accepted) / total(%nntplink_offered) * 100";
- };
- column {
- name "Elapsed";
- format "%10s";
- value "time($nntplink_times{$key})";
- total "time(total(%nntplink_times))";
- };
- graph {
- title "Outgoing Feeds (nntplink)";
- type histo3d;
- sort "%nntplink_accepted";
- data {
- name "Articles accepted";
- color "#0000FF";
- value "%nntplink_accepted";
- };
- data {
- name "Articles rejected";
- color "#FFAF00";
- value "%nntplink_rejected";
- };
- data {
- name "Articles failed";
- color "#FF0000";
- value "%nntplink_failed";
- };
- };
-};
-
-section nntplink_connect2 {
- title "Outgoing Feeds (nntplink) - other information:";
- data "%nntplink_site";
- sort "$nntplink_accepted{$b} <=> $nntplink_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format "%-20.20s";
- value "$key";
- format_total "TOTAL: %-13.13s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%4s";
- format "%4d";
- value "$nntplink_site{$key}";
- total "total(%nntplink_site)";
- };
- column {
- name "Ok";
- format_name "%4s";
- format "%4d";
- value "$nntplink_site{$key} - ($nntplink_eof{$key} +
- $nntplink_sockerr{$key} +
- $nntplink_selecterr{$key} +
- $nntplink_hiload{$key} + $nntplink_bpipe{$key} +
- $nntplink_nospace{$key} + $nntplink_auth{$key} +
- $nntplink_expire{$key} + $nntplink_fail{$key})";
- total "total(%nntplink_site) - (total(%nntplink_eof) +
- total(%nntplink_sockerr) +
- total(%nntplink_selecterr) +
- total(%nntplink_hiload) +
- total(%nntplink_bpipe) +
- total(%nntplink_nospace) +
- total(%nntplink_auth) +
- total(%nntplink_expire) +
- total(%nntplink_fail))";
- };
- column {
- name "EOF";
- format_name "%3s";
- format "%3d";
- value "$nntplink_eof{$key}";
- total "total(%nntplink_eof)";
- };
- column {
- name "Sock";
- format_name "%4s";
- format "%4d";
- value "$nntplink_sockerr{$key}";
- total "total(%nntplink_sockerr)";
- };
- column {
- name "Slct";
- format_name "%4s";
- format "%4d";
- value "$nntplink_selecterr{$key}";
- total "total(%nntplink_selecterr)";
- };
- column {
- name "Load";
- format_name "%4s";
- format "%4d";
- value "$nntplink_hiload{$key}";
- total "total(%nntplink_hiload)";
- };
- column {
- name "Bpip";
- format_name "%4s";
- format "%4d";
- value "$nntplink_bpipe{$key}";
- total "total(%nntplink_bpipe)";
- };
- column {
- name "Spce";
- format_name "%4s";
- format "%4d";
- value "$nntplink_nospace{$key}";
- total "total(%nntplink_nospace)";
- };
- column {
- name "Exp";
- format_name "%4s";
- format "%4d";
- value "$nntplink_expire{$key}";
- total "total(%nntplink_expire)";
- };
- column {
- name "Auth";
- format_name "%4s";
- format "%4d";
- value "$nntplink_auth{$key}";
- total "total(%nntplink_auth)";
- };
- column {
- name "Othr";
- format_name "%4s";
- format "%4d";
- value "$nntplink_fail{$key}";
- total "total(%nntplink_fail)";
- };
- column {
- name "Pct";
- format_name "%4s";
- format "%3d%%";
- value "$nntplink_site{$key} ?
- 100 * ($nntplink_site{$key} -
- ($nntplink_eof{$key} + $nntplink_sockerr{$key} +
- $nntplink_selecterr{$key} +
- $nntplink_hiload{$key} + $nntplink_bpipe{$key} +
- $nntplink_nospace{$key} + $nntplink_auth{$key} +
- $nntplink_expire{$key} +
- $nntplink_fail{$key})) / $nntplink_site{$key} : 0";
- total "total(%nntplink_site) ?
- 100 * (total(%nntplink_site) -
- (total(%nntplink_eof) +
- total(%nntplink_sockerr) +
- total(%nntplink_selecterr) +
- total(%nntplink_hiload) +
- total(%nntplink_bpipe) +
- total(%nntplink_nospace) +
- total(%nntplink_auth) +
- total(%nntplink_expire) +
- total(%nntplink_fail))) / total(%nntplink_site) : 0";
- };
-};
-
-section innxmit_connect {
- title "Outgoing Feeds (innxmit) by Articles:";
- data "%innxmit_times";
- sort "$innxmit_accepted{$b} <=> $innxmit_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format "%-27.27s";
- value "$key";
- format_total "TOTAL: %-20.20s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$innxmit_offered{$key}";
- total "total(%innxmit_offered)";
- };
- column {
- name "Taken";
- format_name "%7s";
- format "%7d";
- value "$innxmit_accepted{$key}";
- total "total(%innxmit_accepted)";
- };
- column {
- name "Refused";
- format_name "%7s";
- format "%7d";
- value "$innxmit_refused{$key}";
- total "total(%innxmit_refused)";
- };
- column {
- name "Reject";
- format_name "%7s";
- format "%7d";
- value "$innxmit_rejected{$key}";
- total "total(%innxmit_rejected)";
- };
- column {
- name "Miss";
- format_name "%5s";
- format "%5d";
- value "$innxmit_missing{$key}";
- total "total(%innxmit_rejected)";
- };
- column {
- name "%Acc";
- format_name "%4s";
- format "%3d%%";
- value "$innxmit_offered{$key} == 0 ? 0 :
- $innxmit_accepted{$key} / $innxmit_offered{$key} * 100";
- total "total(%innxmit_offered) == 0 ? 0 :
- total(%innxmit_accepted) / total(%innxmit_offered) * 100";
- };
- column {
- name "Elapsed";
- format "%8s";
- value "time($innxmit_times{$key})";
- total "time(total(%innxmit_times))";
- };
- graph {
- title "Outgoing Feeds (innxmit)";
- type histo3d;
- sort "%innxmit_accepted";
- data {
- name "Art. accepted";
- color "#0000FF";
- value "%innxmit_accepted";
- };
- data {
- name "Art. refused";
- color "#FFAF00";
- value "%innxmit_refused";
- };
- data {
- name "Art. rejected";
- color "#FF0000";
- value "%innxmit_rejected";
- };
- data {
- name "Art. missing";
- color "#00FF00";
- value "%innxmit_missing";
- };
- };
-};
-
-section innxmit_volume {
- title "Outgoing Feeds (innxmit) by Volume:";
- data "%innxmit_accepted_size";
- sort "$innxmit_accepted_size{$b} <=> $innxmit_accepted_size{$a}";
- numbering true;
- column {
- name "Server";
- format "%-24.24s";
- value "$key";
- format_total "TOTAL: %-17.17s";
- total "$num";
- };
- column {
- name "AcceptVol";
- format "%9s";
- value "bytes($innxmit_accepted_size{$key})";
- total "bytes(total(%innxmit_accepted_size))";
- };
- column {
- name "RejectVol";
- format "%9s";
- value "bytes($innxmit_rejected_size{$key})";
- total "bytes(total(%innxmit_rejected_size))";
- };
- column {
- name "TotalVol";
- format "%9s";
- value "bytes($innxmit_accepted_size{$key} +
- $innxmit_rejected_size{$key} +
- $innxmit_bytes{$key})";
- total "bytes(total(%innxmit_accepted_size) +
- total(%innxmit_rejected_size) +
- total(%innxmit_bytes))";
- };
- column {
- name "KB/s";
- format_name "%5s";
- format "%5.1f";
- value "($innxmit_accepted_size{$key} +
- $innxmit_rejected_size{$key} +
- $innxmit_bytes{$key}) /
- $innxmit_times{$key} / 1024";
- total "(total(%innxmit_accepted_size) +
- total(%innxmit_rejected_size) +
- total(%innxmit_bytes)) /
- total(%innxmit_times) / 1024";
- };
- column {
- name "Vol/Art";
- format "%9s";
- value "bytes(($innxmit_accepted_size{$key} +
- $innxmit_rejected_size{$key} +
- $innxmit_bytes{$key}) /
- ($innxmit_accepted{$key} +
- $innxmit_rejected{$key}))";
- total "bytes((total(%innxmit_accepted_size) +
- total(%innxmit_rejected_size) +
- total(%innxmit_bytes)) /
- (total(%innxmit_accepted) +
- total(%innxmit_rejected)))";
- };
- column {
- name "Elapsed";
- format "%8s";
- value "time($innxmit_times{$key})";
- total "time(total(%innxmit_times))";
- };
- graph {
- title "Outgoing Feeds (innxmit)";
- type histo3d;
- sort "%innxmit_accepted";
- data {
- name "Articles accepted";
- color "#0000FF";
- value "%innxmit_accepted_size";
- };
- data {
- name "Articles rejected";
- color "#FFAF00";
- value "%innxmit_rejected_size";
- };
- data {
- name "Total";
- color "#FF0000";
- value "%innxmit_missing";
- };
- };
-};
-
-
-section innxmit_connect2 {
- title "Outgoing Feeds (innxmit) - other information:";
- data "%innxmit_site";
- sort "$innxmit_accepted{$b} <=> $innxmit_accepted{$a}";
- numbering true;
- column {
- name "Server";
- format "%-25.25s";
- value "$key";
- format_total "TOTAL: %-18.18s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%5s";
- format "%5d";
- value "$innxmit_site{$key}";
- total "total(%innxmit_site)";
- };
- column {
- name "Ok";
- format_name "%5s";
- format "%5d";
- value "$innxmit_site{$key} -
- ($innxmit_afail_host{$key} +
- $innxmit_hiload{$key} + $innxmit_nospace{$key} +
- $innxmit_cfail_host{$key} +
- $innxmit_expire{$key} + $innxmit_crefused{$key})";
- total "total(%innxmit_site) -
- (total(%innxmit_afail_host) +
- total(%innxmit_hiload) +
- total(%innxmit_nospace) +
- total(%innxmit_cfail_host) +
- total(%innxmit_expire) +
- total(%innxmit_crefused))";
- };
- column {
- name "Auth";
- format_name "%4s";
- format "%4d";
- value "$innxmit_afail_host{$key}";
- total "total(%innxmit_afail_host)";
- };
- column {
- name "Load";
- format_name "%4s";
- format "%4d";
- value "$innxmit_hiload{$key}";
- total "total(%innxmit_hiload)";
- };
- column {
- name "Space";
- format_name "%5s";
- format "%5d";
- value "$innxmit_nospace{$key}";
- total "total(%innxmit_nospace)";
- };
- column {
- name "Expire";
- format_name "%6s";
- format "%6d";
- value "$innxmit_expire{$key}";
- total "total(%innxmit_expire)";
- };
- column {
- name "Connct";
- format_name "%6s";
- format "%6d";
- value "$innxmit_cfail_host{$key}";
- total "total(%innxmit_cfail_host)";
- };
- column {
- name "Other";
- format_name "%6s";
- format "%6d";
- value "$innxmit_crefused{$key}";
- total "total(%innxmit_crefused)";
- };
- column {
- name "Pct";
- format_name "%4s";
- format "%3d%%";
- value "$innxmit_site{$key} ? 100 *
- ($innxmit_site{$key} -
- ($innxmit_afail_host{$key} +
- $innxmit_hiload{$key} + $innxmit_nospace{$key} +
- $innxmit_cfail_host{$key} +
- $innxmit_expire{$key} +
- $innxmit_crefused{$key})) / $innxmit_site{$key} : 0";
- total "total(%innxmit_site) ?
- 100 * (total(%innxmit_site) -
- (total(%innxmit_afail_host) +
- total(%innxmit_hiload) +
- total(%innxmit_nospace) +
- total(%innxmit_cfail_host) +
- total(%innxmit_expire) +
- total(%innxmit_crefused))) / total(%innxmit_site) : 0";
- };
-};
-
-section innxmit_unwanted {
- title "Sites fed by innxmit rejecting bad articles:";
- data "%innxmit_badart";
- sort "$innxmit_badart{$b} <=> $innxmit_badart{$a}";
- column {
- numbering true;
- name "Server";
- format "%-23.23s";
- value "$key";
- format_total "TOTAL: %-16.16s";
- total "$num";
- };
- column {
- name "Total";
- format_name "%6s";
- format "%6d";
- value "$innxmit_badart{$key}";
- total "total(%innxmit_badart)";
- };
- column {
- name "Group";
- format_name "%6s";
- format "%6d";
- value "$innxmit_uw_ng_s{$key}";
- total "total(%innxmit_uw_ng_s)";
- };
- column {
- name "Dist";
- format_name "%5s";
- format "%5d";
- value "$innxmit_uw_dist_s{$key}";
- total "total(%innxmit_uw_dist_s)";
- };
- column {
- name "Duplic";
- format_name "%6s";
- format "%6d";
- value "$innxmit_duplicate{$key}";
- total "total(%innxmit_duplicate)";
- };
- column {
- name "Unapp";
- format_name "%5s";
- format "%5d";
- value "$innxmit_unapproved{$key}";
- total "total(%innxmit_unapproved)";
- };
- column {
- name "TooOld";
- format_name "%6s";
- format "%6d";
- value "$innxmit_tooold{$key}";
- total "total(%innxmit_tooold)";
- };
- column {
- name "Site";
- format_name "%4s";
- format "%4d";
- value "$innxmit_uw_site{$key}";
- total "total(%innxmit_uw_site)";
- };
- column {
- name "Line";
- format_name "%4s";
- format "%4d";
- value "$innxmit_linecount{$key}";
- total "total(%innxmit_linecount)";
- };
- column {
- name "Other";
- format_name "%5s";
- format "%5d";
- value "$innxmit_others{$key}";
- total "total(%innxmit_others)";
- };
-};
-
-section crosspost {
- title "Crosspost stats:";
- data "%crosspost";
- column {
- name "Events";
- format "%-63.63s";
- value "$key";
- format_total "TOTAL: %-56.56s";
- total "$num";
- };
- column {
- name "Number";
- value "$crosspost{$key}";
- format "%7s";
- total "total(%crosspost)";
- };
- column {
- name "Num/min";
- value "$crosspost_times{$key}";
- format "%7s";
- total "total(%crosspost_times)";
- };
-};
-
-section batcher_elapsed {
- title "UUCP batches created:";
- data "%batcher_elapsed";
- column {
- name "Server";
- format "%-41.41s";
- value "$key";
- format_total "TOTAL: %-34.34s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$batcher_offered{$key}";
- total "total(%batcher_offered)";
- };
- column {
- name "Articles";
- format_name "%8s";
- format "%8d";
- value "$batcher_articles{$key}";
- total "total(%batcher_articles)";
- };
- column {
- name "Size";
- format "%10s";
- value "bytes($batcher_bytes{$key})";
- total "bytes(total(%batcher_bytes))";
- };
- column {
- name "Elapsed";
- format "%9s";
- value "time($batcher_elapsed{$key})";
- total "time(total(%batcher_elapsed))";
- };
-};
-
-section rnews_host {
- title "Rnews articles offered from:";
- data "%rnews_host";
- sort "$rnews_host{$b} <=> $rnews_host{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$rnews_host{$key}";
- total "total(%rnews_host)";
- };
-};
-
-section rnews_rejected {
- title "Rnews connections rejected:";
- data "%rnews_rejected";
- sort "$rnews_rejected{$b} <=> $rnews_rejected{$a}";
- column {
- name "Reason";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$rnews_rejected{$key}";
- total "total(%rnews_rejected)";
- };
-};
-
-section rnews_misc {
- title "Miscellaneous rnews statistics:";
- data "%rnews_misc";
- sort "$rnews_misc{$b} <=> $rnews_misc{$a}";
- double true;
- column {
- primary true;
- name "Event";
- format "%-69.69s";
- value "$key1";
- format_total "TOTAL: %-62.62s";
- total "";
- };
- column {
- name "Element";
- format " %-67.67s";
- value "$key2";
- total "";
- };
- column {
- name "Number";
- format_name "%9s";
- format "%9d";
- value "$rnews_misc{$key1}{$key2}";
- total "total(%rnews_misc)";
- };
-};
-
-section nnrpd_groups {
- title "NNRP readership statistics:";
- data "%nnrpd_articles";
- sort "$nnrpd_articles{$b} <=> $nnrpd_articles{$a}";
- numbering true;
- column {
- name "System";
- format "%-30.30s";
- value "$key";
- format_total "TOTAL: %-23.23s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%4s";
- format "%4d";
- value "$nnrpd_connect{$key}";
- total "total(%nnrpd_connect)";
- };
- column {
- name "Arts";
- format_name "%6s";
- format "%6d";
- value "$nnrpd_articles{$key}";
- total "total(%nnrpd_articles)";
- };
- column {
- name "Size";
- format "%9s";
- value "bytes($nnrpd_bytes{$key})";
- total "bytes(total(%nnrpd_bytes))";
- };
- column {
- name "Groups";
- format_name "%6s";
- format "%6d";
- value "$nnrpd_groups{$key}";
- total "total(%nnrpd_groups)";
- };
- column {
- name "Post";
- format_name "%4s";
- format "%4d";
- value "$nnrpd_post_ok{$key}";
- total "total(%nnrpd_post_ok)";
- };
- column {
- name "Rej";
- format_name "%4s";
- format "%4d";
- value "($nnrpd_post_rej{$key}||0) +
- ($nnrpd_post_error{$key}||0)";
- total "total(%nnrpd_post_rej) +
- total(%nnrpd_post_error)";
- };
- column {
- name "Elapsed";
- format "%9s";
- value "time($nnrpd_times{$key})";
- total "time(total(%nnrpd_times))";
- };
-};
-
-section nnrpd_dom_groups {
- title "NNRP readership statistics (by domain):";
- data "%nnrpd_dom_connect";
- sort "$nnrpd_dom_articles{$b} <=> $nnrpd_dom_articles{$a}";
- numbering true;
- column {
- name "System";
- format "%-30.30s";
- value "$key";
- format_total "TOTAL: %-23.23s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%4s";
- format "%4d";
- value "$nnrpd_dom_connect{$key}";
- total "total(%nnrpd_dom_connect)";
- };
- column {
- name "Arts";
- format_name "%6s";
- format "%6d";
- value "$nnrpd_dom_articles{$key}";
- total "total(%nnrpd_dom_articles)";
- };
- column {
- name "Size";
- format "%9s";
- value "bytes($nnrpd_dom_bytes{$key})";
- total "bytes(total(%nnrpd_dom_bytes))";
- };
- column {
- name "Groups";
- format_name "%6s";
- format "%6d";
- value "$nnrpd_dom_groups{$key}";
- total "total(%nnrpd_dom_groups)";
- };
- column {
- name "Post";
- format_name "%4s";
- format "%4d";
- value "$nnrpd_dom_post_ok{$key}";
- total "total(%nnrpd_dom_post_ok)";
- };
- column {
- name "Rej";
- format_name "%4s";
- format "%4d";
- value "($nnrpd_dom_post_rej{$key}||0) +
- ($nnrpd_dom_post_error{$key}||0)";
- total "total(%nnrpd_dom_post_rej) +
- total(%nnrpd_dom_post_error)";
- };
- column {
- name "Elapsed";
- format "%9s";
- value "time($nnrpd_dom_times{$key})";
- total "time(total(%nnrpd_dom_times))";
- };
-};
-
-section nnrpd_auth {
- title "NNRP auth users:";
- data "%nnrpd_auth";
- top 20;
- sort "$nnrpd_auth{$b} <=> $nnrpd_auth{$a}";
- column {
- name "User";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_auth{$key}";
- total "total(%nnrpd_auth)";
- };
-};
-
-section nnrpd_resource {
- title "NNRP total resource statistics:";
- data "%nnrpd_resource_elapsed";
- top 20;
- sort "$nnrpd_resource_elapsed{$b} <=> $nnrpd_resource_elapsed{$a}";
- column {
- name "System";
- format "%-40.40s";
- format_total "TOTAL: %-33.33s";
- value "$key";
- total "$num";
- };
- column {
- name "User(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$nnrpd_resource_user{$key}";
- total "total(%nnrpd_resource_user)";
- };
- column {
- name "System(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$nnrpd_resource_system{$key}";
- total "total(%nnrpd_resource_system)";
- };
- column {
- name "Idle(ms)";
- format_name "%9s";
- format "%9.3f";
- value "$nnrpd_resource_idle{$key}";
- total "total(%nnrpd_resource_idle)";
- };
- column {
- name "Elapsed";
- format_name "%8s";
- format "%9s";
- value "time($nnrpd_resource_elapsed{$key})";
- total "time(total(%nnrpd_resource_elapsed))";
- };
-};
-
-section nnrpd_curious {
- title "Curious NNRP server explorers:";
- data "%nnrpd_curious";
- top 20;
- sort "$nnrpd_curious{$b} <=> $nnrpd_curious{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_curious{$key}";
- total "total(%nnrpd_curious)";
- };
-};
-
-section nnrpd_no_permission {
- title "NNRP no permission clients:";
- data "%nnrpd_no_permission";
- sort "$nnrpd_no_permission{$b} <=> $nnrpd_no_permission{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_no_permission{$key}";
- total "total(%nnrpd_no_permission)";
- };
-};
-
-section nnrpd_gethostbyaddr {
- title "NNRP gethostbyaddr failures:";
- data "%nnrpd_gethostbyaddr";
- top 20;
- sort "$nnrpd_gethostbyaddr{$b} <=> $nnrpd_gethostbyaddr{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_gethostbyaddr{$key}";
- total "total(%nnrpd_gethostbyaddr)";
- };
-};
-
-section nnrpd_unrecognized {
- title "NNRP unrecognized commands (by host):";
- data "%nnrpd_unrecognized";
- sort "$nnrpd_unrecognized{$b} <=> $nnrpd_unrecognized{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_unrecognized{$key}";
- total "total(%nnrpd_unrecognized)";
- };
-};
-
-section nnrpd_unrecognized2 {
- title "NNRP unrecognized commands (by command):";
- data "%nnrpd_unrecogn_cmd";
- sort "$nnrpd_unrecogn_cmd{$b} <=> $nnrpd_unrecogn_cmd{$a}";
- column {
- name "Command";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_unrecogn_cmd{$key}";
- total "total(%nnrpd_unrecogn_cmd)";
- };
-};
-
-section nnrpd_timeout {
- title "NNRP client timeouts:";
- data "%nnrpd_timeout";
- top 20;
- sort "$nnrpd_timeout{$b} <=> $nnrpd_timeout{$a}";
- column {
- name "System";
- format "%-67.67s";
- value "$key";
- format_total "TOTAL: %-60.60s";
- total "$num";
- };
- column {
- name "Conn";
- format_name "%5s";
- format "%5d";
- value "$nnrpd_timeout{$key}";
- total "total(%nnrpd_timeout)";
- };
- column {
- name "Peer";
- format_name "%5s";
- format "%5d";
- value "$nnrpd_reset_peer{$key}";
- total "total(%nnrpd_reset_peer)";
- };
-};
-
-section nnrpd_hierarchy {
- title "Newsgroup request counts (by category):";
- data "%nnrpd_hierarchy";
- sort "$nnrpd_hierarchy{$b} <=> $nnrpd_hierarchy{$a}";
- numbering true;
- column {
- name "Category";
- format "%-64.64s";
- value "$key";
- format_total "TOTAL: %-57.57s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_hierarchy{$key}";
- total "total(%nnrpd_hierarchy)";
- };
- column {
- name "Pct";
- format_name "%6s";
- format "%5.1f%%";
- value "$nnrpd_hierarchy{$key} /
- total(%nnrpd_hierarchy) * 100";
- total "100";
- };
- # graph : type piechart
-};
-
-section nnrpd_group {
- title "Newsgroup request counts (by newsgroup):";
- data "%nnrpd_group";
- sort "$nnrpd_group{$b} <=> $nnrpd_group{$a}";
- top 100;
- numbering true;
- column {
- name "Newsgroup";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Count";
- format_name "%7s";
- format "%7d";
- value "$nnrpd_group{$key}";
- total "total(%nnrpd_group)";
- };
-};
-
-section ihave_site {
- title "IHAVE messages offered from:";
- data "%controlchan_ihave_site";
- sort "$controlchan_ihave_site{$b} <=> $controlchan_ihave_site{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$controlchan_ihave_site{$key}";
- total "total(%controlchan_ihave_site)";
- };
-};
-
-section sendme_site {
- title "SENDME messages offered from:";
- data "%controlchan_sendme_site";
- sort "$controlchan_sendme_site{$b} <=>
- $controlchan_sendme_site{$a}";
- column {
- name "System";
- format "%-71.71s";
- value "$key";
- format_total "TOTAL: %-64.64s";
- total "$num";
- };
- column {
- name "Offered";
- format_name "%7s";
- format "%7d";
- value "$controlchan_sendme_site{$key}";
- total "total(%controlchan_sendme_site)";
- };
-};
+++ /dev/null
-## $Revision: 4351 $
-## innwatch.ctl -- control file for innwatch.
-## Indicates what to run to test the state of the news system, and what
-## to do about it. Format:
-## !state!when!command!test!limit!command!reason/comment
-## where
-## <!> Delimiter; pick from [,:@;?!]
-## <state> State to enter if true.
-## <when> States we must be in to match.
-## <command> Command to run to test condition.
-## <test> Operator to use in test(1) command.
-## <limit> Value to test against.
-## <command> Command for innwatch to perform; use exit,
-## flush, go, pause, shutdown, skip, or throttle.
-## <reason> Used in ctlinnd command (if needed).
-
-## First, just exit innwatch if innd has gone away.
-!!! test -f ${LOCKS}/innd.pid && echo 0 || echo 1 ! eq ! 1 ! exit ! innd dead
-
-## If another innwatch has started, exit.
-!!! cat ${LOCKS}/LOCK.${PROGNAME} ! ne ! $$ ! exit ! innwatch replaced
-
-## Next test the load average. Above first threshold pause, above higher
-## threshold throttle, below restart limit undo whatever was done.
-!load!load hiload! uptime | tr -d ,. | awk '{ print $(NF - 2) }' ! lt ! ${INNWATCHLOLOAD} ! go ! loadav
-!hiload!+ load! uptime | tr -d ,. | awk '{ print $(NF - 2) }' ! gt ! ${INNWATCHHILOAD} ! throttle ! loadav
-!load!+! uptime | tr -d ,. | awk '{ print $(NF - 2) }' ! gt ! ${INNWATCHPAUSELOAD} ! pause ! loadav
-##
-## Uncomment these to keep overchan backlog in check. Assumes your overchan
-## feed is named 'overview!'.
-#::overblog:ctlinnd feedinfo overview!|awk 'NR==1{print $7}':lt:100000:go:overviewbacklog
-#:overblog:+:ctlinnd feedinfo overview!|awk 'NR==1{print $7}':gt:400000:throttle:overviewbacklog
-##
-
-## If load is OK, check space (and inodes) on various filesystems
-!!! ${INNDF} . ! lt ! ${INNWATCHSPOOLSPACE} ! throttle ! No space (spool)
-!!! ${INNDF} ${BATCH} ! lt ! ${INNWATCHBATCHSPACE} ! throttle ! No space (newsq)
-!!! ${INNDF} ${PATHDB} ! lt ! ${INNWATCHLIBSPACE} ! throttle ! No space (newslib)
-!!! ${INNDF} -i . ! lt ! ${INNWATCHSPOOLNODES} ! throttle ! No space (spool inodes)
-!!! ${INNDF} ${OVERVIEWDIR} ! lt ! ${INNWATCHSPOOLSPACE} ! throttle ! No space (overview)
+++ /dev/null
-## $Id: moderators 7448 2005-12-11 22:21:06Z eagle $
-##
-## moderators - Mailing addresses for moderators.
-##
-## Whenever possible, the master moderator database at moderators.isc.org
-## should be used rather than adding specific entries to this file. The
-## master database will list any publically propagated moderated group;
-## changes should be sent to moderators-request@isc.org.
-##
-## Exceptions listed in this file are mostly hierarchies for which the
-## master database isn't accurate or updated quickly enough. Local
-## moderated newsgroups can also be added to this file.
-##
-## Format:
-## <newsgroup>:<pathname>
-##
-## <newsgroup> Shell-style newsgroup pattern or specific newsgroup
-## <pathname> Mail address, "%s" becomes newgroup name with dots
-## changed to dashes.
-##
-## The first matching entry is used.
-
-## Public hierarchies with exceptions.
-fido7.*:%s@fido7.ru
-ffm.*:%s@moderators.arcornews.de
-fj.*:%s@moderators.fj-news.org
-medlux.*:%s@news.medlux.ru
-nl.*:%s@nl.news-admin.org
-relcom.*:%s@moderators.relcom.ru
-ukr.*:%s@sita.kiev.ua
-
-## Direct all other public hierarchies to the master moderator database.
-*:%s@moderators.isc.org
+++ /dev/null
-Sample MOTD file. Any text you put in here will be returned
-to the news reader when it issues the LIST MOTD command. It is not
-an error if this file does not exist nor if it is empty.
+++ /dev/null
-# Sample config file for news2mail. Format is:
-#
-# mailing-list-name address
-#
-#
-# In newsfeeds put an entry like:
-#
-# n2m!:!*:Tc,Ac,Wn*:/usr/news/bin/news2mail
-#
-# and for each mailing list have an entry list:
-#
-# news-software@localhost.our.domain.com:rec.pets.redants.*:Tm:n2m!
-#
-# The site name used in the newfeeds entry for a mailing list (above
-# ``news-software@localhost.our.domain.com'') must be the same as the first
-# field in an entry in this file. It is what is put into the ``To'' header of
-# mailed messages.
-#
-#
-news-software@localhost.our.domain.com news-software@real-host.somewhere.com
+++ /dev/null
-## $Id: newsfeeds.in 7741 2008-04-06 09:51:47Z iulius $
-##
-## newsfeeds - determine where Usenet articles get sent
-##
-## Format:
-## site[/exclude,exclude...]\
-## :pattern,pattern...[/distrib,distrib...]\
-## :flag,flag...\
-## :param
-##
-## This file is complicated -- see newsfeeds(5) for full details.
-
-## The ME feed entry is special magic.
-##
-## "/exclude" entries for this feed entry will cause INN to reject all
-## articles that have passed through those listed sites (by matching
-## Path: entries). There are some "pseudo-sites" in general use that can
-## be listed as exclusions to reject specific types of 3rd-party cancel
-## messages (see the "Cancel FAQ" in news.admin.net-abuse.usenet):
-##
-## cyberspam Cancels for spam, munged articles, binaries
-## spewcancel Cancels for munged articles and runaway gateways
-## bincancel Cancels for binary postings to non-binary groups
-## udpcancel Cancels to force sites to enforce antispam policies
-##
-## The "pattern" field for this feed entry gives the initial subscription
-## list for all other feeds specified in this file. These patterns are
-## *prepended* to all other feed patterns. Using this feature is
-## confusing and mildly discouraged; make sure you understand the man
-## page before using it.
-##
-## "/distrib" for this feed entry specifies what distributions the server
-## will accept. If any distributions are listed there, the server will
-## accept only articles with those distributions. If all the
-## distributions listed are negated (starting with !), then the server
-## will only accept articles without those distributions.
-##
-## For the ME line (and the ME line *only*), patterns affect *outgoing*
-## feeds and distributions affect *incoming* feeds.
-
-# Empty default subscription list, reject all incoming articles with a
-# distribution of "local" or "collabra-internal," accept all others.
-ME:!*/!local,!collabra-internal::
-
-# The same as the above, but would reject all posts that have
-# news.example.com in the path (posts passing through that site).
-#ME/news.example.com:!*/!local,!collabra-internal::
-
-# The special feed that handles all newsgroup control messages. Only
-# disable this if you want to ignore all newsgroup control messages; INN
-# no longer handles any control messages except cancel internally.
-controlchan!\
- :!*,control,control.*,!control.cancel\
- :Tc,Wnsm:@prefix@/bin/controlchan
-
-## Uncomment if you're using innfeed. This feed tells INN how to run
-## innfeed, and then every site you're feeding with innfeed has a
-## flag of Tm and an argument of "innfeed!" to funnel into this feed.
-## The feed pattern for innfeed should *always* be "!*"; don't ever
-## feed articles directly into innfeed.
-##
-## Add "-y" as an option to startinnfeed to use the name of each feed as
-## the name of the host to feed articles to; without "-y" an innfeed.conf
-## file is needed.
-
-# innfeed funnel master.
-#innfeed!\
-# :!*\
-# :Tc,Wnm*:@prefix@/bin/startinnfeed
-
-## Only uncomment this feed if both enableoverview and useoverchan are
-## set to true in inn.conf. By default, innd will write out overview
-## internally and doesn't need or want this feed, but useoverchan can
-## optionally be set to true and this feed uncommented to move those
-## operations out of innd's main loop.
-
-# News overview.
-#overview!:*:Tc,WnteO:@prefix@/bin/overchan
-
-
-## OUTGOING NORMAL FEED EXAMPLES
-
-# A real-time feed through innfeed. Don't send articles with a distribution
-# of "foo", since those articles are internal.
-# Note that control messages will be sent even though "!control,!control.*"
-# is specified. It is useful not to forget that pattern since control
-# messages for local.* would still be sent with "*,@local.*" only.
-#news.uu.net/uunet\
-# :*,!junk,!control,!control.*/!foo\
-# :Tm:innfeed!
-
-# Create a batch file in @SPOOLDIR@/outgoing for all articles
-# that haven't already passed through nic.near.net. The batch file will
-# be named nic.near.net, the default file name, and either nntpsend or
-# send-nntp can send articles from that spool file.
-#nic.near.net\
-# :*,!junk,!control,!control.*/!foo\
-# :Tf,Wnm:
-
-# A UUCP feed, where we try to keep the "batching" between 4 KB and 1 KB.
-# You can use send-uucp(8) to process these batch files.
-#ihnp4\
-# :*,!junk,!control,!control.*/!foo\
-# :Tf,Wnb,B4096/1024:
-
-
-## OUTGOING SPECIAL FEED EXAMPLES
-
-# Accumulate Path header statistics. See ninpaths(8) for more details on
-# how to set this up.
-#inpaths!:*:Tc,WP:@prefix@/bin/ninpaths -p -d @LOGDIR@/path/inpaths.%d
-
-# Feed all moderated source postings to an archiver.
-#source-archive!:!*,*sources*,!*wanted*,!*.d\
-# :Tc,Wn:@prefix@/bin/archive -f -i @SPOOLDIR@/archive/INDEX
-
-# News to mail gateway. Similar to innfeed, this uses a master feed and
-# then individual feeds for every separate address that news is being
-# gated to. This sends all posts to rec.pets.redants.* to the address
-# news-software@example.com.
-#news2mail!:!*:Tc,Ac,Wn*:@prefix@/bin/news2mail
-#news-software@example.com:rec.pets.redants.*:Tm:news2mail!
-
-# Capture all local postings (with a distribution of "foo" and no more
-# than two sites in the Path) using a local program (that doesn't come with
-# INN).
-#capture\
-# :*/foo\
-# :Tp,H2:/usr/local/bin/capture %s
+++ /dev/null
-control Various control messages (no posting).
-control.cancel Cancel messages (no posting).
-control.checkgroups Hierarchy check control messages (no posting).
-control.newgroup Newsgroup creation control messages (no posting).
-control.rmgroup Newsgroup removal control messages (no posting).
-junk Unfiled articles (no posting).
+++ /dev/null
-## $Id: nnrpd.py 7897 2008-06-22 18:04:31Z iulius $
-##
-## This module supplies stub Python functions corresponding to the ones
-## provided by nnrpd. It is not used by the server; it is only here so
-## that you can test your filter scripts before loading.
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-
-from types import *
-
-def set_auth_hook(anObject):
- if type(anObject) == InstanceType:
- print "** set_auth_hook for " + repr(anObject)
- else:
- print "** <Your object is not a class instance.>"
-
-def syslog(level, message):
- print "-- syslog level: %s message: %s" % (level, message)
+++ /dev/null
-## $Revision: 513 $
-## nnrpd.track - file to specify which hosts to be tracked by nnrpd
-## Format:
-## <host>:<identity>
-## Where:
-## <host> Wildcard name or IP address
-## <identity> String to be displayed in the logs
-##
-## By adding a host to this file, it will be tracked using the
-## nnrpd tracking system if enabled in inn.conf(5). Each read/post
-## will have an entry logged with the <identity> in the log message
-##
-# nasty.foo.com:nasty@foo.com
-# *.bar.com:VeryNastyClient
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-##
-## Sample code for the nnrpd Perl access hooks.
-
-## This file is loaded when a perl_access: parameter is reached in
-## readers.conf. If it defines a sub named access, which will be
-## called during processing of a perl_access: parameter. Attributes
-## about the connection are passed to the program in the %attributes
-## global variable. It should return a hash containing
-## parameter-value pairs for the access group. If there is a problem,
-## nnrpd will die and syslog the exact error.
-
-## The default behavior of the following code is to look for nnrp.access
-## in INN's configuration file directory and to attempt to implement about
-## the same host-based access control as the previous nnrp.access code in
-## earlier versions of INN. This may be useful for backward compatibility.
-
-## This file cannot be run as a standalone script, although it would be
-## worthwhile to add some code so that it could so that one could test the
-## results of various authentication and connection queries from the
-## command line. The #! line at the top is just so that fixscript will
-## work.
-
-# This function is called when perl_access: is reached in readers.conf.
-# For details on all the information passed to it, see
-# ~news/doc/hook-perl.
-sub access {
- &loadnnrp($inn::newsetc . '/nnrp.access');
- return &checkhost($attributes{hostname}, $attributes{ipaddress});
-}
-
-# Called at startup, this loads the nnrp.access file and converts it into a
-# convenient internal format for later queries.
-sub loadnnrp {
- my $file = shift;
- my ($block, $perm, $user, $pass);
-
- open (ACCESS, $file) or die "Could not open $file: $!\n";
- local $_;
- while (<ACCESS>) {
- my %tmp;
-
- chomp;
- s/\#.*//;
- ($block, $perm, $user, $pass, $tmp{groups}) = split /:/;
- next unless (defined $tmp{groups});
-
- # We don't support username/password entries, so be safe.
- next if ($user || $pass);
-
- # Change the wildmat pattern to a regex (this isn't thorough, as
- # some ranges won't be converted properly, but it should be good
- # enough for this purpose).
- if ($block !~ m%^(?:\d+\.){3}\d+/\d+$%) {
- $block =~ s/\./\\./g;
- $block =~ s/\?/./g;
- $block =~ s/\*/.*/g;
- }
- $tmp{block} = $block;
-
- $tmp{canread} = ($perm =~ /r/i);
- $tmp{canpost} = ($perm =~ /p/i);
-
- unshift(@hosts, { %tmp });
- }
- close ACCESS;
-}
-
-# Given the hostname and IP address of a connecting host, use our @hosts
-# array constructed from nnrp.access and see what permissions that host has.
-sub checkhost {
- my ($host, $ip) = @_;
- my %return_hash;
- my $key;
- for $key (@hosts) {
- my ($read, $post) = ($key->{canread}, $key->{canpost});
-
- # First check for CIDR-style blocks.
- if ($key->{block} =~ m%^(\d+\.\d+\.\d+\.\d+)/(\d+)$%) {
- my $block = unpack('N', pack('C4', split(/\./, $1)));
- my $mask = (0xffffffff << (32 - $2)) & 0xffffffff;
- $block = $block & $mask;
- my $packedip = unpack('N', pack('C4', split(/\./, $ip)));
- if (($packedip & $mask) == $block) {
- if ($read) {
- $return_hash{"read"} = $key->{groups};
- }
- if ($post) {
- $return_hash{"post"} = $key->{groups};
- }
- return %return_hash;
- }
- }
-
- if ($ip =~ /^$key->{block}$/) {
- if ($read) {
- $return_hash{"read"} = $key->{groups};
- }
- if ($post) {
- $return_hash{"post"} = $key->{groups};
- }
- return %return_hash;
- }
-
- if ($host =~ /^$key->{block}$/) {
- if ($read) {
- $return_hash{"read"} = $key->{groups};
- }
- if ($post) {
- $return_hash{"post"} = $key->{groups};
- }
- return %return_hash;
- }
- }
-
- # If we fell through to here, nothing matched, so we should deny
- # permissions.
- return %return_hash;
-}
+++ /dev/null
-## $Id: nnrpd_access.py 7906 2008-06-23 05:44:49Z iulius $
-##
-## This is a sample access module for the Python nnrpd hook.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The perl_access: parameter in readers.conf is used to load this script.
-##
-## An instance of ACCESS class is passed to nnrpd via the set_auth_hook()
-## function imported from nnrpd. The following methods of that class
-## are known to nnrpd:
-##
-## __init__() - Use this method to initialize your
-## general variables or open a common
-## database connection. May be omitted.
-## access_init() - Init function specific to access
-## control. May be omitted.
-## access(attributes) - Called when a python_access
-## statement is reached in the
-## processing of readers.conf. Returns
-## a dictionary of values representing
-## statements to be included in an
-## access group.
-## access_close() - Called on nnrpd termination. Save
-## your state variables or close a
-## database connection. May be omitted.
-##
-## If there is a problem with return codes from any of these methods, then nnrpd
-## will die and syslog the exact reason.
-##
-## There are also a few Python functions defined in nnrpd:
-##
-## set_auth_hook() - Called by nnrpd as this module is loaded.
-## It is used to pass a reference to an
-## instance of authentication class to nnrpd.
-## syslog() - An equivalent replacement for regular syslog.
-## One consideration for using it is to
-## uniform nnrpd logging.
-
-## Sample access class. It defines all access methods known to nnrpd.
-class ACCESS:
- """Provide access callbacks to nnrpd."""
-
- def __init__(self):
- """This is a good place to initialize variables or open a
- database connection."""
- syslog('notice', 'nnrpd access class instance created')
-
- def access_init(self):
- """Called when this script is initialized."""
- pass
-
- def access(self, attributes):
- """Called when python_access: is encountered in readers.conf."""
-
- # Just for debugging purposes.
- syslog('notice', 'n_a access() invoked: hostname %s, ipaddress %s, interface %s, user %s' % (\
- attributes['hostname'], \
- attributes['ipaddress'], \
- attributes['interface'], \
- attributes['user']))
-
- # Allow newsreading from specific host only.
- if '127.0.0.1' == str(attributes['ipaddress']):
- syslog('notice', 'authentication access by IP address succeeded')
- return {'read':'*', 'post':'*'}
- else:
- syslog('notice', 'authentication access by IP address failed')
- return {'read':'!*', 'post':'!*'}
-
- def access_close(self):
- """Called on nnrpd termination."""
- pass
-
-
-## The rest is used to hook up the access module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-myaccess = ACCESS()
-
-## ...and try to hook up on nnrpd. This would make auth object methods visible
-## to nnrpd.
-try:
- set_auth_hook(myaccess)
- syslog('notice', "access module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for access method: %s" % errmsg[0])
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Example wrapper nnrpd_access.pl for support of old perl authentication
-# scripts, by Erik Klavon.
-
-# This file contains a sample perl script which can be used to
-# duplicate the behavior of the old nnrpperlauth functionality. This
-# script only supports access control.
-
-# How to use this wrapper:
-# - append your old script to this file with two changes:
-# - rename the old "auth_init" sub to "old_auth_init"
-# - rename the old "authenticate" sub to "old_authenticate"
-
-
-# access
-# This sub modifies the global hash attributes so that it has all the
-# entries required in the old way of doing things, calls
-# old_authenticate, and creates a return hash with the right attributes.
-
-sub access {
- # Comment this out if you don't need auth_init.
- old_auth_init();
-
- $attributes{type} = "connect";
- my @connect_array = old_authenticate();
- my %hash;
-
- # handle max rate
- if ($connect_array[4]) {
- # Force perl to make a C string out of this integer,
- # or else bad things will happen. Sigh.
- $hash{"max_rate"} = $connect_array[4] . "\0";
- }
-
- # handle read boolean, set to wildmat
- if ($connect_array[1]) {
- $hash{"read"} = $connect_array[3];
- }
-
- # handle post boolean, set to wildmat
- if ($connect_array[2]) {
- $hash{"post"} = $connect_array[3];
- }
-
- return %hash;
-}
+++ /dev/null
-## $Id: nnrpd_access_wrapper.py 7899 2008-06-22 18:22:07Z iulius $
-##
-## Example wrapper for support of old Python authentication scripts,
-## by Erik Klavon.
-##
-## This file contains a sample Python script which can be used to
-## duplicate the behaviour of the old nnrppythonauth functionality.
-## This script only supports access control.
-##
-## How to use this wrapper:
-## - insert your authentication class into this file;
-## - rename your authentication class OLDAUTH.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The use of this file is *discouraged*.
-
-## Old AUTH class.
-## Insert your old auth class here.
-## Do not include the code which sets the hook.
-
-
-
-
-## Wrapper ACCESS class. It creates an instance of the old class and
-## calls its methods. Arguments and return values are munged as
-## needed to fit the new way of doing things.
-
-class MYACCESS:
- """Provide access callbacks to nnrpd."""
- def access_init(self):
- self.old = OLDAUTH()
-
- def access(self, attributes):
- attributes['type'] = buffer('connect')
- perm = (self.old).authenticate(attributes)
- result = dict([('users','*')])
- if perm[1] == 1:
- result['read'] = perm[3]
- if perm[2] == 1:
- result['post'] = perm[3]
- return result
-
- def access_close(self):
- (self.old).close()
-
-
-## The rest is used to hook up the access module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-myaccess = MYACCESS()
-
-## ...and try to hook up on nnrpd. This would make access object methods visible
-## to nnrpd.
-try:
- set_auth_hook(myaccess)
- syslog('notice', "access module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for access method: %s" % errmsg[0])
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-##
-## Sample code for the nnrpd Perl authentication hooks.
-##
-## This file is loaded when a perl_auth: parameter is reached in
-## readers.conf. If it defines a sub named authenticate, that
-## function will be called during processing of a perl_auth:
-## parameter. Attributes about the connection are passed to the
-## program in the %attributes global variable. It should return an
-## array with two elements:
-##
-## 1) NNTP response code. Should be one of the codes from %authcodes
-## below to not risk violating the protocol.
-## 2) An error string to be passed to the client.
-## Both elements are required. If there is a problem, nnrpd will die
-## and syslog the exact error.
-
-## The code below uses a user database based on CDB_File. It is
-## provided here as an example of an authentication script.
-
-## This file cannot be run as a standalone script, although it would be
-## worthwhile to add some code so that it could so that one could test the
-## results of various authentication and connection queries from the
-## command line. The #! line at the top is just so that fixscript will
-## work.
-
-use strict;
-use vars qw(%attributes %authcodes %users);
-
-# These codes are a widely implemented de facto standard.
-%authcodes = ('allowed' => 281, 'denied' => 502);
-
-# This sub should perform any initialization work that the
-# authentication stuff needs.
-sub auth_init {
- require CDB_File;
- tie (%users, 'CDB_File', $inn::pathdb . '/users.cdb')
- or warn "Could not open $inn::pathdb/users.cdb for users: $!\n";
-}
-
-# This function is called for authentication requests. For details on
-# all the information passed to it, see ~news/doc/hook-perl.
-sub authenticate {
- return &checkuser();
-}
-
-# This function assumes that there's a database tied as %users that
-# contains, keyed by users, a tab-separated list of the password (in
-# crypt format), whether they can post, a wildmat matching what
-# newsgroups they have access to, and the number of bytes per second
-# they're allowed to use. This section of the code only accesses the
-# username and password fields. See the file nnrpd_access.pl for
-# access rights based on the other fields.
-sub checkuser {
- my $user = $attributes{'username'};
- my $pass = $attributes{'password'};
-
- return ($authcodes{denied}, "No username given.")
- unless defined $users{$user};
-
- my ($password, $post, $speed, $subscription) = split(/\t/, $users{$user});
- return ($authcodes{denied}, "Incorrect password.")
- if (crypt($pass, $password) ne $password);
-
- return ($authcodes{allowed}, "");
-}
+++ /dev/null
-## $Id: nnrpd_auth.py 7906 2008-06-23 05:44:49Z iulius $
-##
-## This is a sample authentication module for the Python nnrpd hook.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The perl_auth: parameter in readers.conf is used to load this script.
-##
-## An instance of AUTH class is passed to nnrpd via the set_auth_hook()
-## function imported from nnrpd. The following methods of that class
-## are known to nnrpd:
-##
-## __init__() - Use this method to initialize your
-## general variables or open a common
-## database connection. May be omitted.
-## authen_init() - Init function specific to
-## authentication. May be omitted.
-## authenticate(attributes) - Called when a python_auth statement
-## is reached in the processing of
-## readers.conf. Returns a response
-## code, an error string and an
-## optional string to appear in the
-## logs as the username.
-## authen_close() - Called on nnrpd termination. Save
-## your state variables or close a database
-## connection. May be omitted.
-##
-## If there is a problem with return codes from any of these methods, then nnrpd
-## will die and syslog the exact reason.
-##
-## There are also a few Python functions defined in nnrpd:
-##
-## set_auth_hook() - Called by nnrpd as this module is loaded.
-## It is used to pass a reference to an
-## instance of authentication class to nnrpd.
-## syslog() - An equivalent replacement for regular syslog.
-## One consideration for using it is to
-## uniform nnrpd logging.
-
-## Sample authentication class. It defines all auth methods known to nnrpd.
-class AUTH:
- """Provide authentication callbacks to nnrpd."""
-
- def __init__(self):
- """This is a good place to initialize variables or open a
- database connection."""
-
- # Create a list of NNTP codes to respond on connect.
- self.connectcodes = { 'READPOST':200,
- 'READ':201,
- 'AUTHNEEDED':480,
- 'PERMDENIED':502
- }
-
- # Create a list of NNTP codes to respond on authentication.
- self.authcodes = { 'ALLOWED':281,
- 'DENIED':502
- }
-
- syslog('notice', 'nnrpd authentication class instance created')
-
- def authen_init(self):
- """Called when this script is initialized."""
- pass
-
- def authenticate(self, attributes):
- """Called when python_auth: is encountered in readers.conf."""
-
- # Just for debugging purposes.
- syslog('notice', 'n_a authenticate() invoked: hostname %s, ipaddress %s, interface %s, user %s' % (\
- attributes['hostname'], \
- attributes['ipaddress'], \
- attributes['interface'], \
- attributes['user']))
-
- # Do username password authentication.
- if 'foo' == str(attributes['user']) \
- and 'foo' == str(attributes['pass']):
- syslog('notice', 'authentication by username succeeded')
- return (self.authcodes['ALLOWED'], 'No error', 'default_user')
- else:
- syslog('notice', 'authentication by username failed')
- return (self.authcodes['DENIED'], 'Access Denied!')
-
- def authen_close(self):
- """Called on nnrpd termination."""
- pass
-
-
-## The rest is used to hook up the auth module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-myauth = AUTH()
-
-## ...and try to hook up on nnrpd. This would make auth object methods visible
-## to nnrpd.
-try:
- set_auth_hook(myauth)
- syslog('notice', "authentication module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for authentication method: %s" % errmsg[0])
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Example wrapper nnrpd_auth.pl for support of old perl authentication
-# scripts, by Erik Klavon.
-
-# This file contains a sample perl script which can be used to
-# duplicate the behavior of the old nnrpperlauth functionality. This
-# script only supports authentication.
-
-# How to use this wrapper:
-# - append your old script to this file with two changes:
-# - rename the old "auth_init" sub to "old_auth_init"
-# - rename the old "authenticate" sub to "old_authenticate"
-
-
-# auth_init
-# This sub simply calls old_auth_init
-# Comment this out if you don't need auth_init
-
-sub auth_init {
- old_auth_init();
-}
-
-
-# authenticate
-# This sub modifies the global hash attributes so that it has all the
-# entries required in the old way of doing things, calls
-# old_authenticate, and transforms the return array into the new
-# format.
-
-sub authenticate {
- $attributes{type} = "authenticate";
- my @auth_array = old_authenticate();
- my @return_array;
-
- # copy return code
- $return_array[0] = $auth_array[0];
-
- # simple error report
- if ($auth_array[0] != 281) {
- $return_array[1] = "Perl authentication error!";
- return @return_array;
- } else {
- $return_array[1] = "";
- }
-
- return @return_array;
-}
+++ /dev/null
-## $Id: nnrpd_auth_wrapper.py 7899 2008-06-22 18:22:07Z iulius $
-##
-## Example wrapper for support of old Python authentication scripts,
-## by Erik Klavon.
-##
-## This file contains a sample Python script which can be used to
-## duplicate the behaviour of the old nnrppythonauth functionality.
-## This script only supports authentication.
-##
-## How to use this wrapper:
-## - insert your authentication class into this file;
-## - rename your authentication class OLDAUTH.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The use of this file is *discouraged*.
-
-## Old AUTH class.
-## Insert your old auth class here.
-## Do not include the code which sets the hook.
-
-
-
-
-## Wrapper AUTH class. It creates an instance of the old class and
-## calls its methods. Arguments and return values are munged as
-## needed to fit the new way of doing things.
-
-class MYAUTH:
- """Provide auth callbacks to nnrpd."""
- def authen_init(self):
- self.old = OLDAUTH()
-
- def authenticate(self, attributes):
- attributes['type'] = buffer('authinfo')
- perm = (self.old).authenticate(attributes)
- err_str = "No error"
- if perm[0] == 502:
- err_str = "Python authentication error!"
- return (perm[0],err_str)
-
- def authen_close(self):
- (self.old).close()
-
-
-## The rest is used to hook up the auth module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-myauth = MYAUTH()
-
-## ...and try to hook up on nnrpd. This would make auth object methods visible
-## to nnrpd.
-try:
- set_auth_hook(myauth)
- syslog('notice', "authentication module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for authentication method: %s" % errmsg[0])
+++ /dev/null
-## $Id: nnrpd_dynamic.py 7906 2008-06-23 05:44:49Z iulius $
-##
-## This is a sample dynamic access module for the Python nnrpd hook.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The perl_dynamic: parameter in readers.conf is used to load this script.
-##
-## An instance of DYNACCESS class is passed to nnrpd via the set_auth_hook()
-## function imported from nnrpd. The following methods of that class
-## are known to nnrpd:
-##
-## __init__() - Use this method to initialize your
-## general variables or open a common
-## database connection. May be omitted.
-## dynamic_init() - Init function specific to
-## authentication. May be omitted.
-## dynamic(attributes) - Called whenever a reader requests either
-## read or post access to a
-## newsgroup. Returns None to grant
-## access, or a non-empty string (which
-## will be reported back to reader)
-## otherwise.
-## dynamic_close() - Called on nnrpd termination. Save
-## your state variables or close a database
-## connection. May be omitted.
-##
-## If there is a problem with return codes from any of these methods, then nnrpd
-## will die and syslog the exact reason.
-##
-## There are also a few Python functions defined in nnrpd:
-##
-## set_auth_hook() - Called by nnrpd as this module is loaded.
-## It is used to pass a reference to an
-## instance of authentication class to nnrpd.
-## syslog() - An equivalent replacement for regular syslog.
-## One consideration for using it is to
-## uniform nnrpd logging.
-
-## Sample dynamic access class. It defines all dynamic access methods known
-## to nnrpd.
-class DYNACCESS:
- """Provide dynamic access callbacks to nnrpd."""
-
- def __init__(self):
- """This is a good place to initialize variables or open a
- database connection."""
- syslog('notice', 'nnrpd dynamic access class instance created')
-
- def dynamic_init(self):
- """Called when this script is initialized."""
- pass
-
- def dynamic(self, attributes):
- """Called when python_dynamic: is reached in the processing of
- readers.conf and a reader requests either read or post
- permission for particular newsgroup."""
-
- # Just for debugging purposes.
- syslog('notice', 'n_a dynamic() invoked against type %s, hostname %s, ipaddress %s, interface %s, user %s' % (\
- attributes['type'], \
- attributes['hostname'], \
- attributes['ipaddress'], \
- attributes['interface'], \
- attributes['user']))
-
- # Allow reading of any newsgroup but not posting.
- if 'post' == str(attributes['type']):
- syslog('notice', 'dynamic authorization access for post access denied')
- return "no posting for you"
- elif 'read' == str(attributes['type']):
- syslog('notice', 'dynamic authorization access for read access granted')
- return None
- else:
- syslog('notice', 'dynamic authorization access type is not known: %s' % attributes['type'])
- return "Internal error";
-
- def dynamic_close(self):
- """Called on nnrpd termination."""
- pass
-
-
-## The rest is used to hook up the dynamic access module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-mydynaccess = DYNACCESS()
-
-## ...and try to hook up on nnrpd. This would make auth object methods visible
-## to nnrpd.
-try:
- set_auth_hook(mydynaccess)
- syslog('notice', "dynamic access module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for dynamic access method: %s" % errmsg[0])
+++ /dev/null
-## $Id: nnrpd_dynamic_wrapper.py 7899 2008-06-22 18:22:07Z iulius $
-##
-## Example wrapper for support of old Python authentication scripts,
-## by Erik Klavon.
-##
-## This file contains a sample Python script which can be used to
-## duplicate the behaviour of the old nnrppythonauth functionality.
-## This script only supports dynamic access control by group.
-##
-## How to use this wrapper:
-## - insert your authentication class into this file;
-## - rename your authentication class OLDAUTH.
-##
-## See the INN Python Filtering and Authentication Hooks documentation
-## for more information.
-## The use of this file is *discouraged*.
-
-## Old AUTH class.
-## Insert your old auth class here.
-## Do not include the code which sets the hook.
-
-
-
-
-## Wrapper DYNACCESS class. It creates an instance of the old class and
-## calls its methods. Arguments and return values are munged as
-## needed to fit the new way of doing things.
-
-class MYDYNACCESS:
- """Provide dynamic access callbacks to nnrpd."""
- def dynamic_init(self):
- self.old = OLDAUTH()
-
- def dynamic(self, attributes):
- return (self.old).authorize(attributes)
-
- def dynamic_close(self):
- (self.old).close()
-
-
-## The rest is used to hook up the dynamic access module on nnrpd. It is unlikely
-## you will ever need to modify this.
-
-## Import functions exposed by nnrpd. This import must succeed, or nothing
-## will work!
-from nnrpd import *
-
-## Create a class instance.
-mydynaccess = MYDYNACCESS()
-
-## ...and try to hook up on nnrpd. This would make auth object methods visible
-## to nnrpd.
-try:
- set_auth_hook(mydynaccess)
- syslog('notice', "dynamic access module successfully hooked into nnrpd")
-except Exception, errmsg:
- syslog('error', "Cannot obtain nnrpd hook for dynamic access method: %s" % errmsg[0])
+++ /dev/null
-## $Revision: 1165 $
-## Control file for nntpsend.
-## Format:
-## site:fqdn:max_size:[<args...>]
-## <site> The name used in the newsfeeds file for this site;
-## this determines the name of the batchfile, etc.
-## <fqdn> The fully-qualified domain name of the site,
-## passed as the parameter to innxmit.
-## <size> Size to truncate batchfile if it gets too big;
-## see shrinkfile(1).
-## <args> Other args to pass to innxmit
-## Everything after the pound sign is ignored.
-#nsavax:erehwon.nsavax.gov::-S -t60
-#walldrug:walldrug.com:4m-1m:-T1800 -t300
-#kremvax:kremvax.cis:2m:
+++ /dev/null
-# The directory that overview will be stored in (the DB_HOME directory)
-# is set in inn.conf with the 'pathoverview' option. Other parameters
-# for tuning ovdb are in this file.
-
-# Size of the memory pool cache, in Kilobytes. The cache will have a
-# backing store file in the DB directory which will be at least as big.
-# In general, the bigger the cache, the better. Use C<ovdb_stat -m> to see
-# cache hit percentages. If they're less than 80%, try increasing the
-# cache size. To make a change of this parameter take effect, shut down
-# and restart INN (be sure to kill all of the nnrpds when shutting down).
-# Default is 8000, which is adequate for small to medium sized servers.
-# Large servers will probably need at least 14000.
-#cachesize 8000
-
-# Overview data is split between this many files. Currently,
-# innd will keep all of the files open, so don't set this too high
-# or innd may run out of file descriptors. The nnrpds only open one
-# at a time, regardless. May be set to one, or just a few, but only
-# do that if your OS supports large (>2G) files. Changing this
-# parameter has no effect on an already-established database.
-#numdbfiles 32
-
-# If txn_nosync is set to false, BerkeleyDB flushes the log after every
-# transaction. This minimizes the number of transactions that may be
-# lost in the event of a crash, but results in significantly degraded
-# performance. Default is true.
-#txn_nosync true
-
-# If useshm is set to true, BerkeleyDB will use shared memory instead
-# of mmap for its environment regions (cache, lock, etc). With some
-# platforms, this may improve performance. Default is false.
-# This parameter is ignored if you have BerkeleyDB 2.x
-#useshm false
-
-# Sets the shared memory key used by BerkeleyDB when 'useshm' is true.
-# BerkeleyDB will create several (usually 5) shared memory segments,
-# using sequentially numbered keys starting with 'shmkey'.
-# Choose a key that does not conflict with any existing shared memory
-# segments on your system. Default is 6400. This parameter is only
-# used with BerkeleyDB 3.1 or newer.
-#shmkey 6400
-
-# Sets the page size for the DB files (in bytes). Must be a power of 2.
-# Best choices are 4096 or 8192. The default is 8192.
-# Changing this parameter has no effect on an already-established database.
-#pagesize 8192
-
-# Sets the minimum number of keys per page. See the BerkeleyDB
-# documentation for more info. Default is based on page size:
-#
-# default_minkey = MAX(2, pagesize / 2048 - 1)
-#
-# The lowest allowed minkey is 2. Setting minkey higher than the
-# default is not recommended, as it will cause the databases to have
-# a lot of overflow pages.
-# Changing this parameter has no effect on an already-established database.
-#minkey 3
-
-# Sets the BerkeleyDB "lk_max" parameter, which is the maxmium number
-# of locks that can exist in the database at the same time. Default
-# is 4000.
-#maxlocks 4000
-
-# The nocompact parameter affects expireover's behavior. The expireover
-# function in ovdb can do its job in one of two ways: By simply deleting
-# expired records from the database; or by re-writing the overview records
-# into a different location leaving out the expired records. The first
-# method is faster, but it leaves 'holes' that result in space that can
-# not immediately be reused. The second method 'compacts' the records
-# by rewriting them.
-#
-# If this parameter is set to 0, expireover will compact all newsgroups;
-# if set to 1, expireover will not compact any newsgroups; and if set to
-# a value greater than one, expireover will only compact groups that
-# have less than that number of articles. Default is 1000.
-#
-# Experience has shown that compacting has minimal effect (other than
-# making expireover take longer) so the default is now 1. This parameter
-# will probably be removed in the future.
-#nocompact 1
-
-# Normally, each nnrpd process directly accesses the BerkeleyDB environment.
-# The process of attaching to the database (and detaching when finished) is
-# fairly expensive, and can result in high loads in situations when there are
-# lots of reader connections of relatively short duration.
-#
-# When the readserver parameter is "true", the nnrpds will access overview
-# via a helper server (ovdb_server -- which is started by ovdb_init).
-# Default is false.
-#readserver false
-
-# This parameter is only used when 'readserver' is true. It sets the number
-# of ovdb_server processes. As each ovdb_server can process only one
-# transaction at a time, running more servers can improve reader response
-# times. Default is 5.
-#numrsprocs 5
-
-# This parameter is only used when 'readserver' is true. It sets a maximum
-# number of readers that a given ovdb_server process will serve at one time.
-# This means the maximum number of readers for all of the ovdb_server
-# processes is (numrsprocs * maxrsconn). Default is 0, which means an
-# umlimited number of connections is allowed.
-#maxrsconn 0
-
+++ /dev/null
-## $Revision: 573 $
-## overview.fmt - format of news overview database
-## Format
-## <header>
-## <header>:full
-## header is a news article header, known by innd. If ":full" appears,
-## then header name will be prepended. Order of lines is important!
-Subject:
-From:
-Date:
-Message-ID:
-References:
-Bytes:
-Lines:
-Xref:full
-#Keywords:full
+++ /dev/null
-## $Revision: 1165 $
-## passwd.nntp - passwords for connecting to remote NNTP servers
-## Format:
-## <host>:<name>:<pass>[:<style>]
-## Clients need only one entry, for where innd is running. The
-## server will have more entries for connecting to peers to feed them
-## articles.
-## <host> Host this line is for.
-## <name> Name to use to authenticate with
-## <pass> Password to send, after sending name
-## <style> Optional authentication style, defaults to "authinfo"
-## <name> and <pass> can be empty string; a peer innd doesn't need a
-## <name>, for example.
-#news.foo.com:rsalz:martha
+++ /dev/null
-# $Id: radius.conf 7556 2006-08-28 02:00:28Z eagle $
-#
-# Sample RADIUS configuration file for the RADIUS readers.conf
-# authenticator. If you're not using that authenticator, this file is not
-# used.
-
-server radius {
-
-# Hostname of the RADIUS server.
-
-#radhost: radius-server.example.com
-
-# Port to query on the RADIUS server.
-
-radport: 1645
-
-# Local hostname or IP address.
-#
-# The RADIUS server expects an IP address; a hostname will be translated
-# into an IP address with gethostbyname(). If not given, not included in
-# the request (not all RADIUS setups need this information).
-
-#lochost: news.example.com
-
-# Local port of connection.
-#
-# The port the client we're authenticating is connecting to. If not
-# given, defaults to 119. You'll only need to set this if you're readers
-# are connecting on a non-standard port.
-
-#locport: 119
-
-# Shared secret with RADIUS server.
-#
-# Be careful not to use the '#' symbol in your secret, since in this
-# file that indicates the beginning of a comment.
-
-#secret: SECRET-WORD
-
-# Prefix for username.
-#
-# Before given to the RADIUS server, usernames will be rewritten by
-# prepending the prefix, if given, and then appending the suffix, if
-# given.
-
-#prefix: news-
-
-# Suffix for username.
-
-#suffix: @example.com
-
-# Whether to ignore bad reply IP.
-#
-# If set to false, the RADIUS authenticator will check to ensure that the
-# response it receives is from the same IP address as it sent the request
-# to (for some added security). If set to true, it will skip this
-# verification check (if your RADIUS server has multiple IP addresses or
-# if other odd things are going on, it may be perfectly normal for the
-# response to come from a different IP address).
-
-ignore-source: false
-
-}
+++ /dev/null
-## $Id: readers.conf 4371 2001-01-16 15:35:38Z rra $
-##
-## readers.conf - Access control and configuration for nnrpd
-##
-## Format:
-## auth "<name>" {
-## hosts: "<hostlist>"
-## auth: "<authprog>"
-## res: "<resprog>"
-## default: "<identity>"
-## default-domain: "<email-domain>"
-## }
-## access "<name>" {
-## users: "<userlist>"
-## newsgroups: "<newsgroups>"
-## read: "<read>"
-## post: "<post>"
-## access: "<perm>"
-## }
-##
-## Other parameters are possible. See readers.conf(5) for all the
-## details. Only one of newsgroups or read/post may be used in a single
-## access group.
-##
-## If the connecting host is not matched by any hosts: parameter of any
-## auth group, it will be denied access. auth groups assign an identity
-## string to connections, access groups grant privileges to identity
-## strings matched by their users: parameters.
-##
-## In all cases, the last match found is used, so put defaults first.
-##
-## For a news server that allows connections from anyone within a
-## particular domain or IP address range, just uncomment the "local" auth
-## group and the "local" access group below and adjust the hosts: and
-## default: parameters of the auth group and the users: parameter of the
-## access group for your local network and domain name. That's all there
-## is to it.
-##
-## For more complicated configurations, read the comments on the examples
-## and also see the examples and explanations in readers.conf(5). The
-## examples in readers.conf(5) include setups that require the user to
-## log in with a username and password (the example in this file only
-## uses simple host-based authentication).
-##
-## NOTE: Unlike in previous versions of INN, nnrpd will now refuse any
-## post from anyone to a moderated newsgroup that contains an Approved:
-## header unless their access block has an access: key containing the
-## "A" flag. This is to prevent abuse of moderated groups, but it means
-## that if you support any newsgroup moderators, you need to make sure
-## to add such a line to the access group that affects them. See the
-## access group for localhost below for an example.
-
-# The only groups enabled by default (the rest of this file is
-# commented-out examples). This assigns the identity of <localhost> to
-# the local machine
-
-auth "localhost" {
- hosts: "localhost, 127.0.0.1, stdin"
- default: "<localhost>"
-}
-
-# Grant that specific identity access to read and post to any newsgroup
-# and allow it to post articles with Approved: headers to moderated
-# groups.
-
-access "localhost" {
- users: "<localhost>"
- newsgroups: "*"
- access: RPA
-}
-
-
-# This auth group matches all connections from example.com or machines in
-# the example.com domain and gives them the identity <local>@example.com.
-# Instead of using wildmat patterns to match machine names, you could also
-# put a wildmat pattern matching IP addresses or an IP range specified
-# using CIDR notation (like 10.10.10.0/24) here.
-
-#auth "local" {
-# hosts: "*.example.com, example.com"
-# default: "<local>@example.com"
-#}
-
-# This auth group matches a subset of machines and assigns connections
-# from there an identity of "<read>@example.com"; these systems should
-# only have read access, no posting privileges.
-
-#auth "read-only" {
-# hosts: "*.newuser.example.com"
-# default: "<read>@example.com"
-#}
-
-# This auth group matches the systems at a guest institution that should
-# be allowed to read the example.events.* hierarchy but nothing else.
-
-#auth "events-only" {
-# hosts: "*.example.org"
-# default: "<events-only>@example.org"
-#}
-
-# Finally, this auth group matches some particular systems which have been
-# abusing the server. Note that it doesn't assign them an identity at
-# all; the "empty" identity created in this fashion won't match any users:
-# parameters. Note also that it's last, so anything matching this entry
-# will take precedent over everything above it.
-
-#auth "abusers" {
-# hosts: "badguy-dsl.example.com, kiosk.public-access.example.com"
-#}
-
-
-# Now for the access groups. All of our access groups should have users:
-# parameters so there are no access groups that match connections without
-# an identity (such as are generated by the "abusers" entry above).
-# First, the default case of local users, who get to read and post to
-# everything.
-
-#access "local" {
-# users: "<local>@example.com"
-# newsgroups: "*"
-#}
-
-# Now, the read-only folks, who only get to read everything.
-
-#access "read-only" {
-# users: "<read>@example.com"
-# read: "*"
-#}
-
-# Finally, the events-only people who get to read and post but only to a
-# specific hierarchy.
-
-#access "events-only" {
-# users: "<events-only>@example.org"
-# newsgroups: "example.events.*"
-#}
+++ /dev/null
-tls_ca_path: @prefix@/lib
-tls_cert_file: @prefix@/lib/cert.pem
-tls_key_file: @prefix@/lib/cert.pem
+++ /dev/null
-## $Id: startup.tcl 4353 2001-01-15 13:32:40Z rra $
-##
-## Tcl filter initialization code
-##
-## If you compile with Tcl support enabled, this file (even if empty) must
-## exist as pathfilter/_PATH_TCL_STARTUP (as defined in paths.h). This
-## sample file defines the two functions that are called before and after
-## reloading the filter code, but defines them as empty procs that do
-## nothing.
-
-proc filter_before_reload {} {
-}
-
-proc filter_after_reload {} {
-}
+++ /dev/null
-#
-# RCSId: $Id: startup_innd.pl 6312 2003-05-04 21:40:11Z rra $
-# Description: Sample startup code for Perl hooks in INN. This file, after
-# it's installed in the right spot, will be loaded when
-# innd starts up. The following functions should be defined
-# by it (they don't have to be, in fact this file can be
-# empty, but it must exist if you've compiled in Perl support).
-#
-# sub filter_before_reload { ... }
-# Called before the filter definition file filter_innd.pl
-# is loaded (every time).
-# sub filter_after_reload { ... }
-# Called after the filter definition file filter_innd.pl
-# is loaded (every time).
-#
-# See the sample file filter_innd.pl for details on what it does.
-
-
-my $before_count = 1 ;
-# Gets no arguments, and its caller expects no return value.
-sub filter_before_reload {
- if ($before_count == 1) {
-# Do one thing
-# print "First time (before)\n" ;
- $before_count++ ;
- } else {
-# Do something else
-# print "Time number $before_count (before)\n" ;
- $before_count++ ;
- }
-}
-
-my $after_count = 1 ;
-# Gets no arguments, and its caller expects no return value.
-sub filter_after_reload {
- if ($after_count == 1) {
-# Do one thing
-# print "First time (after)\n" ;
- $after_count++ ;
- } else {
-# Do another
-# print "Time number $after_count (after)\n" ;
- $after_count++ ;
- }
-}
-
+++ /dev/null
-## $Id: storage.conf 6567 2003-12-27 04:18:33Z rra $
-##
-## Rules for where INN should store incoming articles.
-##
-## This file is used to determine which storage method articles are sent
-## to to be stored and which storage class they are stored as. Each
-## method is described as follows:
-##
-## method <methodname> {
-## newsgroups: <wildmat>
-## class: <storage class #>
-## size: <minsize>[,<maxsize>]
-## expires: <mintime>[,<maxtime>]
-## options: <options>
-## }
-##
-## Only newsgroups, class, and (for CNFS, to specify the metacycbuff)
-## options are required; the other keys are optional. If any CNFS
-## methods are configured, you will also need to set up cycbuff.conf.
-
-# By default, store everything in tradspool.
-method tradspool {
- newsgroups: *
- class: 0
-}
-
-## Here are some samples for a CNFS configuration. This assumes that you
-## have two metacycbuffs configured, one for text newsgroups and one for
-## binaries. Cancel messages, which tend to be very high-volume, are
-## stored in the binary metacycbuff as well. This assumes storeonxref is
-## set to true in inn.conf.
-
-# Pick off the binary newsgroups first.
-#method cnfs {
-# newsgroups: *.bina*,control.cancel
-# class: 1
-# options: BINARY
-#}
-
-# Put the remaining (text) groups in the other cycbuff.
-#method cnfs {
-# newsgroups: *
-# class: 2
-# options: TEXT
-#}
+++ /dev/null
-news.announce.newusers
-news.newusers.questions
-misc.test
-misc.test.moderated
-news.announce.newgroups
-news.answers
+++ /dev/null
-## $Id: Makefile 7739 2008-04-06 09:38:31Z iulius $
-##
-## Files that can be handled by fixscript (and need to be so handled) need
-## a rule to build them from the .in version, and then all files need an
-## installation rule. Do the installation rules individually so as to
-## avoid needless work if the files haven't changed. We also need lists
-## of files to build and files to install for the all and install rules.
-
-include ../Makefile.global
-
-top = ..
-
-ALL = innmail innreport innstat innupgrade innwatch rc.news \
- scanlogs simpleftp tally.control writelog
-
-EXTRA = inncheck innshellvars innshellvars.pl innshellvars.tcl \
- news.daily
-
-INSTALLED = $(D)$(PATHBIN)/inncheck \
- $(D)$(PATHBIN)/innmail \
- $(D)$(PATHBIN)/innreport \
- $(D)$(PATHBIN)/innstat \
- $(D)$(PATHBIN)/innupgrade \
- $(D)$(PATHBIN)/innwatch \
- $(D)$(PATHBIN)/news.daily \
- $(D)$(PATHBIN)/rc.news \
- $(D)$(PATHBIN)/scanlogs \
- $(D)$(PATHBIN)/simpleftp \
- $(D)$(PATHBIN)/tally.control \
- $(D)$(PATHBIN)/writelog \
- $(D)$(PATHLIB)/innreport_inn.pm \
- $(D)$(PATHLIB)/innshellvars \
- $(D)$(PATHLIB)/innshellvars.pl \
- $(D)$(PATHLIB)/innshellvars.tcl
-
-all: $(ALL) $(EXTRA)
-
-install: all
- for F in innmail innreport simpleftp ; do \
- $(CP_XPUB) $$F $D$(PATHBIN)/$$F ; \
- done
- for F in inncheck innstat innupgrade innwatch news.daily rc.news \
- scanlogs tally.control writelog ; do \
- $(CP_XPRI) $$F $D$(PATHBIN)/$$F ; \
- done
- for F in innreport_inn.pm innshellvars innshellvars.pl \
- innshellvars.tcl ; do \
- $(CP_RPUB) $$F $D$(PATHLIB)/$$F ; \
- done
-
-clean:
- rm -f $(ALL)
-
-clobber distclean: clean
- rm -f $(EXTRA)
-
-depend:
-
-profiled: all
-
-$(EXTRA) $(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-
-## Build rules.
-
-FIX = $(FIXSCRIPT)
-
-innmail: innmail.in $(FIX) ; $(FIX) innmail.in
-innreport: innreport.in $(FIX) ; $(FIX) innreport.in
-innstat: innstat.in $(FIX) ; $(FIX) innstat.in
-innupgrade: innupgrade.in $(FIX) ; $(FIX) -i innupgrade.in
-innwatch: innwatch.in $(FIX) ; $(FIX) innwatch.in
-rc.news: rc.news.in $(FIX) ; $(FIX) rc.news.in
-scanlogs: scanlogs.in $(FIX) ; $(FIX) scanlogs.in
-simpleftp: simpleftp.in $(FIX) ; $(FIX) -i simpleftp.in
-tally.control: tally.control.in $(FIX) ; $(FIX) tally.control.in
-writelog: writelog.in $(FIX) ; $(FIX) writelog.in
+++ /dev/null
-#!@_PATH_PERL@ --
-## $Revision: 7748 $
-## Sanity-check the configuration of an INN system
-## by Brendan Kehoe <brendan@cygnus.com> and Rich $alz.
-
-require "@LIBDIR@/innshellvars.pl" ;
-
-$ST_MODE = 2;
-$ST_UID = 4;
-$ST_GID = 5;
-
-$newsuser = '@NEWSUSER@';
-$newsgroup = '@NEWSGRP@';
-
-## We use simple names, mapping them to the real filenames only when
-## we actually need a filename.
-%paths = (
- 'active', "$inn::pathdb/active",
- 'archive', "$inn::patharchive",
- 'badnews', "$inn::pathincoming/bad",
- 'batchdir', "$inn::pathoutgoing",
- 'control.ctl', "$inn::pathetc/control.ctl",
- 'ctlprogs', "$inn::pathcontrol",
- 'expire.ctl', "$inn::pathetc/expire.ctl",
- 'history', "$inn::pathdb/history",
- 'incoming.conf', "$inn::pathetc/incoming.conf",
- 'inews', "$inn::pathbin/inews",
- 'inn.conf', "$inn::pathetc/inn.conf",
- 'innd', "$inn::pathbin/innd",
- 'innddir', "$inn::pathrun",
- 'inndstart', "$inn::pathbin/inndstart",
- 'moderators', "$inn::pathetc/moderators",
- 'most_logs', "$inn::pathlog",
- 'newsbin', "$inn::pathbin",
- 'newsboot', "$inn::pathbin/rc.news",
- 'newsfeeds', "$inn::pathetc/newsfeeds",
- 'overview.fmt', "$inn::pathetc/overview.fmt",
- 'newsetc', "$inn::pathetc",
- 'newslib', "@LIBDIR@",
- 'nnrpd', "$inn::pathbin/nnrpd",
- 'nntpsend.ctl', "$inn::pathetc/nntpsend.ctl",
- 'oldlogs', "$inn::pathlog/OLD",
- 'passwd.nntp', "$inn::pathetc/passwd.nntp",
- 'readers.conf', "$inn::pathetc/readers.conf",
- 'rnews', "$inn::pathbin/rnews",
- 'rnewsprogs', "$inn::pathbin/rnews.libexec",
- 'spooltemp', "$inn::pathtmp",
- 'spool', "$inn::patharticles",
- 'spoolnews', "$inn::pathincoming"
-);
-
-## The sub's that check the config files.
-%checklist = (
- 'active', 'active',
- 'control.ctl', 'control_ctl',
- 'expire.ctl', 'expire_ctl',
- 'incoming.conf', 'incoming_conf',
- 'inn.conf', 'inn_conf',
- 'moderators', 'moderators',
- 'newsfeeds', 'newsfeeds',
- 'overview.fmt', 'overview_fmt',
- 'nntpsend.ctl', 'nntpsend_ctl',
- 'passwd.nntp', 'passwd_nntp',
- 'readers.conf', 'readers_conf'
-);
-
-## The modes of the config files we can check.
-%modes = (
- 'active', @FILEMODE@,
- 'control.ctl', 0644,
- 'expire.ctl', 0644,
- 'incoming.conf', 0640,
- 'inn.conf', 0644,
- 'moderators', 0644,
- 'newsfeeds', 0644,
- 'overview.fmt', 0644,
- 'nntpsend.ctl', 0644,
- 'passwd.nntp', 0640,
- 'readers.conf', 0644
-);
-
-
-sub
-spacious
-{
- local ($i);
-
- chop;
- study;
- if ( /^#/ || /^$/ ) {
- $i = 1;
- } elsif ( /^\s/ ) {
- print "$file:$line: starts with whitespace\n";
- $i = 1;
- } elsif ( /\s$/ ) {
- print "$file:$line: ends with whitespace\n";
- $i = 1;
- }
- $i;
-}
-\f
-##
-## These are the functions that verify each individual file, called
-## from the main code. Each function gets <IN> as the open file, $line
-## as the linecount, and $file as the name of the file.
-##
-
-
-##
-## active
-##
-sub
-active
-{
- local ($group, $hi, $lo, $f, $alias, %groups, %aliases);
-
- input: while ( <IN> ) {
- $line++;
- unless ( ($group, $hi, $lo, $f) = /^([^ ]+) (\d+) (\d+) (.+)\n$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
-
- print "$file:$line: group `$group' already appeared\n"
- if $groups{$group}++;
- print "$file:$line: `$hi' < '$lo'.\n"
- if $hi < $lo && $lo != $hi + 1;
-
- next input if $f =~ /^[jmynx]$/;
- unless ( ($alias) = $f =~ /^=(.*)$/ ) {
- print "$file:$line: bad flag `$f'.\n";
- next input;
- }
- if ($alias eq "") {
- print "$file:$line: empty alias.\n";
- next input;
- }
- $aliases{$alias} = $line
- unless defined $groups{$alias};
- }
- foreach $key ( keys %aliases ) {
- print "$file:$aliases{$group} aliased to unknown group `$key'.\n"
- unless defined $groups{$key};
- }
- 1;
-}
-
-
-##
-## control.ctl
-##
-%control'messages = (
- 'all', 1,
- 'checkgroups', 1,
- 'ihave', 1,
- 'newgroup', 1,
- 'rmgroup', 1,
- 'sendme', 1,
- 'sendsys', 1,
- 'senduuname', 1,
- 'version', 1,
-);
-%control'actions = (
- 'drop', 1,
- 'log', 1,
- 'mail', 1,
- 'doit', 1,
- 'doifarg', 1,
- 'verify', 1
-);
-
-sub
-control_ctl
-{
- local ($msg, $from, $ng, $act);
-
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- unless ( ($msg, $from, $ng, $act) =
- /^([^:]+):([^:]+):([^:]+):(.+)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
- if ( !defined $control'messages{$msg} ) {
- print "$file:$line: unknown control message `$msg'.\n";
- next input;
- }
- print "$file:$line: action for unknown control messages is `doit'.\n"
- if $msg eq "default" && $act eq "doit";
- print "$file:$line: empty from field.\n"
- if $from eq "";
- print "$file:$line: bad email address.\n"
- if $from ne "*" && $from !~ /[@!]/;
-
- ## Perhaps check for conflicting rules, or warn about the last-match
- ## rule? Maybe later...
- print "$file:$line: may not match groups properly.\n"
- if $ng ne "*" && $ng !~ /\./;
- if ( $act !~ /([^=]+)(=.+)?/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
- $act =~ s/=.*//;
- $act = "verify" if ($act =~ /^verify-.+/) ;
- print "$file:$line: unknown action `$act'\n"
- if !defined $control'actions{$act};
- }
- 1;
-}
-
-
-##
-## expire.ctl
-##
-sub
-expire_ctl
-{
- local ($rem, $v, $def, $class, $pat, $flag, $keep, $default, $purge, $groupbaseexpiry);
-
- $groupbaseexpiry = $inn::groupbaseexpiry;
- $groupbaseexpiry =~ tr/A-Z/a-z/;
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- if ( ($v) = m@/remember/:(.+)@ ) {
- print "$file:$line: more than one /remember/ line.\n"
- if $rem++;
- if ( $v !~ /[\d\.]+/ ) {
- print "$file:$line: illegal value `$v' for remember.\n";
- next input;
- }
- print "$file:$line: are you sure about your /remember/ value?\n"
- ## These are arbitrary "sane" values.
- if $v != 0 && ($v > 60.0 || $v < 5.0);
- next input;
- }
-
- ## Could check for conflicting lines, but that's hard.
- if ($groupbaseexpiry =~ /^true$/ || $groupbaseexpiry =~ /^yes$/ ||
- $groupbaseexpiry =~ /^on$/) {
- unless ( ($pat, $flag, $keep, $default, $purge) =
- /^([^:])+:([^:]+):([\d\.]+|never):([\d\.]+|never):([\d\.]+|never)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
- print "$file:$line: duplicate default line\n"
- if $pat eq "*" && $flag eq "a" && $def++;
- print "$file:$line: unknown modflag `$flag'\n"
- if $flag !~ /[mMuUaAxX]/;
- } else {
- unless ( ($class, $keep, $default, $purge) =
- /^(\d+):([\d\.]+|never):([\d\.]+|never):([\d\.]+|never)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
- print "$file:$line: invalid class\n"
- if $class < 0;
- }
- print "$file:$line: purge `$purge' younger than default `$default'.\n"
- if $purge ne "never" && $default > $purge;
- print "$file:$line: default `$default' younger than keep `$keep'.\n"
- if $default ne "never" && $keep ne "never" && $keep > $default;
- }
- 1;
-}
-
-
-##
-## incoming.conf
-##
-sub
-incoming_conf
-{
- 1;
-}
-
-
-##
-## inn.conf
-##
-sub
-inn_conf
-{
- system ("$inn::pathbin/innconfval", '-C');
-
-# if ( $k eq "domain" ) {
-# print "$file:$line: domain (`$v') isn't local domain\n"
-# if $fqdn =~ /[^\.]+\(\..*\)/ && $v ne $1;
-# print "$file:$line: domain should not have a leading period\n"
-# if $v =~ /^\./;
-# } elsif ( $k eq "fromhost" ) {
-# print "$file:$line: fromhost isn't a valid FQDN\n"
-# if $v !~ /[\w\-]+\.[\w\-]+/;
-# } elsif ( $k eq "moderatormailer" ) {
-# # FIXME: shouldn't warn about blank lines if the
-# # moderators file exists
-# print "$file:$line: moderatormailer has bad address\n"
-# if $v !~ /[\w\-]+\.[\w\-]+/ && $v ne "%s";
-# } elsif ( $k eq "organization" ) {
-# print "$file:$line: org is blank\n"
-# if $v eq "";
-# } elsif ( $k eq "pathhost" ) {
-# print "$file:$line: pathhost has a ! in it\n"
-# if $v =~ /!/;
-# } elsif ( $k eq "pathalias" ) {
-# print "$file:$line: pathalias has a ! in it\n"
-# if $v =~ /!/;
-# } elsif ( $k eq "pathcluster" ) {
-# print "$file:$line: pathcluster has a ! in it\n"
-# if $v =~ /!/;
-# } elsif ( $k eq "server" ) {
-# print "$file:$line: server (`$v') isn't local hostname\n"
-# if $pedantic && $fqdn !~ /^$v/;
-# }
-#
-# if ( $key eq "moderatormailer" ) {
-# printf "$file:$line: missing $key and no moderators file.\n"
-# if ! -f $paths{"moderators"};
-# }
-
- 1;
-}
-
-
-##
-## moderators
-##
-sub
-moderators
-{
- local ($k, $v);
-
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- unless ( ($k, $v) = /^([^:]+):(.+)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
-
- if ( $k eq "" || $v eq "" ) {
- print "$file:$line: missing field\n";
- next input;
- }
- print "$file:$line: not an email address\n"
- if $pedantic && $v !~ /[@!]/;
- print "$file:$line: `$v' goes to local address\n"
- if $pedantic && $v eq "%s";
- print "$file:$line: more than one %s in address field\n"
- if $v =~ /%s.*%s/;
- }
- 1;
-}
-
-
-##
-## newsfeeds
-##
-%newsfeeds'flags = (
- '<', '^\d+$',
- '>', '^\d+$',
- 'A', '^[cCdeoOp]+$',
- 'B', '^\d+(/\d+)?$',
- 'C', '^\d+$',
- 'F', '^.+$',
- 'G', '^\d+$',
- 'H', '^\d+$',
- 'I', '^\d+$',
- 'N', '^[mu]$',
- 'O', '^\S+$',
- 'P', '^\d+$',
- 'Q', '^@?\d+(-\d+)?/\d+(_\d+)?$',
- 'S', '^\d+$',
- 'T', '^[cflmpx]$',
- 'W', '^[befghmnpst*DGHNPOR]*$',
-);
-
-sub
-newsfeeds
-{
- local ($next, $start, $me_empty, @muxes, %sites);
- local ($site, $pats, $dists, $flags, $param, $type, $k, $v, $defsub);
- local ($bang, $nobang, $prog, $dir);
-
- input: while ( <IN> ) {
- $line++;
- next input if /^$/;
- chop;
- print "$file:$line: starts with whitespace\n"
- if /^\s+/;
-
- ## Read continuation lines.
- $start = $line;
- while ( /\\$/ ) {
- chop;
- chop($next = <IN>);
- $line++;
- $next =~ s/^\s*//;
- $_ .= $next;
- }
- next input if /^#/;
- print "$file:$line: ends with whitespace\n"
- if /\s+$/;
-
- # Catch a variable setting.
- if ( /^\$([A-Za-z0-9]+)=/ ) {
- print "$file:$line: variable name too long\n"
- if length ($1) > 31;
- next input;
- }
-
- unless ( ($site, $pats, $flags, $param) =
- /^([^:]+):([^:]*):([^:]*):(.*)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
-
- print "$file:$line: Newsfeed `$site' has whitespace in its name\n"
- if $site =~ /\s/;
- print "$file:$line: comma-space in site name\n"
- if $site =~ m@, @;
- print "$file:$line: comma-space in subscription list\n"
- if $pats =~ m@, @;
- print "$file:$line: comma-space in flags\n"
- if $flags =~ m@, @;
-
- print "$file:$start: ME has exclusions\n"
- if $site =~ m@^ME/@;
- print "$file:$start: multiple slashes in exclusions for `$site'\n"
- if $site =~ m@/.*/@;
- $site =~ s@([^/]*)/.*@$1@;
- print "$site, "
- if $verbose;
-
- if ( $site eq "ME" ) {
- $defsub = $pats;
- $defsub =~ s@(.*)/.*@$1@;
- } elsif ( $defsub ne "" ) {
- $pats = "$defsub,$pats";
- }
- print "$file:$start: Multiple slashes in distribution for `$site'\n"
- if $pats =~ m@/.*/@;
-
- if ( $site eq "ME" ) {
- print "$file:$start: ME flags should be empty\n"
- if $flags ne "";
- print "$file:$start: ME param should be empty\n"
- if $param ne "";
- $me_empty = 1
- if $pats !~ "/.+";
- }
-
- ## If we don't have !junk,!control, give a helpful warning.
-# if ( $site ne "ME" && $pats =~ /!\*,/ ) {
-# print "$file:$start: consider adding !junk to $site\n"
-# if $pats !~ /!junk/;
-# print "$file:$start: consider adding !control to $site\n"
-# if $pats !~ /!control/;
-# }
-
- ## Check distributions.
- if ( ($dists) = $pats =~ m@.*/(.*)@ ) {
- $bang = $nobang = 0;
- dist: foreach $d ( split(/,/, $dists) ) {
- if ( $d =~ /^!/ ) {
- $bang++;
- }
- else {
- $nobang++;
- }
- print "$file:$start: questionable distribution `$d'\n"
- if $d !~ /^!?[a-z0-9-]+$/;
- }
- print "$file:$start: both ! and non-! distributions\n"
- if $bang && $nobang;
- }
- $type = "f";
- flag: foreach $flag ( split(/,/, $flags) ) {
- ($k, $v) = $flag =~ /(.)(.*)/;
- if ( !defined $newsfeeds'flags{$k} ) {
- print "$file:$start: unknown flag `$flag'\n";
- next flag;
- }
- if ( $v !~ /$newsfeeds'flags{$k}/ ) {
- print "$file:$start: bad value `$v' for flag `$k'\n";
- next flag;
- }
- $type = $v
- if $k eq "T";
- }
-
- ## Warn about multiple feeds.
- if ( !defined $sites{$site} ) {
- $sites{$site} = $type;
- } elsif ( $sites{$site} ne $type ) {
- print "$file:$start: feed $site multiple conflicting feeds\n";
- }
-
- if ( $type =~ /[cpx]/ ) {
- $prog = $param;
- $prog =~ s/\s.*//;
- print "$file:$start: relative path for $site\n"
- if $prog !~ m@^/@;
- print "$file:$start: `$prog' is not executable for $site\n"
- if ! -x $prog;
- }
- if ( $type eq "f" && $param =~ m@/@ ) {
- $dir = $param;
- $dir =~ s@(.*)/.*@$1@;
- $dir = $paths{'batchdir'} . "/" . $dir
- unless $dir =~ m@^/@;
- print "$file:$start: directory `$dir' does not exist for $site\n"
- if ! -d $dir;
- }
-
- ## If multiplex target not known, add to multiplex list.
- push(@muxes, "$start: undefined multiplex `$param'")
- if $type eq "m" && !defined $sites{$param};
- }
-
- ## Go through and make sure all referenced multiplex exist.
- foreach (@muxes) {
- print "$file:$_\n"
- if /`(.*)'/ && !defined $sites{$1};
- }
- print "$file:0: warning you accept all incoming article distributions\n"
- if !defined $sites{"ME"} || $me_empty;
-
- print "done.\n"
- if $verbose;
- 1;
-}
-
-
-##
-## overview.fmt
-##
-#%overview_fmtheaders = (
-# 'Approved', 1,
-# 'Bytes', 1,
-# 'Control', 1,
-# 'Date', 1,
-# 'Distribution', 1,
-# 'Expires', 1,
-# 'From', 1,
-# 'Lines', 1,
-# 'Message-ID', 1,
-# 'Newsgroups', 1,
-# 'Path', 1,
-# 'References', 1,
-# 'Reply-To', 1,
-# 'Sender', 1,
-# 'Subject', 1,
-# 'Supersedes', 1,
-#);
-
-sub
-overview_fmt
-{
- local ($header, $mode, $sawfull);
-
- $sawfull = 0;
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- unless ( ($header, $mode) = /^([^:]+):([^:]*)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
-
- #print "$file:$line: unknown header `$header'\n"
- # if !defined $overview_fmtheaders{$header};
- if ( $mode eq "full" ) {
- $sawfull++;
- } elsif ( $mode eq "" ) {
- print "$file:$line: short header `$header' appears after full one\n"
- if $sawfull;
- } else {
- print "$file:$line: unknown mode `$mode'\n";
- }
- }
- 1;
-}
-
-
-##
-## nntpsend.ctl
-##
-sub
-nntpsend_ctl
-{
- local ($site, $fqdn, $flags, $f, $v);
-
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- ## Ignore the size info for now.
- unless ( ($site, $fqdn, $flags) =
- /^([\w\-\.]+):([^:]*):[^:]*:([^:]*)$/ ) {
- print "$file:$line: malformed line.\n";
- next input;
- }
- print "$file:$line: FQDN is empty for `$site'\n"
- if $fqdn eq "";
-
- next input if $flags eq "";
- flag: foreach (split(/ /, $flags)) {
- unless ( ($f, $v) = /^-([adrvtTpSP])(.*)$/ ) {
- print "$file:$line: unknown argument for `$site'\n";
- next flag;
- }
- print "$file:$line: unknown argument to option `$f': $flags\n"
- if ( $f eq "t" || $f eq "T" || $f eq "P") && $v !~ /\d+/;
- }
- }
- 1;
-}
-
-
-##
-## passwd.nntp
-##
-sub
-passwd_nntp
-{
- local ($name, $pass);
-
- input: while ( <IN> ) {
- next input if &spacious($file, ++$line);
-
- unless ( ($name, $pass) = /[\w\-\.]+:(.*):(.*)(:authinfo)?$/ ) {
- next input;
- print "$file:$line: malformed line.\n";
- }
- print "$file:$line: username/password must both be blank or non-blank\n"
- if ( $name eq "" && $pass ne "" ) || ($name ne "" && $pass eq "");
- }
- 1;
-}
-
-
-##
-## readers.conf
-##
-sub
-readers_conf
-{
- 1;
-}
-\f
-
-##
-## Routines to check permissions
-##
-
-## Given a file F, check its mode to be M, and its ownership to be by the
-## user U in the group G. U and G have defaults.
-sub
-checkperm
-{
- local ($f, $m, $u, $g) = ( @_, $newsuser, $newsgroup);
- local (@sb, $owner, $group, $mode);
-
- die "Internal error, undefined name in perm from ", (caller(0))[2], "\n"
- if !defined $f;
- die "Internal error, undefined mode in perm from ", (caller(0))[2], "\n"
- if !defined $m;
-
- if ( ! -e $f ) {
- print "$pfx$f:0: missing\n";
- }
- else {
- @sb = stat _;
- $owner = (getpwuid($sb[$ST_UID]))[0];
- $group = (getgrgid($sb[$ST_GID]))[0];
- $mode = $sb[$ST_MODE] & ~0770000;
-
- ## Ignore setgid bit on directories.
- $mode &= ~0777000
- if -d _;
-
- if ( $owner ne $u ) {
- print "$pfx$f:0: owned by $owner, should be $u\n";
- print "chown $u $f\n"
- if $fix;
- }
- if ( $group ne $g ) {
- print "$pfx$f:0: in group $group, should be $g\n";
- print "chgrp $g $f\n"
- if $fix;
- }
- if ( $mode ne $m ) {
- printf "$pfx$f:0: mode %o, should be %o\n", $mode, $m;
- printf "chmod %o $f\n", $m
- if $fix;
- }
- }
-}
-
-## Return 1 if the Intersection of the files in the DIR and FILES is empty.
-## Otherwise, report an error for each illegal file, and return 0.
-sub
-intersect
-{
- local ($dir, @files) = @_;
- local (@in, %dummy, $i);
-
- if ( !opendir(DH, $dir) ) {
- print "$pfx$dir:0: can't open directory\n";
- }
- else {
- @in = grep($_ ne "." && $_ ne "..", readdir(DH));
- closedir(DH);
- }
-
- $i = 1;
- if ( scalar(@in) ) {
- foreach ( @files ) {
- $dummy{$_}++;
- }
- foreach ( grep ($dummy{$_} == 0, @in) ) {
- print "$pfx$dir:0: ERROR: illegal file `$_' in directory\n";
- $i = 0;
- }
- }
- $i;
-}
-
-@directories = (
- 'archive', 'badnews', 'batchdir', 'ctlprogs', 'most_logs', 'newsbin',
- 'newsetc', 'newslib', 'oldlogs', 'rnewsprogs', 'spooltemp', 'spool', 'spoolnews'
-);
-@rnews_programs = (
- 'c7unbatch', 'decode', 'encode', 'gunbatch'
-);
-@newsbin_public = (
- 'archive', 'batcher', 'buffchan', 'convdate', 'cvtbatch', 'expire',
- 'filechan', 'getlist', 'grephistory', 'innconfval', 'innxmit',
- 'makehistory', 'nntpget', 'overchan', 'prunehistory', 'shlock',
- 'shrinkfile'
-);
-@newsbin_private = (
- 'ctlinnd', 'expirerm', 'inncheck', 'innstat', 'innwatch',
- 'news.daily', 'nntpsend', 'scanlogs', 'sendbatch',
- 'tally.control', 'writelog',
- 'send-ihave', 'send-nntp', 'send-uucp'
-);
-#@newslib_private_read = (
-# 'innlog.pl'
-#);
-
-## The modes for the various programs.
-%prog_modes = (
- 'inews', @INEWSMODE@,
- 'innd', 0550,
- 'newsboot', 0550,
- 'nnrpd', 0555,
- 'rnews', @RNEWSMODE@,
-);
-
-## Check the permissions of nearly every file in an INN installation.
-sub
-check_all_perms
-{
- local ($rnewsprogs) = $paths{'rnewsprogs'};
- local ($newsbin) = $paths{'newsbin'};
- local ($newslib) = $paths{'newslib'};
-
- foreach ( @directories ) {
- &checkperm($paths{$_}, 0755);
- }
- &checkperm($paths{'innddir'}, 0750);
- foreach ( keys %prog_modes ) {
- &checkperm($paths{$_}, $prog_modes{$_});
- }
- &checkperm($paths{'inndstart'}, 04550, 'root', $newsgroup);
- foreach ( keys %paths ) {
- &checkperm($paths{$_}, $modes{$_})
- if defined $modes{$_};
- }
- &checkperm($paths{'history'}, 0644);
- # Commented out for now since it depends on the history type.
- #&checkperm($paths{'history'} . ".dir", 0644);
- #&checkperm($paths{'history'} . ".index", 0644);
- #&checkperm($paths{'history'} . ".hash", 0644);
- #foreach ( @newslib_private_read ) {
- # &checkperm("$newslib/$_", 0440);
- #}
- foreach ( @newsbin_private ) {
- &checkperm("$newsbin/$_", 0550);
- }
- foreach ( @newsbin_public ) {
- &checkperm("$newsbin/$_", 0555);
- }
- foreach ( @rnews_programs ) {
- &checkperm("$rnewsprogs/$_", 0555);
- }
-
- ## Also make sure that @rnews_programs are the *only* programs in there;
- ## anything else is probably someone trying to spoof rnews into being bad.
- &intersect($rnewsprogs, @rnews_programs);
-
- 1;
-}
-
-\f
-##
-## Parsing, main routine.
-##
-
-sub
-Usage
-{
- local ($i) = 0;
-
- print "Usage error: @_.\n";
- print
-"Usage:
- $program [-v] [-noperm] [-pedantic] [-perms [-fix] ] [-a|file...]
-File to check may be followed by \"=path\" to use the specified path. All
-files are checked if -a is used or if -perms is not used. Files that may
-be checked are:\n";
- foreach ( sort(keys %checklist) ) {
- printf " %-20s", $_;
- if ( ++$i == 3) {
- print "\n";
- $i = 0;
- }
- }
- print "\n"
- if $i;
- exit 0;
-}
-
-
-sub
-parse_flags
-{
- $all = 0;
- $fix = 0;
- $perms = 0;
- $noperms = 0;
- $verbose = 0;
- @todo = ();
-
- arg: foreach ( @ARGV ) {
- if ( /-a/ ) {
- $all++;
- next arg;
- }
- if ( /^-v/ ) {
- $verbose++;
- next arg;
- }
- if ( /^-ped/ ) {
- $pedantic++;
- next arg;
- }
- if ( /^-f/ ) {
- $fix++;
- next arg;
- }
- if ( /^-per/ ) {
- $perms++;
- next arg;
- }
- if ( /^-noperm/ ) {
- $noperms++;
- next arg;
- }
- if ( /^-/ ) {
- &Usage("Unknown flag `$_'");
- }
- if ( ($k, $v) = /(.*)=(.*)/ ) {
- &Usage("Can't check `$k'")
- if !defined $checklist{$k};
- push(@todo, $k);
- $paths{$k} = $v;
- next arg;
- }
- &Usage("Can't check `$_'")
- if !defined $checklist{$_};
- push(@todo, $_);
- }
-
- &Usage("Can't use `-fix' without `-perm'")
- if $fix && !$perms;
- &Usage("Can't use `-noperm' with `-perm'")
- if $noperms && $perms;
- $pfx = $fix ? '# ' : '';
-
- @todo = grep(defined $checklist{$_}, sort(keys %paths))
- if $all || (scalar(@todo) == 0 && ! $perms);
-}
-
-
-$program = $0;
-$program =~ s@.*/@@;
-$| = 1;
-&parse_flags();
-action: foreach $workfile ( @todo ) {
- $file = $paths{$workfile};
- if ( ! -f $file ) {
- print "$file:0: file missing\n";
- next action;
- }
- print "Looking at $file...\n"
- if $verbose;
- if ( !open(IN, $file) ) {
- print "$pfx$workfile:0: can't open $!\n";
- next action;
- }
- &checkperm($file, $modes{$workfile})
- if $noperms == 0 && !$perms && defined $modes{$workfile};
- $line = 0;
- eval "&$checklist{$workfile}" || warn "$@";
- close(IN);
-}
-
-&check_all_perms()
- if $perms;
-exit(0);
-
-if ( 0 ) {
- &active();
- &control_ctl();
- &incoming_conf();
- &expire_ctl();
- &inn_conf();
- &moderators();
- &nntpsend_ctl();
- &newsfeeds();
- &overview_fmt();
- &passwd_nntp();
- &readers_conf();
-}
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Fri, 25 Apr 1997 14:11:23 +0200
-# Project: INN
-# File: innmail.pl
-# RCSId: $Id: innmail.in 2677 1999-11-15 06:33:13Z rra $
-# Description: A simple replacement for UCB Mail to avoid nasty security
-# problems.
-#
-
-$0 =~ s!.*/!! ;
-
-require 5.001 ;
-require 'getopts.pl' ;
-
-die "$0: No \$inn::mta variable defined.\n"
- if ! defined ($inn::mta);
-
-$sm = $inn::mta ;
-
-die "$0: MTA path is not absolute\n" unless ($sm =~ m!^/!) ;
-
-$usage = "usage: $0 -s subject addresses\n\n" .
- "Reads stdin for message body\n" ;
-
-&Getopts ("s:h") || die $usage ;
-
-die $usage if $opt_h ;
-
-if ( !$opt_s ) {
- warn "No subject given. Hope that's ok\n" ;
- $opt_s = "NO SUBJECT" ;
-} else {
- $opt_s =~ s/\n+\Z//;
-}
-
-# fix up any addresses.
-foreach ( @ARGV ) {
- s![^-a-zA-Z0-9+_.@%]!!g ;
-
- push (@addrs,$_) if ($_ ne "") ;
-}
-
-die "$0: No addresses specified\n\n$usage" unless @addrs ;
-
-if ($sm =~ m!%s!) {
- $sm = sprintf $sm,join (' ',@addrs);
-} else {
- $sm .= " " . join(' ', @addrs);
-}
-
-@smarr = split(/\s+/,$sm);
-
-($t = $inn::mta) =~ s!\s.*!!;
-die "$0: MTA variable definition is changed after subsitution\n"
- if ($t ne $smarr[0]);
-
-die "$0: MTA excutable doesn't appear to exist: $smarr[0]\n"
- if ! -x $smarr[0];
-
-# startup mta without using the shell
-$pid = open (MTA,"|-") ;
-if ($pid == 0) {
- exec (@smarr) || die "$0: exec of $sm failed: $!\n" ;
-} elsif ($pid < 0) {
- die "$0: Fork failed: $!\n" ;
-}
-
-print MTA "To: ", join (",\n\t",@addrs), "\n" ;
-print MTA "Subject: $opt_s\n" ;
-print MTA "\n" ;
-while (<STDIN>) {
- print MTA $_ ;
-}
-close (MTA) ;
-exit ;
+++ /dev/null
-#! /usr/bin/perl
-# fixscript will replace this line with require innshellvars.pl
-
-##########################################################################
-#
-# innreport: Perl script to summarize news log files
-# (with optional HTML output and graphs).
-#
-# version: 3.0.2
-#
-# Copyright (c) 1996-1999, Fabien Tassin (fta@sofaraway.org).
-#
-##########################################################################
-#
-# Usage: innreport -f config_file [-[no]options] logfile [logfile2 [...]]
-# where options are:
-# -h (or -help) : this help page
-# -html : HTML output
-# -v : display the version number of INNreport
-# -f config_file : name of the configuration file
-# -config : print INNreport configuration information
-# -g : want graphs [default]
-# -graph : an alias for option -g
-# -d directory : directory for Web pages
-# -dir directory : an alias for option -d
-# -p directory : pictures path (file space)
-# -path directory : an alias for option -p
-# -w directory : pictures path (web space)
-# -webpath directory : an alias for option -w
-# -i : name of index page
-# -index : an alias for option -i
-# -a : want to archive HTML results
-# -archive : an alias for option -a
-# -c number : how many report files to keep (0 = all)
-# -cycle number : an alias for option -c
-# -s char : separator for filename
-# -separator char : an alias for option -s
-# -unknown : Unknown entries from news log file
-# -maxunrec : Max number of unrecognized line to display
-# -casesensitive : Case sensitive
-# -notdaily : Never perform daily actions
-#
-# Use no in front of boolean options to unset them.
-# For example, "-html" is set by default. Use "-nohtml" to remove this
-# feature.
-#
-##########################################################################
-#
-# ABSOLUTELY NO WARRANTY WITH THIS PACKAGE. USE IT AT YOUR OWN RISKS.
-#
-# Note: You need the Perl graphic library GD.pm if you want the graphs.
-# GD is available on all good CPAN ftp sites:
-# ex: [CPAN_DIR]/authors/id/LDS/GD-1.1_.tar.gz (or greater)
-# or directly to:
-# <URL:http://www-genome.wi.mit.edu/pub/software/WWW/GD.html>
-# Note : innreport will create PNG or GIF files depending upon
-# the GD version.
-#
-# Documentation: for a short explaination of the different options, you
-# can read the usage (obtained with the -h or -help switch).
-#
-# Install: - check the Perl location (first line). Require Perl 5.002
-# or greater.
-# - look at the parameters in the configuration file (section
-# 'default')
-# - copy the configuration file into ${PATHETC}/innreport.conf
-# - copy the INN module into ${PATHETC}/innreport_inn.pm
-# - copy this script into ${PATHETC}/innreport
-# - be sure that the news user can run it (chmod 755 or 750)
-# - in "scanlog", comment the line containing innlog and add:
-# ${PATHETC}/innreport -f ${PATHETC}/innreport.conf ${OLD_SYSLOG}
-# or, if you want to change some options:
-# ${PATHETC}/innreport -f ${PATHETC}/innreport.conf options ${OLD_SYSLOG}
-#
-# Report: please report bugs (preferably) to the INN mailing list
-# (see README) or directly to the author (do not forget to
-# include the result of the "-config" switch, the parameters
-# passed on the command line and the INN version).
-# Please also report unknown entries.
-# Be sure your are using the latest version of this script before
-# any report.
-#
-##########################################################################
-
-# Note: References to <ftp://ftp.sofaraway.org/pub/innreport/> have been
-# removed from the output because this site appears to no longer exist. It
-# used to be the upstream source for innreport. If there is a new site for
-# innreport releases, please notify the INN maintainers.
-
-# remember to add '-w' on the first line and to uncomment the 'use strict'
-# below before doing any changes to this file.
-
-use strict;
-
-## Do you want to create a Web page. Pick DO or DONT.
-my $HTML = "DO";
-
-## Do you want the graphs (need $HTML too). Pick DO or DONT.
-my $GRAPH = "DO";
-
-## Directory for the Web pages (used only if the previous line is active)
-my $HTML_dir = "$inn::pathhttp";
-
-## Directory for the pictures (need HTML support) in the file space
-my $IMG_dir = "$HTML_dir/pics";
-
-## Directory for the pictures (need HTML support) in the Web space
-## (can be relative or global)
-my $IMG_pth = "pics";
-
-## Do you want to archive HTML results (& pics) [ will add a date in each
-## name ]. Pick DO or DONT.
-my $ARCHIVE = "DO";
-
-## index page will be called:
-my $index = "index.html";
-
-## How many report files to keep (0 = all) (need $ARCHIVE).
-my $CYCLE = 0;
-
-## separator between hours-minutes-seconds in filenames
-## (normaly a ":" but some web-browsers (Lynx, MS-IE, Mosaic) can't read it)
-## Warning: never use "/". Use only a _valid_ filename char.
-my $SEPARATOR = ".";
-
-## Do you want the "Unknown entries from news log file" report. Pick DO or
-## DONT.
-my $WANT_UNKNOWN = "DO";
-
-## Max number of unrecognized lines to display (if $WANT_UNKNOWN)
-## (-1 = no limit)
-my $MAX_UNRECOGNIZED = 50;
-
-## Do you want to be case sensitive. Pick DO or DONT.
-my $CASE_SENSITIVE = "DO";
-
-## Some actions must only be performed daily (once for a log file).
-## (ex: unwanted.log with INN). Default value (DONT) means to perform
-## these actions each . Pick DO or DONT.
-my $NOT_DAILY = "DONT";
-
-###############################################
-## THERE'S NOTHING TO CHANGE AFTER THIS LINE ##
-###############################################
-
-my $version = "3.0.2";
-my %output; # content of the configuration file.
-my $DEBUG = 0; # set to 1 to verify the structure/content of the conf file.
-my $start_time = time;
-
-# Require Perl 5.002 or greater.
-require 5.002;
-use Getopt::Long;
-use vars qw/$HAVE_GD $GD_FORMAT/;
-
-my @old_argv = @ARGV;
-
-# Convert DO/DONT into boolean values.
-{
- my $i;
- foreach $i (\$HTML, \$GRAPH, \$ARCHIVE, \$WANT_UNKNOWN,
- \$CASE_SENSITIVE, \$NOT_DAILY) {
- $$i = $$i eq 'DO' ? 1 : 0 ;
- }
-}
-
-my %ref;
-GetOptions (\%ref,
- qw(-h -help
- -html!
- -config
- -f=s
- -g! -graph!
- -d=s -dir=s
- -p=s -path=s
- -w=s -webpath=s
- -i=s -index=s
- -a! -archive!
- -c=i -cycle=i
- -s=s -separator=s
- -unknown!
- -html-unknown!
- -maxunrec=i
- -casesensitive!
- -notdaily!
- -v
- ));
-
-&Version if $ref{'v'};
-
-&Decode_Config_File($ref{'f'}) if defined $ref{'f'};
-&Usage if $ref{'h'} || $ref{'help'} || !defined $ref{'f'};
-
-$HTML = 0 if defined $output{'default'}{'html'};
-$HTML = 1 if $output{'default'}{'html'} eq 'true';
-$HTML = 0 if defined $ref{'html'};
-$HTML = 1 if $ref{'html'};
-
-$GRAPH = 0 if defined $output{'default'}{'graph'};
-$GRAPH = 1 if $HTML && ($output{'default'}{'graph'} eq 'true');
-$GRAPH = 0 if defined $ref{'g'} || defined $ref{'graph'};
-$GRAPH = 1 if $HTML && ($ref{'g'} || $ref{'graph'});
-
-$HTML_dir = &GetValue ($output{'default'}{'html_dir'})
- if defined $output{'default'}{'html_dir'};
-$HTML_dir = $ref{'d'} if defined $ref{'d'};
-$HTML_dir = $ref{'dir'} if defined $ref{'dir'};
-
-$IMG_pth = &GetValue ($output{'default'}{'img_dir'})
- if defined $output{'default'}{'img_dir'};
-$IMG_pth = $ref{'w'} if defined $ref{'w'};
-$IMG_pth = $ref{'webpath'} if defined $ref{'webpath'};
-
-$IMG_dir = $HTML_dir . "/" . $IMG_pth
- if (defined $output{'default'}{'img_dir'} ||
- defined $ref{'w'} || defined $ref{'webpath'})
- &&
- (defined $output{'default'}{'html_dir'} ||
- defined $ref{'d'} || defined $ref{'dir'});
-
-$IMG_dir = $ref{'p'} if defined $ref{'p'};
-$IMG_dir = $ref{'path'} if defined $ref{'path'};
-
-$index = &GetValue ($output{'default'}{'index'})
- if defined $output{'default'}{'index'};
-$index = $ref{'i'} if defined $ref{'i'};
-$index = $ref{'index'} if defined $ref{'index'};
-
-$ARCHIVE = &GetValue ($output{'default'}{'archive'})
- if defined $output{'default'}{'archive'};
-$ARCHIVE = $ARCHIVE eq 'true';
-$ARCHIVE = 0 if defined $ref{'a'} || defined $ref{'archive'};
-$ARCHIVE = 1 if ($ref{'a'} || $ref{'archive'}) && $HTML;
-$ARCHIVE = 0 unless $HTML;
-
-$CYCLE = &GetValue ($output{'default'}{'cycle'})
- if defined $output{'default'}{'cycle'};
-$CYCLE = 0 if $CYCLE eq 'none';
-$CYCLE = $ref{'c'} if defined $ref{'c'};
-$CYCLE = $ref{'cycle'} if defined $ref{'cycle'};
-
-$SEPARATOR = &GetValue ($output{'default'}{'separator'})
- if defined $output{'default'}{'separator'};
-$SEPARATOR = $ref{'s'} if defined $ref{'s'};
-$SEPARATOR = $ref{'separator'} if defined $ref{'separator'};
-
-if (defined $output{'default'}{'unknown'}) {
- $WANT_UNKNOWN = &GetValue ($output{'default'}{'unknown'});
- $WANT_UNKNOWN = $WANT_UNKNOWN eq 'true' ? 1 : 0;
-}
-$WANT_UNKNOWN = 0 if defined $ref{'unknown'};
-$WANT_UNKNOWN = 1 if $ref{'unknown'};
-
-my $WANT_HTML_UNKNOWN = $WANT_UNKNOWN;
-if (defined $output{'default'}{'html-unknown'}) {
- $WANT_HTML_UNKNOWN = &GetValue ($output{'default'}{'html-unknown'});
- $WANT_HTML_UNKNOWN = $WANT_HTML_UNKNOWN eq 'true' ? 1 : 0;
-}
-$WANT_HTML_UNKNOWN = 0 if defined $ref{'html-unknown'};
-$WANT_HTML_UNKNOWN = 1 if $ref{'html-unknown'};
-
-$NOT_DAILY = 0 if defined $ref{'notdaily'};
-$NOT_DAILY = 1 if $ref{'notdaily'};
-
-$MAX_UNRECOGNIZED = &GetValue ($output{'default'}{'max_unknown'})
- if defined $output{'default'}{'max_unknown'};
-$MAX_UNRECOGNIZED = $ref{'maxunrec'} if defined ($ref{'maxunrec'});
-
-$CASE_SENSITIVE = &GetValue ($output{'default'}{'casesensitive'})
- if defined $output{'default'}{'casesensitive'};
-$CASE_SENSITIVE = 1 if $CASE_SENSITIVE eq 'true';
-$CASE_SENSITIVE = 0 if defined $ref{'casesensitive'};
-$CASE_SENSITIVE = 1 if $ref{'casesensitive'};
-
-my $CLASS = &GetValue ($output{'default'}{'module'});
-my $LIBPATH = &GetValue ($output{'default'}{'libpath'});
-
-umask 022;
-
-BEGIN {
- eval "use GD;";
- $HAVE_GD = $@ eq '';
- if ($HAVE_GD) {
- my $gd = new GD::Image(1,1);
- $GD_FORMAT = "gif" if $gd->can('gif');
- $GD_FORMAT = "png" if $gd->can('png');
- }
- $HAVE_GD;
-};
-undef $GRAPH unless $HTML;
-if ($GRAPH && !$::HAVE_GD) {
- print "WARNING: can't make graphs as required.\n" .
- " Install GD.pm or disable this option.\n\n";
- undef $GRAPH;
-}
-
-if ($HTML) {
- if ($GRAPH) {
- $IMG_dir = "." if defined $IMG_dir && $IMG_dir eq '';
- $IMG_pth .= "/" if $IMG_pth;
- $IMG_pth =~ s|/+|/|g;
- $IMG_dir =~ s|/+|/|g;
- unless (-w $IMG_dir) {
- print "WARNING: can't write in \"$IMG_dir\" as required by -g " .
- "switch.\n Option -g removed. Please see the -p switch.\n\n";
- undef $GRAPH;
- }
- }
- $HTML_dir = "." if defined $HTML_dir && $HTML_dir eq '';
- unless (-w $HTML_dir) {
- print "WARNING: can't write in \"$HTML_dir\" as required by -html " .
- "switch.\n Option -html and -a removed. Please see the " .
- "-d switch.\n\n";
- undef $HTML;
- $ARCHIVE = 0;
- }
-}
-
-# Now, we are sure that HTML and graphs can be made if options are active.
-&Summary if defined $ref{'config'};
-
-my $unrecognize_max = 0;
-my @unrecognize;
-my ($total_line, $total_size) = (0, 0);
-my ($suffix, $HTML_output, %config, $first_date, $last_date,
- %prog_type, %prog_size);
-
-my $HTML_header = '';
-my $HTML_footer = '';
-
-my $MIN = 1E10;
-my $MAX = -1;
-
-my $xmax = &GetValue ($output{'default'}{'graph_width'}) # Graph size..
- if defined $output{'default'}{'graph_width'};
-$xmax = 550 unless $xmax;
-
-my $transparent = &GetValue ($output{'default'}{'transparent'})
- if defined $output{'default'}{'transparent'};
-$transparent = (defined $transparent && $transparent eq 'true') ? 1 : 0;
-
-my $repeated = 1;
-
-my $first_date_cvt = $MIN;
-my $last_date_cvt = $MAX;
-
-
-#########################################################################
-my $s = sprintf "use lib qw($LIBPATH); use $CLASS;";
-eval $s; # initialization
-die "Can't find/load $CLASS.pm : $@\n" if $@;
-
-my $save_line = <>;
-$_ = $save_line;
-local $^W = 0 if $] < 5.004; # to avoid a warning for each '+=' first use.
-LINE: while (!eof ()) {
- $total_line++;
- my $size = length;
- $total_size += $size;
-
- # Syslog optimization
- if ($repeated) {
- $repeated--;
- $_ = $save_line;
- }
- else {
- $_ = <>;
- if ($_ =~ /last message repeated (\d+) times?$/o) {
- $repeated = $1;
- $_ = $save_line;
- }
- else {
- $save_line = $_;
- }
- }
-
- # skip empty lines
- next LINE if $_ eq '';
-
- my $res;
- my ($day, $hour, $prog, $left) =
- $_ =~ m/^(\S+\s+\S+) (\S+) \S+ (\S+): \[ID \d+ \S+\] (.*)$/o;
- ($day, $hour, $prog, $left) =
- $_ =~ m/^(\S+\s+\S+) (\S+) \S+ (\S+): (.*)$/o unless $day;
- ($day, $hour, $prog, $left) =
- $_ =~ m/^(\S+\s+\S+) (\S+) \d+ \S+ (\S+): (.*)$/o unless $day;
-
- unless ($day) {
- ($day, $hour, $res, $left) = $_ =~ m/^(\S+\s+\S+) (\S+)\.\d+ (\S+) (.*)$/o;
- if ($day) {
- my $cvtdate = &ConvDate ("$day $hour");
- if ($cvtdate < $first_date_cvt) {
- $first_date_cvt = $cvtdate;
- $first_date = "$day $hour";
- }
- elsif ($cvtdate > $last_date_cvt) {
- $last_date_cvt = $cvtdate;
- $last_date = "$day $hour";
- }
- $prog = "inn";
- }
- else {
- next if $_ =~ /^$/;
- # Unrecognize line... skip
- $unrecognize[$unrecognize_max] = $_
- unless $unrecognize_max > $MAX_UNRECOGNIZED
- && $MAX_UNRECOGNIZED > 0;
- $unrecognize_max++;
- next LINE;
- }
- }
- else {
- my $cvtdate = &ConvDate ("$day $hour");
- if ($cvtdate < $first_date_cvt) {
- $first_date_cvt = $cvtdate;
- $first_date = "$day $hour";
- }
- elsif ($cvtdate > $last_date_cvt) {
- $last_date_cvt = $cvtdate;
- $last_date = "$day $hour";
- }
- }
-
- ########
- ## Program name
- # word[7164] -> word
- my ($pid) = $prog =~ s/\[(\d+)\]$//o;
- # word: -> word
- $prog =~ s/:$//o;
- # wordX -> word (where X is a digit)
- $prog =~ s/\d+$//o;
-
- $prog_type{$prog}++;
- $prog_size{$prog} = 0 unless defined $prog_size{$prog}; # stupid warning :(
- $prog_size{$prog} += $size;
-
- # The "heart" of the tool.
- {
- no strict;
- next LINE if
- &{$CLASS."::collect"} ($day, $hour, $prog, $res, $left, $CASE_SENSITIVE);
- }
-
- $unrecognize[$unrecognize_max] = $_
- unless $unrecognize_max > $MAX_UNRECOGNIZED
- && $MAX_UNRECOGNIZED > 0;
- $unrecognize_max++;
-}
-
-{
- no strict;
- &{$CLASS . "::adjust"} ($first_date, $last_date);
-}
-
-$| = 1;
-
-die "no data. Abort.\n" unless $total_line;
-
-my $sec_glob = &ConvDate ("$last_date") - &ConvDate ("$first_date");
-unless ($sec_glob) {
- print "WARNING: bad date (\"$last_date\" or \"$first_date\")\n" .
- " Please, contact the author of innreport.\n";
- $sec_glob = 24 * 60 * 60; # one day
-}
-
-$HTML_output = '';
-
-if ($HTML) {
- # Create a new filename (unique and _sortable_)
- if ($ARCHIVE) {
- # The filename will contain the first date of the log or the current time.
- my ($ts, $tm, $th, $dd, $dm, $dy) = localtime;
- my ($m, $d, $h, $mn, $s) =
- $first_date =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)$/;
- if ($m) {
- my $ddm = (index "JanFebMarAprMayJunJulAugSepOctNovDec", $m) / 3;
- # Adjust the year because syslog doesn't record it. We assume that
- # it's the current year unless the last date is in the future.
- my $ld = &ConvDate($last_date);
- $dy-- if $ld > $ts + 60 * ($tm + 60 * ($th + 24 * ($dd - 1 +
- substr("000031059090120151181212243273304334", $dm * 3, 3)))) ||
- $ld < &ConvDate($first_date);
- ($dm, $dd, $th, $tm, $ts) = ($ddm, $d, $h, $mn, $s);
- }
- $dm++; # because January = 0 and we prefer 1
- $dy += 100 if $dy < 90; # Try to pacify the year 2000 !
- $dy += 1900;
- $suffix = sprintf ".%02d.%02d.%02d-%02d$SEPARATOR%02d$SEPARATOR%02d",
- $dy, $dm, $dd, $th, $tm, $ts;
- }
- else {
- $suffix = '';
- }
- $HTML_output = "$HTML_dir" . "/news-notice" . "$suffix" . ".html";
- $HTML_output =~ s|/+|/|g;
- if (defined $output{'default'}{'html_header_file'}) {
- my $file = &GetValue ($output{'default'}{'html_header_file'});
- $file = $HTML_dir . "/" . $file;
- open (F, $file) && do {
- local $/ = undef;
- $HTML_header = <F>;
- close F;
- };
- }
- if (defined $output{'default'}{'html_footer_file'}) {
- my $file = &GetValue ($output{'default'}{'html_footer_file'});
- $file = $HTML_dir . "/" . $file;
- open (F, $file) && do {
- local $/ = undef;
- $HTML_footer = <F>;
- close F;
- };
- }
-}
-
-&Write_all_results ($HTML_output, \%output);
-
-&Make_Index ($HTML_dir, $index, "news-notice$suffix.html", \%output)
- if $HTML && $index;
-
-#====================================================================
-
-if ($ARCHIVE) {
- # rotate html files
- &Rotate ($CYCLE, $HTML_dir, "news-notice", ".html");
-
- # rotate pictures
- my $report;
- foreach $report (@{$output{'_order_'}}) {
- next if $report =~ m/^(default|index)$/;
- next unless defined $output{$report}{'graph'};
-
- my $i = 0;
- while ($GRAPH && defined ${${$output{$report}{'graph'}}[$i]}{'type'}) {
- my $name = $report . ($i ? $i : '');
- &Rotate ($CYCLE, $IMG_dir, $name, '.' . $GD_FORMAT);
- $i++;
- }
- }
-}
-
-# Code needed by INN only. It must be in innreport_inn.pm to keep things clean.
-if (!$NOT_DAILY && defined $output{'default'}{'unwanted_log'}) {
- my $logfile = &GetValue ($output{'default'}{'unwanted_log'});
- my $logpath = &GetValue ($output{'default'}{'logpath'});
- {
- no strict;
- &{$CLASS . "::report_unwanted_ng"} ("$logpath/$logfile");
- }
-}
-
-################
-# End of report.
-###################################################################
-
-######
-# Misc...
-
-# Compare 2 dates (+hour)
-sub DateCompare {
- # ex: "May 12 06" for May 12, 6:00am
- local $[ = 0;
- # The 2 dates are near. The range is less than a few days that's why we
- # can cheat to determine the order. It is only important if one date
- # is in January and the other in December.
-
- my $date1 = substr ($a, 4, 2) * 24;
- my $date2 = substr ($b, 4, 2) * 24;
- $date1 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($a,0,3)) * 288;
- $date2 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($b,0,3)) * 288;
- if ($date1 - $date2 > 300 * 24) {
- $date2 += 288 * 3 * 12;
- }
- elsif ($date2 - $date1 > 300 * 24) {
- $date1 += 288 * 3 * 12;
- }
- $date1 += substr($a, 7, 2);
- $date2 += substr($b, 7, 2);
- $date1 - $date2;
-}
-
-
-# Convert: seconds to hh:mm:ss
-sub second2time {
- my $temp;
- my $t = shift;
- # Hours
- $temp = sprintf "%02d", $t / 3600;
- my $chaine = "$temp:";
- $t %= 3600;
- # Min
- $temp = sprintf "%02d", $t / 60;
- $chaine .= "$temp:";
- $t %= 60;
- # Sec
- $chaine .= sprintf "%02d", $t;
- return $chaine;
-}
-
-# Convert: milliseconds to hh:mm:ss:mm
-sub ms2time {
- my $temp;
- my $t = shift;
- # Hours
- $temp = sprintf "%02d", $t / 3600000;
- my $chaine = "$temp:";
- $t %= 3600000;
- # Min
- $temp = sprintf "%02d", $t / 60000;
- $chaine .= "$temp:";
- $t %= 60000;
- # Sec
- $temp = sprintf "%02d", $t / 1000;
- $chaine .= "$temp.";
- $t %= 1000;
- # Millisec
- $chaine .= sprintf "%03d", $t;
- return $chaine;
-}
-
-# Rotate the archive files..
-sub Rotate {
- # Usage: &Rotate ($max_files, "$directory", "prefix", "suffix");
- my ($max, $rep, $prefix, $suffix) = @_;
- my ($file, $num, %files);
- local ($a, $b);
-
- return 1 unless $max;
- opendir (DIR, "$rep") || die "Error: Cant open directory \"$rep\"\n";
-
- FILE : while (defined ($file = readdir (DIR))) {
- next FILE
- unless $file =~ /^ # e.g. news-notice.1997.05.14-01:34:29.html
- $prefix # Prefix : news-notice
- \. # dot : .
- (\d\d)?\d\d # Year : 1997 (or 97)
- \. # dot : .
- \d\d # Month : 05
- \. # dot : .
- \d\d # Day : 14
- - # Separator : -
- \d\d # Hour : 01
- $SEPARATOR # Separator : ":"
- \d\d # Minute : 34
- $SEPARATOR # Separator : ":"
- \d\d # Second : 29
- $suffix # Suffix : ".html"
- $/x;
- $files{$file}++;
- }
- closedir DIR;
- $num = 0;
- foreach $file (sort {$b cmp $a} (keys (%files))) {
- unlink "$rep/$file" if $num++ >= $max && -f "$rep/$file";
- }
- return 1;
-}
-
-# convert a date to a number of seconds
-sub ConvDate {
- # usage: $num = &ConvDate ($date);
- # date format is Aug 22 01:49:40
- my $T = shift;
- my ($m, $d, $h, $mn, $s) = $T =~ /^(\S+)\s+(\d+)\s+(\d+):(\d+):(\d+)$/;
- my $out = $s + 60 * $mn + 3600 * $h + 86400 * ($d - 1);
-
- $m = substr("000031059090120151181212243273304334",
- index ("JanFebMarAprMayJunJulAugSepOctNovDec", $m), 3);
- $out += $m * 86400;
- return $out;
-}
-
-# Compare 2 filenames
-sub filenamecmp {
- local $[ = 0;
- my ($la, $lb) = ($a, $b);
- my ($ya) = $la =~ m/news-notice\.(\d+)\./o;
- $ya += 100 if $ya < 90; # Try to pacify the year 2000 !
- $ya += 1900 if $ya < 1900; # xx -> xxxx
- my ($yb) = $lb =~ m/news-notice\.(\d+)\./o;
- $yb += 100 if $yb < 90; # Try to pacify the year 2000 !
- $yb += 1900 if $yb < 1900; # xx -> xxxx
-
- $la =~ s/news-notice\.(\d+)\./$ya\./;
- $lb =~ s/news-notice\.(\d+)\./$yb\./;
- $la =~ s/[\.\-\:html]//g;
- $lb =~ s/[\.\-\:html]//g;
-
- $lb <=> $la;
-}
-
-sub ComputeTotal {
- my $h = shift;
- my $total = 0;
- my $key;
- foreach $key (keys (%$h)) {
- $total += $$h{$key};
- }
- $total;
-}
-
-sub ComputeTotalDouble {
- my $h = shift;
- my $total = 0;
- my ($key1, $key2);
- foreach $key1 (keys (%$h)) {
- foreach $key2 (keys (%{$$h{$key1}})) {
- $total += ${$$h{$key1}}{$key2};
- }
- }
- $total;
-}
-
-# make an index for archive pages
-sub Make_Index {
- my ($rep, $index, $filename, $data) = @_;
- my %output = %$data;
-
- $index =~ s/^\"\s*(.*?)\s*\"$/$1/o;
-
- # add requested data at the end of the database.
- open (DATA, ">> $rep/innreport.db") || die "can't open $rep/innreport.db\n";
- my $i = 0;
- my $res = "$filename";
- while (defined ${${$output{'index'}{'column'}}[$i]}{'value'}) {
- my $data = &GetValue (${${$output{'index'}{'column'}}[$i]}{'value'});
- $data =~ s/\n//sog;
- my @list = split /\|/, $data;
- my $val;
- foreach $val (@list) {
- $res .= ($val eq 'date' ? "|$first_date -- $last_date"
- : "|" . &EvalExpr($val));
- }
- $i++;
- }
- print DATA "$res\n";
- close DATA;
-
- # sort the database (reverse order), remove duplicates.
- open (DATA, "$rep/innreport.db") || die "can't open $rep/innreport.db\n";
- my %data;
- while (<DATA>) {
- m/^([^\|]+)\|(.*)$/o;
- $data{$1} = $2;
- }
- close DATA;
- open (DATA, "> $rep/innreport.db") || die "can't open $rep/innreport.db\n";
- $i = 0;
- foreach (sort {$b cmp $a} (keys %data)) {
- print DATA "$_|$data{$_}\n" if $CYCLE == 0 || $i < $CYCLE;
- $i++;
- }
- close DATA;
-
- my $title = "Daily Usenet report";
- $title = &GetValue ($output{'default'}{'title'})
- if defined $output{'default'}{'title'};
- $title =~ s/\\\"/\"/g;
- my $Title = $title;
- $Title =~ s/<.*?>//g;
- my $body = '';
- $body = &GetValue ($output{'default'}{'html_body'})
- if defined $output{'default'}{'html_body'};
- $body =~ s/\\\"/\"/go;
- my $result = sprintf <<EOF;
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<HTML><HEAD>
-<TITLE>$Title: index</TITLE>
-</HEAD><BODY $body>
-$HTML_header
-<HR ALIGN=CENTER SIZE=\"4\" WIDTH=\"100%%\">
-<BR><CENTER><FONT SIZE=\"+2\">
-<B>$title - archives</B>
-</FONT></CENTER>
-<BR CLEAR=ALL>
-<HR ALIGN=CENTER SIZE=4 WIDTH=\"100%%\"><P>
-<CENTER>
-EOF
-
- if ($GRAPH) {
- my $i = 0;
- while (defined ${${$output{'index'}{'graph'}}[$i]}{'title'}) {
- my $title = &GetValue (${${$output{'index'}{'graph'}}[$i]}{'title'});
- my $filename = "index$i.$GD_FORMAT";
- my $color_bg = &GetValue (${${$output{'index'}{'graph'}}[$i]}{'color'});
- my $unit = &GetValue (${${$output{'index'}{'graph'}}[$i]}{'unit'});
- my $date_idx = &GetValue (${${$output{'index'}{'graph'}}[$i]}{'value'});
- $date_idx =~ s/^val(\d+)$/$1/o;
- my @c = @{${${$output{'index'}{'graph'}}[$i]}{'data'}};
- my $label_in = &GetValue (${$c[0]}{'name'});
- my $color_in = &GetValue (${$c[0]}{'color'});
- my $value_in = &GetValue (${$c[0]}{'value'});
- my $type_in = 0;
- $type_in = $value_in =~ s/^byte\((.*?)\)$/$1/o;
- $value_in =~ s/^val(\d+)$/$1/o;
- my $label_out = &GetValue (${$c[1]}{'name'});
- my $color_out = &GetValue (${$c[1]}{'color'});
- my $value_out = &GetValue (${$c[1]}{'value'});
- my $type_out = 0;
- $type_out = $value_out =~ s/^byte\((.*?)\)$/$1/o;
- $value_out =~ s/^val(\d+)$/$1/o;
- my (%in, %out, %dates, $k);
- foreach $k (keys (%data)) {
- my @res = split /\|/, $data{$k};
- my ($year) = $k =~ m/^news-notice\.(\d+)\.\d+\.\d+-\d+.\d+.\d+\.html/;
- next unless $year; # bad filename.. strange.
- my ($start, $end) =
- $res[$date_idx - 1] =~ m/^(\w+\s+\d+ \S+) -- (\w+\s+\d+ \S+)$/o;
- next unless $start; # bad date
- $start = &ConvDate ($start);
- $end = &ConvDate ($end);
- # 31/12 - 1/1 ?
- my $inc = $end < $start ? 1 : 0;
- $start += (($year - 1970) * 365 +
- int (($year - 1968) / 4)) * 3600 * 24;
- $year += $inc;
- $end += (($year - 1970) * 365 + int (($year - 1968) / 4)) * 3600 * 24;
- $in{$start} = $type_in ? &kb2i($res[$value_in - 1])
- : $res[$value_in - 1];
- $out{$start} = $type_out ? &kb2i($res[$value_out - 1])
- : $res[$value_out - 1];
- $dates{$start} = $end;
- }
- my ($xmax, $ymax) = (500, 170);
- &Chrono ("$IMG_dir/$filename", $title, $color_bg, $xmax, $ymax,
- \%in, \%out, \%dates, $label_in, $label_out,
- $color_in, $color_out, $unit);
- $result .= "<IMG WIDTH=\"$xmax\" HEIGHT=\"$ymax\" ";
- $result .= "SRC=\"$IMG_pth$filename\" ALT=\"Graph\">\n";
- $i++;
- }
- $result .= "<P>\n";
- }
- $i = 0;
- $result .= "<TABLE BORDER=\"1\"><TR>";
- my $temp = '';
- while (defined ${${$output{'index'}{'column'}}[$i]}{'title'}) {
- my $title = &GetValue (${${$output{'index'}{'column'}}[$i]}{'title'});
- my $name = '';
- $name = &GetValue (${${$output{'index'}{'column'}}[$i]}{'name'})
- if defined ${${$output{'index'}{'column'}}[$i]}{'name'};
- my @list = split /\|/, $name;
- if ($name) {
- $result .= sprintf "<TH COLSPAN=%d>$title</TH>", $#list + 1;
- }
- else {
- $result .= "<TH ROWSPAN=\"2\">$title</TH>";
- }
- foreach (@list) {
- $temp .= "<TH>$_</TH>";
- }
- $i++;
- }
- $result .= "</TR>\n<TR>$temp</TR>\n";
-
- $i = 0;
- foreach (sort {$b cmp $a} (keys %data)) {
- if ($CYCLE == 0 || $i < $CYCLE) {
- my @list = split /\|/, $data{$_};
- my $str = "<TR><TD ALIGN=LEFT>";
- $str .= "<A HREF=\"$_\">" if -e "$rep/$_";
- $str .= shift @list;
- $str .= "</A>" if -e "$rep/$_";;
- $str .= "</TD>";
- while (@list) {
- $str .= "<TD ALIGN=RIGHT>";
- my $t = shift @list;
- $t =~ s/^\0+//o; # remove garbage, if any.
- $str .= "$t</TD>";
- }
- $str .= "</TR>\n";
- $result .= "$str";
- }
- $i++;
- }
- $result .= "</TABLE>\n</CENTER>\n<P><HR>";
- $result .= "innreport $version (c) 1996-1999 ";
- $result .= "by Fabien Tassin <<A HREF=\"mailto:fta\@sofaraway.org\">";
- $result .= "fta\@sofaraway.org</A>>.\n";
- if (defined ($output{'default'}{'footer'})) {
- my ($t) = $output{'default'}{'footer'} =~ m/^\"\s*(.*?)\s*\"$/o;
- $t =~ s/\\\"/\"/go;
- $result .= "<BR>" . $t;
- }
- $result .= "$HTML_footer\n</BODY>\n</HTML>\n";
- my $name = $rep . "/" . $index;
- while ($name =~ m/\/\.\.\//o) {
- $name =~ s|^\./||o; # ^./xxx => ^xxx
- $name =~ s|/\./|/|go; # xxx/./yyy => xxx/yyy
- $name =~ s|/+|/|go; # xxx//yyy => xxx/yyy
- $name =~ s|^/\.\./|/|o; # ^/../xxx => ^/xxx
- $name =~ s|^[^/]+/\.\./||o; # ^xxx/../ => ^nothing
- $name =~ s|/[^/]+/\.\./|/|go; # /yyy/../ => /
- }
-
- open (INDEX, "> $name") || die "Error: Unable to create $name\n";
- print INDEX $result;
- close INDEX;
- 1;
-}
-
-sub Graph3d {
- my $filename = shift; # filename
- my $title = shift; # title
- my $xmax = shift; # width
- my $n = shift; # Number of hash code tables
-
- no strict;
- my ($i, $k, $t);
- my @val;
- for $i (0 .. $n - 1) {
- push @val, shift; # hash code table
- }
- my $colors = shift; # colors table
- my $labels = shift; # labels
-
- my $max = 0;
- my $max_size = 0;
- my $size = 0;
- foreach $k (sort keys (%{$val[0]})) {
- $t = 0;
- $size++;
- for $i (0 .. $n - 1) {
- $t += ${$val[$i]}{$k} if defined ${$val[$i]}{$k};
- }
- $max = $t if $max < $t;
- $t = length "$k";
- $max_size = $t if $max_size < $t;
- }
- $max = 1 unless $max;
- $max_size *= gdSmallFont->width;
-
- # relief
- my ($rx, $ry) = (15, 5);
-
- # margins
- my ($mt, $mb) = (40, 40);
- my $ml = $max_size > 30 ? $max_size + 8 : 30;
-
- my $mr = 7 + (length "$max") * gdSmallFont->width;
- $mr = 30 if $mr < 30;
-
- # height of each bar
- my $h = 12;
-
- # difference between 2 bars
- my $d = 25;
-
- my $ymax = $size * $d + $mt + $mb;
- my $image = new GD::Image ($xmax, $ymax);
-
- my ($white, $black);
- if (defined $output{'default'}{'graph_fg'}) {
- my $t = $output{'default'}{'graph_fg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_fg'. Bad color.\n";
- my @c = map { hex ($_) } ($t =~ m/^(..)(..)(..)$/);
- $black = $image->colorAllocate (@c);
- }
- else {
- $black = $image->colorAllocate ( 0, 0, 0);
- }
- if (defined $output{'default'}{'graph_bg'}) {
- my $t = $output{'default'}{'graph_bg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_bg'. Bad color.\n";
- my @c = map { hex ($_) } ($t =~ m/^(..)(..)(..)$/);
- $white = $image->colorAllocate (@c);
- }
- else {
- $white = $image->colorAllocate (255, 255, 255);
- }
- $image->filledRectangle (0, 0, $xmax, $ymax, $white);
- my @col;
- for $i (0 .. $n - 1) {
- $col[$i][0] = $image->colorAllocate
- ($$colors[$i][0], $$colors[$i][1], $$colors[$i][2]);
- $col[$i][1] = $image->colorAllocate
- ($$colors[$i][0] * 3 / 4, $$colors[$i][1] * 3 / 4,
- $$colors[$i][2] * 3 / 4);
- $col[$i][2] = $image->colorAllocate
- ($$colors[$i][0] * 2 / 3, $$colors[$i][1] * 2 / 3,
- $$colors[$i][2] * 2 / 3);
- }
-
- $image->transparent ($white) if $transparent;
-
- $image->rectangle (0, 0, $xmax - 1, $size * $d + $mt + $mb - 1, $black);
- $image->line (0, $mt - 5, $xmax - 1, $mt - 5, $black);
- for $i (0 .. $n - 1) {
- $image->string (gdSmallFont, $i * $xmax / $n + $mt - 10 + $rx,
- ($mt - gdSmallFont->height) / 2, "$$labels[$i]", $black);
- $image->filledRectangle ($i * $xmax / $n + 10, 8 + $ry / 2,
- $i * $xmax / $n + $mt - 10, $mt - 12, $col[$i][0]);
- $image->rectangle ($i * $xmax / $n + 10, 8 + $ry / 2,
- $i * $xmax / $n + $mt - 10, $mt - 12, $black);
- {
- my $poly = new GD::Polygon;
- $poly->addPt($i * $xmax / $n + 10, 8 + $ry / 2);
- $poly->addPt($i * $xmax / $n + 10 + $rx / 2, 8);
- $poly->addPt($i * $xmax / $n + $mt - 10 + $rx / 2, 8);
- $poly->addPt($i * $xmax / $n + $mt - 10, 8 + $ry / 2);
-
- $image->filledPolygon($poly, $col[$i][1]);
- $image->polygon($poly, $black);
- }
- {
- my $poly = new GD::Polygon;
- $poly->addPt($i * $xmax / $n + $mt - 10 + $rx / 2, 8);
- $poly->addPt($i * $xmax / $n + $mt - 10, 8 + $ry / 2);
- $poly->addPt($i * $xmax / $n + $mt - 10, $mt - 12);
- $poly->addPt($i * $xmax / $n + $mt - 10 + $rx / 2, $mt - 12 - $ry / 2);
-
- $image->filledPolygon($poly, $col[$i][2]);
- $image->polygon($poly, $black);
- }
- }
- # Title
- $image->string (gdMediumBoldFont, ($xmax - gdMediumBoldFont->width *
- (length "$title")) / 2, $ymax - gdMediumBoldFont->height - 7,
- "$title", $black);
-
- my $e = $mt - $h + $d;
- my $r = ($xmax - $ml - $mr - $rx) / $max;
-
- # Axe Oz
- $image->line ($ml + $rx, $mt, $ml + $rx, $size * $d + $mt - $ry, $black);
- $image->line ($ml + $rx + $max * $r, $mt, $ml + $rx + $max * $r,
- $size * $d + $mt - $ry, $black);
- $image->line ($ml, $mt + $ry, $ml, $size * $d + $mt, $black);
- # Axe Ox
- $image->line ($ml + $rx, $size * $d + $mt - $ry,
- $ml + $rx - 2 * $rx, $size * $d + $mt + $ry, $black);
- # Axe Oy
- $image->line ($ml + $rx, $size * $d + $mt - $ry,
- $xmax - $mr / 2, $size * $d + $mt - $ry, $black);
- $image->line ($ml, $size * $d + $mt,
- $xmax - $mr - $rx, $size * $d + $mt, $black);
-
- # Graduations..
- my $nn = 10;
- for $k (1 .. ($nn - 1)) {
- $image->dashedLine ($ml + $rx + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $mt + 10, $ml + $rx + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $size * $d + $mt - $ry, $black);
- $image->dashedLine ($ml + $rx + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $size * $d + $mt - $ry,
- $ml + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $size * $d + $mt, $black);
- $image->line ($ml + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $size * $d + $mt,
- $ml + $k * ($xmax - $ml - $mr - $rx) / $nn,
- $size * $d + $mt + 5, $black);
- my $t = sprintf "%d%%", $k * 10;
- $image->string (gdSmallFont, $ml + $k * ($xmax - $ml - $mr - $rx) / $nn -
- (length "$t") * gdSmallFont->width / 2,
- $size * $d + $mt + 6, "$t", $black);
- }
- {
- my $t = sprintf "%d%%", 0;
- $image->line ($ml, $size * $d + $mt, $ml, $size * $d + $mt + 5, $black);
- $image->string (gdSmallFont, $ml - (length "$t") * gdSmallFont->width / 2,
- $size * $d + $mt + 6, "$t", $black);
- $image->line ($xmax - $mr, $size * $d + $mt - $ry,
- $xmax - $mr - $rx, $size * $d + $mt, $black);
- $image->line ($xmax - $mr - $rx, $size * $d + $mt,
- $xmax - $mr - $rx, $size * $d + $mt + 5, $black);
- $t = sprintf "%d%%", 100;
- $image->string (gdSmallFont, $xmax - $mr - $rx
- - (length "$t") * gdSmallFont->width / 2,
- $size * $d + $mt + 6, "$t", $black);
- }
- foreach $k (sort {${$val[0]}{$b} <=> ${$val[0]}{$a}} keys (%{$val[0]})) {
- $image->string (gdSmallFont, $ml - (length "$k") * gdSmallFont->width - 3,
- $e + $h / 2 - gdSmallFont->height / 2, "$k", $black);
- my $t = 0;
- $image->line ($ml + ($t + ${$val[0]}{$k}) * $r + $rx - $rx, $e + $h,
- $ml + ($t + ${$val[0]}{$k}) * $r + $rx, $e - $ry + $h,
- $black);
- for $i (0 .. $n - 1) {
- next unless defined ${$val[$i]}{$k};
- {
- my $poly = new GD::Polygon;
- $poly->addPt($ml + $t * $r, $e);
- $poly->addPt($ml + $t * $r + $rx, $e - $ry);
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r + $rx, $e - $ry);
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r, $e);
-
- $image->filledPolygon($poly, $col[$i][1]);
- $image->polygon($poly, $black);
- }
- unless (${$val[$i + 1]}{$k} || ${$val[$i]}{$k} == 0) {
- my $poly = new GD::Polygon;
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r + $rx, $e - $ry);
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r + $rx - $rx, $e);
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r + $rx - $rx, $e + $h);
- $poly->addPt($ml + ($t + ${$val[$i]}{$k}) * $r + $rx, $e - $ry + $h);
-
- $image->filledPolygon($poly, $col[$i][2]);
- $image->polygon($poly, $black);
- }
- $image->filledRectangle ($ml + $t * $r, $e,
- $ml + ($t + ${$val[$i]}{$k}) * $r, $e + $h,
- $col[$i][0]);
- $image->rectangle ($ml + $t * $r, $e, $ml + ($t + ${$val[$i]}{$k}) * $r,
- $e + $h, $black);
- $t += ${$val[$i]}{$k};
- }
- # total length (offered)
- $image->filledRectangle ($ml + $t * $r + $rx + 3,
- $e - 2 - gdSmallFont->height / 2,
- $ml + $t * $r + $rx + 4 +
- gdSmallFont->width * length $t,
- $e - 6 + gdSmallFont->height / 2, $white);
- $image->string (gdSmallFont, $ml + $t * $r + $rx + 5,
- $e - 3 - gdSmallFont->height / 2, "$t", $black);
- # first value (accepted)
- $image->filledRectangle ($ml + $t * $r + $rx + 3,
- $e - 4 + gdSmallFont->height / 2,
- $ml + $t * $r + $rx + 4 +
- gdSmallFont->width * length "${$val[0]}{$k}",
- $e - 2 + gdSmallFont->height, $white);
- $image->string (gdSmallFont, $ml + $t * $r + $rx + 5,
- $e - 5 + gdSmallFont->height / 2, ${$val[0]}{$k}, $black);
- $e += $d;
- }
- open (IMG, "> $filename") || die "Error: Can't open \"$filename\": $!\n";
- if ($GD_FORMAT eq 'png') {
- print IMG $image->png;
- }
- else {
- print IMG $image->gif;
- }
- close IMG;
- $ymax;
-}
-
-sub Histo {
- my ($filename, $title, $xmax, $factor,
- $labelx, $labely, $val1, $labels1) = @_;
-
- no strict;
- my $max = 0;
- my $ymax = 300;
- my $nb = 0;
- # A hugly hack to convert hashes to lists..
- # and to adjust the first and the last value...
- # this function should be rewritten..
- my (@a, @b, $kk);
- foreach $kk (sort keys (%$val1)) {
- if (defined $$val1{$kk}) {
- $nb++;
- # Arg... the following MUST be removed !!!!!!!!!
- $$val1{$kk} = $$val1{$kk} / $innreport_inn::inn_flow_time{$kk} * 3600
- if ($innreport_inn::inn_flow_time{$kk} != 3600) &&
- ($innreport_inn::inn_flow_time{$kk} != 0);
- push @a, $$val1{$kk};
- $max = $$val1{$kk} if $$val1{$kk} > $max;
- push @b, $$labels1{$kk};
- }
- }
- return 0 unless $nb; # strange, no data.
- my $val = \@a;
- my $labels = \@b;
- my ($i, $j);
- my ($marginl, $marginr, $margint, $marginb, $shx, $shy);
-
- my $image = new GD::Image($xmax, $ymax);
- my ($white, $black);
- if (defined $output{'default'}{'graph_fg'}) {
- my $t = $output{'default'}{'graph_fg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_fg'. Bad color.\n";
- my @c = map { hex ($_) } ($t =~ m/^(..)(..)(..)$/);
- $black = $image->colorAllocate (@c);
- }
- else {
- $black = $image->colorAllocate ( 0, 0, 0);
- }
- if (defined $output{'default'}{'graph_bg'}) {
- my $t = $output{'default'}{'graph_bg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_bg'. Bad color.\n";
- my @c = map { hex $_ } ($t =~ m/^(..)(..)(..)$/);
- $white = $image->colorAllocate (@c);
- }
- else {
- $white = $image->colorAllocate (255, 255, 255);
- }
- $image->filledRectangle (0, 0, $xmax, $ymax, $white);
- my $gray = $image->colorAllocate (128, 128, 128);
- my $red = $image->colorAllocate (255, 0, 0);
- my $red2 = $image->colorAllocate (189, 0, 0);
- my $red3 = $image->colorAllocate (127, 0, 0);
- my $coltxt = $black;
-
- $image->transparent ($white) if $transparent;
-
- my $FontWidth = gdSmallFont->width;
- my $FontHeight = gdSmallFont->height;
-
- $marginl = 60;
- $marginr = 30;
- $margint = 60;
- $marginb = 30;
- $shx = 7;
- $shy = 7;
-
- $max = 1 unless $max;
- my $part = 8;
- $max /= $factor;
-
- my $old_max = $max;
- {
- my $t = log ($max) / log 10;
- $t = sprintf "%.0f", $t - 1;
- $t = exp ($t * log 10);
- $max = sprintf "%.0f", $max / $t * 10 + 0.4;
- my $t2 = sprintf "%.0f", $max / $part;
- unless ($part * $t2 == $max) {
- while ($part * $t2 != $max) {
- $max++;
- $t2 = sprintf "%d", $max / $part;
- }
- }
- $max = $max * $t / 10;
- }
-
- # Title
- $image->string (gdMediumBoldFont,
- ($xmax - length ($title) * gdMediumBoldFont->width) / 2,
- ($margint - $shy - gdMediumBoldFont->height) / 2,
- $title, $coltxt);
-
- # Labels
- $image->string (gdSmallFont, $marginl / 2, $margint / 2, $labely, $coltxt);
- $image->string (gdSmallFont, $xmax - $marginr / 2 -
- $FontWidth * length ($labelx), $ymax - $marginb / 2,
- $labelx, $coltxt);
-
- # Max
- $image->line ($marginl, $ymax - $marginb - $shy -
- $old_max * ($ymax - $marginb - $margint - $shy) / $max,
- $xmax - $marginr, $ymax - $marginb - $shy -
- $old_max * ($ymax - $marginb - $margint - $shy) / $max, $red);
- $image->line ($marginl, $ymax - $marginb - $shy -
- $old_max * ($ymax - $marginb - $margint - $shy) / $max,
- $marginl - $shx, $ymax - $marginb -
- $old_max * ($ymax - $marginb - $margint - $shy) / $max, $red);
-
- # Left
- $image->line ($marginl - $shx, $margint + $shy,
- $marginl - $shx, $ymax - $marginb, $coltxt);
- $image->line ($marginl, $margint,
- $marginl, $ymax - $marginb - $shy, $coltxt);
- $image->line ($marginl, $margint,
- $marginl - $shx, $margint + $shy, $coltxt);
- $image->line ($marginl - $shx, $ymax - $marginb,
- $marginl, $ymax - $marginb - $shy, $coltxt);
-
- # Right
- $image->line ($xmax - $marginr, $margint,
- $xmax - $marginr, $ymax - $marginb - $shy, $coltxt);
- $image->line ($xmax - $marginr - $shx, $ymax - $marginb,
- $xmax - $marginr, $ymax - $marginb - $shy, $coltxt);
-
- # Bottom
- $image->line ($marginl - $shx, $ymax - $marginb,
- $xmax - $marginr - $shx, $ymax - $marginb, $coltxt);
- $image->line ($marginl, $ymax - $marginb - $shy,
- $xmax - $marginr, $ymax - $marginb - $shy, $coltxt);
- $image->fill ($xmax / 2, $ymax - $marginb - $shy / 2, $gray);
-
- # Top
- $image->line ($marginl, $margint,
- $xmax - $marginr, $margint, $coltxt);
- $image->setStyle ($coltxt, $coltxt, &GD::gdTransparent,
- &GD::gdTransparent, &GD::gdTransparent);
- # Graduations
- for ($i = 0; $i <= $part; $i++) {
- $j = $max * $i / $part ; # Warning to floor
- # $j = ($max / $part) * ($i / 10000);
- # $j *= 10000;
-
- # Little hack...
- $j = sprintf "%d", $j if $j > 100;
-
- $image->line ($marginl - $shx - 3, $ymax - $marginb -
- $i * ($ymax - $marginb - $margint - $shy) / $part,
- $marginl - $shx, $ymax - $marginb -
- $i * ($ymax - $marginb - $margint - $shy) / $part, $coltxt);
- $image->line ($marginl - $shx, $ymax - $marginb -
- $i * ($ymax - $marginb - $margint - $shy) / $part,
- $marginl, $ymax - $marginb - $shy -
- $i * ($ymax - $marginb - $margint - $shy) / $part, gdStyled);
- $image->line ($marginl, $ymax - $marginb - $shy -
- $i * ($ymax - $marginb - $margint - $shy) / $part,
- $xmax - $marginr, $ymax - $marginb - $shy -
- $i * ($ymax - $marginb - $margint - $shy) / $part, gdStyled);
- $image->string (gdSmallFont,
- $marginl - $shx - $FontWidth * length ("$j") - 7,
- $ymax - $marginb -
- ($i) * ($ymax - $marginb - $margint - $shy) / ($part) -
- $FontHeight / 2, "$j", $coltxt);
- }
-
- # Graduation (right bottom corner)
- $image->line ($xmax - $marginr - $shx, $ymax - $marginb,
- $xmax - $marginr - $shx, $ymax - $marginb + 3, $coltxt);
- # Bars
- $i = 0;
- my $w = ($xmax - $marginl - $marginr) / $nb;
- my $k = $w / 5;
- $$val[$nb - 1] = 0 unless $$val[$nb - 1];
- foreach $j (@$val) {
- my $MAX = 1;
- if ($i++ <= $nb) {
- # Graduation
- $image->line ($marginl + ($i - 1) * $w - $shx, $ymax - $marginb,
- $marginl + ($i - 1) * $w - $shx, $ymax - $marginb + 3,
- $coltxt);
- my $ii = sprintf "%d", $i / $MAX;
- $image->string (gdSmallFont,
- $marginl + ($i - 0.5) * $w + 1 -
- ($FontWidth * length ($$labels[$i-1])) / 2 - $shx,
- $ymax - $marginb + 3, $$labels[$i-1], $coltxt)
- unless ($w < $FontWidth * length ($$labels[$i-1]))
- && ($i != $MAX * $ii);
-
- # Right
- my $poly = new GD::Polygon;
- $poly->addPt($marginl + ($i) * $w - $k, $ymax - $marginb - $shy -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
- $poly->addPt($marginl + ($i) * $w - $k, $ymax - $marginb - $shy);
- $poly->addPt($marginl + ($i) * $w - $k - $shx, $ymax - $marginb);
- $poly->addPt($marginl + ($i) * $w - $k - $shx, $ymax - $marginb -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
-
- $image->filledPolygon($poly, $red3);
- $image->polygon($poly, $coltxt);
-
- # Front
- $image->filledRectangle ($marginl + ($i - 1) * $w + $k - $shx,
- $ymax - $marginb -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max,
- $marginl + ($i) * $w - $k - $shx,
- $ymax - $marginb, $red);
- $image->rectangle ($marginl + ($i - 1) * $w + $k - $shx,
- $ymax - $marginb -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max,
- $marginl + ($i) * $w - $k - $shx,
- $ymax - $marginb, $coltxt);
- # Top
- my $poly2 = new GD::Polygon;
- $poly2->addPt($marginl + ($i - 1) * $w + $k, $ymax - $marginb - $shy -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
- $poly2->addPt($marginl + ($i) * $w - $k, $ymax - $marginb - $shy -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
- $poly2->addPt($marginl + ($i) * $w - $k - $shx, $ymax - $marginb -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
- $poly2->addPt($marginl + ($i - 1) * $w + $k - $shx, $ymax - $marginb -
- $j / $factor * ($ymax - $marginb - $margint - $shy) / $max);
-
- $image->rectangle (0, 0, $xmax - 1, $ymax - 1, $coltxt);
- $image->filledPolygon($poly2, $red2);
- $image->polygon($poly2, $coltxt);
- }
- }
-
- open (IMG, "> $filename") || die "Can't create '$filename'\n";
- if ($GD_FORMAT eq 'png') {
- print IMG $image->png;
- }
- else {
- print IMG $image->gif;
- }
- close IMG;
- 1;
-}
-
-sub Chrono {
- my $filename = shift; # filename
- my $title = shift; # title
- my $color_bg = shift; # background color
- my $xmax = shift; # width
- my $ymax = shift; # height
-
- my $in = shift;
- my $out = shift;
- my $dates = shift;
-
- my $legend_in = shift;
- my $legend_out = shift;
-
- my $color_in = shift;
- my $color_out = shift;
-
- my $unit = shift;
-
- my $key;
- my $x_min = 1E30;
- my $x_max = 0;
- my $y_min = 0;
- my $y_max;
- my $y_max_in = 0;
- my $y_max_out = 0;
-
- foreach $key (sort keys %$dates) {
- $x_min = $key if $x_min > $key;
- $x_max = $$dates{$key} if $x_max < $$dates{$key};
- my $t = $$out{$key} / ($$dates{$key} - $key);
- $y_max_out = $t if $y_max_out < $t;
- $t = $$in{$key} / ($$dates{$key} - $key);
- $y_max_in = $t if $y_max_in < $t;
- }
- $y_max = $y_max_out > $y_max_in ? $y_max_out : $y_max_in;
- my $factor = 1;
- if ($y_max < 1) {
- $factor = 60;
- if ($y_max < 4 / 60) {
- $y_max = 4 / 60;
- }
- else {
- $y_max = int ($y_max * $factor) + 1;
- $y_max += (4 - ($y_max % 4)) % 4;
- $y_max /= $factor;
- }
- }
- else {
- $y_max = int ($y_max) + 1;
- $y_max += (4 - ($y_max % 4)) % 4;
- }
-
- $unit .= "/" . ($factor == 60 ? "min" : "sec");
-
- # min range is 4 weeks.
- my $delta = $x_max - $x_min;
- $x_min = $x_max - 3024000 if $delta < 3024000;
- # between 4 weeks and one year, range is a year.
- $x_min = $x_max - 31536000 if ($delta < 31536000 && $delta > 3024000);
- # max range is 13 months
- $x_min = $x_max - 34128000 if $delta > 34128000;
- my $image = new GD::Image ($xmax, $ymax);
- my ($white, $black);
- if (defined $output{'default'}{'graph_fg'}) {
- my $t = $output{'default'}{'graph_fg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_fg'. Bad color.\n";
- my @c = map { hex $_ } ($t =~ m/^(..)(..)(..)$/);
- $black = $image->colorAllocate (@c);
- }
- else {
- $black = $image->colorAllocate ( 0, 0, 0);
- }
- if (defined $output{'default'}{'graph_bg'}) {
- my $t = $output{'default'}{'graph_bg'};
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section 'default' section 'graph_bg'. Bad color.\n";
- my @c = map { hex $_ } ($t =~ m/^(..)(..)(..)$/);
- $white = $image->colorAllocate (@c);
- }
- else {
- $white = $image->colorAllocate (255, 255, 255);
- }
- my $bg;
- if (defined $color_bg) {
- $color_bg =~ m/^\#[\da-fA-F]{6}$/o ||
- die "Error in section 'index'. Bad color $color_bg.\n";
- my @c = map { hex $_ } ($color_bg =~ m/^\#(..)(..)(..)$/);
- $bg = $image->colorAllocate (@c);
- }
- else {
- $bg = $image->colorAllocate (255, 255, 206);
- }
- my $col_in;
- if (defined $color_in) {
- $color_in =~ m/^\#[\da-fA-F]{6}$/o ||
- die "Error in section 'index'. Bad color $color_in.\n";
- my @c = map { hex $_ } ($color_in =~ m/^\#(..)(..)(..)$/);
- $col_in = $image->colorAllocate (@c);
- }
- else {
- $col_in = $image->colorAllocate ( 80, 159, 207);
- }
- my $col_out;
- my @col_out = ( 0, 0, 255);
- if (defined $color_out) {
- $color_out =~ m/^\#[\da-fA-F]{6}$/o ||
- die "Error in section 'index'. Bad color $color_out.\n";
- my @c = map { hex $_ } ($color_out =~ m/^\#(..)(..)(..)$/);
- $col_out = $image->colorAllocate (@c);
- @col_out = @c;
- }
- else {
- $col_out = $image->colorAllocate (@col_out);
- }
-
- my $white2 = $image->colorAllocate (255, 255, 255);
- my $gray = $image->colorAllocate (192, 192, 192);
- my $red = $image->colorAllocate (255, 0, 0);
- my $coltxt = $black;
-
- my $size = 22; # legend
- # legend statistics
- my ($max_in, $max_out) = (0, 0); # min
- my ($min_in, $min_out) = (1E10, 1E10); # max
- my ($t_in, $t_out) = (0, 0); # time
- my ($s_in, $s_out) = (0, 0); # sum
-
- $image->filledRectangle (0, 0, $xmax, $ymax, $gray);
- $image->transparent ($gray) if $transparent;
-
- my $FontWidth = gdSmallFont->width;
- my $FontHeight = gdSmallFont->height;
- $image->setStyle ($black, &GD::gdTransparent, &GD::gdTransparent);
-
- my $marginl = 13 + $FontWidth * length (sprintf "%d", $y_max * $factor);
- my $marginr = 15 + 4 * $FontWidth; # "100%"
- my $margint = 2 * $FontHeight + gdMediumBoldFont->height;
- my $marginb = 2 * $FontHeight + $size;
- my $xratio = ($xmax - $marginl - $marginr) / ($x_max - $x_min);
- my $yratio = ($ymax - $margint - $marginb) / ($y_max - $y_min);
-
- my $frame = new GD::Polygon;
- $frame->addPt(2, $margint - $FontHeight -3);
- $frame->addPt($xmax - 2, $margint - $FontHeight -3);
- $frame->addPt($xmax - 2, $ymax - 3);
- $frame->addPt(2, $ymax - 3);
- $image->filledPolygon($frame, $white2);
- $image->polygon($frame, $black);
-
- $image->filledRectangle ($marginl, $margint,
- $xmax - $marginr, $ymax - $marginb, $bg);
- my $brush = new GD::Image(1, 2);
- my $b_col = $brush->colorAllocate(@col_out);
- $brush->line(0, 0, 0, 1, $b_col);
- $image->setBrush($brush);
- my ($old_x, $old_y_in, $old_y_out);
- foreach $key (sort keys %$dates) {
- next if $key < $x_min;
- my $delta = $$dates{$key} - $key;
- $min_in = $$in{$key} / $delta if $min_in > $$in{$key} / $delta;
- $max_in = $$in{$key} / $delta if $max_in < $$in{$key} / $delta;
- $min_out = $$out{$key} / $delta if $min_out > $$out{$key} / $delta;
- $max_out = $$out{$key} / $delta if $max_out < $$out{$key} / $delta;
- $t_in += $delta;
- $s_in += $$in{$key};
- $s_out += $$out{$key};
-
- my $tt_in = $$in{$key} / ($$dates{$key} - $key) * $yratio;
- my $tt_out = $$out{$key} / ($$dates{$key} - $key) * $yratio;
- my $new_x = $marginl + ($key - $x_min) * $xratio;
- $image->filledRectangle ($marginl + ($key - $x_min) * $xratio,
- $ymax - $marginb - $tt_in,
- $marginl + ($$dates{$key} - $x_min) * $xratio,
- $ymax - $marginb, $col_in);
- if (defined $old_x) {
- $old_x = $new_x if $old_x > $new_x;
- my $poly = new GD::Polygon;
- $poly->addPt($old_x, $old_y_in);
- $poly->addPt($new_x, $ymax - $marginb - $tt_in);
- $poly->addPt($new_x, $ymax - $marginb);
- $poly->addPt($old_x, $ymax - $marginb);
- $image->filledPolygon($poly, $col_in);
- }
- $image->line ($marginl + ($key - $x_min) * $xratio,
- $ymax - $marginb - $tt_out,
- $marginl + ($$dates{$key} - $x_min) * $xratio,
- $ymax - $marginb - $tt_out, &GD::gdBrushed);
- $image->line ($old_x, $old_y_out, $new_x,
- $ymax - $marginb - $tt_out, $col_out) if defined $old_x;
- $old_x = $marginl + ($$dates{$key} - $x_min) * $xratio;
- $old_y_in = $ymax - $marginb - $tt_in;
- $old_y_out = $ymax - $marginb - $tt_out;
- }
- $t_out = $t_in;
-
- # main frame
- $image->rectangle ($marginl, $margint,
- $xmax - $marginr, $ymax - $marginb, $black);
- # graduations
- my $i;
- foreach $i (0, 25, 50, 75, 100) {
- my $t = $ymax - $margint - $marginb;
- $image->line ($marginl, $ymax - $marginb - $i / 100 * $t,
- $xmax - $marginr, $ymax - $marginb - $i / 100 * $t,
- &GD::gdStyled);
- $image->line ($xmax - $marginr, $ymax - $marginb - $i / 100 * $t,
- $xmax - $marginr + 3, $ymax - $marginb - $i / 100 * $t,
- $black);
- $image->line ($marginl - 3, $ymax - $marginb - $i / 100 * $t,
- $marginl, $ymax - $marginb - $i / 100 * $t,
- $black);
- $image->string (&GD::gdSmallFont, $xmax - $marginr + 8, - $FontHeight / 2 +
- $ymax - $marginb - $i / 100 * $t, "$i%", $black);
- my $s = sprintf "%d", $y_max * $i / 100 * $factor;
- $image->string (&GD::gdSmallFont, $marginl - 5 - $FontWidth * length $s,
- - $FontHeight / 2 +
- $ymax - $marginb - $i / 100 * $t, $s, $black);
- }
- ##
- my $w = 604800; # number of seconds in a week
- my $y = 31536000; # number of seconds in a 365 days year
- my $mm = 2592000; # number of seconds in a 30 days month
- if ($x_max - $x_min <= 3024000) { # less than five weeks
- # unit is a week
- # 1/1/1990 is a monday. Use this as a basis.
- my $d = 631152000; # number of seconds between 1/1/1970 and 1/1/1990
- my $n = int ($x_min / $y);
- my $t = $x_min - $n * $y - int (($n - 2) / 4) * 24 * 3600;
- my $f = int ($t / $w);
- $n = $d + int (($x_min - $d) / $w) * $w;
- while ($n < $x_max) {
- $t = $marginl + ($n - $x_min) * $xratio;
- if ($n > $x_min) {
- $image->line ($t, $margint, $t, $ymax - $marginb, &GD::gdStyled);
- $image->line ($t, $ymax - $marginb, $t, $ymax - $marginb + 2, $black);
- }
- $image->string (&GD::gdSmallFont, $FontWidth * 7 / 2 + $t,
- $ymax - $marginb + 4, (sprintf "Week %02d", $f), $black)
- if ($n + $w / 2 > $x_min) && ($n + $w / 2 < $x_max);
- $f++;
- $n += $w;
- $t = int ($n / $y);
- $f = 0
- if $n - $y * $t - int (($t - 2) / 4) * 24 * 3600 < $w && $f > 50;
- }
- $d = 86400; # 1 day
- $n = int ($x_min / $y);
- $t = $n * $y + int (($n - 2) / 4) * 24 * 3600;
- $i = 0;
- my $x;
- while ($t < $x_max) {
- $x = $marginl + ($t - $x_min) * $xratio;
- $image->line ($x, $margint, $x, $ymax - $marginb + 2, $red)
- if $t > $x_min;
- $t += $mm;
- $t += $d if $i == 0 || $i == 2 || $i == 4 ||
- $i == 6 || $i == 7 || $i == 9 || $i == 11; # 31 days months
- if ($i == 1) { # february ?
- $t -= 2 * $d;
- $t += $d unless (1970 + int ($t / $y)) % 4;
- }
- $i++;
- $i = 0 if $i == 12; # Happy New Year !!
- }
- }
- else {
- # unit is a month
- my $n = int ($x_min / $y);
- my $t = $n * $y + int (($n - 2) / 4) * 24 * 3600;
- my @m = ("Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
- my $d = 86400; # 1 day
- my $i = 0;
- my $x;
- while ($t < $x_max) {
- $x = $marginl + ($t - $x_min) * $xratio;
- if ($t > $x_min) {
- $image->line ($x, $margint, $x, $ymax - $marginb, &GD::gdStyled);
- $image->line ($x, $ymax - $marginb, $x,
- $ymax - $marginb + 2, $black);
- $image->line ($x, $margint, $x, $ymax - $marginb, $red) unless $i;
- }
- $image->string (&GD::gdSmallFont,
- $mm * $xratio / 2 - $FontWidth * 3 / 2 +
- $x, $ymax - $marginb + 4, (sprintf "%s", $m[$i]),
- $black)
- if ($t + 2 * $w > $x_min) && ($x_max > 2 * $w + $t);
- $t += $mm;
- $t += $d if ($i == 0 || $i == 2 || $i == 4 ||
- $i == 6 || $i == 7 || $i == 9 || $i == 11); # 31 days months
- if ($i == 1) { # february ?
- $t -= 2 * $d;
- $t += $d unless (1970 + int ($t / $y)) % 4;
- }
- $i++;
- $i = 0 if $i == 12; # Happy New Year !!
- }
- }
-
- # Add the little red arrow
- my $poly = new GD::Polygon;
- $poly->addPt($xmax - $marginr - 2, $ymax - $marginb - 3);
- $poly->addPt($xmax - $marginr + 4, $ymax - $marginb);
- $poly->addPt($xmax - $marginr - 2, $ymax - $marginb + 3);
- $image->filledPolygon($poly, $red);
-
- # Title
- $image->string (&GD::gdMediumBoldFont,
- $xmax / 2 - $FontWidth * length ($title) / 2, 4,
- $title, $black);
-
- # Legend
- my $y_in = $ymax - $size - $FontHeight + 5;
- $image->string (&GD::gdSmallFont, $marginl, $y_in, $legend_in, $col_in);
- $image->string (&GD::gdSmallFont, $xmax / 4, $y_in,
- (sprintf "Min: %5.1f $unit", $min_in * $factor), $black);
- $image->string (&GD::gdSmallFont, $xmax / 2, $y_in,
- (sprintf "Avg: %5.1f $unit", $s_in / $t_in * $factor), $black);
- $image->string (&GD::gdSmallFont, 3 * $xmax / 4, $y_in,
- (sprintf "Max: %5.1f $unit", $max_in * $factor), $black);
-
- my $y_out = $ymax - $size + 5;
- $image->string (&GD::gdSmallFont, $marginl, $y_out, $legend_out, $col_out);
- $image->string (&GD::gdSmallFont, $xmax / 4, $y_out,
- (sprintf "Min: %5.1f $unit", $min_out * $factor), $black);
- $image->string (&GD::gdSmallFont, $xmax / 2, $y_out,
- (sprintf "Avg: %5.1f $unit", $s_out / $t_out * $factor), $black);
- $image->string (&GD::gdSmallFont, 3 * $xmax / 4, $y_out,
- (sprintf "Max: %5.1f $unit", $max_out * $factor), $black);
-
- open (IMG, "> $filename") || die "Error: Can't open \"$filename\": $!\n";
- if ($GD_FORMAT eq 'png') {
- print IMG $image->png;
- }
- else {
- print IMG $image->gif;
- }
- close IMG;
- return $ymax;
-}
-
-sub Write_all_results {
- my $HTML_output = shift;
- my $h = shift;
- my $k;
-
- my $title = $$h{'default'}{'title'} ?
- $$h{'default'}{'title'} : "Daily Usenet report";
- $title =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $title =~ s/\\\"/\"/go;
- my $Title = $title;
- $Title =~ s/<.*?>//go;
- {
- my $Title = $Title;
- $Title =~ s/\&/&/go;
- $Title =~ s/\</</go;
- $Title =~ s/\>/>/go;
- print "$Title from $first_date to $last_date\n\n";
- }
-
- if ($HTML) {
- my $body = defined $output{'default'}{'html_body'} ?
- $output{'default'}{'html_body'} : '';
- $body =~ s/^\"\s*(.*?)\s*\"$/ $1/o;
- $body =~ s/\\\"/\"/go;
- open (HTML, "> $HTML_output") || die "Error: cant open $HTML_output\n";
-
- print HTML "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n" .
- "<HTML>\n<HEAD>\n<TITLE>$Title: $first_date</TITLE>\n" .
- "<!-- innreport $version -->\n</HEAD>\n<BODY $body>\n" .
- "$HTML_header\n<CENTER><H1>$title</H1>\n" .
- "<H3>$first_date -- $last_date</H3>\n</CENTER>\n<P><HR><P>\n";
-
- # Index
- print HTML "<UL>\n";
- foreach $k (@{$$h{'_order_'}}) {
- next if $k =~ m/^(default|index)$/;
- my ($data) = $$h{$k}{'data'} =~ m/^\"\s*(.*?)\s*\"$/o;
- $data =~ s/^\%/\%$CLASS\:\:/ unless $data eq '%prog_type';
- my %data;
- { local $^W = 0; no strict; %data = eval $data }
- my ($string) = $$h{$k}{'title'} =~ m/^\"\s*(.*?)\s*\"$/o;
- $string =~ s/\s*:$//o;
- my $want = 1;
-
- ($want) = $$h{$k}{'skip'} =~ m/^\"?\s*(.*?)\s*\"?$/o
- if defined $$h{$k}{'skip'};
- $want = $want eq 'true' ? 0 : 1;
- print HTML "<LI><A HREF=\"#$k\">$string</A>\n" if %data && $want;
- }
- print HTML "</UL><P><HR><P>\n";
- }
- if (@unrecognize && $WANT_UNKNOWN) {
- my $mm = $#unrecognize;
- print HTML "<A NAME=\"unrecognize\">" if $HTML && $WANT_HTML_UNKNOWN;
- print "Unknown entries from news log file:\n";
- print HTML "<STRONG>Unknown entries from news log file:</STRONG></A><P>\n"
- if $HTML && $WANT_HTML_UNKNOWN;
- $mm = $MAX_UNRECOGNIZED - 1
- if $MAX_UNRECOGNIZED > 0 && $mm > $MAX_UNRECOGNIZED - 1;
- if ($mm < $unrecognize_max && $unrecognize_max > 0) {
- printf HTML "First %d / $unrecognize_max lines (%3.1f%%)<BR>\n", $mm + 1,
- ($mm + 1) / $unrecognize_max * 100 if $HTML && $WANT_HTML_UNKNOWN;
- printf "First %d / $unrecognize_max lines (%3.1f%%)\n", $mm + 1,
- ($mm + 1) / $unrecognize_max * 100;
- }
-
- my $l;
- for $l (0 .. $mm) {
- chomp $unrecognize[$l]; # sometimes, the last line need a CR
- print "$unrecognize[$l]\n"; # so, we always add one
- if ($HTML && $WANT_HTML_UNKNOWN) {
- $unrecognize[$l] =~ s/&/\&/g;
- $unrecognize[$l] =~ s/</\</g;
- $unrecognize[$l] =~ s/>/\>/g;
- print HTML "$unrecognize[$l]<BR>\n";
- }
- }
- print "\n";
- print HTML "<P><HR><P>\n" if $HTML && $WANT_HTML_UNKNOWN;
- }
-
- close HTML if $HTML;
- foreach $k (@{$$h{'_order_'}}) {
- next if $k =~ m/^(default|index)$/;
- &Write_Results($HTML_output, $k, $h);
- }
- if ($HTML) {
- open (HTML, ">> $HTML_output") || die "Error: cant open $HTML_output\n";
- print HTML <<EOT;
-innreport $version (c) 1996-1999 by Fabien Tassin
-<<A HREF="mailto:fta\@sofaraway.org">fta\@sofaraway.org</A>>.
-EOT
- if (defined $$h{'default'}{'footer'}) {
- my ($t) = $$h{'default'}{'footer'} =~ m/^\"\s*(.*?)\s*\"$/o;
- $t =~ s/\\\"/\"/go;
- print HTML "<BR>" . $t;
- }
- print HTML "\n$HTML_footer";
- printf HTML "\n<!-- Running time: %s -->", second2time(time - $start_time);
- print HTML "\n</BODY>\n</HTML>\n";
- close HTML;
- }
-}
-
-sub Write_Results {
- my $HTML_output = shift;
- my $report = shift;
- my $data = shift;
- my %output = %$data;
- return 0 unless defined $output{$report}; # no data to write
- return 0 if defined $output{$report}{'skip'} &&
- $output{$report}{'skip'} =~ m/^true$/io;
- my ($TEXT, $HTML, $DOUBLE);
-
- # Need a text report ?
- $TEXT = defined $output{$report}{'text'} ? $output{$report}{'text'} :
- (defined $output{'default'}{'text'} ? $output{'default'}{'text'} : '');
- die "Error in config file. Field 'text' is mandatory.\n" unless $TEXT;
- $TEXT = ($TEXT =~ m/^true$/io) ? 1 : 0;
-
- # Need an html report ?
- if ($HTML_output) {
- $HTML = defined $output{$report}{'html'} ? $output{$report}{'html'} :
- (defined $output{'default'}{'html'} ? $output{'default'}{'html'} : '');
- die "Error in config file. Field 'html' is mandatory.\n" unless $HTML;
- $HTML = ($HTML =~ m/^true$/io) ? 1 : 0;
- }
- # Double table ?
- $DOUBLE = defined $output{$report}{'double'} ?
- $output{$report}{'double'} : 0;
- $DOUBLE = ($DOUBLE =~ m/^true$/io) ? 1 : 0;
-
- # Want to truncate the report ?
- my $TOP = defined $output{$report}{'top'} ? $output{$report}{'top'} : -1;
- my $TOP_HTML = defined $output{$report}{'top_html'} ?
- $output{$report}{'top_html'} : $TOP;
- my $TOP_TEXT = defined $output{$report}{'top_text'} ?
- $output{$report}{'top_text'} : $TOP;
-
- my (%h, %d, $h);
- {
- my $t = $output{$report}{'data'} ||
- die "Error in section $report. Need a 'data' field.\n";
- $t =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $t =~ s/^\%/\%$CLASS\:\:/ unless $t eq '%prog_type';
- %d = eval $t;
- return unless %d; # nothing to report. exit.
- return unless keys (%d); # nothing to report. exit.
- }
- {
- my $t = defined $output{$report}{'sort'} ? $output{$report}{'sort'} :
- "\$a cmp \$b";
- $t =~ s/\n/ /smog;
- $t =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $t =~ s/([\$\%\@])/$1${CLASS}\:\:/go;
- $t =~ s/([\$\%\@])${CLASS}\:\:(prog_(?:size|type)|key|num)/$1$2/go;
- $t =~ s/\{\$${CLASS}\:\:(a|b)\}/\{\$$1\}/go;
- $t =~ s/\$${CLASS}\:\:(a|b)/\$$1/go;
- $h = $t;
- }
-
- if ($HTML) {
- open (HTML, ">> $HTML_output") || die "Error: cant open $HTML_output\n";
- }
- print "\n" if $TEXT;
- my ($key, $key1, $key2);
- if (defined $output{$report}{'title'}) {
- my $t = $output{$report}{'title'};
- $t =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- if ($HTML) {
- print HTML "<A NAME=\"$report\">";
- my $html = $t;
- $html =~ s/(:?)$/ [Top $TOP_HTML]$1/o if $TOP_HTML > 0;
- $html =~ s|^(.*)$|<STRONG>$1</STRONG>|;
- print HTML "$html</A>\n<P>\n<CENTER>\n<TABLE BORDER=\"1\">\n";
- }
- $t =~ s/(:?)$/ [Top $TOP_TEXT]$1/o if $TOP_TEXT > 0;
- print "$t\n" if $TEXT;
- }
- my $numbering = 0;
- $numbering = 1 if defined $output{$report}{'numbering'} &&
- $output{$report}{'numbering'} =~ m/^true$/o;
- my $i;
- my $s = '';
- my $html = '';
- my $first = 0;
-
- foreach $i (@{$output{$report}{'column'}}) {
- my ($v1, $v2);
-
- my $wtext = defined $$i{'text'} ? $$i{'text'} : 1;
- $wtext = $wtext =~ m/^(1|true)$/io ? 1 : 0;
- my $whtml = defined $$i{'html'} ? $$i{'html'} : 1;
- $whtml = $whtml =~ m/^(1|true)$/io ? 1 : 0;
-
- $v1 = defined ($$i{'format_name'}) ? $$i{'format_name'} :
- (defined ($$i{'format'}) ? $$i{'format'} : "%s");
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $v2 = $$i{'name'};
- $v2 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $s .= sprintf $v1 . " ", $v2 if $wtext && !($DOUBLE && $first == 1);
- if ($HTML && $whtml) {
- my $v1 = $v1;
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?(\w)/\%$1/g;
- my $temp = $first ? "CENTER" : "LEFT";
- $temp .= "\" COLSPAN=\"2" if $numbering && !$first;
- $html .= sprintf "<TH ALIGN=\"$temp\">$v1</TH>", $v2;
- }
- $first++;
- }
- $s =~ s/\s*$//;
- print "$s\n" if $TEXT;
- $s = '';
- if ($HTML) {
- print HTML "<TR>$html</TR>\n<TR><TD></TD></TR>\n";
- $html = '';
- }
- my $num = 0;
- my $done;
- if ($DOUBLE) {
- my $num_d = 0;
- foreach $key1 (sort keys (%d)) {
- $done = 0;
- $num = 0;
- $num_d++;
- $s = '';
- $html = '';
- my @res;
- foreach $key2 (sort {$d{$key1}{$b} <=> $d{$key1}{$a}}
- keys (%{$d{$key1}})) {
- my $first = 0;
- $num++;
- foreach $i (@{$output{$report}{'column'}}) {
- my ($v1, $v2, $p);
-
- my $wtext = defined $$i{'text'} ? $$i{'text'} : 1;
- $wtext = $wtext =~ m/^(1|true)$/io ? 1 : 0;
- my $whtml = defined $$i{'html'} ? $$i{'html'} : 1;
- $whtml = $whtml =~ m/^(1|true)$/io ? 1 : 0;
-
- # is it the primary key ?
- $p = 0;
- $p = 1 if defined $$i{'primary'} && $$i{'primary'} =~ m/true/;
-
- # format
- $v1 = defined ($$i{'format'}) ? $$i{'format'} : "%s";
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
-
- # value
- $v2 = $$i{'value'};
- $v2 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $r ='';
- if ($v2) {
- $r = &EvalExpr ($v2, $key2, $num, $key1);
- die "Error in section $report column $$i{'name'}. " .
- "Invalid 'value' value.\n" unless defined $r;
- }
- $res[$first] += $r if $v1 =~ m/\%-?(?:\d+(?:\.\d+)?)?d/o;
- if ($p) {
- $s .= sprintf $v1. "\n", $r unless $done || !$wtext;
- if ($HTML && $whtml) {
- if ($done) {
- $html .= "<TD></TD>";
- }
- else {
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- $html .= $numbering ? "<TH ALIGN=\"CENTER\">$num_d</TH>" : '';
- # unless $first;
- $html .= sprintf "<TD ALIGN=\"LEFT\">$v1</TD></TR>\n", $r;
- $html .= "<TR><TD></TD>";
- }
- }
- }
- else {
- if ($wtext) {
- $s .= " " if $first == 1;
- $s .= sprintf $v1 . " ", $r;
- }
- if ($HTML && $whtml) {
- $html .= $numbering ? "<TD></TD>" : '' if $first == 1;
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- my $temp = $first > 1 ? "RIGHT" : "LEFT";
- $html .= sprintf "<TD ALIGN=\"$temp\">$v1</TD>", $r;
- }
- }
- $done = 1 if $p;
- $first++;
- }
- $s =~ s/\s*$//;
- $s =~ s/\\n/\n/g;
- print "$s\n" if $TEXT && ($num <= $TOP_TEXT || $TOP_TEXT == -1);
- if ($HTML && ($num <= $TOP_HTML || $TOP_HTML == -1)) {
- $html =~ s/\\n//g;
- print HTML "<TR>$html</TR>\n";
- }
- $s = '';
- $html = '';
- }
- $first = 0;
- $s = '';
- $html = '';
- if ($TOP_TEXT != -1 && $TOP_HTML != -1) {
- foreach $i (@{$output{$report}{'column'}}) {
- if (defined $$i{'primary'} && $$i{'primary'} =~ m/true/o) {
- $first++;
- $s .= ' ';
- $html .= "<TD></TD>" if $HTML;
- $html .= "<TD></TD>" if $HTML && $numbering;
- next;
- }
- my ($v1, $v2);
- $v1 = defined ($$i{'format_total'}) ? $$i{'format_total'} :
- (defined ($$i{'format'}) ? $$i{'format'} : "%s");
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $r = $first == 1 ? $num : $res[$first];
- $s .= sprintf $v1 . " ", $r;
- if ($HTML) {
- my $temp = $first > 1 ? "RIGHT" : "LEFT";
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- $v1 =~ s|(.*)|<STRONG>$1</STRONG>|o unless $first > 1;
- $html .= sprintf "<TD ALIGN=\"$temp\">$v1</TD>", $r;
- }
- $first++;
- }
- $s =~ s/\s*$//;
- $s =~ s/\\n//g;
- print "$s\n" if $TEXT;
- print HTML "<TR>$html</TR>\n" if $HTML;
- }
- }
- print "\n" if $TEXT;
- print HTML "<TR><TD></TD></TR>\n" if $HTML;
- $first = 0;
- $num = $num_d;
- $s = '';
- $html = '';
- foreach $i (@{$output{$report}{'column'}}) {
- my $wtext = defined $$i{'text'} ? $$i{'text'} : 1;
- $wtext = $wtext =~ m/^(1|true)$/io ? 1 : 0;
- my $whtml = defined $$i{'html'} ? $$i{'html'} : 1;
- $whtml = $whtml =~ m/^(1|true)$/io ? 1 : 0;
-
- my ($v1, $v2);
- $v1 = defined $$i{'format_total'} ? $$i{'format_total'} :
- (defined $$i{'format'} ? $$i{'format'} : "%s");
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $v2 = $$i{'total'} ||
- die "Error in section $report column $$i{'name'}. " .
- "Need a 'total' field.\n";
- $v2 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $r = '';
- if ($v2) {
- $r = &EvalExpr ($v2, $key2, $num, 1);
- die "Error in section $report column $$i{'name'}. " .
- "Invalid 'total' value.\n" unless defined $r;
- }
- $s .= sprintf $v1 . " ", $r if $wtext && $first != 1;
- if ($HTML && $whtml) {
- my $temp = $first ? "RIGHT" : "LEFT";
- $temp .= "\" COLSPAN=\"2" if $numbering && !$first;
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- $v1 =~ s|(.*)|<STRONG>$1</STRONG>|o unless $first;
- $html .= $first == 1 ? "<TD></TD>" :
- sprintf "<TD ALIGN=\"$temp\">$v1</TD>", $r;
- }
- $first++;
- }
- $s =~ s/\s*$//;
- $s =~ s/\\n//g;
- print "$s\n" if $TEXT;
- print HTML "<TR>$html</TR>\n</TABLE>\n</CENTER>\n<P>\n<HR>\n" if $HTML;
- }
- else {
- # foreach $key (sort { local $^W = 0; no strict; eval $h } (keys (%d)))
- foreach $key ((eval "sort {local \$^W = 0; no strict; $h} (keys (%d))")) {
- next unless defined $key;
- next unless defined $d{$key}; # to avoid problems after some undef()
- $num++;
- next unless $num <= $TOP_HTML || $TOP_HTML == -1 ||
- $num <= $TOP_TEXT || $TOP_TEXT == -1;
- my $first = 0;
- foreach $i (@{$output{$report}{'column'}}) {
- my $wtext = defined $$i{'text'} ? $$i{'text'} : 1;
- $wtext = $wtext =~ m/^(1|true)$/io ? 1 : 0;
- my $whtml = defined $$i{'html'} ? $$i{'html'} : 1;
- $whtml = $whtml =~ m/^(1|true)$/io ? 1 : 0;
-
- my ($v1, $v2);
- $v1 = defined ($$i{'format'}) ? $$i{'format'} : "%s";
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $v2 = $$i{'value'};
- $v2 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $r ='';
- if ($v2) {
- $r = &EvalExpr ($v2, $key, $num);
- die "Error in section $report column $$i{'name'}. " .
- "Invalid 'value' value.\n" unless defined $r;
- }
- $s .= sprintf $v1 . " ", $r
- if $wtext && (($num <= $TOP_TEXT) || ($TOP_TEXT == -1));
- if ($HTML && $whtml && ($num <= $TOP_HTML || $TOP_HTML == -1)) {
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- $html .= "<TH ALIGN=\"CENTER\">$num</TH>" if $numbering && !$first;
- my $temp = $first ? "RIGHT" : "LEFT";
- $html .= sprintf "<TD ALIGN=\"$temp\">$v1</TD>", $r;
- }
- $first++;
- }
- $s =~ s/\s*$//;
- print "$s\n" if $TEXT && ($num <= $TOP_TEXT || $TOP_TEXT == -1);
- $s = '';
- if ($HTML && ($num <= $TOP_HTML || $TOP_HTML == -1)) {
- print HTML "<TR>$html</TR>\n";
- $html = '';
- }
- }
- print "\n" if $TEXT;
- print HTML "<TR><TD></TD></TR>\n" if $HTML;
- $first = 0;
- foreach $i (@{$output{$report}{'column'}}) {
- my $wtext = defined $$i{'text'} ? $$i{'text'} : 1;
- $wtext = $wtext =~ m/^(1|true)$/io ? 1 : 0;
- my $whtml = defined $$i{'html'} ? $$i{'html'} : 1;
- $whtml = $whtml =~ m/^(1|true)$/io ? 1 : 0;
-
- my ($v1, $v2);
- $v1 = defined ($$i{'format_total'}) ? $$i{'format_total'} :
- (defined ($$i{'format'}) ? $$i{'format'} : "%s");
- $v1 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $v2 = $$i{'total'} ||
- die "Error in section $report column $$i{'name'}. " .
- "Need a 'total' field.\n";
- $v2 =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $r = '';
- if ($v2) {
- $r = &EvalExpr ($v2, $key, $num);
- die "Error in section $report column $$i{'name'}. " .
- "Invalid 'total' value.\n" unless defined $r;
- }
- $s .= sprintf $v1 . " ", $r if $wtext;
- if ($HTML && $whtml) {
- $v1 =~ s/\%-?(?:\d+(?:\.\d+)?)?s/\%s/g;
- my $temp = $first ? "RIGHT" : "LEFT";
- $temp .= "\" COLSPAN=\"2" if $numbering && !$first;
- $v1 =~ s|(.*)|<STRONG>$1</STRONG>|o unless $first;
- $html .= sprintf "<TD ALIGN=\"$temp\">$v1</TD>", $r;
- }
- $first++;
- }
- $s =~ s/\s*$//;
- print "$s\n" if $TEXT;
- if ($HTML) {
- print HTML "<TR>$html</TR>\n";
- print HTML "</TABLE>\n</CENTER><P>\n";
-
- my $i = 0;
- while ($GRAPH && defined ${${$output{$report}{'graph'}}[$i]}{'type'}) {
- my $type = ${${$output{$report}{'graph'}}[$i]}{'type'};
- my ($title) = ${${$output{$report}{'graph'}}[$i]}{'title'} =~
- m/^\"\s*(.*?)\s*\"$/o;
- if ($type eq 'histo3d') {
- my (@values, @colors, @labels);
- my $num = 0;
- my $j;
- foreach $j (@{${${$output{$report}{'graph'}}[$i]}{'data'}}) {
- $num++;
- my ($h) = $$j{'value'} =~ m/^\"\s*(.*?)\s*\"$/o;
- my %hh;
- $h =~ s/^\%/\%$CLASS\:\:/ unless $h eq '%prog_type';
- { local $^W = 0; no strict; %hh = eval $h }
- push @values, \%hh;
- my ($t) = $$j{'name'} =~ m/^\"\s*(.*?)\s*\"$/o;
- push @labels, $t;
- $t = $$j{'color'} ||
- die "Error in section $report section 'graph'. " .
- "No color specified for 'value' $$j{'value'}.\n";
- $t =~ s/^\"\s*\#(.*?)\s*\"$/$1/o;
- $t =~ m/^[\da-fA-F]{6}$/o ||
- die "Error in section $report section 'graph'. " .
- "Bad color for 'value' $$j{'value'}.\n";
- my @c = map { hex $_ } ($t =~ m/^(..)(..)(..)$/);
- push @colors, \@c;
- }
- $suffix = '' unless defined $suffix;
- my $s = ($i ? $i : '') . $suffix;
- print HTML "<CENTER><IMG ALT=\"$title\" ";
- close HTML;
- my $y = &Graph3d ("$IMG_dir/$report$s.$GD_FORMAT",
- $title, $xmax, $num, @values, \@colors, \@labels);
- open (HTML, ">> $HTML_output") ||
- die "Error: cant open $HTML_output\n";
- print HTML "WIDTH=\"$xmax\" HEIGHT=\"$y\" ";
- print HTML "SRC=\"$IMG_pth$report$s.$GD_FORMAT\"></CENTER>\n";
- }
- elsif ($type eq 'histo') {
- my (%values, %labels);
- my $factor =
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[1]}{'factor'}
- || die "Error in section $report section 'graph'. " .
- "No factor specified for 'value' " .
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[1]}{'name'} .
- ".\n";
- $factor =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $labelx =
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[0]}{'name'}
- || die "Error in section $report section 'graph'. " .
- "No name specified for value.\n";
- $labelx =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $labely =
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[1]}{'name'}
- || die "Error in section $report section 'graph'. " .
- "No name specified for value.\n";
- $labely =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- my $t = ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[0]}{'value'}
- || die "Error in section $report section 'graph'. " .
- "No 'value' specified for " .
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[0]}{'name'} .
- ".\n";
- $t =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $t =~ s/^\%/\%$CLASS\:\:/ unless $t eq '%prog_type';
- { local $^W = 0; no strict; %labels = eval $t }
-
- $t = ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[1]}{'value'} ||
- die "Error in section $report section 'graph'. " .
- "No 'value' specified for " .
- ${${${${$output{$report}{'graph'}}[$i]}{'data'}}[1]}{'name'} .
- ".\n";
- $t =~ s/^\"\s*(.*?)\s*\"$/$1/o;
- $t =~ s/^\%/\%$CLASS\:\:/ unless $t eq '%prog_type';
- { local $^W = 0; no strict; %values = eval $t }
- my $s = ($i ? $i : '') . $suffix;
- {
- my $r;
- close HTML;
- $r = &Histo ("$IMG_dir/$report$s.$GD_FORMAT", $title, $xmax,
- $factor, $labelx, $labely, \%values, \%labels);
- open (HTML, ">> $HTML_output") ||
- die "Error: cant open $HTML_output\n";
- print HTML "<CENTER><IMG ALT=\"$title\" WIDTH=\"$xmax\" " .
- "SRC=\"$IMG_pth$report$s.$GD_FORMAT\"></CENTER>\n" if $r;
- }
- }
- elsif ($type eq 'piechart') {
- print "Sorry, graph type 'piechart' not supported yet..\n";
- }
- else {
- die "Error in section $report section 'graph'. " .
- "Invalid 'type' value.\n"
- }
- $i++;
- print HTML "<P>\n";
- }
- print HTML "\n<HR>\n";
- }
- }
- close HTML if $HTML;
-}
-
-sub EvalExpr {
- my $v = shift;
- my ($key, $num, $key1) = @_;
- my $key2;
-
- $v =~ s/\n/ /smog;
- $v =~ s/^\"(.*?)\"$/$1/o;
- if ($key1) {
- $key2 = $key;
- $v =~ s/([^a-zA-Z_\-]?)total\s*\(\s*%/$1&ComputeTotalDouble\(\\%/og;
- }
- else {
- $v =~ s/([^a-zA-Z_\-]?)total\s*\(\s*%/$1&ComputeTotal\(\\%/og;
- # $v =~ s/([^a-zA-Z_\-]?)total\s*\(\s*%([^\)]*)\)/$1&ComputeTotal\("$2"\)/og;
- }
- $v =~ s/([^a-zA-Z_\-]?)bytes\s*\(\s*/$1&NiceByte\(/og;
- $v =~ s/([^a-zA-Z_\-]?)time\s*\(\s*/$1&second2time\(/og;
- $v =~ s/([^a-zA-Z_\-]?)time_ms\s*\(\s*/$1&ms2time\(/og;
- # $v =~ s/([\$\%\@])/$1${CLASS}\:\:/og;
- $v =~ s/([\$\%\@])([^{\s\d])/$1${CLASS}\:\:$2/og;
- $v =~ s/([\$\%\@])${CLASS}\:\:(prog_(?:size|type)|key|sec_glob|num)/$1$2/og;
- my $r;
- # eval { local $^W = 0; no strict; ($r) = eval $v; };
- eval " local \$^W = 0; no strict; (\$r) = $v; ";
- $r = 0 unless defined $r;
- $r;
-}
-
-sub NiceByte {
- my $size = shift;
- my $t;
-
- $size = 0 unless defined $size;
- $t = $size / 1024 / 1024 / 1024 > 1 ?
- sprintf "%.1f GB", $size / 1024 / 1024 / 1024 :
- ($size / 1024 / 1024 > 1 ? sprintf "%.1f MB", $size / 1024 / 1024 :
- sprintf "%.1f KB", $size / 1024);
- return $t;
-}
-
-sub kb2i {
- my $s = shift;
- my ($i, $u) = $s =~ m/^(\S+) (\S+)$/;
- $i *= 1024 * 8 if $u =~ m/MB/o;
- $i *= 1024 * 1024 * 8 if $u =~ m/GB/o;
- return $i;
-}
-
-sub Decode_Config_File {
- my $file = shift;
- my ($line, $section);
- my $linenum = 0;
- my $info;
- my @list;
- open (FILE, "$file") || die "Can\'t open config file \"$file\". Abort.\n";
- while (defined ($line = <FILE>)) {
- $linenum++;
- last if eof (FILE);
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be 'section' instead of '$info'\n"
- unless ($info eq 'section');
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: invalid section name '$info'\n"
- unless $info =~ /^\w+$/;
- print "section $info {\n" if $DEBUG;
- $section = $info;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a '{' instead of '$info'\n"
- unless ($info eq '{');
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- push @list, $section;
- while ($info ne '}') { # it is a block
- last if eof (FILE);
- my $keyword = $info;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- my $value = $info;
- if ($info eq '{') { # it is a sub-block
- my @a;
- $output{$section}{$keyword} = \@a unless $output{$section}{$keyword};
- my %hash;
- print "\t$keyword {\n" if $DEBUG;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- my @sublist; # to store the "data" blocks
-
- while ($info ne '}') {
- last if eof (FILE);
- my $subkeyword = $info;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- my $subvalue = $info;
- if ($info eq '{') {
- # it is a sub-sub-block
- my %subhash;
- print "\t\t$subkeyword {\n" if $DEBUG;
- my @b;
- $hash{$subkeyword} = \@b unless ${hash}{$subkeyword};
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- while ($info ne '}') {
- last if eof (FILE);
- my $subsubkeyword = $info;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- my $subsubvalue = $info;
- if ($info eq '{') {
- die "Error in $file line $linenum: too many blocks.\n";
- }
- else {
- ($info, $linenum, $line) =
- &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead " .
- "of '$info'\n" unless ($info eq ';');
- print "\t\t\t$subsubkeyword\t$subsubvalue;\n" if $DEBUG;
- $subhash{$subsubkeyword} = $subsubvalue;
- ($info, $linenum, $line) =
- &read_conf ($linenum, $line, \*FILE);
- }
- }
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead of " .
- "'$info'\n" unless $info eq ';';
- push @{$hash{$subkeyword}} , \%subhash;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- print "\t\t};\n" if $DEBUG;
- }
- else {
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead " .
- "of '$info'\n" unless $info eq ';';
- print "\t\t$subkeyword\t$subvalue;\n" if $DEBUG;
- $hash{$subkeyword} = $subvalue;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- }
- }
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead of '$info'\n"
- unless $info eq ';';
- push @{$output{$section}{$keyword}}, \%hash;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- print "\t};\n" if $DEBUG;
- }
- else {
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead of '$info'\n"
- unless $info eq ';';
- print "\t$keyword\t$value;\n" if $DEBUG;
- $output{$section}{$keyword} = $value;
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- }
- }
- die "Error in $file line $linenum: must be a '}' instead of '$info'\n"
- unless $info eq '}';
- ($info, $linenum, $line) = &read_conf ($linenum, $line, \*FILE);
- die "Error in $file line $linenum: must be a ';' instead of '$info'\n"
- unless $info eq ';';
- print "};\n\n" if $DEBUG;
- }
- close FILE;
- $output{'_order_'} = \@list;
-}
-
-sub read_conf {
- my ($linenum, $line, $file) = @_;
- *FILE = *$file;
-
- $line =~ s,^\s+,,o; # remove useless blanks
- $line =~ s,^(\#|//).*$,,o; # remove comments (at the beginning)
- while (($line =~ m/^$/o || $line =~ m/^\"[^\"]*$/o) && !(eof (FILE))) {
- $line .= <FILE>; # read one line
- $linenum++;
- $line =~ s,^\s*,,om; # remove useless blanks
- $line =~ s,^(\#|//).*$,,om; # remove comments (at the beginning)
- }
- $line =~ s/^( # at the beginning
- [{};] # match '{', '}', or ';'
- | # OR
- \" # a double quoted string
- (?:\\.|[^\"\\])*
- \"
- | # OR
- [^{};\"\s]+ # a word
- )\s*//mox;
- my $info = $1;
- if (defined $info && $info) {
- chomp $info;
- }
- else {
- warn "Syntax error in conf file line $linenum.\n";
- }
- return ($info, $linenum, $line);
-}
-
-sub GetValue {
- my $v = shift;
- my ($r) = $v =~ m/^(?:\"\s*)?(.*?)(?:\s*\")?$/so;
- return $r;
-}
-
-sub Usage {
- my ($base) = $0 =~ /([^\/]+)$/;
- print "Usage: $base -f innreport.conf [-[no]options]\n";
- print " where options are:\n";
- print " -h (or -help) this help page\n";
- print " -v display the version number of INNreport\n";
- print " -config print INNreport configuration information\n";
- print " -html HTML output";
- print " [default]" if ($HTML);
- print "\n";
- print " -g want graphs";
- print " [default]" if ($GRAPH);
- print "\n";
- print " -graph an alias for option -g\n";
- print " -d directory directory for Web pages";
- print "\n [default=$HTML_dir]"
- if (defined ($HTML_dir));
- print "\n";
- print " -dir directory an alias for option -d\n";
- print " -p directory pictures path (file space)";
- print "\n [default=$IMG_dir]"
- if (defined ($IMG_dir));
- print "\n";
- print " -path directory an alias for option -p\n";
- print " -w directory pictures path (web space)";
- print " [default=$IMG_pth]" if (defined ($IMG_pth));
- print "\n";
- print " -webpath directory an alias for option -w\n";
- print "\n";
- print " -i file Name of index file";
- print " [default=$index]" if (defined ($index));
- print "\n";
- print " -index file an alias for option -i\n";
- print " -a want to archive HTML results";
- print " [default]" if ($ARCHIVE);
- print "\n";
- print " -archive an alias for option -a\n";
- print " -c number how many report files to keep (0 = all)\n";
- print " [default=$CYCLE]"
- if (defined ($CYCLE));
- print "\n";
- print " -cycle number an alias for option -c\n";
- print " -s char separator for filename";
- print " [default=\"$SEPARATOR\"]\n";
- print " -separator char an alias for option -s\n";
- print " -unknown \"Unknown entries from news log file\"\n";
- print " report";
- print " [default]" if ($WANT_UNKNOWN);
- print "\n";
- print " -html-unknown Same as above, but in generated HTML output.";
- print " [default]" if ($WANT_UNKNOWN);
- print "\n";
- print " -maxunrec Max number of unrecognized lines to display\n";
- print " [default=$MAX_UNRECOGNIZED]"
- if (defined ($MAX_UNRECOGNIZED));
- print "\n";
- print " -notdaily Never perform daily actions";
- print " [default]" if $NOT_DAILY;
- print "\n";
- print " -casesensitive Case sensitive";
- print " [default]" if ($CASE_SENSITIVE);
- print "\n\n";
- print "Use no in front of boolean options to unset them.\n";
- print "For example, \"-html\" is set by default. Use \"-nohtml\" to remove this\n";
- print "feature.\n";
- exit 0;
-}
-
-sub Version {
- print "\nThis is INNreport version $version\n\n";
- print "Copyright 1996-1999, Fabien Tassin <fta\@sofaraway.org>\n";
- exit 0;
-}
-
-sub Summary {
- use Config;
-
- # Convert empty arguments into null string ("")
- my $i = 0;
- foreach (@old_argv) {
- $old_argv[$i] = '""' if $_ eq '';
- $i++;
- }
-
- # Display the summary
- print "\nSummary of my INNreport (version $version) configuration:\n";
- print " General options:\n";
- print " command line='@old_argv' (please, check this value)\n";
- print " html=" . ($HTML?"yes":"no") . ", graph=" .
- ($GRAPH?"yes":"no") . ", haveGD=" .
- ($::HAVE_GD?"yes":"no") . "\n";
- print " archive=" . ($ARCHIVE?"yes":"no") .
- ", cycle=$CYCLE, separator=\"" . $SEPARATOR . "\"\n";
- print " case_sensitive=" .
- ($CASE_SENSITIVE?"yes":"no") . ", want_unknown=" .
- ($WANT_UNKNOWN?"yes":"no") .
- ", max_unrecog=$MAX_UNRECOGNIZED\n";
- print " Paths:\n";
- print " html_dir=$HTML_dir\n";
- print " img_dir=$IMG_dir\n";
- print " img_pth=$IMG_pth\n";
- print " index=$index\n";
- print " Platform:\n";
- print " perl version $::Config{baserev} "
- . "patchlevel $::Config{patchlevel} "
- . "subversion $::Config{subversion}\n";
- print " libperl=$::Config{libperl}, useshrplib=$::Config{useshrplib}, "
- . "bincompat3=$::Config{bincompat3}\n";
- print " osname=$::Config{osname}, osvers=$::Config{osvers}, "
- . "archname=$::Config{archname}\n";
- print " uname=$::Config{myuname}\n\n";
-
- exit 0;
-}
-
-######################### End of File ##########################
+++ /dev/null
-##########################################################
-# INN module for innreport (3.*).
-#
-# Sample file tested with INN 2.4, 2.3, 2.2, 1.7.2 and 1.5.1
-#
-# (c) 1997-1999 by Fabien Tassin <fta@sofaraway.org>
-# version 3.0.2
-##########################################################
-
-# TODO: add the map file.
-
-package innreport_inn;
-
-my $MIN = 1E10;
-my $MAX = -1;
-
-my %ctlinnd = ('a', 'addhist', 'D', 'allow',
- 'b', 'begin', 'c', 'cancel',
- 'u', 'changegroup', 'd', 'checkfile',
- 'e', 'drop', 'f', 'flush',
- 'g', 'flushlogs', 'h', 'go',
- 'i', 'hangup', 's', 'mode',
- 'j', 'name', 'k', 'newgroup',
- 'l', 'param', 'm', 'pause',
- 'v', 'readers', 't', 'refile',
- 'C', 'reject', 'o', 'reload',
- 'n', 'renumber', 'z', 'reserve',
- 'p', 'rmgroup', 'A', 'send',
- 'q', 'shutdown', 'B', 'signal',
- 'r', 'throttle', 'w', 'trace',
- 'x', 'xabort', 'y', 'xexec',
- 'E', 'logmode', 'F', 'feedinfo',
- 'T', 'filter', 'P', 'perl',);
-
-my %timer_names = (idle => 'idle',
- hishave => 'history lookup',
- hisgrep => 'history grep',
- hiswrite => 'history write',
- hissync => 'history sync',
- nntpread => 'nntp read',
- artparse => 'article parse',
- artclean => 'article cleanup',
- artwrite => 'article write',
- artcncl => 'article cancel',
- artlog => 'article logging',
- sitesend => 'site send',
- overv => 'overview write',
- perl => 'perl filter',
- python => 'python filter',
- datamove => 'data move'
-);
-
-my %innfeed_timer_names = (
- 'idle' => 'idle',
- 'blstats' => 'backlog stats',
- 'stsfile' => 'status file',
- 'newart' => 'article new',
- 'prepart' => 'article prepare',
- 'readart' => 'article read',
- 'read' => 'data read',
- 'write' => 'data write',
- 'cb' => 'callbacks',
-);
-
-my %nnrpd_timer_names = (
- 'idle' => 'idle',
- 'newnews' => 'newnews',
-);
-
-# init innd timer
-foreach (values %timer_names) {
- $innd_time_min{$_} = $MIN;
- $innd_time_max{$_} = $MAX;
- $innd_time_time{$_} = 0; # to avoid a warning... Perl < 5.004
- $innd_time_num{$_} = 0; # ...
-}
-$innd_time_times = 0; # ...
-
-# init innfeed timer
-foreach (values %innfeed_timer_names) {
- $innfeed_time_min{$_} = $MIN;
- $innfeed_time_max{$_} = $MAX;
- $innfeed_time_time{$_} = 0; # to avoid a warning... Perl < 5.004
- $innfeed_time_num{$_} = 0; # ...
-}
-$innfeed_time_times = 0; # ...
-
-# init nnrpd timer
-foreach (values %nnrpd_timer_names) {
- $nnrpd_time_min{$_} = $MIN;
- $nnrpd_time_max{$_} = $MAX;
- $nnrpd_time_time{$_} = 0; # to avoid a warning... Perl < 5.004
- $nnrpd_time_num{$_} = 0; # ...
-}
-$nnrpd_time_times = 0; # ...
-
-# collect: Used to collect the data.
-sub collect {
- my ($day, $hour, $prog, $res, $left, $CASE_SENSITIVE) = @_;
-
- return 1 if $left =~ /Reading config from (\S+)$/o;
-
- ########
- ## inn (from the "news" log file - not from "news.notice")
- ##
- if ($prog eq "inn") {
- # accepted article
- if ($res =~ m/[\+j]/o) {
- $hour =~ s/:.*$//o;
- $inn_flow{"$day $hour"}++;
- $inn_flow_total++;
-
- # Memorize the size. This can only be done with INN >= 1.5xx and
- # DO_LOG_SIZE = DO.
-
- # server <msg-id> size [feeds]
- # or
- # server <msg-id> (filename) size [feeds]
-
- my ($s) = $left =~ /^\S+ \S+ (?:\(\S+\) )?(\d+)(?: |$)/o;
- if ($s) {
- $inn_flow_size{"$day $hour"} += $s;
- $inn_flow_size_total += $s;
- }
- return 1;
- }
-
- # 437 Duplicate article
- if ($left =~ /(\S+) <[^>]+> 437 Duplicate(?: article)?$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_duplicate{$server}++;
- return 1;
- }
- # 437 Unapproved for
- if ($left =~ /(\S+) <[^>]+> 437 Unapproved for \"([^\"]+)\"$/o) {
- my ($server, $group) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_unapproved{$server}++;
- $inn_unapproved_g{$group}++;
- return 1;
- }
- # 437 Too old -- ...
- if ($left =~ /(\S+) <[^>]+> 437 Too old -- /o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_tooold{$server}++;
- return 1;
- }
- # 437 Unwanted site ... in path
- if ($left =~ /(\S+) <[^>]+> 437 Unwanted site (\S+) in path$/o) {
- my ($server, $site) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_uw_site{$server}++;
- $inn_site_path{$site}++;
- return 1;
- }
- # 437 Unwanted newsgroup "..."
- if ($left =~ /(\S+) <[^>]+> 437 Unwanted newsgroup \"(\S+)\"$/o) {
- my ($server, $group) = ($1, $2);
- ($group) = split(/,/, $group);
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_uw_ng_s{$server}++;
- $inn_uw_ng{$group}++;
- return 1;
- }
- # 437 Unwanted distribution "..."
- if ($left =~ /(\S+) <[^>]+> 437 Unwanted distribution \"(\S+)\"$/o) {
- my ($server, $dist) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_uw_dist_s{$server}++;
- $inn_uw_dist{$dist}++;
- return 1;
- }
- # 437 Linecount x != y +- z
- if ($left =~ /(\S+) <[^>]+> 437 Linecount/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $inn_linecount{$server}++;
- return 1;
- }
- # 437 No colon-space in "xxxx" header
- if ($left =~ /(\S+) <[^>]+> 437 No colon-space in \"[^\"]+\" header/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $innd_others{$server}++;
- $innd_no_colon_space{$server}++;
- return 1;
- }
- # 437 Article posted in the future -- "xxxxx"
- if ($left =~ /(\S+) <[^>]+> 437 Article posted in the future -- \"[^\"]+\"/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_posted_future{$server}++;
- $innd_others{$server}++;
- $inn_badart{$server}++;
- return 1;
- }
- # 437 article includes "....."
- if ($left =~ /(\S+) <[^>]+> 437 article includes/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_strange_strings{$server}++;
- $innd_others{$server}++;
- $inn_badart{$server}++;
- return 1;
- }
- # Cancelling <...>
- if ($left =~ /(\S+) <[^>]+> Cancelling/o) {
- return 1;
- }
- # all others are just counted as "Other"
- if ($left =~ /(\S+) /o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $inn_badart{$server}++;
- $innd_others{$server}++;
- return 1;
- }
- }
-
- ########
- ## innd
- if ($prog eq "innd") {
- ## Note for innd logs:
- ## there's a lot of entries detected but still not used
- ## (because of a lack of interest).
-
- # think it's a dotquad
- return 1 if $left =~ /^think it\'s a dotquad$/o;
- if ($left =~ /^SERVER /o) {
- # SERVER perl filtering enabled
- return 1 if $left =~ /^SERVER perl filtering enabled$/o;
- # SERVER perl filtering disabled
- return 1 if $left =~ /^SERVER perl filtering disabled$/o;
- # SERVER Python filtering enabled
- return 1 if $left =~ /^SERVER Python filtering enabled$/o;
- # SERVER Python filtering disabled
- return 1 if $left =~ /^SERVER Python filtering disabled$/o;
- # SERVER cancelled +id
- return 1 if $left =~ /^SERVER cancelled /o;
- }
- # Python filter
- return 1 if $left =~ /^defined python methods$/o;
- return 1 if $left =~ /^reloading pyfilter$/o;
- return 1 if $left =~ /^reloaded pyfilter OK$/o;
- return 1 if $left =~ /^python interpreter initialized OK$/o;
- return 1 if $left =~ /^python method \w+ not found$/o;
- return 1 if $left =~ /^python: First load, so I can do initialization stuff\.$/o;
- return 1 if $left =~ /^python: filter_before_reload executing\.\.\.$/o;
- return 1 if $left =~ /^python: I\'m just reloading, so skip the formalities\.$/o;
- return 1 if $left =~ /^python: spamfilter successfully hooked into INN$/o;
- return 1 if $left =~ /^python: state change from \w+ to \w+ - /o;
- return 1 if $left =~ /^python: filter_close running, bye!$/o;
- # rejecting[perl]
- if ($left =~ /^rejecting\[perl\] <[^>]+> \d+ (.*)/o) {
- $innd_filter_perl{$1}++;
- return 1;
- }
- # rejecting[python]
- if ($left =~ /^rejecting\[python\] <[^>]+> \d+ (.*)/o) {
- $innd_filter_python{$1}++;
- return 1;
- }
- # closed lost
- return 1 if $left =~ /^\S+ closed lost \d+/o;
- # new control command
- if ($left =~ /^ctlinnd command (\w)(:.*)?/o) {
- my $command = $1;
- my $cmd = $ctlinnd{$command};
- $cmd = $command unless $cmd;
- return 1 if $cmd eq 'flush'; # to avoid a double count
- $innd_control{"$cmd"}++;
- return 1;
- }
- # old control command (by letter)
- if ($left =~ /^(\w)$/o) {
- my $command = $1;
- my $cmd = $ctlinnd{$command};
- $cmd = $command unless $cmd;
- return 1 if $cmd eq 'flush'; # to avoid a double count
- $innd_control{"$cmd"}++;
- return 1;
- }
- # old control command (letter + reason)
- if ($left =~ /^(\w):.*$/o) {
- my $command = $1;
- my $cmd = $ctlinnd{$command};
- $cmd = $command unless $cmd;
- return 1 if $cmd eq 'flush'; # to avoid a double count
- $innd_control{"$cmd"}++;
- return 1;
- }
- # opened
- return 1 if $left =~ /\S+ opened \S+:\d+:file$/o;
- # buffered
- return 1 if $left =~ /\S+ buffered$/o;
- # spawned
- return 1 if $left =~ /\S+ spawned \S+:\d+:proc:\d+$/o;
- return 1 if $left =~ /\S+ spawned \S+:\d+:file$/o;
- # running
- return 1 if $left =~ /\S+ running$/o;
- # sleeping
- if ($left =~ /(\S+):\d+:proc:\d+ sleeping$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_blocked{$server}++;
- return 1;
- }
- # blocked sleeping
- if ($left =~ /(\S+):\d+:proc:\d+ blocked sleeping/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_blocked{$server}++;
- return 1;
- }
- if ($left =~ /(\S+):\d+ blocked sleeping/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_blocked{$server}++;
- return 1;
- }
- # restarted
- return 1 if $left =~ m/^\S+ restarted$/o;
- # starting
- return 1 if $left =~ m/^\S+ starting$/o;
- # readclose
- return 1 if $left =~ m/^\S+:\d+ readclose+$/o;
- # rejected 502
- if ($left =~ m/^(\S+) rejected 502$/) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_no_permission{$server}++;
- return 1;
- }
- # rejected 505
- if ($left =~ m/^(\S+) rejected 505$/) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_too_many_connects_per_minute{$server}++;
- return 1;
- }
- # connected
- if ($left =~ /^(\S+) connected \d+/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_connect{$server}++;
- return 1;
- }
- # closed (with times)
- if ($left =~ /(\S+):\d+ closed seconds (\d+) accepted (\d+) refused (\d+) rejected (\d+) duplicate (\d+) accepted size (\d+) duplicate size (\d+)(?: rejected size (\d+))?$/o) {
- my ($server, $seconds, $accepted, $refused, $rejected, $duplicate, $accptsize, $dupsize) =
- ($1, $2, $3, $4, $5, $6, $7, $8);
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_seconds{$server} += $seconds;
- $innd_accepted{$server} += $accepted;
- $innd_refused{$server} += $refused;
- $innd_rejected{$server} += $rejected;
- $innd_stored_size{$server} += $accptsize;
- $innd_duplicated_size{$server} += $dupsize;
- return 1;
- } elsif ($left =~ /(\S+):\d+ closed seconds (\d+) accepted (\d+) refused (\d+) rejected (\d+)$/o) {
- # closed (with times)
- my ($server, $seconds, $accepted, $refused, $rejected) =
- ($1, $2, $3, $4, $5);
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_seconds{$server} += $seconds;
- $innd_accepted{$server} += $accepted;
- $innd_refused{$server} += $refused;
- $innd_rejected{$server} += $rejected;
- return 1;
- }
- # closed (without times (?))
- return 1 if $left =~ m/\S+ closed$/o;
- # closed (for a cancel feed - MODE CANCEL)
- return 1 if $left =~ m/localhost:\d+ closed seconds \d+ cancels \d+$/o;
- # checkpoint
- return 1 if $left =~ m/^\S+:\d+ checkpoint /o;
- # if ($left =~ /(\S+):\d+ checkpoint seconds (\d+) accepted (\d+)
- # refused (\d+) rejected (\d+)$/) {
- # # Skipped...
- # my ($server, $seconds, $accepted, $refused, $rejected) =
- # ($1, $2, $3, $4, $5);
- # $innd_seconds{$server} += $seconds;
- # $innd_accepted{$server} += $accepted;
- # $innd_refused{$server} += $refused;
- # $innd_rejected{$server} += $rejected;
- # return 1;
- # }
-
- # flush
- if ($left =~ /(\S+) flush$/o) {
- $innd_control{"flush"}++;
- return 1;
- }
- # flush-file
- if ($left =~ /flush_file/) {
- $innd_control{"flush_file"}++;
- return 1;
- }
- # too many connections from site
- if ($left =~ /too many connections from (\S+)/o) {
- $innd_max_conn{$1}++;
- return 1;
- }
- # overview exit 0 elapsed 23 pid 28461
- return 1 if $left =~ m/\S+ exit \d+ .*$/o;
- # internal rejecting huge article
- if ($left =~ /(\S+) internal rejecting huge article/o) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_huge{$server}++;
- return 1;
- }
- # internal closing free channel
- if ($left =~ /(\S+) internal closing free channel/o) {
- $innd_misc{"Free channel"}++;
- return 1;
- }
- # internal (other)
- return 1 if $left =~ /\S+ internal/o;
- # wakeup
- return 1 if $left =~ /\S+ wakeup$/o;
- # throttle
- if ($left =~ /(\S+) throttled? /) {
- $innd_control{"throttle"}++;
- return 1;
- }
- # profile timer
- # ME time X nnnn X(X) [...]
- # The exact timers change from various versions of INN, so try to deal
- # with this in a general fashion.
- if ($left =~ m/^\S+\s+ # ME
- time\s(\d+)\s+ # time
- ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $innd_time_times += $1;
- my $timers = $2;
-
- while ($timers =~ /(\S+) (\d+)\((\d+)\)\s*/g) {
- my $name = $timer_names{$1} || $1;
- my $average = $2 / ($3 || 1);
- $innd_time_time{$name} += $2;
- $innd_time_num{$name} += $3;
- $innd_time_min{$name} = $average
- if ($3 && $innd_time_min{$name} > $average);
- $innd_time_max{$name} = $average
- if ($3 && $innd_time_max{$name} < $average);
- }
- return 1;
- }
- # ME time xx idle xx(xx) [ bug ? a part of timer ?]
- return 1 if $left =~ m/^ME time \d+ idle \d+\(\d+\)\s*$/o;
- # ME HISstats x hitpos x hitneg x missed x dne
- #
- # from innd/his.c:
- # HIShitpos: the entry existed in the cache and in history.
- # HIShitneg: the entry existed in the cache but not in history.
- # HISmisses: the entry was not in the cache, but was in the history file.
- # HISdne: the entry was not in cache or history.
- if ($left =~ m/^ME\ HISstats # ME HISstats
- \ (\d+)\s+hitpos # hitpos
- \ (\d+)\s+hitneg # hitneg
- \ (\d+)\s+missed # missed
- \ (\d+)\s+dne # dne
- $/ox) {
- $innd_his{'Positive hits'} += $1;
- $innd_his{'Negative hits'} += $2;
- $innd_his{'Cache misses'} += $3;
- $innd_his{'Do not exist'} += $4;
- return 1;
- }
- # SERVER history cache final: 388656 lookups, 1360 hits
- if ($left =~ m/^SERVER history cache final: (\d+) lookups, (\d+) hits$/) {
- $innd_cache{'Lookups'} += $1;
- $innd_cache{'Hits'} += $2;
- return 1;
- }
- # bad_hosts (appears after a "cant gesthostbyname" from a feed)
- return 1 if $left =~ m/\S+ bad_hosts /o;
- # cant read
- return 1 if $left =~ m/\S+ cant read/o;
- # cant write
- return 1 if $left =~ m/\S+ cant write/o;
- # cant flush
- return 1 if $left =~ m/\S+ cant flush/o;
- # spoolwake
- return 1 if $left =~ m/\S+ spoolwake$/o;
- # spooling
- return 1 if $left =~ m/\S+ spooling/o;
- # DEBUG
- return 1 if $left =~ m/^DEBUG /o;
- # NCmode
- return 1 if $left =~ m/\S+ NCmode /o;
- # outgoing
- return 1 if $left =~ m/\S+ outgoing/o;
- # inactive
- return 1 if $left =~ m/\S+ inactive/o;
- # timeout
- return 1 if $left =~ m/\S+ timeout/o;
- # lcsetup
- return 1 if $left =~ m/\S+ lcsetup/o;
- # rcsetup
- return 1 if $left =~ m/\S+ rcsetup/o;
- # flush_all
- return 1 if $left =~ m/\S+ flush_all/o;
- # buffered
- return 1 if $left =~ m/\S+ buffered$/o;
- # descriptors
- return 1 if $left =~ m/\S+ descriptors/o;
- # ccsetup
- return 1 if $left =~ m/\S+ ccsetup/o;
- # renumbering
- return 1 if $left =~ m/\S+ renumbering/o;
- # renumber
- return 1 if $left =~ m/\S+ renumber /o;
- # ihave from me
- if ($left =~ m/\S+ ihave_from_me /o) {
- $controlchan_ihave_site{'ME'}++;
- return 1;
- }
- # sendme from me
- if ($left =~ m/\S+ sendme_from_me /o) {
- $controlchan_sendme_site{'ME'}++;
- return 1;
- }
- # newgroup
- if ($left =~ m/\S+ newgroup (\S+) as (\S)/o) {
- $innd_newgroup{$1} = $2;
- return 1;
- }
- # rmgroup
- if ($left =~ m/\S+ rmgroup (\S+)$/o) {
- $innd_rmgroup{$1}++;
- return 1;
- }
- # changegroup
- if ($left =~ m/\S+ change_group (\S+) to (\S)/o) {
- $innd_changegroup{$1} = $2;
- return 1;
- }
- # paused
- if ($left =~ m/(\S+) paused /o) {
- $innd_control{"paused"}++;
- return 1;
- }
- # throttled
- return 1 if $left =~ m/\S+ throttled/o;
- # reload
- if ($left =~ m/(\S+) reload/o) {
- $innd_control{"reload"}++;
- return 1;
- }
- # shutdown
- if ($left =~ m/(\S+) shutdown/o) {
- $innd_control{"shutdown"}++;
- return 1;
- }
- # SERVER servermode paused
- return 1 if ($left =~ /(\S+) servermode paused$/o);
- # SERVER servermode running
- return 1 if ($left =~ /(\S+) servermode running$/o);
- # SERVER flushlogs paused
- if ($left =~ /(\S+) flushlogs /) {
- $innd_control{"flushlogs"}++;
- return 1;
- }
- # think it's a dotquad
- return 1 if $left =~ /think it\'s a dotquad: /o;
- # bad_ihave
- if ($left =~ /(\S+) bad_ihave /) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_bad_ihave{$server}++;
- return 1;
- }
- # bad_messageid
- if ($left =~ /(\S+) bad_messageid/o) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_bad_msgid{$server}++;
- return 1;
- }
- # bad_sendme
- if ($left =~ /(\S+) bad_sendme /o) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_bad_sendme{$server}++;
- return 1;
- }
- # bad_command
- if ($left =~ /(\S+) bad_command /o) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $server = lc $server unless $CASE_SENSITIVE;
- $innd_bad_command{$server}++;
- return 1;
- }
- # bad_newsgroup
- if ($left =~ /(\S+) bad_newsgroup /o) {
- my $server = $1;
- $server =~ s/:\d+$//o;
- $innd_bad_newsgroup{$server}++;
- $server = lc $server unless $CASE_SENSITIVE;
- return 1;
- }
- if ($left =~ m/ cant /o) {
- # cant select Bad file number
- if ($left =~ / cant select Bad file number/o) {
- $innd_misc{"Bad file number"}++;
- return 1;
- }
- # cant gethostbyname
- if ($left =~ / cant gethostbyname/o) {
- $innd_misc{"gethostbyname error"}++;
- return 1;
- }
- # cant accept RCreader
- if ($left =~ / cant accept RCreader /o) {
- $innd_misc{"RCreader"}++;
- return 1;
- }
- # cant sendto CCreader
- if ($left =~ / cant sendto CCreader /o) {
- $innd_misc{"CCreader"}++;
- return 1;
- }
- # cant (other) skipped - not particularly interesting
- return 1;
- }
- # bad_newsfeeds no feeding sites
- return 1 if $left =~ /\S+ bad_newsfeeds no feeding sites/o;
- # CNFS: cycbuff rollover - possibly interesting
- return 1 if $left =~ /CNFS(?:-sm)?: cycbuff \S+ rollover to cycle/o;
- # CNFS: CNFSflushallheads: flushing - possibly interesting
- return 1 if $left =~ /CNFS(?:-sm)?: CNFSflushallheads: flushing /o;
- # CNFS: metacycbuff rollover with SEQUENTIAL
- return 1 if $left =~ /CNFS(?:-sm)?: metacycbuff \S+ cycbuff is moved to /o;
- # Cleanfeed status reports
- return 1 if $left =~ /^filter: status/o;
- return 1 if $left =~ /^filter: Reloading bad files/o;
- }
- ########
- ## innfeed
- if ($prog eq "innfeed") {
- # connected
- if ($left =~ /(\S+):\d+ connected$/) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innfeed_connect{$server}++;
- return 1;
- }
- # closed periodic
- return 1 if $left =~ m/\S+:\d+ closed periodic$/o;
- # periodic close
- return 1 if $left =~ m/\S+:\d+ periodic close$/o;
- # final (child)
- return 1 if $left =~ m/\S+:\d+ final seconds \d+ offered \d+ accepted \d+ refused \d+ rejected \d+/o;
- # global (real)
- return 1 if $left =~ m/\S+ global seconds \d+ offered \d+ accepted \d+ refused \d+ rejected \d+ missing \d+/o;
- # final (real) (new format)
- if ($left =~ /(\S+) final seconds (\d+) offered (\d+) accepted (\d+) refused (\d+) rejected (\d+) missing (\d+) accsize (\d+) rejsize (\d+) spooled (\d+)/o) {
- my ($server, $seconds, $offered, $accepted, $refused, $rejected,
- $missing, $accepted_size, $rejected_size, $spooled) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
- $server = lc $server unless $CASE_SENSITIVE;
- $innfeed_seconds{$server} += $seconds;
- $innfeed_offered{$server} += $offered;
- $innfeed_accepted{$server} += $accepted;
- $innfeed_refused{$server} += $refused;
- $innfeed_rejected{$server} += $rejected;
- $innfeed_missing{$server} += $missing;
- $innfeed_spooled{$server} += $spooled;
- $innfeed_accepted_size{$server} += $accepted_size;
- $innfeed_rejected_size{$server} += $rejected_size;
- return 1;
- } elsif ($left =~ /(\S+) final seconds (\d+) offered (\d+) accepted (\d+) refused (\d+) rejected (\d+) missing (\d+) spooled (\d+)/o) {
- my ($server, $seconds, $offered, $accepted, $refused, $rejected,
- $missing, $spooled) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
- $server = lc $server unless $CASE_SENSITIVE;
- $innfeed_seconds{$server} += $seconds;
- $innfeed_offered{$server} += $offered;
- $innfeed_accepted{$server} += $accepted;
- $innfeed_refused{$server} += $refused;
- $innfeed_rejected{$server} += $rejected;
- $innfeed_missing{$server} += $missing;
- $innfeed_spooled{$server} += $spooled;
- return 1;
- }
- # final (only seconds & spooled)
- if ($left =~ /(\S+) final seconds (\d+) spooled (\d+)/o) {
- my ($server, $seconds, $spooled) = ($1, $2, $3);
- $server = lc $server unless $CASE_SENSITIVE;
- $innfeed_seconds{$server} += $seconds;
- $innfeed_spooled{$server} += $spooled;
- return 1;
- }
- # checkpoint
- return 1 if $left =~ m/\S+ checkpoint seconds/o;
- # ME file xxxx shrunk from yyyy to zzz
- if ($left =~ /^ME file (.*)\.output shrunk from (\d+) to (\d+)$/) {
- my ($file, $s1, $s2) = ($1, $2, $3);
- $file =~ s|^.*/([^/]+)$|$1|; # keep only the server name
- $innfeed_shrunk{$file} += $s1 - $s2;
- return 1;
- }
- # profile timer
- # ME time X nnnn X(X) [...]
- return 1 if $left =~ m/backlogstats/;
- if ($left =~ m/^\S+\s+ # ME
- time\s(\d+)\s+ # time
- ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $innfeed_time_times += $1;
- my $timers = $2;
-
- while ($timers =~ /(\S+) (\d+)\((\d+)\)\s*/g) {
- my $name = $innfeed_timer_names{$1} || $1;
- my $average = $2 / ($3 || 1);
- $innfeed_time_time{$name} += $2;
- $innfeed_time_num{$name} += $3;
- $innfeed_time_min{$name} = $average
- if ($3 && $innfeed_time_min{$name} > $average);
- $innfeed_time_max{$name} = $average
- if ($3 && $innfeed_time_max{$name} < $average);
- }
- return 1;
- }
- # xxx grabbing external tape file
- return 1 if $left =~ m/ grabbing external tape file/o;
- # hostChkCxns - maxConnections was
- return 1 if $left =~ m/hostChkCxns - maxConnections was /o;
- # cxnsleep
- return 1 if $left =~ m/\S+ cxnsleep .*$/o;
- # idle
- return 1 if $left =~ m/\S+ idle tearing down connection$/o;
- # remote
- return 1 if $left =~ m/\S+ remote .*$/o;
- # spooling
- return 1 if $left =~ m/\S+ spooling no active connections$/o;
- # ME articles total
- return 1 if $left =~ m/(?:SERVER|ME) articles total \d+ bytes \d+/o;
- # ME articles active
- return 1 if $left =~ m/(?:SERVER|ME) articles active \d+ bytes \d+/o;
- # connect : Connection refused
- return 1 if $left =~ m/connect : Connection refused/o;
- # connect : Network is unreachable
- return 1 if $left =~ m/connect : Network is unreachable/o;
- # connect : Address family not supported by protocol
- return 1 if $left =~ m/connect : Address family not supported by protocol/o;
- # connect : No route to host
- return 1 if $left =~ m/connect : No route to host/o;
- # connection vanishing
- return 1 if $left =~ m/connection vanishing/o;
- # can't resolve hostname
- return 1 if $left =~ m/can\'t resolve hostname/o;
- # new hand-prepared backlog file
- return 1 if $left =~ m/new hand-prepared backlog file/o;
- # flush re-connect failed
- return 1 if $left =~ m/flush re-connect failed/o;
- # internal QUIT while write pending
- return 1 if $left =~ m/internal QUIT while write pending/o;
- # ME source lost . Exiting
- return 1 if $left =~ m/(?:SERVER|ME) source lost . Exiting/o;
- # ME starting innfeed (+version & date)
- return 1 if $left =~ m/(?:SERVER|ME) starting (?:innfeed|at)/o;
- # ME finishing at (date)
- return 1 if $left =~ m/(?:SERVER|ME) finishing at /o;
- # mode no-CHECK entered
- return 1 if $left =~ m/mode no-CHECK entered/o;
- # mode no-CHECK exited
- return 1 if $left =~ m/mode no-CHECK exited/o;
- # closed
- return 1 if $left =~ m/^(\S+) closed$/o;
- # global (+ seconds offered accepted refused rejected missing)
- return 1 if $left =~ m/^(\S+) global/o;
- # idle connection still has articles
- return 1 if $left =~ m/^(\S+) idle connection still has articles$/o;
- # missing article for IHAVE-body
- return 1 if $left =~ m/^(\S+) missing article for IHAVE-body$/o;
- # cannot continue
- return 1 if $left =~ m/^cannot continue/o;
- if ($left =~ /^(?:SERVER|ME)/o) {
- # ME dropping articles into ...
- return 1 if $left =~ / dropping articles into /o;
- # ME dropped ...
- return 1 if $left =~ / dropped /o;
- # ME internal bad data in checkpoint file
- return 1 if $left =~ m/ internal bad data in checkpoint/o;
- # ME two filenames for same article
- return 1 if $left =~ m/ two filenames for same article/o;
- # ME unconfigured peer
- return 1 if $left =~ m/ unconfigured peer/o;
- # exceeding maximum article size
- return 1 if $left =~ m/ exceeding maximum article byte/o;
- # no space left on device errors
- return 1 if $left =~ m/ ioerr fclose/o;
- return 1 if $left =~ m/ lock failed for host/o;
- return 1 if $left =~ m/ lock file pid-write/o;
- return 1 if $left =~ m/ locked cannot setup peer/o;
- return 1 if $left =~ m/ received shutdown signal/o;
- # unconfigured peer
- return 1 if $left =~ m/ unconfigured peer/o;
- # ME lock
- return 1 if $left =~ m/ lock/o;
- # ME exception: getsockopt (0): Socket operation on non-socket
- return 1 if $left =~ m/ exception: getsockopt /o;
- # ME config aborting fopen (...) Permission denied
- return 1 if $left =~ m/ config aborting fopen /o;
- # ME cant chmod innfeed.pid....
- return 1 if $left =~ m/ cant chmod \S+\/innfeed.pid/o;
- return 1 if $left =~ m/ tape open failed /o;
- return 1 if $left =~ m/ oserr open checkpoint file:/o;
- # ME finishing (quickly)
- return 1 if $left =~ m/\(quickly\) /o;
- # ME config: value of streaming is not a boolean
- return 1 if $left =~ m/config: value of \S+ is not/o;
- }
- # hostChkCxn - now: x.xx, prev: x.xx, abs: xx, curr: x
- return 1 if $left =~ m/ hostChkCxn - now/o;
- # loading path_to_config_file/innfeed.conf
- return 1 if $left =~ m/loading /o;
- # Finnaly, to avoid problems with strange error lines, ignore them.
- #return 1 if ($left =~ /ME /);
- }
- ########
- ## innxmit
- if ($prog eq "innxmit") {
- # 437 Duplicate article
- if ($left =~ /(\S+) rejected [^\s]+ \(.*?\) 437 Duplicate article$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_duplicate{$server}++;
- return 1;
- }
- # 437 Unapproved for
- if ($left =~ /(\S+) rejected [^\s]+ \(.*\) 437 Unapproved for \"(.*?)\"$/o) {
- my ($server, $group) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_unapproved{$server}++;
- $innxmit_unapproved_g{$group}++;
- return 1;
- }
- # 437 Too old -- ...
- if ($left =~ /(\S+) rejected [^\s]+ \(.*\) 437 Too old -- \".*?\"$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_tooold{$server}++;
- return 1;
- }
- # 437 Unwanted site ... in path
- if ($left =~
- /(\S+) rejected [^\s]+ \(.*?\) 437 Unwanted site (\S+) in path$/o) {
- my ($server, $site) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_uw_site{$server}++;
- # $innxmit_site_path{$site}++;
- return 1;
- }
- # 437 Unwanted newsgroup "..."
- if ($left =~
- /(\S+) rejected [^\s]+ \(.*?\) 437 Unwanted newsgroup \"(\S+)\"$/o) {
- my ($server, $group) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_uw_ng_s{$server}++;
- $innxmit_uw_ng{$group}++;
- return 1;
- }
- # 437 Unwanted distribution "..."
- if ($left =~
- /(\S+) rejected [^\s]+ \(.*?\) 437 Unwanted distribution \"(\S+)\"$/o) {
- my ($server, $dist) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_uw_dist_s{$server}++;
- $innxmit_uw_dist{$dist}++;
- return 1;
- }
- # xx rejected foo.bar/12345 (foo/bar/12345) 437 Unwanted distribution "..."
- if ($left =~ /^(\S+) rejected .* 437 Unwanted distribution \"(\S+)\"$/o) {
- my ($server, $dist) = ($1, $2);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_uw_dist_s{$server}++;
- $innxmit_uw_dist{$dist}++;
- return 1;
- }
- # 437 Linecount x != y +- z
- if ($left =~ /(\S+) rejected [^\s]+ \(.*?\) 437 Linecount/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_badart{$server}++;
- $innxmit_linecount{$server}++;
- return 1;
- }
- # 437 Newsgroup name illegal -- "xxx"
- if ($left =~ /(\S+) rejected .* 437 Newsgroup name illegal -- "[^\"]*"$/) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_others{$server}++;
- $innxmit_badart{$server}++;
- return 1;
- }
- # Streaming retries
- return 1 if ($left =~ /\d+ Streaming retries$/o);
- # ihave failed
- if ($left =~ /(\S+) ihave failed/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_ihfail{$server} = 1;
- if ($left = /436 \S+ NNTP \S+ out of space/o) {
- $innxmit_nospace{$server}++;
- return 1;
- }
- if ($left = /400 \S+ space/o) {
- $innxmit_nospace{$server}++;
- return 1;
- }
- if ($left = /400 Bad file/o) {
- $innxmit_crefused{$server}++;
- return 1;
- }
- if ($left = /480 Transfer permission denied/o) {
- $innxmit_crefused{$server}++;
- return 1;
- }
- }
- # stats (new format)
- if ($left =~
- /(\S+) stats offered (\d+) accepted (\d+) refused (\d+) rejected (\d+) missing (\d+) accsize (\d+) rejsize (\d+)$/o) {
- my ($server, $offered, $accepted, $refused, $rejected, $missing, $accbytes, $rejbytes) =
- ($1, $2, $3, $4, $5, $6, $7, $8);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_offered{$server} += $offered;
- $innxmit_offered{$server} -= $innxmit_ihfail{$server}
- if ($innxmit_ihfail{$server});
- $innxmit_accepted{$server} += $accepted;
- $innxmit_refused{$server} += $refused;
- $innxmit_rejected{$server} += $rejected;
- $innxmit_missing{$server} += $missing;
- $innxmit_accepted_size{$server} += $accbytes;
- $innxmit_rejected_size{$server} += $rejbytes;
- $innxmit_site{$server}++;
- $innxmit_ihfail{$server} = 0;
- return 1;
- }
- # stats
- if ($left =~
- /(\S+) stats offered (\d+) accepted (\d+) refused (\d+) rejected (\d+)$/o) {
- my ($server, $offered, $accepted, $refused, $rejected) =
- ($1, $2, $3, $4, $5);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_offered{$server} += $offered;
- $innxmit_offered{$server} -= $innxmit_ihfail{$server}
- if ($innxmit_ihfail{$server});
- $innxmit_accepted{$server} += $accepted;
- $innxmit_refused{$server} += $refused;
- $innxmit_rejected{$server} += $rejected;
- $innxmit_site{$server}++;
- $innxmit_ihfail{$server} = 0;
- return 1;
- }
- # times
- if ($left =~ /(\S+) times user (\S+) system (\S+) elapsed (\S+)$/o) {
- my ($server, $user, $system, $elapsed) = ($1, $2, $3, $4);
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_times{$server} += $elapsed;
- return 1;
- }
- # connect & no space
- if ($left =~ /(\S+) connect \S+ 400 No space/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_nospace{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- # connect & NNTP no space
- if ($left =~ /(\S+) connect \S+ 400 \S+ out of space/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_nospace{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- # connect & loadav
- if ($left =~ /(\S+) connect \S+ 400 loadav/o) {
- my $server = $1;
- if ($left =~ /expir/i) {
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_expire{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- }
- # connect 400 (other)
- if ($left =~ /(\S+) connect \S+ 400/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_crefused{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- # connect failed
- if ($left =~ /(\S+) connect failed/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_cfail_host{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- # authenticate failed
- if ($left =~ /(\S+) authenticate failed/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_afail_host{$server}++;
- $innxmit_site{$server}++;
- return 1;
- }
- # xxx ihave failed 400 loadav [innwatch:hiload] yyy gt zzz
- if ($left =~ /^(\S+) ihave failed 400 loadav/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $innxmit_hiload{$server}++;
- return 1;
- }
- # ihave failed
- return 1 if ($left =~ /\S+ ihave failed/o);
- # requeued (....) 436 No space
- return 1 if ($left =~ /\S+ requeued \S+ 436 No space/o);
- # requeued (....) 400 No space
- return 1 if ($left =~ /\S+ requeued \S+ 400 No space/o);
- # requeued (....) 436 Can't write history
- return 1 if ($left =~ /\S+ requeued \S+ 436 Can\'t write history/o);
- # unexpected response code
- return 1 if ($left =~ /unexpected response code /o);
- }
-
- ########
- ## nntplink
- if ($prog eq "nntplink") {
- $left =~ s/^(\S+):/$1/;
- # EOF
- if ($left =~ /(\S+) EOF /o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_eof{$server}++;
- return 1;
- }
- # Broken pipe
- if ($left =~ /(\S+) Broken pipe$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_bpipe{$server}++;
- return 1;
- }
- # already running - won't die
- return 1 if $left =~ /\S+ nntplink.* already running /o;
- # connection timed out
- if ($left =~ /(\S+) connection timed out/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_bpipe{$server}++;
- return 1;
- }
- # greeted us with 400 No space
- if ($left =~ /(\S+) greeted us with 400 No space/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_nospace{$server}++;
- return 1;
- }
- # greeted us with 400 loadav
- if ($left =~ /(\S+) greeted us with 400 loadav/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_hiload{$server}++;
- return 1;
- }
- # greeted us with 400 (other)
- if ($left =~ /(\S+) greeted us with 400/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- if ($left =~ /expir/i) {
- $nntplink_expire{$server}++;
- } else {
- $nntplink_fail{$server}++;
- }
- return 1;
- }
- # greeted us with 502
- if ($left =~ /(\S+) greeted us with 502/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_auth{$server}++;
- return 1;
- }
- # sent authinfo
- if ($left =~ /(\S+) sent authinfo/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_auth{$server}++;
- return 1;
- }
- # socket()
- if ($left =~ /(\S+) socket\(\): /o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_sockerr{$server}++;
- return 1;
- }
- # select()
- if ($left =~ /(\S+) select\(\) /o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_site{$server}++;
- $nntplink_selecterr{$server}++;
- return 1;
- }
- # sent IHAVE
- if ($left =~ /(\S+) sent IHAVE/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_ihfail{$server}++;
- if (($left =~ / 436 /) && ($left =~ / out of space /)) {
- $nntplink_fake_connects{$server}++;
- $nntplink_nospace{$server}++;
- }
- return 1;
- }
- # article .... failed(saved): 436 No space
- if ($left =~ /(\S+) .* failed\(saved\): 436 No space$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_nospace{$server}++;
- return 1;
- }
- # article .. 400 No space left on device writing article file -- throttling
- if ($left =~ /(\S+) .* 400 No space left on device writing article file -- throttling$/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_nospace{$server}++;
- return 1;
- }
- # stats
- if ($left =~ /(\S+) stats (\d+) offered (\d+) accepted (\d+) rejected (\d+) failed (\d+) connects$/o) {
- my ($server, $offered, $accepted, $rejected, $failed, $connects) =
- ($1, $2, $3, $4, $5, $6);
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_offered{$server} += $offered - $nntplink_ihfail{$server}++;
- $nntplink_accepted{$server} += $accepted;
- $nntplink_rejected{$server} += $rejected;
- $nntplink_failed{$server} += $failed;
- $nntplink_connects{$server} += $connects;
- $nntplink_ihfail{$server} = 0;
- if ($nntplink_fake_connects{$server}) {
- $nntplink_site{$server} += $nntplink_fake_connects{$server};
- $nntplink_fake_connects{$server} = 0;
- } else {
- $nntplink_site{$server}++;
- }
- return 1;
- }
- # xmit
- if ($left =~ /(\S+) xmit user (\S+) system (\S+) elapsed (\S+)$/o) {
- my ($server, $user, $system, $elapsed) = ($1, $2, $3, $4);
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_times{$server} += $elapsed;
- return 1;
- }
- # xfer
- return 1 if $left =~ /\S+ xfer/o;
- # Links down .. x hours
- if ($left =~ /(\S+) Links* down \S+ \d+/o) {
- # Collected but not used
- # my $server = $1;
- # $server = lc $server unless $CASE_SENSITIVE;
- # $nntplink_down{$server} += $hours;
- return 1;
- }
- # 503 Timeout
- if ($left =~ /^(\S+) \S+ \S+ \S+ 503 Timeout/o) {
- # Collected but not used
- # my $server = $1;
- # $server = lc $server unless $CASE_SENSITIVE;
- # $nntplink_timeout{$server}++;
- return 1;
- }
- # read() error while reading reply
- if ($left =~ /^(\S+): read\(\) error while reading reply/o) {
- my $server = $1;
- $server = lc $server unless $CASE_SENSITIVE;
- $nntplink_failed{$server}++;
- return 1;
- }
- # Password file xxxx not found
- return 1 if $left =~ /^\S+ Password file \S+ not found/;
- # No such
- return 1 if $left =~ /^\S+ \S+ \S+ No such/;
- # already running
- return 1 if $left =~ /^\S+ \S+ already running/;
- # error reading version from datafile
- return 1 if $left =~ /error reading version from datafile/;
- }
- ########
- ## nnrpd
- if ($prog =~ /^nnrpd(?:-ssl)?$/)
- {
- # Fix a small bug of nnrpd (inn 1.4*)
- $left =~ s/^ /\? /o;
- # Another bug (in INN 1.5b1)
- return 1 if $left =~ /^\020\002m$/o; # ^P^Bm
- # bad_history at num for <ref>
- return 1 if $left =~ /bad_history at \d+ for /o;
- # timeout short
- return 1 if $left =~ /\S+ timeout short$/o;
- # < or > + (blablabla)
- return 1 if $left =~ /^\S+ [\<\>] /o;
- # cant opendir ... I/O error
- return 1 if $left =~ /\S+ cant opendir \S+ I\/O error$/o;
- # perl filtering enabled
- return 1 if $left =~ /perl filtering enabled$/o;
- # Python filtering enabled
- return 1 if $left =~ /Python filtering enabled$/o;
- return 1 if $left =~ /^python interpreter initialized OK$/o;
- return 1 if $left =~ /^python method \S+ not found$/o;
- return 1 if $left =~ /^python authenticate method succeeded, return code \d+, error string /o;
- return 1 if $left =~ /^python access method succeeded$/o;
- return 1 if $left =~ /^python dynamic method \(\w+ access\) succeeded, refusion string: /o;
- return 1 if $left =~ /^python: .+ module successfully hooked into nnrpd$/o;
- return 1 if $left =~ /^python: nnrpd .+ class instance created$/o;
- return 1 if $left =~ /^python: n_a authenticate\(\) invoked: hostname \S+, ipaddress \S+, interface \S+, user /o;
- return 1 if $left =~ /^python: n_a access\(\) invoked: hostname \S+, ipaddress \S+, interface \S+, user /o;
- return 1 if $left =~ /^python: n_a dynamic\(\) invoked against type \S+, hostname \S+, ipaddress \S+, interface \S+, user /o;
- return 1 if $left =~ /^python: authentication by username succeeded$/o;
- return 1 if $left =~ /^python: authentication by username failed$/o;
- return 1 if $left =~ /^python: authentication access by IP address succeeded$/o;
- return 1 if $left =~ /^python: authentication access by IP address failed$/o;
- return 1 if $left =~ /^python: dynamic access module successfully hooked into nnrpd$/o;
- return 1 if $left =~ /^python: dynamic authorization access for read access granted$/o;
- return 1 if $left =~ /^python: dynamic authorization access type is not known: /o;
- # connect
- if ($left =~ /(\S+) (\([0-9a-fA-F:.]*\) )?connect$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_connect{$dom}++;
- $nnrpd_connect{$cust}++;
- return 1;
- }
- # group
- if ($left =~ /(\S+) group (\S+) (\d+)$/o) {
- my ($cust, $group, $num) = ($1, $2, $3);
- if ($num) {
- $nnrpd_group{$group} += $num;
- my ($hierarchy) = $group =~ /^([^\.]+).*$/o;
- $nnrpd_hierarchy{$hierarchy} += $num;
- }
- return 1;
- }
- # post failed
- if ($left =~ /(\S+) post failed (.*)$/o) {
- my ($cust, $error) = ($1, $2);
- $nnrpd_post_error{$error}++;
- return 1;
- }
- # post ok
- return 1 if $left =~ /\S+ post ok/o;
- # posts
- if ($left =~ /(\S+) posts received (\d+) rejected (\d+)$/o) {
- my ($cust, $received, $rejected) = ($1, $2, $3);
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_post_ok{$dom} += $received;
- $nnrpd_dom_post_rej{$dom} += $rejected;
- $nnrpd_post_ok{$cust} += $received;
- $nnrpd_post_rej{$cust} += $rejected;
- return 1;
- }
- # noperm post without permission
- if ($left =~ /(\S+) noperm post without permission/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_post_rej{$dom} ++;
- $nnrpd_post_rej{$cust} ++;
- return 1;
- }
- # no_permission
- if ($left =~ /(\S+) no_(permission|access)$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_no_permission{$cust}++;
- $nnrpd_dom_no_permission{$dom}++;
- return 1;
- }
- # bad_auth
- if ($left =~ /(\S+) bad_auth$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_no_permission{$dom}++;
- $nnrpd_no_permission{$cust}++;
- return 1;
- }
- # Authentication failure
- # User not known to the underlying authentication module
- return 1 if $left =~ / ckpasswd: pam_authenticate failed: /o;
- return 1 if $left =~ / ckpasswd: user .+ unknown$/o;
- # authinfo
- if ($left =~ /\S+ user (\S+)$/o) {
- my $user = $1;
- $nnrpd_auth{$user}++;
- return 1;
- }
- # unrecognized + command
- if ($left =~ /(\S+) unrecognized (.*)$/o) {
- my ($cust, $error) = ($1, $2);
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $error = "_null command_" if ($error !~ /\S/);
- $error =~ s/^(xmotd) .*$/$1/i if ($error =~ /^xmotd .*$/i);
- $nnrpd_dom_unrecognized{$dom}++;
- $nnrpd_unrecognized{$cust}++;
- $nnrpd_unrecogn_cmd{$error}++;
- return 1;
- }
- # exit
- if ($left =~ /(\S+) exit articles (\d+) groups (\d+)$/o) {
- my ($cust, $articles, $groups) = ($1, $2, $3);
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust) || '?';
- $nnrpd_connect{$cust}++, $nnrpd_dom_connect{$dom}++ if $cust eq '?';
- $nnrpd_groups{$cust} += $groups;
- $nnrpd_dom_groups{$dom} += $groups;
- $nnrpd_articles{$cust} += $articles;
- $nnrpd_dom_articles{$dom} += $articles;
- return 1;
- }
- # times
- if ($left =~ /(\S+) times user (\S+) system (\S+) idle (\S+) elapsed (\S+)$/o) {
- my ($cust, $user, $system, $idle, $elapsed) = ($1, $2, $3, $4, $5);
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_times{$cust} += $elapsed;
- $nnrpd_resource_user{$cust} += $user;
- $nnrpd_resource_system{$cust} += $system;
- $nnrpd_resource_idle{$cust} += $idle;
- $nnrpd_resource_elapsed{$cust} += $elapsed;
- $nnrpd_dom_times{$dom} += $elapsed;
- return 1;
- }
- # artstats
- if ($left =~ /(\S+) artstats get (\d+) time (\d+) size (\d+)$/o) {
- my ($cust, $articles, $time, $bytes) = ($1, $2, $3, $4);
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_bytes{$cust} += $bytes;
- $nnrpd_dom_bytes{$dom} += $bytes;
- return 1;
- }
- # timeout
- if ($left =~ /(\S+) timeout$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_timeout{$dom}++;
- $nnrpd_timeout{$cust}++;
- return 1;
- }
- # timeout in post
- if ($left =~ /(\S+) timeout in post$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_timeout{$dom}++;
- $nnrpd_timeout{$cust}++;
- return 1;
- }
- # can't read: Connection timed out
- if ($left =~ /(\S+) can\'t read: Connection timed out$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_timeout{$dom}++;
- $nnrpd_timeout{$cust}++;
- return 1;
- }
- # can't read: Operation timed out
- if ($left =~ /(\S+) can\'t read: Operation timed out$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_timeout{$dom}++;
- $nnrpd_timeout{$cust}++;
- return 1;
- }
- # can't read: Connection reset by peer
- if ($left =~ /(\S+) can\'t read: Connection reset by peer$/o) {
- my $cust = $1;
- $cust = lc $cust unless $CASE_SENSITIVE;
- my $dom = &host2dom($cust);
- $nnrpd_dom_reset_peer{$dom}++;
- $nnrpd_reset_peer{$cust}++;
- return 1;
- }
- # can't read: Network is unreachable
- return 1 if $left =~ /(\S+) can\'t read: Network is unreachable$/o;
- # gethostbyaddr: xxx.yyy.zzz != a.b.c.d
- if ($left =~ /^gethostbyaddr: (.*)$/o) {
- my $msg = $1;
- $nnrpd_gethostbyaddr{$msg}++;
- return 1;
- }
- # cant gethostbyaddr
- if ($left =~ /\? cant gethostbyaddr (\S+) .*$/o) {
- my $ip = $1;
- $nnrpd_gethostbyaddr{$ip}++;
- return 1;
- }
- # cant getpeername
- if ($left =~ /\? cant getpeername/o) {
- # $nnrpd_getpeername++;
- $nnrpd_gethostbyaddr{"? (can't getpeername)"}++;
- return 1;
- }
- # can't getsockname
- return 1 if $left =~ /^\S+ can\'t getsockname$/o;
- # reverse lookup failed
- return 1 if $left =~ /^\? reverse lookup for \S+ failed: .* -- using IP address for access$/o;
- # profile timer
- # ME time X nnnn X(X) [...]
- # The exact timers change from various versions of INN, so try to deal
- # with this in a general fashion.
- if ($left =~ m/^\S+\s+ # ME
- time\s(\d+)\s+ # time
- ((?:\S+\s\d+\(\d+\)\s*)+) # timer values
- $/ox) {
- $nnrpd_time_times += $1;
- my $timers = $2;
-
- while ($timers =~ /(\S+) (\d+)\((\d+)\)\s*/g) {
- my $name = $nnrpd_timer_names{$1} || $1;
- my $average = $2 / ($3 || 1);
- $nnrpd_time_time{$name} += $2;
- $nnrpd_time_num{$name} += $3;
- if ($3) {
- my $min = $nnrpd_time_min{$name};
- $nnrpd_time_min{$name} = $average
- if (defined($min) && $min > $average);
- my $max = $nnrpd_time_max{$name};
- $nnrpd_time_max{$name} = $average
- if (defined($max) && $max < $average);
- }
- }
- return 1;
- }
- # ME dropping articles into ...
- return 1 if $left =~ /ME dropping articles into /o;
- # newnews (interesting but ignored till now)
- return 1 if $left =~ /^\S+ newnews /o;
- # cant fopen (ignored too)
- return 1 if $left =~ /^\S+ cant fopen /o;
- # can't read: No route to host
- return 1 if $left =~ /can\'t read: No route to host/o;
- # can't read: Broken pipe
- return 1 if $left =~ /can\'t read: Broken pipe/o;
- # eof in post
- return 1 if $left =~ /^\S+ eof in post$/o;
- # ioctl: ...
- return 1 if $left =~ /^ioctl: /o;
- # other stats
- return 1 if $left =~ /^\S+ overstats count \d+ hit \d+ miss \d+ time \d+ size \d+ dbz \d+ seek \d+ get \d+ artcheck \d+$/o;
- # starttls
- return 1 if $left =~ /^starttls: \S+ with cipher \S+ \(\d+\/\d+ bits\) no authentication$/o;
- }
- ########
- ## inndstart
- if ($prog eq "inndstart") {
- # cant bind Address already in use
- # cant bind Permission denied
- return 1 if $left =~ /cant bind /o;
- # cant setgroups Operation not permitted
- return 1 if $left =~ /cant setgroups /o;
- }
- ########
- ## overchan
- if ($prog eq "overchan") {
- # times
- if ($left =~ /timings (\d+) arts (\d+) of (\d+) ms$/o) {
- my ($articles, $work_time, $run_time) = ($1, $2, $3);
- # ??? What to do with numbers
- return 1;
- }
- }
- ########
- ## batcher
- if ($prog eq "batcher") {
- # times
- if ($left =~ /(\S+) times user (\S+) system (\S+) elapsed (\S+)$/o) {
- my ($server, $user, $system, $elapsed) = ($1, $2, $3, $4);
- $server = lc $server unless $CASE_SENSITIVE;
- # $batcher_user{$server} += $user;
- # $batcher_system{$server} += $system;
- $batcher_elapsed{$server} += $elapsed;
- return 1;
- }
- # stats
- if ($left =~ /(\S+) stats batches (\d+) articles (\d+) bytes (\d+)$/o) {
- my ($server, $batches, $articles, $bytes) = ($1, $2, $3, $4);
- $server = lc $server unless $CASE_SENSITIVE;
- $batcher_offered{$server} += $batches;
- $batcher_articles{$server} += $articles;
- $batcher_bytes{$server} += $bytes;
- return 1;
- }
- }
- ########
- ## rnews
- if ($prog eq "rnews") {
- # rejected connection
- if ($left =~ /rejected connection (.*)$/o) {
- $rnews_rejected{$1}++;
- return 1;
- }
- # cant open_remote
- if ($left =~ /(cant open_remote .*)$/o) {
- $rnews_rejected{$1}++;
- return 1;
- }
- # rejected 437 Unwanted newsgroup
- if ($left =~ /rejected 437 Unwanted newsgroup \"(.*)\"$/o) {
- $rnews_bogus_ng{$1}++;
- return 1;
- }
- # rejected 437 Unapproved for "xx"
- if ($left =~ /rejected 437 Unapproved for \"(.*)\"$/o) {
- $rnews_unapproved{$1}++;
- return 1;
- }
- # rejected 437 Unwanted distribution
- if ($left =~ /rejected 437 Unwanted distribution (.*)$/o) {
- $rnews_bogus_dist{$1}++;
- return 1;
- }
- # rejected 437 Bad "Date"
- if ($left =~ /rejected 437 Bad \"Date\" (.*)$/o) {
- $rnews_bogus_date{$1}++;
- return 1;
- }
- # rejected 437 Article posted in the future
- if ($left =~ /rejected 437 Article posted in the future -- \"(.*)\"$/o) {
- $rnews_bogus_date{"(future) $1"}++;
- return 1;
- }
- # rejected 437 Too old -- "..."
- if ($left =~ /rejected 437 Too old -- (.*)$/o) {
- $rnews_too_old++;
- return 1;
- }
- # rejected 437 Linecount...
- if ($left =~ /rejected 437 (Linecount) \d+ \!= \d+/o) {
- $rnews_linecount++;
- return 1;
- }
- # rejected 437 Duplicate
- if ($left =~ /rejected 437 Duplicate$/o) {
- $rnews_duplicate++;
- return 1;
- }
- # rejected 437 Duplicate article
- if ($left =~ /rejected 437 (Duplicate article)/o) {
- $rnews_duplicate++;
- return 1;
- }
- # rejected 437 No colon-space ...
- if ($left =~ /rejected 437 No colon-space in \"(.*)\" header$/o) {
- $rnews_no_colon_space++;
- return 1;
- }
- # duplicate <msg-id> path..
- if ($left =~ /^duplicate /o) {
- $rnews_duplicate++;
- return 1;
- }
- # offered <msg-id> feed
- if ($left =~ /^offered \S+ (\S+)/o) {
- my $host = $1;
- $host = lc $host unless $CASE_SENSITIVE;
- # Small hack used to join article spooled when innd is throttle.
- # In this situation, the hostname is a 8 hex digits string
- # To avoid confusions with real feeds, the first character is forced
- # to be a '3' or a '4' (will work between 9/7/1995 and 13/7/2012).
- $host = "Local postings" if $host =~ /^[34][0-9a-f]{7}$/;
- $rnews_host{$host}++;
- return 1;
- }
- # rejected 437 ECP rejected
- return 1 if $left =~ m/rejected 437 ECP rejected/o;
- # rejected 437 "Subject" header too long
- return 1 if $left =~ m/header too long/o;
- # rejected 437 Too long line in header 1163 bytes
- return 1 if $left =~ m/rejected 437 Too long line in header/o;
- # rejected 437 Too many newsgroups (meow)
- return 1 if $left =~ m/rejected 437 Too many newsgroups/o;
- # rejected 437 Space before colon in "<a" header
- return 1 if $left =~ m/rejected 437 Space before colon in/o;
- # rejected 437 EMP (phl)
- return 1 if $left =~ m/rejected 437 EMP/o;
- # rejected 437 Scoring filter (8)
- return 1 if $left =~ m/rejected 437 Scoring filter/o;
- # bad_article missing Message-ID
- return 1 if $left =~ m/bad_article missing Message-ID/o;
- # cant unspool saving to xxx
- return 1 if $left =~ m/cant unspool saving to/o;
- }
-
- ###########
- ## ncmspool
- if ($prog eq "ncmspool") {
- # <article> good signature from foo@bar.com
- if ($left =~ /good signature from (.*)/o) {
- $nocem_goodsigs{$1}++;
- $nocem_totalgood++;
- $nocem_lastid = $1;
- return 1;
- }
- # <article> bad signature from foo@bar.com
- if ($left =~ /bad signature from (.*)/o) {
- $nocem_badsigs{$1}++;
- $nocem_goodsigs{$1} = 0 unless ($nocem_goodsigs{$1});
- $nocem_totalbad++;
- $nocem_lastid = $1;
- return 1;
- }
- # <article> contained 123 new 456 total ids
- if ($left =~ /contained (\d+) new (\d+) total ids/o) {
- $nocem_newids += $1;
- $nocem_newids{$nocem_lastid} += $1;
- $nocem_totalids += $2;
- $nocem_totalids{$nocem_lastid} += $2;
- return 1;
- }
- return 1;
- }
-
- ########
- ## nocem
- if ($prog eq "nocem") {
- if ($left =~ /processed notice .* by (.*) \((\d+) ids,/o) {
- $nocem_goodsigs{$1}++;
- $nocem_totalgood++;
- $nocem_lastid = $1;
- $nocem_newids += $2;
- $nocem_newids{$nocem_lastid} += $2;
- $nocem_totalids += $2;
- $nocem_totalids{$nocem_lastid} += $2;
- return 1;
- }
- if ($left =~ /Article <[^>]*>: (.*) \(ID [[:xdigit:]]*\) not in keyring/o) {
- $nocem_badsigs{$1}++;
- $nocem_goodsigs{$1} = 0 unless ($nocem_goodsigs{$1});
- $nocem_totalbad++;
- $nocem_lastid = $1;
- return 1;
- }
- if ($left =~ /Article <[^>]*>: bad signature from (.*)/o) {
- $nocem_badsigs{$1}++;
- $nocem_goodsigs{$1} = 0 unless ($nocem_goodsigs{$1});
- $nocem_totalbad++;
- $nocem_lastid = $1;
- return 1;
- }
- if ($left =~ /Article <[^>]*>: malformed signature/o) {
- $nocem_badsigs{'N/A'}++;
- $nocem_goodsigs{'N/A'} = 0 unless ($nocem_goodsigs{'N/A'});
- $nocem_totalbad++;
- $nocem_lastid = 'N/A';
- return 1;
- }
-
- return 1;
- }
-
- ###########
- ## controlchan
- if ($prog eq "controlchan") {
- # loaded /x/y/z/foo.pl
- return 1 if $left =~ m/^loaded /;
- # starting
- return 1 if $left =~ m/^starting/;
- # skipping rmgroup x@y (pgpverify failed) in <foo@bar>
- if ($left =~ m/^skipping \S+ (\S+) \(pgpverify failed\) in /) {
- $controlchan_skippgp{$1}++;
- $controlchan_who{$1}++;
- return 1;
- }
- if ($left =~ m/^control_(sendme|ihave), [^,]+, (\S+), doit,/o) {
- if ($1 eq "sendme") {
- $controlchan_sendme_site{$2}++;
- } else {
- $controlchan_ihave_site{$2}++;
- }
- return 1;
- }
- # control_XXgroup, foo.bar [moderated] who who /x/y/12, peer, action, 1
- #
- # Various other random junk can end up in the moderated field, like y,
- # unmoderated, m, etc. depending on what the control message says. It
- # can even have multiple words, which we still don't handle.
- if ($left =~ m/^control_(\S+), # type of msg
- \s(?:\S+)? # newsgroup name
- (\s\S+)? # optional
- \s(\S+) # e-mail
- \s\S+ # e-mail
- \s\S+, # filename
- \s\S+, # server
- \s([^=,]+(?:=\S+)?), # action
- \s*(.*) # code
- /x) {
- if ($1 eq 'newgroup') {
- $controlchan_new{$3}++;
- } elsif ($1 eq 'rmgroup') {
- $controlchan_rm{$3}++;
- } else {
- $controlchan_other{$3}++;
- }
- $controlchan_who{$3}++;
- $controlchan_ok{$3} += $5;
- my $action = $4;
- my $email = $3;
- $action =~ s/=.*//;
- $controlchan_doit{$email}++ if $action eq 'doit';
- return 1;
- }
- # checkgroups processed (no change or not)
- return 1 if $left =~ /^checkgroups by \S+ processed/o;
- }
-
- ###########
- ## crosspost
- if ($prog eq "crosspost") {
- # seconds 1001 links 3182 0 symlinks 0 0 mkdirs 0 0
- # missing 13 toolong 0 other 0
- if ($left =~ /^seconds\ (\d+)
- \ links\ (\d+)\ (\d+)
- \ symlinks\ (\d+)\ (\d+)
- \ mkdirs\ (\d+)\ (\d+)
- \ missing\ (\d+)
- \ toolong\ (\d+)
- \ other\ (\d+)
- $/ox) {
- $crosspost_time += $1;
- $crosspost{'Links made'} += $2;
- $crosspost{'Links failed'} += $3;
- $crosspost{'Symlinks made'} += $4;
- $crosspost{'Symlinks failed'} += $5;
- $crosspost{'Mkdirs made'} += $6;
- $crosspost{'Mkdirs failed'} += $7;
- $crosspost{'Files missing'} += $8;
- $crosspost{'Paths too long'} += $9;
- $crosspost{'Others'} += $10;
- return 1;
- }
- }
-
- ###########
- ## cnfsstat
- if ($prog eq "cnfsstat") {
- # Class ALT for groups matching "alt.*" article size min/max: 0/1048576
- # Buffer T3, len: 1953 Mbytes, used: 483.75 Mbytes (24.8%) 0 cycles
- if ($left =~ m|^Class\ (\S+)\ for\ groups\ matching\ \S+
- (\ article\ size\ min/max:\ \d+/\d+)?
- \ Buffer\ (\S+),
- \ len:\ ([\d.]+)\s+Mbytes,
- \ used:\ ([\d.]+)\ Mbytes\ \(\s*[\d.]+%\)
- \s+(\d+)\ cycles\s*
- $|ox) {
- my ($class, $buffer, $size, $used, $cycles) = ($1, $3, $4, $5, $6);
- my ($h, $m, $s) = $hour =~ m/^(\d+):(\d+):(\d+)$/;
- my $time = $h * 3600 + $m * 60 + $s;
- $size *= 1024 * 1024;
- $used *= 1024 * 1024;
- $cnfsstat{$buffer} = $class;
-
- # If the size changed, invalidate all of our running fill rate stats.
- if (!exists($cnfsstat_size{$buffer}) || $size != $cnfsstat_size{$buffer}) {
- delete $cnfsstat_rate{$buffer};
- delete $cnfsstat_samples{$buffer};
- delete $cnfsstat_time{$buffer};
- $cnfsstat_size{$buffer} = $size;
- }
- elsif ($cnfsstat_time{$buffer}) {
- # We want to gather the rate at which cycbuffs fill. Store a
- # running total of bytes/second and a total number of samples.
- # Ideally we'd want a weighted average of those samples by the
- # length of the sample period, but we'll ignore that and assume
- # cnfsstat runs at a roughly consistent interval.
- my ($period, $added);
- $period = $time - $cnfsstat_time{$buffer};
- $period = 86400 - $cnfsstat_time{$buffer} + $time if $period <= 0;
- $added = $used - $cnfsstat_used{$buffer};
- if ($cycles > $cnfsstat_cycles{$buffer}) {
- $added += $size * ($cycles - $cnfsstat_cycles{$buffer});
- }
- if ($added > 0) {
- $cnfsstat_rate{$buffer} += $added / $period;
- $cnfsstat_samples{$buffer}++;
- }
- }
- $cnfsstat_used{$buffer} = $used;
- $cnfsstat_cycles{$buffer} = $cycles;
- $cnfsstat_time{$buffer} = $time;
- return 1;
- }
- }
-
- # Ignore following programs :
- return 1 if ($prog eq "uxfxn");
- return 1 if ($prog eq "beverage");
- return 1 if ($prog eq "newsx");
- return 1 if ($prog eq "demmf");
- return 1 if ($prog eq "nnnn");
- return 1 if ($prog eq "slurp");
- return 0;
-}
-
-#################################
-# Adjust some values..
-
-sub adjust {
- my ($first_date, $last_date) = @_;
-
- my $nnrpd_doit = 0;
- my $curious;
-
- {
- my $serv;
- if (%nnrpd_connect) {
- my $c = keys (%nnrpd_connect);
- foreach $serv (keys (%nnrpd_connect)) {
- my $dom = &host2dom($serv);
- if ($nnrpd_no_permission{$serv}) {
- $nnrpd_dom_connect{$dom} -= $nnrpd_connect{$serv}
- if defined $nnrpd_dom_connect{$dom} && defined $nnrpd_connect{$serv};
- $nnrpd_dom_groups{$dom} -= $nnrpd_groups{$serv}
- if defined $nnrpd_dom_groups{$dom} && defined $nnrpd_groups{$serv};
- $nnrpd_dom_times{$dom} -= $nnrpd_times{$serv}
- if defined $nnrpd_dom_times{$dom};
- $nnrpd_connect{$serv} -= $nnrpd_no_permission{$serv};
- $nnrpd_groups{$serv} -= $nnrpd_no_permission{$serv}
- if defined $nnrpd_groups{$serv};
- delete $nnrpd_connect{$serv} unless $nnrpd_connect{$serv};
- delete $nnrpd_groups{$serv} unless $nnrpd_groups{$serv};
- delete $nnrpd_times{$serv} unless $nnrpd_times{$serv};
- delete $nnrpd_usr_times{$serv} unless $nnrpd_usr_times{$serv};
- delete $nnrpd_sys_times{$serv} unless $nnrpd_sys_times{$serv};
- delete $nnrpd_dom_connect{$dom} unless $nnrpd_dom_connect{$dom};
- delete $nnrpd_dom_groups{$dom} unless $nnrpd_dom_groups{$dom};
- delete $nnrpd_dom_times{$dom} unless $nnrpd_dom_times{$dom};
- $c--;
- }
- $nnrpd_doit++
- if $nnrpd_groups{$serv} || $nnrpd_post_ok{$serv};
- }
- undef %nnrpd_connect unless $c;
- }
- foreach $serv (keys (%nnrpd_groups)) {
- $curious = "ok" unless $nnrpd_groups{$serv} || $nnrpd_post_ok{$serv} ||
- $nnrpd_articles{$serv};
- }
- }
-
- # Fill some hashes
- {
- my $key;
- foreach $key (keys (%innd_connect)) {
- $innd_offered{$key} = ($innd_accepted{$key} || 0)
- + ($innd_refused{$key} || 0)
- + ($innd_rejected{$key} || 0);
- $innd_offered_size{$key} = ($innd_stored_size{$key} || 0)
- + ($innd_duplicated_size{$key} || 0);
- }
-
-
- # adjust min/max of innd timer stats.
- if (%innd_time_min) {
- foreach $key (keys (%innd_time_min)) {
- $innd_time_min{$key} = 0 if ($innd_time_min{$key} == $MIN);
- $innd_time_max{$key} = 0 if ($innd_time_max{$key} == $MAX);
-
- #$innd_time_min{$key} /= 1000;
- #$innd_time_max{$key} /= 1000;
- }
- }
- if (%innfeed_time_min) {
- foreach $key (keys (%innfeed_time_min)) {
- $innfeed_time_min{$key} = 0 if ($innfeed_time_min{$key} == $MIN);
- $innfeed_time_max{$key} = 0 if ($innfeed_time_max{$key} == $MAX);
- }
- }
- if (%nnrpd_time_min) {
- foreach $key (keys (%nnrpd_time_min)) {
- $nnrpd_time_min{$key} = 0 if ($nnrpd_time_min{$key} == $MIN);
- $nnrpd_time_max{$key} = 0 if ($nnrpd_time_max{$key} == $MAX);
- }
- }
- # remove the innd timer stats if not used.
- unless ($innd_time_times) {
- undef %innd_time_min;
- undef %innd_time_max;
- undef %innd_time_num;
- undef %innd_time_time;
- }
- # same thing for innfeed timer
- unless ($innfeed_time_times) {
- undef %innfeed_time_min;
- undef %innfeed_time_max;
- undef %innfeed_time_num;
- undef %innfeed_time_time;
- }
- # same thing for nnrpd timer
- unless ($nnrpd_time_times) {
- undef %nnrpd_time_min;
- undef %nnrpd_time_max;
- undef %nnrpd_time_num;
- undef %nnrpd_time_time;
- }
-
- # adjust the crosspost stats.
- if (%crosspost) {
- foreach $key (keys (%crosspost)) {
- $crosspost_times{$key} = $crosspost_time ?
- sprintf "%.2f", $crosspost{$key} / $crosspost_time * 60 : "?";
- }
- }
- }
-
- if (%inn_flow) {
- my ($prev_dd, $prev_d, $prev_h) = ("", -1, -1);
- my $day;
- foreach $day (sort datecmp keys (%inn_flow)) {
- my ($r, $h) = $day =~ /^(.*) (\d+)$/;
- my $d = index ("JanFebMarAprMayJunJulAugSepOctNovDec",
- substr ($r,0,3)) / 3 * 31 + substr ($r, 4, 2);
- $prev_h = $h if ($prev_h == -1);
- if ($prev_d == -1) {
- $prev_d = $d;
- $prev_dd = $r;
- }
- if ($r eq $prev_dd) { # Same day and same month ?
- if ($h != $prev_h) {
- if ($h == $prev_h + 1) {
- $prev_h++;
- }
- else {
- my $j;
- for ($j = $prev_h + 1; $j < $h; $j++) {
- my $t = sprintf "%02d", $j;
- $inn_flow{"$r $t"} = 0;
- }
- $prev_h = $h;
- }
- }
- }
- else {
- my $j;
- # then end of the first day...
- for ($j = ($prev_h == 23) ? 24 : $prev_h + 1; $j < 24; $j++) {
- my $t = sprintf "%02d", $j;
- $inn_flow{"$prev_dd $t"} = 0;
- }
-
- # all the days between (if any)
- # well, we can forget them as it is supposed to be a tool
- # launched daily.
-
- # the beginning of the last day..
- for ($j = 0; $j < $h; $j++) {
- my $t = sprintf "%02d", $j;
- $inn_flow{"$r $t"} = 0;
- }
- $prev_dd = $r;
- $prev_d = $d;
- $prev_h = $h;
- }
- }
- my $first = 1;
- my (%hash, %hash_time, %hash_size, $date, $delay);
- foreach $day (sort datecmp keys (%inn_flow)) {
- my ($r, $h) = $day =~ /^(.*) (\d+)$/o;
- if ($first) {
- $first = 0;
- my ($t) = $first_date =~ m/:(\d\d:\d\d)$/o;
- $date = "$day:$t - $h:59:59";
- $t =~ m/(\d\d):(\d\d)/o;
- $delay = 3600 - $1 * 60 - $2;
- }
- else {
- $date = "$day:00:00 - $h:59:59";
- $delay = 3600;
- }
- $hash{$date} = $inn_flow{$day};
- $hash_size{$date} = $inn_flow_size{$day};
- $inn_flow_labels{$date} = $h;
- $hash_time{$date} = $delay;
- }
- my ($h, $t) = $last_date =~ m/ (\d+):(\d\d:\d\d)$/o;
- my ($h2) = $date =~ m/ (\d+):\d\d:\d\d /o;
- my $date2 = $date;
- $date2 =~ s/$h2:59:59$/$h:$t/;
- $hash{$date2} = $hash{$date};
- delete $hash{"$date"};
- $hash_size{$date2} = $hash_size{$date};
- delete $hash_size{"$date"};
- $t =~ m/(\d\d):(\d\d)/o;
- $hash_time{$date2} = $hash_time{$date} - ($h2 == $h) * 3600 + $1 * 60 + $2;
- delete $hash_time{"$date"};
- $inn_flow_labels{$date2} = $h;
- %inn_flow = %hash;
- %inn_flow_time = %hash_time;
- %inn_flow_size = %hash_size;
- }
-
- if (%innd_bad_ihave) {
- my $key;
- my $msg = 'Bad ihave control messages received';
- foreach $key (keys %innd_bad_ihave) {
- $innd_misc_stat{$msg}{$key} = $innd_bad_ihave{$key};
- }
- }
- if (%innd_bad_msgid) {
- my $key;
- my $msg = 'Bad Message-ID\'s offered';
- foreach $key (keys %innd_bad_msgid) {
- $innd_misc_stat{$msg}{$key} = $innd_bad_msgid{$key};
- }
- }
- if (%innd_bad_sendme) {
- my $key;
- my $msg = 'Ignored sendme control messages received';
- foreach $key (keys %innd_bad_sendme) {
- $innd_misc_stat{$msg}{$key} = $innd_bad_sendme{$key};
- }
- }
- if (%innd_bad_command) {
- my $key;
- my $msg = 'Bad command received';
- foreach $key (keys %innd_bad_command) {
- $innd_misc_stat{$msg}{$key} = $innd_bad_command{$key};
- }
- }
- if (%innd_bad_newsgroup) {
- my $key;
- my $msg = 'Bad newsgroups received';
- foreach $key (keys %innd_bad_newsgroup) {
- $innd_misc_stat{$msg}{$key} = $innd_bad_newsgroup{$key};
- }
- }
- if (%innd_posted_future) {
- my $key;
- my $msg = 'Article posted in the future';
- foreach $key (keys %innd_posted_future) {
- $innd_misc_stat{$msg}{$key} = $innd_posted_future{$key};
- }
- }
- if (%innd_no_colon_space) {
- my $key;
- my $msg = 'No colon-space in header';
- foreach $key (keys %innd_no_colon_space) {
- $innd_misc_stat{$msg}{$key} = $innd_no_colon_space{$key};
- }
- }
- if (%innd_huge) {
- my $key;
- my $msg = 'Huge articles';
- foreach $key (keys %innd_huge) {
- $innd_misc_stat{$msg}{$key} = $innd_huge{$key};
- }
- }
- if (%innd_blocked) {
- my $key;
- my $msg = 'Blocked server feeds';
- foreach $key (keys %innd_blocked) {
- $innd_misc_stat{$msg}{$key} = $innd_blocked{$key};
- }
- }
- if (%innd_strange_strings) {
- my $key;
- my $msg = 'Including strange strings';
- foreach $key (keys %innd_strange_strings) {
- $innd_misc_stat{$msg}{$key} = $innd_strange_strings{$key};
- }
- }
- if (%rnews_bogus_ng) {
- my $key;
- my $msg = 'Unwanted newsgroups';
- foreach $key (keys %rnews_bogus_ng) {
- $rnews_misc{$msg}{$key} = $rnews_bogus_ng{$key};
- }
- }
- if (%rnews_bogus_dist) {
- my $key;
- my $msg = 'Unwanted distributions';
- foreach $key (keys %rnews_bogus_dist) {
- $rnews_misc{$msg}{$key} = $rnews_bogus_dist{$key};
- }
- }
- if (%rnews_unapproved) {
- my $key;
- my $msg = 'Articles unapproved';
- foreach $key (keys %rnews_unapproved) {
- $rnews_misc{$msg}{$key} = $rnews_unapproved{$key};
- }
- }
- if (%rnews_bogus_date) {
- my $key;
- my $msg = 'Bad Date';
- foreach $key (keys %rnews_bogus_date) {
- $rnews_misc{$msg}{$key} = $rnews_bogus_date{$key};
- }
- }
-
- $rnews_misc{'Too old'}{'--'} = $rnews_too_old if $rnews_too_old;
- $rnews_misc{'Bad linecount'}{'--'} = $rnews_linecount if $rnews_linecount;
- $rnews_misc{'Duplicate articles'}{'--'} = $rnews_duplicate
- if $rnews_duplicate;
- $rnews_misc{'No colon-space'}{'--'} = $rnews_no_colon_space
- if $rnews_no_colon_space;
-
- if (%nnrpd_groups) {
- my $key;
- foreach $key (keys (%nnrpd_connect)) {
- unless ($nnrpd_groups{"$key"} || $nnrpd_post_ok{"$key"} ||
- $nnrpd_articles{"$key"}) {
- $nnrpd_curious{$key} = $nnrpd_connect{$key};
- undef $nnrpd_connect{$key};
- }
- }
- }
-}
-
-sub report_unwanted_ng {
- my $file = shift;
- open (FILE, "$file") && do {
- while (<FILE>) {
- my ($c, $n) = $_ =~ m/^\s*(\d+)\s+(.*)$/;
- next unless defined $n;
- $n =~ s/^newsgroup //o; # for pre 1.8 logs
- $inn_uw_ng{$n} += $c;
- }
- close (FILE);
- };
-
- unlink ("${file}.old");
- rename ($file, "${file}.old");
-
- open (FILE, "> $file") && do {
- my $g;
- foreach $g (sort {$inn_uw_ng{$b} <=> $inn_uw_ng{$a}} (keys (%inn_uw_ng))) {
- printf FILE "%d %s\n", $inn_uw_ng{$g}, $g;
- }
- close (FILE);
- chmod(0660, "$file");
- };
- unlink ("${file}.old");
-}
-
-###########################################################################
-
-# Compare 2 dates (+hour)
-sub datecmp {
- # ex: "May 12 06" for May 12, 6:00am
- local($[) = 0;
- # The 2 dates are near. The range is less than a few days that's why we
- # can cheat to determine the order. It is only important if one date
- # is in January and the other in December.
-
- my($date1) = substr($a, 4, 2) * 24;
- my($date2) = substr($b, 4, 2) * 24;
- $date1 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($a,0,3)) * 288;
- $date2 += index("JanFebMarAprMayJunJulAugSepOctNovDec",substr($b,0,3)) * 288;
- if ($date1 - $date2 > 300 * 24) {
- $date2 += 288 * 3 * 12;
- }
- elsif ($date2 - $date1 > 300 * 24) {
- $date1 += 288 * 3 * 12;
- }
- $date1 += substr($a, 7, 2);
- $date2 += substr($b, 7, 2);
- $date1 - $date2;
-}
-
-sub host2dom {
- my $host = shift;
-
- $host =~ m/^[^\.]+(.*)/;
- $host =~ m/^[\d\.]+$/ ? "unresolved" : $1 ? "*$1" : "?";
-}
-
-1;
+++ /dev/null
-#!@_PATH_SH@
-## $Revision: 7466 $
-## Set up any and all shell variables that an INN shell script
-## might need. Also sets umask.
-
-## NOTE: When adding stuff here, add the corresponding variables to
-## innshellvars.pl and innshellvars.tcl and innshellvars.csh
-
-eval `@prefix@/bin/innconfval -s`
-
-NEWSHOME=${PATHNEWS}
-SPOOLBASE=${PATHSPOOL}
-MOST_LOGS=${PATHLOG}
-export NEWSHOME SPOOL MOST_LOGS
-
-NEWSBIN=${PATHBIN}
-NEWSETC=${PATHETC}
-NEWSLIB=@LIBDIR@
-INNDDIR=${PATHRUN}
-LOCKS=${PATHRUN}
-export NEWSBIN NEWSETC INNDDIR NEWSHOME
-
-ERRLOG=${MOST_LOGS}/errlog
-LOG=${MOST_LOGS}/news
-
-ARCHIVEDIR=${PATHARCHIVE}
-SPOOL=${PATHARTICLES}
-BATCH=${PATHOUTGOING}
-INCOMING=${PATHINCOMING}
-OVERVIEWDIR=${PATHOVERVIEW}
-SPOOLNEWS=${PATHINCOMING}
-BADNEWS=${PATHINCOMING}/bad
-
-ACTIVE=${PATHDB}/active
-ACTIVETIMES=${PATHDB}/active.times
-CTLFILE=${NEWSETC}/control.ctl
-CTLWATCH=${NEWSETC}/innwatch.ctl
-HISTORY=${PATHDB}/history
-NEWACTIVE=${PATHDB}/active.tmp
-NEWSFEEDS=${NEWSETC}/newsfeeds
-NEWSGROUPS=${PATHDB}/newsgroups
-OLDACTIVE=${PATHDB}/active.old
-PATH_MOTD=${NEWSETC}/motd.news
-EXPIRECTL=${NEWSETC}/expire.ctl
-LOCALGROUPS=${NEWSETC}/localgroups
-
-CONTROLPROGS=${PATHCONTROL}
-INNCONFVAL=${NEWSBIN}/innconfval
-INND=${NEWSBIN}/innd
-INNDSTART=${NEWSBIN}/inndstart
-INNWATCH=${NEWSBIN}/innwatch
-INEWS=${NEWSBIN}/inews
-RNEWS=${NEWSBIN}/rnews
-PERL_STARTUP_INND=${PATHFILTER}/startup_innd.pl
-PERL_FILTER_INND=${PATHFILTER}/filter_innd.pl
-PERL_FILTER_NNRPD=${PATHFILTER}/filter_nnrpd.pl
-PYTHON_FILTER_INND=${PATHFILTER}/filter_innd.py
-PATH_PYTHON_INN_MODULE=${PATHFILTER}/INN.py
-PATH_TCL_STARTUP=${PATHFILTER}/startup.tcl
-PATH_TCL_FILTER=${PATHFILTER}/filter.tcl
-
-DAILY=${LOCKS}/LOCK.news.daily
-
-NEWSCONTROL=${INNDDIR}/control
-NNTPCONNECT=${INNDDIR}/nntpin
-SERVERPID=${INNDDIR}/innd.pid
-INNWSTATUS=${INNDDIR}/innwatch.status
-WATCHPID=${INNDDIR}/innwatch.pid
-
-AWK=@_PATH_AWK@
-SED=@_PATH_SED@
-INNDF=${NEWSBIN}/inndf
-EGREP=@_PATH_EGREP@
-PERL=@_PATH_PERL@
-GPGV=@PATH_GPGV@
-PGP=@_PATH_PGP@
-SORT="@_PATH_SORT@"
-GETFTP="@GETFTP@"
-UUX=@_PATH_UUX@
-
-COMPRESS=@COMPRESS@
-GZIP=@GZIP@
-UNCOMPRESS="@UNCOMPRESS@"
-LOG_COMPRESS=@LOG_COMPRESS@
-Z=@LOG_COMPRESSEXT@
-
-if [ "$OVMETHOD" = "ovdb" ]; then
- DB_HOME="${PATHOVERVIEW}"
- export DB_HOME
-fi
-
-TEMPSOCK=`basename ${INNDDIR}/ctlinndXXXXXX | ${SED} -e 's/XXXXXX$/*/'`
-TEMPSOCKDIR=`echo ${INNDDIR}/ctlinndXXXXXX | ${SED} -e 's@/[^/]*$@@'`
-
-HAVE_UUSTAT=@HAVE_UUSTAT@
-
-NEWSMASTER=@NEWSMASTER@
-NEWSUSER=@NEWSUSER@
-NEWSGROUP=@NEWSGRP@
-
-TMPDIR=${PATHTMP}; export TMPDIR;
-
-SPOOLTEMP=${PATHTMP}
-
-NEWSLBIN=${NEWSHOME}/local
-export NEWSLBIN
-
-umask @NEWSUMASK@
-
-PATH=${NEWSLBIN}:${NEWSBIN}:${PATH}:/bin:/usr/bin:/usr/ucb
-export PATH
-
-HOME=$PATHNEWS
-export HOME
+++ /dev/null
-#
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Sat, 24 Aug 1996 22:08:19 +0200
-# Project: INN
-# File: innshellvars.pl
-# RCSId: $Id: innshellvars.pl.in 7466 2005-12-12 03:04:08Z eagle $
-# Description: Set up any and all variables that an INN perl script
-# might need.
-
-package inn ;
-
-eval `@prefix@/bin/innconfval -p`;
-
-$newshome = $pathnews;
-$newslib = "@LIBDIR@";
-$spooldir = $pathspool;
-$most_logs = $pathlog;
-
-$errlog = "${most_logs}/errlog" ;
-$log = "${most_logs}/news" ;
-
-$spool = $patharticles;
-$overviewdir = $pathoverview;
-$archivedir = $patharchive;
-$badnews = "$pathincoming/bad";
-$spoolnews = $pathincoming;
-$batch = $pathoutgoing;
-$incoming = $pathincoming;
-
-$locks = $pathrun;
-$newsbin = $pathbin;
-$innddir = $pathrun;
-$newsetc = $pathetc;
-$newslbin = "$pathnews/local";
-
-$active = "${pathdb}/active" ;
-$activetimes = "${pathdb}/active.times" ;
-$ctlfile = "${newsetc}/control.ctl" ;
-$ctlwatch = "${newsetc}/innwatch.ctl" ;
-$history = "${pathdb}/history" ;
-$newactive = "${pathdb}/active.tmp" ;
-$newsfeeds = "${newsetc}/newsfeeds" ;
-$newsgroups = "${pathdb}/newsgroups" ;
-$oldactive = "${pathdb}/active.old" ;
-$path_motd = "${newsetc}/motd.news" ;
-$localgroups = "$newsetc/localgroups" ;
-$expirectl = "${newsetc}/expire.ctl" ;
-
-$controlprogs = $pathcontrol;
-$inews = "${newsbin}/inews" ;
-$innconfval = "${newsbin}/innconfval" ;
-$innd = "${newsbin}/innd" ;
-$inndstart = "${newsbin}/inndstart" ;
-$innwatch = "${newsbin}/innwatch" ;
-$rnews = "${newsbin}/rnews" ;
-$perl_startup_innd = "$pathfilter/startup_innd.pl" ;
-$perl_filter_innd = "$pathfilter/filter_innd.pl" ;
-$perl_filter_nnrpd = "$pathfilter/filter_nnrpd.pl" ;
-$python_filter_innd = "$pathfilter/filter_innd.py" ;
-$path_python_inn_module ="$pathfilter/INN.py" ;
-$path_tcl_startup = "$pathfilter/startup.tcl" ;
-$path_tcl_filter = "$pathfilter/filter.tcl" ;
-
-$daily = "${locks}/LOCK.news.daily" ;
-
-$newscontrol = "${innddir}/control" ;
-$nntpconnect = "${innddir}/nntpin" ;
-$serverpid = "${innddir}/innd.pid" ;
-$innwstatus = "${innddir}/innwatch.status" ;
-$watchpid = "${innddir}/innwatch.pid" ;
-
-$awk = "@_PATH_AWK@" ;
-$sed = "@_PATH_SED@" ;
-$inndf = "${newsbin}/inndf" ;
-$egrep = "@_PATH_EGREP@" ;
-$gpgv = "@PATH_GPGV@" ;
-$perl = "@_PATH_PERL@" ;
-$pgp = "@_PATH_PGP@" ;
-$sort = "@_PATH_SORT@" ;
-$getftp = "@GETFTP@" ;
-$uux = "@_PATH_UUX@" ;
-
-$compress = "@COMPRESS@" ;
-$gzip = "@GZIP@" ;
-$uncompress = "@UNCOMPRESS@" ;
-$log_compress = "@LOG_COMPRESS@" ;
-$z = "@LOG_COMPRESSEXT@" ;
-
-if ($ovmethod && $ovmethod eq "ovdb") {
- $ENV{'DB_HOME'} = $pathoverview;
-}
-
-($tempsock = "${innddir}/ctlinndXXXXXX") =~ s!.*/(.*)XXXXXX$!$1*! ;
-($tempsockdir = "${innddir}/ctlinndXXXXXX") =~ s!/[^/]*$!! ;
-
-$have_uustat = ("@HAVE_UUSTAT@" eq "DO" ? 1 : 0) ;
-
-$newsmaster = '@NEWSMASTER@' ;
-$newsuser = '@NEWSUSER@' ;
-$newsgroup = '@NEWSGRP@' ;
-
-$ENV{'TMPDIR'} = $pathtmp;
-$tmpdir = $pathtmp;
-$spooltemp = $pathtmp;
-
-$umask = @NEWSUMASK@ ;
-
-$syslog_facility = lc("@SYSLOG_FACILITY@");
-$syslog_facility =~ s/log_//;
-
-$ENV{'PATH'} ||= '';
-$ENV{'PATH'} = "${newslbin}:${newsbin}:$ENV{'PATH'}:/bin:/usr/bin:/usr/ucb" ;
-
-$ENV{'HOME'} = ${pathnews};
-
-1 ;
+++ /dev/null
-# -*- tcl -*-
-#
-# Author: James Brister <brister@vix.com> -- berkeley-unix --
-# Start Date: Sat, 24 Aug 1996 23:45:34 +0200
-# Project: INN
-# File: innshellvars.tcl
-# RCSId: $Id: innshellvars.tcl.in 7466 2005-12-12 03:04:08Z eagle $
-# Description: Set up any and all variables that an INN tcl script
-# might need.
-
-eval `@prefix@/bin/innconfval -t`
-
-set inn_newshome "$inn_pathnews"
-set inn_newslib "@LIBDIR@"
-set inn_spooldir "$inn_pathspool"
-set inn_most_logs "$inn_pathlog"
-
-set inn_errlog "${inn_most_logs}/errlog"
-set inn_log "${inn_most_logs}/news"
-
-set inn_batch "${inn_pathoutgoing}"
-set inn_incoming "${inn_pathincoming}"
-set inn_spool "${inn_patharticles}"
-set inn_overviewdir "${inn_pathoverview}"
-set inn_archivedir "${inn_patharchive}"
-set inn_badnews "${inn_pathincoming}/bad"
-set inn_spoolnews "${inn_pathincoming}"
-
-set inn_newslbin "${inn_newshome}/local"
-set inn_innddir "${inn_pathrun}"
-set inn_locks "${inn_pathrun}"
-set inn_newsbin "${inn_pathbin}"
-set inn_newsetc "${inn_newshome}/etc"
-
-set inn_active "${inn_pathdb}/active"
-set inn_activetimes "${inn_pathdb}/active.times"
-set inn_ctlfile "${inn_newsetc}/control.ctl"
-set inn_ctlwatch "${inn_newsetc}/innwatch.ctl"
-set inn_history "${inn_pathdb}/history"
-set inn_newactive "${inn_pathdb}/active.tmp"
-set inn_newsfeeds "${inn_newsetc}/newsfeeds"
-set inn_newsgroups "${inn_pathdb}/newsgroups"
-set inn_oldactive "${inn_pathdb}/active.old"
-set inn_localgroups "${inn_newsetc}/localgroups"
-set inn_expirectl "${inn_newsetc}/expire.ctl"
-set inn_path_motd "${inn_newsetc}/motd.news"
-
-set inn_daily "${inn_locks}/locks/LOCK.news.daily"
-
-set inn_inews "${inn_newsbin}/inews"
-set inn_innconfval "${inn_newsbin}/innconfval"
-set inn_innd "${inn_newsbin}/innd"
-set inn_inndstart "${inn_newsbin}/inndstart"
-set inn_innwatch "${inn_newsbin}/innwatch"
-set inn_rnews "${inn_newsbin}/rnews"
-set inn_controlprogs "${inn_pathcontrol}/control"
-set inn_perl_startup_innd "${inn_pathfilter}/startup_innd.pl"
-set inn_perl_filter_innd "${inn_pathfilter}/filter_innd.pl"
-set inn_perl_filter_nnrpd "${inn_pathfilter}/filter_nnrpd.pl"
-set inn_python_filter_innd "${pathfilter}/filter_innd.py"
-set inn_path_python_inn_module "${pathfilter}/INN.py"
-set inn_path_tcl_startup "${inn_pathfilter}/startup.tcl"
-set inn_path_tcl_filter "${inn_pathfilter}/filter.tcl"
-
-set inn_newscontrol "${inn_innddir}/control"
-set inn_nntpconnect "${inn_innddir}/nntpin"
-set inn_innwstatus "${inn_innddir}/innwatch.status"
-set inn_watchpid "${inn_innddir}/innwatch.pid"
-set inn_serverpid "${inn_innddir}/innd.pid"
-
-set inn_awk "@_PATH_AWK@"
-set inn_sed "@_PATH_SED@"
-set inn_perl "@_PATH_PERL@"
-set inn_gpgv "@PATH_GPGV@"
-set inn_pgp "@_PATH_PGP@"
-set inn_inndf "${inn_newsbin}/inndf"
-set inn_egrep "@_PATH_EGREP@"
-set inn_sort "@_PATH_SORT@"
-set inn_getftp "@GETFTP@"
-set inn_uux "@_PATH_UUX@"
-
-set inn_compress "@COMPRESS@"
-set inn_gzip "@GZIP@"
-set inn_uncompress "@UNCOMPRESS@"
-set inn_log_compress "@LOG_COMPRESS@"
-set inn_z "@LOG_COMPRESSEXT@"
-
-set inn_tempsock [ eval exec basename ${inn_innddir}/ctlinndXXXXXX | $inn_sed -e {s/XXXXXX$/*/} ]
-set inn_tempsockdir [ exec echo ${inn_innddir}/ctlinndXXXXXX | $inn_sed -e {s@/[^/]*$@@} ]
-
-set inn_have_uustat [ expr { "@HAVE_UUSTAT@" == "DO" ? 1 : 0 } ]
-
-set inn_newsmaster "@NEWSMASTER@"
-set inn_newsuser "@NEWSUSER@"
-set inn_newsgroup "@NEWSGRP@"
-
-set env(TMPDIR) "$inn_pathtmp"
-set inn_tmpdir "$inn_pathtmp"
-set inn_spooltemp "$inn_pathtmp"
-
-scan "@NEWSUMASK@" "%o" inn_umask
-
-set env(PATH) "$inn_newslbin:$inn_newsbin:$env(PATH):/bin:/usr/bin:/usr/ucb"
-
-set env(HOME) "$inn_pathnews"
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 6994 $
-## Display status of INN.
-## Written by Landon Curt Noll <chongo@toad.com>.
-
-SYSLOG_CRIT=news.crit
-SYSLOG_ERR=news.err
-SYSLOG_NOTICE=news.notice
-SYSLOGS="${SYSLOG_CRIT} ${SYSLOG_ERR} ${SYSLOG_NOTICE}"
-
-## Set up the list of log files.
-LOGS="${SYSLOGS}"
-if [ -f "${MOST_LOGS}/`basename ${ERRLOG}`" ]; then
- LOGS="${LOGS} `basename ${ERRLOG}`"
-else
- LOGS="${LOGS} ${ERRLOG}"
-fi
-if [ -f "${MOST_LOGS}/`basename ${LOG}`" ]; then
- LOGS="${LOGS} `basename ${LOG}`"
-else
- LOGS="${LOGS} ${LOG}"
-fi
-
-## Show INND status.
-echo 'Server status:'
-ctlinnd mode 2>&1
-
-## Show disk usage. You might have to change this.
-echo ''
-echo 'Disk usage:'
-${INNDF} ${SPOOL} ${OVERVIEWDIR} ${PATHETC} ${INCOMING} ${BATCH} \
- ${PATHDB} ${MOST_LOGS} | sort -u
-
-## Show size of batch files.
-echo ''
-echo 'Batch file sizes:'
-( cd ${BATCH}; ls -Cs | sed 1d )
-
-## Show size of log files.
-echo ''
-echo 'Log file sizes:'
-( cd ${MOST_LOGS}; ls -Cs ${LOGS} *.log 2>&1 )
-
-## Show the lock files
-echo ''
-( cd ${LOCKS}
- set -$- LOCK.*
- if [ -f "$1" ]; then
- echo 'Lock files:'
- ls -C LOCK.* 2>&1
- else
- echo 'Innwatch is not running'
- fi
-)
-
-echo ''
-echo 'Server connections:'
-ctlinnd -t60 name '' 2>&1 \
- | ${PERL} -ne '
- next if m/(^((rem|local)conn|control)|:proc|:file):/;
- s/^(\S+):(\d+):.*:.*:.*$/${1}:${2}/;
- m/^(\S+):(\d+)$/;
- $c{$1} = [] unless $c{$1};
- @l = @{$c{$1}};
- push @l, $2;
- $c{$1} = [@l];
- $m++;
-
- END {
- $n = 0;
- foreach $f (sort {$#{$c{$b}} <=> $#{$c{$a}}} keys %c) {
- printf "%-35.35s %3d (%s", $f, 1 + $#{$c{$f}}, "@{$c{$f}})\n";
- $n++;
- }
- printf "\n%-35s %3d\n", "TOTAL: $n", $m;
- }'
-
+++ /dev/null
-#! /usr/bin/perl
-
-## $Id: innupgrade.in 6458 2003-09-03 02:58:51Z rra $
-##
-## Convert INN configuration files to the current syntax.
-##
-## Intended to be run during a major version upgrade, this script tries to
-## convert existing INN configuration files to the syntax expected by the
-## current version, if that's changed.
-##
-## Note that this script cannot use innshellvars.pl, since loading that file
-## requires innconfval be able to parse inn.conf, and until this script runs,
-## inn.conf may not be valid.
-##
-## Currently handles the following conversions:
-##
-## * Clean up inn.conf for the new parser in INN 2.4.
-## * Add the hismethod parameter to inn.conf if not found.
-
-require 5.003;
-
-use strict;
-use vars qw(%FIXES);
-use subs qw(fix_inn_conf);
-
-use Getopt::Long qw(GetOptions);
-
-# The mappings of file names to fixes.
-%FIXES = ('inn.conf' => \&fix_inn_conf);
-
-# Clean up inn.conf for the new parser in INN 2.4. Null keys (keys without
-# values) need to be commented out since they're no longer allowed (don't just
-# remove them entirely since people may want them there as examples), and
-# string values must be quoted if they contain any special characters. Takes
-# a reference to an array containing the contents of the file, a reference to
-# an array into which the output should be put, and the file name for error
-# reporting.
-sub fix_inn_conf {
- my ($input, $output, $file) = @_;
- my $line = 0;
- my ($raw, $hismethod);
- local $_;
- for $raw (@$input) {
- $_ = $raw;
- $line++;
- if (/^\s*\#/ || /^\s*$/) {
- push (@$output, $_);
- next;
- }
- chomp;
- unless (/^(\s*)(\S+):(\s*)(.*)/) {
- warn "$file:$line: cannot parse line: $_\n";
- push (@$output, $_);
- next;
- }
- my ($indent, $key, $space, $value) = ($1, $2, $3, $4);
- if ($value eq '') {
- push (@$output, "#$_\n");
- next;
- }
- $hismethod = 1 if $key eq 'hismethod';
- $value =~ s/\s+$//;
- if ($value =~ /[\s;\"<>\[\]\\{}]/ && $value !~ /^\".*\"\s*$/) {
- $value =~ s/([\"\\])/\\$1/g;
- $value = '"' . $value . '"';
- }
- push (@$output, "$indent$key:$space$value\n");
- }
-
- # Add a setting of hismethod if one wasn't present in the original file.
- unless ($hismethod) {
- push (@$output, "\n# Added by innupgrade\nhismethod: hisv6\n");
- }
-}
-
-# Upgrade a particular file. Open the file, read it into an array, and then
-# run the fix function on it. If the fix function generates different output
-# than the current contents of the file, change the file.
-sub upgrade_file {
- my ($file, $function) = @_;
- open (INPUT, $file) or die "$file: cannot open: $!\n";
- my @input = <INPUT>;
- close INPUT;
- my @output;
- &$function (\@input, \@output, $file);
- if (join ('', @input) ne join ('', @output)) {
- if (-e "$file.OLD") {
- if (-t STDIN) {
- print "$file.OLD already exists, overwrite (y/N)? ";
- my $answer = <STDIN>;
- if ($answer !~ /y/i) {
- die "$file: backup $file.OLD already exists, aborting\n";
- }
- } else {
- die "$file: backup $file.OLD already exists\n";
- }
- }
- print "Updating $file, old version saved as $file.OLD\n";
- my ($user, $group) = (stat $file)[4,5];
- open (OUTPUT, "> $file.new.$$")
- or die "$file: cannot create $file.new.$$: $!\n";
- print OUTPUT @output;
- close OUTPUT or die "$file: cannot flush new file: $!\n";
- unless (link ($file, "$file.OLD")) {
- rename ($file, "$file.OLD")
- or die "$file: cannot rename to $file.OLD: $!\n";
- }
- if ($> == 0) {
- if (defined ($user) && defined ($group)) {
- chown ($user, $group, "$file.new.$$")
- or warn "$file: cannot chown $file.new.$$: $!\n";
- } else {
- warn "$file: cannot find owner and group of $file\n";
- }
- }
- rename ("$file.new.$$", $file)
- or die "$file: cannot replace with $file.new.$$: $!\n";
- }
-}
-
-# Upgrade a directory. Scan the directory for files that have upgrade rules
-# defined and for each one of those, try running the upgrade rule.
-sub upgrade_directory {
- my $directory = shift;
- chdir $directory or die "Can't chdir to $directory: $!\n";
- opendir (DIR, ".") or die "Can't opendir $directory: $!\n";
- for (readdir DIR) {
- if ($FIXES{$_}) {
- upgrade_file ($_, $FIXES{$_});
- }
- }
- closedir DIR;
-}
-
-
-# The main routine. Parse command-line options to figure out what we're
-# doing.
-my ($file, $type);
-Getopt::Long::config ('bundling');
-GetOptions ('file|f=s' => \$file,
- 'type|t=s' => \$type) or exit 1;
-if ($file) {
- my $basename = $file;
- $basename =~ s%.*/%%;
- $type ||= $basename;
- if (!$FIXES{$type}) { die "No upgrade rules defined for $basename\n" }
- upgrade_file ($file, $FIXES{$type});
-} else {
- if (@ARGV != 1) { die "Usage: innupgrade <directory>\n" }
- my $directory = shift;
- upgrade_directory ($directory);
-}
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 2677 $
-## Watch the state of the system relative to the news subsystem.
-## As controlled by the control file, when space or inodes are almost
-## exhausted innd is throttled, or paused, similarly if the load is
-## too high - when conditions revert to normal, innd is restarted.
-## No logging is done here, watch for syslog reports from innd.
-## Written by Mike Cooper <mcooper@usc.edu>.
-## Extensively modified by <kre@munnari.oz.au>.
-## Watch a log file and send mail when it gets new output by
-## Steve Groom <stevo@elroy.Jpl.Nasa.Gov>
-## Steve's extensions merged in innwatch by
-## <Christophe.Wolfhugel@grasp.insa-lyon.fr>
-
-PROGNAME=innwatch
-LOCK=${LOCKS}/LOCK.${PROGNAME}
-DAILY=${LOCKS}/LOCK.news.daily
-## Where to put the timestamp file (directory and filename).
-TIMESTAMP=${LOCKS}/${PROGNAME}.time
-
-## Logfile to watch. Comment out if no logwatch.
-LOGFILE=${MOST_LOGS}/news.crit
-
-## Default value in case there is no definition in inn.conf
-: ${INNWATCHPAUSELOAD:=1500}
-: ${INNWATCHHILOAD:=2000}
-: ${INNWATCHLOLOAD:=1000}
-: ${INNWATCHSPOOLSPACE:=8000}
-: ${INNWATCHBATCHSPACE:=800}
-: ${INNWATCHLIBSPACE:=25000}
-: ${INNWATCHSPOOLNODES:=200}
-: ${INNWATCHSLEEPTIME:=600}
-
-## Parse JCL.
-while [ $# -gt 0 ] ; do
- case X"$1" in
- X-f)
- FILE=$2
- shift
- ;;
- X-f*)
- FILE=`expr "$1" : '-s\(.*\)'`
- ;;
- X-l)
- LOGFILE=$2
- shift
- ;;
- X-l*)
- LOGFILE=`expr "$1" : '-s\(.*\)'`
- ;;
- X-t)
- INNWATCHSLEEPTIME=$2
- shift
- ;;
- X-t*)
- INNWATCHSLEEPTIME=`expr "$1" : '-t\(.*\)'`
- ;;
- X--)
- shift
- break
- ;;
- X-*)
- echo "${PROGNAME}: Unknown flag $1" 1>&2
- exit 1
- ;;
- *)
- break
- ;;
- esac
- shift
-done
-
-## Process arguments.
-if [ $# -ne 0 ] ; then
- echo "Usage: ${PROGNAME} [flags]" 1>&2
- exit 1
-fi
-
-trap '' 2
-
-## Anyone else there?
-shlock -p $$ -f ${LOCK} || {
- echo "${PROGNAME}: [$$] locked by [`cat ${LOCK}`]"
- exit 0
-}
-
-trap 'rm -f ${LOCK} ${WATCHPID} ; exit 1' 1 3 15
-echo "$$" > ${WATCHPID}
-
-## The reason why we turned INND off, and its, and our current state.
-REASON=''
-INND=''
-STATE=''
-
-trap '(
- echo "${PROGNAME} waiting for INND to start (pid: $$)"
- date
- ) >${INNWSTATUS}' 2
-
-## We need to remember the process ID of innd, in case one exits
-## But we need to wait for innd to start before we can do that
-while PID=`cat ${SERVERPID} 2>/dev/null`; test -z "${PID}"; do
- sleep ${INNWATCHSLEEPTIME}
-done
-
-trap '(
- if [ -z "${STATE}" ]; then
- echo "${PROGNAME} state RUN interval ${INNWATCHSLEEPTIME} pid $$"
- else
- echo "${PROGNAME} state ${STATE} interval ${INNWATCHSLEEPTIME} pid $$"
- fi
- if [ -z "${INND}" ]; then
- X=GO
- else
- X="${INND}"
- fi
- test -n "${REASON}" && X="${X}: ${REASON}"
- echo "INND state ${X}"
- date
- ) >${INNWSTATUS}' 2
-
-cd ${SPOOL}
-
-NEXTSLEEP=1
-HASEXITED=false
-
-while { sleep ${NEXTSLEEP} & wait; } ; : ; do
- NEXTSLEEP=${INNWATCHSLEEPTIME}
-
- ## If news.daily is running, idle: we don't want to change the
- ## status of anything while news.daily may be depending on what we
- ## have done.
- test -f "${DAILY}" && continue
-
- ## Check to see if INND is running.
- ## Notify NEWSMASTER if it has stopped or just restarted.
- if ctlinnd -s -t 120 mode 2>/dev/null ; then
- ${HASEXITED} && {
- HASEXITED=false
- ${MAILCMD} -s "INND is now running" ${NEWSMASTER} </dev/null
- }
- else
- ${HASEXITED} || {
- HASEXITED=true
- ${MAILCMD} -s "INND is NOT running" ${NEWSMASTER} </dev/null
- }
- continue
- fi
-
- ## If innd has exited & restarted, put the new one into the
- ## same state the old one was in
-
- nPID=`cat ${SERVERPID} 2>/dev/null`
- test -n "${nPID}" -a "${PID}" -ne "${nPID}" && {
- test -n "${INND}" -a "${INND}" != go && ctlinnd -s "${INND}" "${REASON}"
- PID="${nPID}"
- }
-
- VALUE=0
- PREVEXP=''
-
- exec 3<&0
- exec 0<${CTLWATCH}
-
- LINE=0
- while read line ; do
- LINE=`expr ${LINE} + 1`
- test -z "$line" && continue
-
- ## The first character on the line is the field delimiter,
- ## except '#' which marks the line as a comment
- delim=`expr "${line}" : '\(.\).*'`
- test "X${delim}" = 'X#' && continue
-
- ## Parse the line into seven fields, and assign them to local vars.
- ## You're welcome to work out what's going on with quoting in
- ## the next few lines if you feel inclined.
- eval `trap '' 2; echo "${line}" \
- | ${SED} -e "s/'/'\"'\"'/g" \
- -e "s/[ ]*\\\\${delim}[ ]*/\\\\${delim}/g" \
- | ${AWK} -F"${delim}" '{ print "LAB='"'"'" $2 "'"'"'", \
- "CND='"'"'" $3 "'"'"'", \
- "EXP='"'"'" $4 "'"'"'", \
- "TST='"'"'" $5 "'"'"'", \
- "LIM=" $6, \
- "CMD='"'"'" $7 "'"'"'", \
- "CMT='"'"'" $8 "'"'"'" }'`
-
- ## If there's no label, the label is the line number.
- test -z "${LAB}" && LAB=${LINE}
-
- ## Should we act on this line? We will if one (or more) of the
- ## specified conditions is satisfied.
- for X in a b; do # meaningless trash because we have no goto
- if [ -z "${CND}" ]; then
- X=-
- else
- X="${CND}"
- fi
- set -$- X ${X}; shift
- for cnd
- do
- case "${cnd}" in
- -)
- test -n "${STATE}" -a "X${STATE}" != "X${LAB}" && continue
- ;;
- +)
- test -n "${STATE}" && continue
- ;;
- '*')
- ;;
- -*)
- test "X-${STATE}" = "X${cnd}" && continue
- ;;
- *)
- test "X${STATE}" != "X${cnd}" && continue;
- ;;
- esac
- break 2; # OK, continue with this line
- done
- continue 2; # No, skip it.
- done
-
- ## Evaluate the expression, if there is one, and if that works.
- if [ -z "${EXP}" -o "${EXP}" = "${PREVEXP}" ] \
- || { PREVEXP="${EXP}"; VALUE=`trap '' 2;eval "${EXP}"`; }; then
- ## If innd is running, and test "succeeds", stop it.
- case "${CMD}" in
- throttle|pause)
- OK=n
- ;;
- *)
- OK=y
- ;;
- esac
-
- if [ \( -z "${STATE}" -o "${STATE}" != "${LAB}" -o "${OK}" = y \) \
- -a "${VALUE}" "-${TST}" "${LIM}" ] ; then
- R="${CMT} [${PROGNAME}:${LAB}] ${VALUE} ${TST} ${LIM}"
- O=
- case "${CMD}" in
- throttle)
- case "${STATE}" in
- ''|go)
- REASON="${R}"
- ;;
- *)
- ;;
- esac
- O="${LAB}"
- ARG="${REASON}"
- ;;
- pause)
- O="${LAB}"
- REASON="${R}"
- ARG="${REASON}"
- ;;
- shutdown)
- ARG="${R}"
- ;;
- flush)
- ARG=''
- O="${STATE}"
- ARG="${REASON}"
- ;;
- go)
- ARG="${REASON}"
- NEXTSLEEP=1
- REASON=''
- ;;
- exit)
- exit 0
- ;;
- *)
- break
- ;;
- esac
-
- ctlinnd -s "${CMD}" "${ARG}" && STATE="${O}" && INND="${CMD}"
- break
-
- ## Otherwise, if innd is not running, and reverse test succeeds
- ## restart it.
- elif [ "${STATE}" = "${LAB}" -a \
- \( "${CMD}" = "throttle" -o "${CMD}" = pause \) -a \
- ! "${VALUE}" "-${TST}" "${LIM}" ] ; then
- ctlinnd -s go "${REASON}"
- STATE=''
- REASON=''
- INND=''
-
- ## If we have started innd, run all tests again quickly in
- ## case there is some other condition that should stop it.
- NEXTSLEEP=1
- break
- fi
- fi
-
- done
-
- exec 0<&3
- exec 3<&-
-
- if [ -n "${LOGFILE}" -a -f "${LOGFILE}" ]; then
- if [ ! -f ${TIMESTAMP} ]; then
- DOIT=${LOGFILE}
- else
- # use ls to print most recently modified file first.
- # If that's ${LOGFILE}, it's changed since the last pass.
- DOIT="`ls -t ${TIMESTAMP} ${LOGFILE} | ${SED} -e 1q | grep ${LOGFILE}`"
- fi
-
- # If the file has been modified more recently than the timestamp,
- # and the file has length greater than 0, send the warning.
- if [ -n "${DOIT}" -a -s ${LOGFILE} ]; then
- date >${TIMESTAMP}
- (
- ls -l ${LOGFILE}
- echo "-----"
- ctlinnd -t120 mode
- echo "-----"
- cat ${LOGFILE}
- ) 2>&1 \
- | sed -e 's/^~/~~/' \
- | ${MAILCMD} -s "${PROGNAME} warning: messages in ${LOGFILE}" \
- ${NEWSMASTER}
- fi
- fi
-
-done
-
-rm -f ${LOCK}
+++ /dev/null
-#!@_PATH_SH@
-## $Revision: 5999 $
-## Daily news maintenance.
-## Optional arguments:
-## expdir=xxx Directory in which to build new history file
-## tmpdir=xxx Working directory for `sort' and such
-## expirectl=xxx Use xxx as expire.ctl file
-## flags=xxx Pass xxx flags to expire
-## lowmark Create and use a lowmark file
-## noexpire Do not expire
-## noexplog Do not log expire output
-## nologs Do not scan logfiles
-## nomail Do not capture and mail output
-## norenumber Do not renumber the active file
-## norm Do not remove certain old files
-## norotate Do not rotate logfiles
-## nostat Do not run innstat
-## notdaily Not a daily run, and therefore implies nologs.
-## delayrm Delay unlink files, then do it quicker (expire -z)
-## /full/path Path to a program to run before expiring
-
-. @LIBDIR@/innshellvars
-
-EXPLOG=${MOST_LOGS}/expire.log
-INNSTAT=${PATHBIN}/innstat
-HOSTNAME=`hostname`
-DATE=`date`
-TAGGEDHASH=@DO_DBZ_TAGGED_HASH@
-SORT=sort
-
-## If your expire does not pause or throttle innd, enable this next line:
-#MESSAGE="Expiration script $$"
-## Renumber all at once, or in steps? Set to the delay if steps (that
-## may take a long time!).
-RENUMBER=
-
-PROGNAME=news.daily
-LOCK=${LOCKS}/LOCK.${PROGNAME}
-
-## Set defaults.
-DAILY=true
-DOEXPIRE=true
-DOEXPLOG=true
-DOEXPIREOVER=false
-DOLOGS=true
-DOMAIL=true
-DORENUMBER=true
-DORM=true
-DOSTAT=true
-EXPIRECTL=
-EXPDIR=
-EXPIREFLAGS="-v1"
-EXPIREOVER=expireover
-LOWMARKFILE=
-RMFILE=
-
-HISTDIR="`dirname ${HISTORY}`"
-TOUT=600 # timeout value for ctlinnd commands
-if [ -z "${HISTDIR}" -o X"." = X"${HISTDIR}" -o ! -d "${HISTDIR}" ]; then
- if [ -d "${PATHETC}/hist" ]; then
- HISTDIR="${PATHETC}/hist"
- else
- HISTDIR="${PATHETC}"
- fi
-fi
-if [ "${ENABLEOVERVIEW}" = "true" ]; then
- DOEXPIREOVER=true
- RMFILE=${MOST_LOGS}/expire.rm
-fi
-
-EXPIREOVERFLAGS=
-PROGRAMS=
-POSTPROGRAMS=
-REASON=
-SCANARG=
-DOGROUPBASEEXPIRY=false
-
-if [ "${GROUPBASEEXPIRY}" = "true" ]; then
- if [ "${ENABLEOVERVIEW}" = "true" ]; then
- DOGROUPBASEEXPIRY=true
- else
- DOEXPIREOVER=false
- RMFILE=
- fi
-fi
-
-## Parse JCL.
-for I
-do
- case "X$I" in
- Xdelayrm)
- RMFILE=${MOST_LOGS}/expire.rm
- ;;
- Xexpctl=*)
- EXPIRECTL=`expr "${I}" : 'expctl=\(.*\)'`
- case ${EXPIRECTL} in
- /*)
- ;;
- *)
- EXPIRECTL=`/bin/pwd`/${EXPIRECTL}
- ;;
- esac
- ;;
- Xexpdir=*)
- EXPDIR=`expr "${I}" : 'expdir=\(.*\)'`
- ;;
- Xtmpdir=*)
- TMPDIR=`expr "${I}" : 'tmpdir=\(.*\)'`
- ;;
- Xexpireover)
- DOEXPIREOVER=true
- RMFILE=${MOST_LOGS}/expire.rm
- ;;
- Xexpireoverflags=*)
- EXPIREOVERFLAGS=`expr "${I}" : 'expireoverflags=\(.*\)'`
- ;;
- Xflags=*)
- EXPIREFLAGS=`expr "${I}" : 'flags=\(.*\)'`
- ;;
- Xlowmark)
- LOWMARKFILE=${MOST_LOGS}/expire.lowmark
- DORENUMBER=false
- ;;
- Xnotdaily)
- DAILY=false
- DOLOGS=false
- ;;
- Xnoexpire)
- DOEXPIRE=false
- ;;
- Xnoexpireover)
- DOEXPIREOVER=false
- RMFILE=
- ;;
- Xnoexplog)
- DOEXPLOG=false
- ;;
- Xnologs)
- DOLOGS=false
- ;;
- Xnomail)
- DOMAIL=false
- MAIL="cut -c 1-1022 | ${SED} -e 's/^~/~~/'"
- ;;
- Xnonn)
- # Ignore this.
- ;;
- Xnorenumber)
- DORENUMBER=false
- ;;
- Xnorm)
- DORM=false
- ;;
- Xnorotate)
- SCANARG="${SCANARG} norotate"
- ;;
- Xnostat)
- DOSTAT=false
- ;;
- X/*)
- PROGRAMS="${PROGRAMS} ${I}"
- ;;
- Xpostexec=*)
- POSTEXEC=`expr "${I}" : 'postexec=\(.*\)'`
- POSTPROGRAMS="${POSTPROGRAMS} ${POSTEXEC}"
- ;;
- *)
- echo "Unknown flag ${I}" 1>&2
- exit 1
- ;;
- esac
-done
-
-##
-## Setup mail subject and command
-##
-if ${DAILY} ; then
- MAILSUBJ="${HOSTNAME} Daily Usenet report for ${DATE}"
-else
- MAILSUBJ="${HOSTNAME} intermediate usenet report for ${DATE}"
-fi
-MAIL="cut -c 1-1022 | ${SED} -e 's/^~/~~/' | \
- ${MAILCMD} -s '$MAILSUBJ' ${NEWSMASTER}"
-
-#
-# Sanity check. Shouldn't we just bail out here with an error
-# instead of trying to patch things up?
-#
-${DOEXPIRE} || {
- EXPDIR=
- RMFILE=
-}
-
-test -n "${EXPDIR}" && {
- test -z "${REASON}" && REASON="Expiring $$ on ${EXPDIR}"
- EXPIREFLAGS="${EXPIREFLAGS} '-d${EXPDIR}' '-r${REASON}'"
-}
-
-test -n "${RMFILE}" && {
- if ${DOGROUPBASEEXPIRY} ; then
- EXPIREOVERFLAGS="${EXPIREOVERFLAGS} -z${RMFILE}"
- else
- EXPIREFLAGS="${EXPIREFLAGS} -z${RMFILE}"
- fi
- }
-
-test -n "${LOWMARKFILE}" && {
- EXPIREOVERFLAGS="${EXPIREOVERFLAGS} -Z${LOWMARKFILE}"
-}
-
-
-if ${DOMAIL} ; then
- ## Try to get a temporary file.
- TEMP=${TMPDIR}/doex$$
- test -f ${TEMP} && {
- echo "Temporary file ${TEMP} exists" | eval ${MAIL}
- exit 1
- }
- touch ${TEMP}
- chmod 0660 ${TEMP}
- exec 3>&1 >${TEMP} 2>&1
-fi
-
-cd ${PATHETC}
-
-## Show the status of the news system.
-${DOSTAT} && {
- ${INNSTAT}
- echo ''
-}
-
-## Lock out others.
-trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
-shlock -p $$ -f ${LOCK} || {
- ( echo "$0: Locked by `cat ${LOCK}`"; ${INNSTAT} ) | eval ${MAIL}
- exit 1
-}
-
-## Run any user programs.
-if [ -n "${PROGRAMS}" ] ; then
- for P in ${PROGRAMS} ; do
- echo ''
- echo "${P}:"
- eval ${P}
- done
-fi
-
-${DOLOGS} && {
- echo ''
- scanlogs ${SCANARG}
-}
-
-# group-based expiry (delete expired overview first)
-if [ ${DOGROUPBASEEXPIRY} = true -a ${DOEXPIREOVER} = true ] ; then
- if ${DOEXPLOG}; then
- echo "${EXPIREOVER} start `date`: (${EXPIREOVERFLAGS})" >>${EXPLOG}
- fi
- ( cd ${HISTDIR} ; exec 2>&1 ; eval ${EXPIREOVER} "${EXPIREOVERFLAGS}" ) \
- >>${EXPLOG}
- if ${DOEXPLOG}; then
- echo "${EXPIREOVER} end `date`" >>${EXPLOG}
- fi
- test -n "${LOWMARKFILE}" && {
- echo "lowmarkrenumber begin `date`: (${LOWMARKFILE})" >>${EXPLOG}
- ctlinnd -s -t`wc -l <${ACTIVE}` lowmark ${LOWMARKFILE} 2>&1
- echo "lowmarkrenumber end `date`" >>${EXPLOG}
- rm -f ${MOST_LOGS}/expire.lastlowmark
- mv ${LOWMARKFILE} ${MOST_LOGS}/expire.lastlowmark
- }
- test -n "${RMFILE}" -a -s "${RMFILE}" && {
- mv ${RMFILE} ${RMFILE}.$$ && RMFILE=${RMFILE}.$$
-
- test -n "${TMPDIR}" && SORT="${SORT} -T ${TMPDIR}"
- ${SORT} -u -o ${RMFILE} ${RMFILE}
- if ${DOEXPLOG}; then
- echo " expirerm start `date`" >>${EXPLOG}
- fi
- expirerm ${RMFILE}
- if ${DOEXPLOG}; then
- echo " expirerm end `date`" >>${EXPLOG}
- fi
- }
- DOEXPIREOVER=false
-fi
-
-## The heart of the matter: prologs, expire, epilogs.
-if ${DOEXPIRE} ; then
-
- ## Wait to be fairly certain innwatch is not in the middle of a pass
- ## Since we're locked, innwatch will pause now till we're done
- sleep 30
-
- ## See if we're throttled for lack of space.
- SERVERMODE=`ctlinnd -t $TOUT mode 2>/dev/null | ${SED} 1q`
- case "${SERVERMODE}" in
- 'Server paused'*'[innwatch:'*)
- ## If paused, by innwatch, then turn pause into throttle
- ## as we're going to stay that way for a while now
- ctlinnd -t $TOUT -s throttle \
- "`expr \"${SERVERMODE}\" : 'Server paused \(.*\)'`" || {
- ( echo "$0: Cannot throttle while innwatch paused";
- ${INNSTAT} ) | eval ${MAIL}
- exit 1
- }
- esac
- case "${SERVERMODE}" in
- *space*" -- throttling")
- echo "${SERVERMODE} -- trying to recover"
- THROTTLED=true
- EXPIREFLAGS="${EXPIREFLAGS} -n"
- MESSAGE=
- ;;
- *"[innwatch:"*)
- echo "${SERVERMODE} -- pressing on"
- THROTTLED=false
- EXPIREFLAGS="${EXPIREFLAGS} -n"
- MESSAGE=
- DORENUMBER=false
- ;;
- *)
- THROTTLED=false
- ;;
- esac
-
- ## Throttle server if we need to.
- if [ -n "${MESSAGE}" ] ; then
- ctlinnd -t $TOUT -s -t120 throttle "${MESSAGE}" 2>&1 || {
- ( echo "$0: Cannot throttle news"; ${INNSTAT} ) | eval ${MAIL}
- exit 1
- }
- fi
-
- #
- # Get rid of an old expire RMFILE since news.daily locks itself and
- # we would not get here if another instance were still running.
- #
- if [ -n "${RMFILE}" ] ; then
- rm -f ${RMFILE}
- fi
-
- ## Actual expire the articles (finally!).
- test -n "${EXPIRECTL}" && EXPIREFLAGS="${EXPIREFLAGS} ${EXPIRECTL}"
- if ${DOEXPLOG}; then
- echo "expire begin `date`: (${EXPIREFLAGS})" >>${EXPLOG}
- ( cd ${HISTDIR}; exec 2>&1 ; eval expire "${EXPIREFLAGS}" ) \
- | ${SED} -e '/No such file or directory/d' \
- -e 's/^/ /' >>${EXPLOG}
- echo "expire end `date`" >>${EXPLOG}
- else
- eval expire "${EXPIREFLAGS}" 2>&1 | grep -v 'No such file or directory'
- fi
-
- ## If built on another filesystem, move history files.
- if [ -n "${EXPDIR}" ] ; then
- if [ ! -f ${EXPDIR}/history.n -o ! -f ${EXPDIR}/history.n.done ] ; then
- ( echo "$0: No new history files"; ${INNSTAT} ) | eval ${MAIL}
- exit 1
- fi
- cp /dev/null ${HISTORY}
- mv -f ${EXPDIR}/history.n ${HISTORY}
- mv -f ${EXPDIR}/history.n.dir ${HISTORY}.dir
- if [ X${TAGGEDHASH} = XDO ] ; then
- mv -f ${EXPDIR}/history.n.pag ${HISTORY}.pag
- else
- mv -f ${EXPDIR}/history.n.index ${HISTORY}.index
- mv -f ${EXPDIR}/history.n.hash ${HISTORY}.hash
- fi
- rm -f ${EXPDIR}/history.n.done
-
- case "${EXPIREFLAGS}" in
- *-n*)
- ;;
- *)
- MESSAGE="${REASON}"
- ;;
- esac
- fi
-
- ## Restart the server if we need to.
- if ${THROTTLED} || test -n "${MESSAGE}" ; then
- ctlinnd -t "$TOUT" -s go "${MESSAGE}" 2>&1 || {
- ( echo "$0: Cannot unthrottle news"; ${INNSTAT} ) | eval ${MAIL}
- exit 1
- }
- fi
- if ${DOEXPLOG}; then
- echo " all done `date`" >>${EXPLOG}
- fi
-fi
-
-## Remove old sockets.
-${DORM} &&
- find ${TEMPSOCKDIR} -name "${TEMPSOCK}" -mtime +2 -exec rm -f '{}' ';'
-
-## Did we became throttled during the run?
-SERVERMODE=`ctlinnd mode 2>/dev/null | ${SED} 1q`
-case "${SERVERMODE}" in
-*space*" -- throttling")
- ## We did, try to unthrottle the server.
- echo "${SERVERMODE} -- trying to recover"
- ctlinnd -s go ""
- ;;
-esac
-
-## Release the lock now, everything below this must be able to withstand
-## simultaneous news.daily's running. We do this so innwatch can start
-## monitoring again asap after the expire is done -- removing the
-## articles isn't critical, nor is the renumber.
-rm ${LOCK}
-
-## Remove the articles that are supposed to go
-if [ ${DOEXPIRE} = true -a ${DOGROUPBASEEXPIRY} != true ] ; then
- test -n "${RMFILE}" -a -s "${RMFILE}" && {
- mv ${RMFILE} ${RMFILE}.$$ && RMFILE=${RMFILE}.$$
-
- test -n "${TMPDIR}" && SORT="${SORT} -T ${TMPDIR}"
- ${SORT} -u -o ${RMFILE} ${RMFILE}
- if ${DOEXPLOG}; then
- echo " expirerm start `date`" >>${EXPLOG}
- fi
- expirerm ${RMFILE}
- if ${DOEXPLOG}; then
- echo " expirerm end `date`" >>${EXPLOG}
- fi
- ${DOEXPIREOVER} && {
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} start `date`" >>${EXPLOG}
- fi
- ( cd ${HISTDIR} ; eval ${EXPIREOVER} "${EXPIREOVERFLAGS}" 2>&1 ) | \
- grep -v 'No such file or directory'
- DOEXPIREOVER=false
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} end `date`" >>${EXPLOG}
- fi
- }
- test -n "${LOWMARKFILE}" && {
- echo "lowmarkrenumber begin `date`: (${LOWMARKFILE})" >>${EXPLOG}
- ctlinnd -s -t`wc -l <${ACTIVE}` lowmark ${LOWMARKFILE} 2>&1
- echo "lowmarkrenumber end `date`" >>${EXPLOG}
- rm -f ${MOST_LOGS}/expire.lastlowmark
- mv ${LOWMARKFILE} ${MOST_LOGS}/expire.lastlowmark
- }
- }
- # expire overview lines for files we just removed
- if ${DOEXPIREOVER}; then
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} start `date`" >>${EXPLOG}
- fi
- ( cd ${HISTDIR} ; eval ${EXPIREOVER} "${EXPIREOVERFLAGS}" 2>&1 ) | \
- grep -v 'No such file or directory'
- DOEXPIREOVER=false
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} end `date`" >>${EXPLOG}
- fi
- test -n "${LOWMARKFILE}" && {
- echo "lowmarkrenumber begin `date`: (${LOWMARKFILE})" >>${EXPLOG}
- ctlinnd -s -t`wc -l <${ACTIVE}` lowmark ${LOWMARKFILE} 2>&1
- echo "lowmarkrenumber end `date`" >>${EXPLOG}
- rm -f ${MOST_LOGS}/expire.lastlowmark
- mv ${LOWMARKFILE} ${MOST_LOGS}/expire.lastlowmark
- }
- fi
-fi
-# in case noexpire expireover
-if ${DOEXPIREOVER}; then
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} start `date`" >>${EXPLOG}
- fi
- ( cd ${HISTDIR} ; eval ${EXPIREOVER} "${EXPIREOVERFLAGS}" 2>&1 ) | \
- grep -v 'No such file or directory'
- if ${DOEXPLOG}; then
- echo " ${EXPIREOVER} end `date`" >>${EXPLOG}
- fi
- test -n "${LOWMARKFILE}" && {
- echo "lowmarkrenumber begin `date`: (${LOWMARKFILE})" >>${EXPLOG}
- ctlinnd -s -t`wc -l <${ACTIVE}` lowmark ${LOWMARKFILE} 2>&1
- echo "lowmarkrenumber end `date`" >>${EXPLOG}
- rm -f ${MOST_LOGS}/expire.lastlowmark
- mv ${LOWMARKFILE} ${MOST_LOGS}/expire.lastlowmark
- }
-fi
-
-## Renumber the active file.
-if ${DORENUMBER} ; then
- echo ''
- echo 'Renumbering active file.'
- if [ -z "${RENUMBER}" ] ;then
- ctlinnd -s -t`wc -l <${ACTIVE}` renumber '' 2>&1
- else
- while read GROUP hi lo flag ; do
- ctlinnd -s renumber ${GROUP} 2>&1
- sleep ${RENUMBER}
- done <${ACTIVE}
- fi
-fi
-
-## Display expire log messages
-if ${DOMAIL} ; then
- if [ -s ${EXPLOG} ] ; then
- echo Expire messages:
- cat ${EXPLOG}
- echo ---------
- echo ''
- fi
-fi
-
-## Show the status of the news system after expiration.
-${DOSTAT} && {
- echo 'Post expiration status:' ; echo ''
- ${INNSTAT}
- echo ''
-}
-
-## Mail the report.
-if ${DOMAIL} ; then
- # Stop using the temp file, and mail captured output.
- exec 1>&3 2>&1 3>&-
- MAIL="${MAILCMD} -s \"${MAILSUBJ}\" ${NEWSMASTER}"
- test -s ${TEMP} && cat ${TEMP} | ${SED} -e 's/^~/~~/' | eval ${MAIL}
- rm -f ${TEMP}
-fi
-
-## Run any user programs.
-if [ -n "${POSTPROGRAMS}" ] ; then
- for P in ${POSTPROGRAMS} ; do
- echo ''
- echo "${P}:"
- eval ${P}
- done
-fi
-
-## All done
-if ${DAILY} ; then
- date >${PATHDB}/.news.daily
-fi
-${RNEWS} -U
-exit 0
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 7435 $
-## News boot script. Runs as "news" user. Requires inndstart be
-## setuid root. Run from rc.whatever as:
-## su news -c /path/to/rc.news >/dev/console
-##
-## Or to stop INN:
-## su news -c '/path/to/rc.news stop'
-
-waitforpid()
-{
- i=12
- while [ $i -gt 0 ];
- do
- kill -0 $1 2>/dev/null || break
- sleep 5
- printf "."
- i=`expr $i - 1`
- done
- printf "\n"
-}
-
-case X"$1" in
-Xstop)
- # Stop cnfsstat (if running)
- if [ -f ${PATHRUN}/cnfsstat.pid ]; then
- kill `cat ${PATHRUN}/cnfsstat.pid`
- rm -f ${PATHRUN}/cnfsstat.pid
- fi
-
- # Stop innwatch (if running)
- if [ -f $WATCHPID ]; then
- kill `cat $WATCHPID`
- rm -f $WATCHPID
- fi
-
- printf "Stopping innd: "
- ${PATHBIN}/ctlinnd throttle 'rc.news stop'
- ${PATHBIN}/ctlinnd shutdown 'rc.news stop'
-
- # wait for innd to exit (up to 60 sec)
- pid=`cat ${SERVERPID} 2>/dev/null`
- if [ "$pid" != "" ]; then
- waitforpid $pid
- else
- printf "\n"
- fi
-
- # Turn off ovdb support procs, and close the DB environment
- if [ "$OVMETHOD" = "ovdb" -a -f ${PATHRUN}/ovdb_server.pid ]; then
- pid=`cat ${PATHRUN}/ovdb_server.pid 2>/dev/null`
- if [ "$pid" != "" ]; then
- printf "Stopping ovdb_server: "
- kill $pid
- waitforpid $pid
- fi
- fi
- if [ "$OVMETHOD" = "ovdb" -a -f ${PATHRUN}/ovdb_monitor.pid ]; then
- pid=`cat ${PATHRUN}/ovdb_monitor.pid 2>/dev/null`
- if [ "$pid" != "" ]; then
- printf "Stopping ovdb_monitor: "
- kill $pid
- waitforpid $pid
- fi
- fi
-
- if [ -f ${PATHBIN}/rc.news.local ]; then
- ${PATHBIN}/rc.news.local stop
- fi
-
- # Delete all of the PID files that we know about to avoid having them
- # stick around after a fresh start.
- rm -f ${PATHRUN}/cnfsstat.pid $WATCHPID $SERVERPID
- rm -f ${PATHRUN}/ovdb_server.pid ${PATHRUN}/ovdb_monitor.pid
-
- exit 0
-;;
-esac
-
-## Pick ${INND} or ${INNDSTART}
-WHAT=${INNDSTART}
-
-MAIL="${MAILCMD} -s 'Boot-time Usenet warning on `hostname`' ${NEWSMASTER}"
-
-## RFLAG is set below; set INNFLAGS in inn.conf(5)
-RFLAG=""
-
-## Clean shutdown or already running?
-if [ -f ${SERVERPID} ] ; then
- if kill -0 `cat ${SERVERPID}` 2>/dev/null; then
- echo 'INND is running'
- exit 0
- fi
- echo 'INND: PID file exists -- unclean shutdown!'
- RFLAG="-r"
-fi
-
-if [ ! -f ${PATHDB}/.news.daily ] ; then
- case `find ${PATHBIN}/innd -mtime +1 -print 2>/dev/null` in
- "")
- ;;
- *)
- echo 'No .news.daily file; need to run news.daily?' | eval ${MAIL}
- ;;
- esac
-else
- case `find ${PATHDB}/.news.daily -mtime +1 -print 2>/dev/null` in
- "")
- ;;
- *)
- echo 'Old .news.daily file; need to run news.daily?' | eval ${MAIL}
- ;;
- esac
-fi
-
-## Active file recovery.
-if [ ! -s ${ACTIVE} ] ; then
- if [ -s ${NEWACTIVE} ] ; then
- mv ${NEWACTIVE} ${ACTIVE}
- else
- if [ -s ${OLDACTIVE} ] ; then
- cp ${OLDACTIVE} ${ACTIVE}
- else
- echo 'INND: No active file!'
- exit 1
- fi
- fi
- RFLAG="-r"
- # You might want to rebuild the DBZ database, too:
- #cd ${PATHDB} \
- # && makehistory -r \
- # && mv history.n.dir history.dir \
- # && mv history.n.index history.index \
- # && mv history.n.hash history.hash
-fi
-
-## Remove temporary batchfiles and lock files.
-( cd ${BATCH} && rm -f bch* )
-( cd ${LOCKS} && rm -f LOCK* )
-( cd ${TEMPSOCKDIR} && rm -f ${TEMPSOCK} )
-rm -f ${NEWSCONTROL} ${NNTPCONNECT} ${SERVERPID}
-
-## Initialize ovdb. Must be done before starting innd.
-if [ "$OVMETHOD" = "ovdb" ]; then
- echo 'Starting ovdb.'
- ovdb_init || {
- echo "Can't initialize ovdb (check news.err for OVDB messages)"
- exit 1
- }
- sleep 1
-fi
-
-## Start the show.
-echo 'Starting innd.'
-eval ${WHAT} ${RFLAG} ${INNFLAGS}
-
-# Gee, looks like lisp, doesn't it?
-${DOINNWATCH} && {
- echo "Scheduled start of ${INNWATCH}."
- ( sleep 60 ; ${INNWATCH} ) > /dev/null &
-}
-
-${DOCNFSSTAT} && {
- echo "Scheduled start of cnfsstat."
- ( sleep 60 ; ${PATHBIN}/cnfsstat -s -l -P ) > /dev/null &
-}
-
-RMFILE=${MOST_LOGS}/expire.rm
-for F in ${RMFILE} ${RMFILE}.*; do
- if [ -f $F -a -s $F ] ; then
- echo "Removing articles from pre-downtime expire run (${F})."
- (
- echo 'System shut down during expire.' \
- 'Unlinking articles listed in'
- echo ${F}
- ) | eval ${MAIL}
- ${PATHBIN}/expirerm ${F}
- fi
-done &
-
-# Run any additional local startup commands.
-if [ -f ${PATHBIN}/rc.news.local ] ; then
- ${PATHBIN}/rc.news.local start
-fi
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 7770 $
-## Summarize INN log files.
-## Optional arguments:
-## norotate Do not rotate logfiles
-
-## If you get an error from this line:
-## sh -c 'egrep "`ls /etc`" /dev/null'
-## then get a better egrep, like the FSF one.
-
-## Directory where old log files are kept.
-OLD=${MOST_LOGS}/OLD
-## If you want to archive the active file, enable this line.
-ACTIVEFILE=${ACTIVE}
-## Number of lines of error in each category to report.
-TOP=${TOP-20}
-## NN log file.
-NN=${PATHETC}/nn/Log
-
-## Where these programs, if used, write their logs.
-## We also have to find innfeed's log file.
-INNFEEDLOG=`${AWK} '{gsub(/:|#/, " & ")} {if ($1 == "log-file" && $2 == ":") print $3}' ${PATHETC}/innfeed.conf`
-INNFEED=
-for F in "${INNFEEDLOG}" ; do
- test -f "${MOST_LOGS}/${F}" && INNFEED="${INNFEED} ${MOST_LOGS}/${F}"
-done
-test -z "${INNFEED}" && test -f ${MOST_LOGS}/innfeed.log && INNFEED="${MOST_LOGS}/innfeed.log"
-
-
-## Where nntpsend, if used, writes its log information.
-NNTPSEND=${MOST_LOGS}/nntpsend.log
-SENDNNTP=${MOST_LOGS}/send-nntp.log
-SENDUUCP=${MOST_LOGS}/send-uucp.log
-LIVEFILES="${INNFEED} ${NNTPSEND} ${SENDNNTP} ${SENDUUCP}"
-## Where news.daily places expire output, unless noexplog was used.
-EXPLOG=${MOST_LOGS}/expire.log
-
-## If you divide your news syslog into separate files, list them here.
-SYSLOG_CRIT=${MOST_LOGS}/news.crit
-SYSLOG_ERR=${MOST_LOGS}/news.err
-SYSLOG_NOTICE=${MOST_LOGS}/news.notice
-SYSLOGS="${SYSLOG_CRIT} ${SYSLOG_ERR} ${SYSLOG_NOTICE}"
-
-## Where tally control and unwanted processors are found.
-TALLY_CONTROL=${PATHBIN}/tally.control
-TALLY_UNWANTED=${PATHBIN}/tally.unwanted
-UNWANTED_LOG=${MOST_LOGS}/unwanted.log
-CONTROL_LOG=${MOST_LOGS}/control.log
-CONTROL_DATA=
-test -f ${MOST_LOGS}/newgroup.log && CONTROL_DATA=${MOST_LOGS}/newgroup.log
-test -f ${MOST_LOGS}/rmgroup.log \
- && CONTROL_DATA="${CONTROL_DATA} ${MOST_LOGS}/rmgroup.log"
-
-## Build up the list of log files to process.
-LOGS="${ERRLOG} ${EXPLOG} ${LOG} ${ACTIVEFILE} ${SYSLOGS} ${UNWANTED_LOG}"
-
-for F in ${LIVEFILES} ; do
- test -n "${F}" -a -f "${F}" && LOGS="${LOGS} ${F}"
-done
-
-test -n "${CONTROL_DATA}" && LOGS="${LOGS} ${CONTROL_LOG}"
-for F in checkgroups default ihave newgroup rmgroup sendme sendsys \
- senduuname version miscctl badcontrol failedpgp badpgp; do
- test -f ${MOST_LOGS}/${F}.log && LOGS="${LOGS} ${MOST_LOGS}/${F}.log"
-done
-
-PROGNAME=scanlogs
-LOCK=${LOCKS}/LOCK.${PROGNAME}
-
-## Set defaults.
-ROTATE=true
-
-## Parse JCL.
-for I
-do
- case "X${I}" in
- Xnonn)
- # Ignore this.
- ;;
- Xnorotate)
- ROTATE=false
- ;;
- *)
- echo "Unknown flag ${I}" 1>&2
- exit 1
- ;;
- esac
-done
-
-## Make sure every log exists.
-for F in ${LOGS} ; do
- test ! -f ${F} && touch ${F}
-done
-
-## Temporary files.
-T=${TMPDIR}/scan$$
-PROBS=${TMPDIR}/scanlog$$
-trap "rm -f ${T} ${PROBS}; exit 0" 0 1 2 3 15
-
-## Rotate the logs?
-if ${ROTATE} ; then
- ## Lock out others.
- shlock -p $$ -f ${LOCK} || {
- echo "$0: Locked by `cat ${LOCK}`"
- exit 1
- }
- trap "rm -f ${T} ${PROBS} ${LOCK}; exit 0" 1 2 3 15
-
- HERE=`pwd`
- cd ${MOST_LOGS}
- test ! -d ${OLD} && mkdir ${OLD}
-
- ctlinnd -s logmode
- PAUSED=false
- ctlinnd -s pause "Flushing log and syslog files" 2>&1 && PAUSED=true
- OUTPUT=`ctlinnd flushlogs 2>&1`
- if [ "$OUTPUT" != "Ok" -a "$OUTPUT" != "In debug mode" ]; then
- echo "$OUTPUT"
- echo 'Cannot flush logs.'
- rm -f ${LOCK}
- exit 1
- fi
-
- ## Make sure these .old files exist, in case innd is down.
- for F in ${LOG} ${ERRLOG} ${EXPLOG} ; do
- if [ ! -f ${F}.old ]; then
- rm -f ${F}.old
- cp ${F} ${F}.old
- cat /dev/null >${F}
- fi
- done
-
- ## Copy syslog files, truncating old inode since syslog has it open.
- for F in ${SYSLOGS}; do
- rm -f ${F}.old
- cp ${F} ${F}.old
- cat /dev/null >${F}
- done
- ctlinnd -s logmode
-
- ## Make a copy of the active file.
- if [ -n ${ACTIVEFILE} ] ; then
- BASE=`basename ${ACTIVEFILE}`
- rm -f ${OLD}/${BASE}.old
- cp ${ACTIVEFILE} ${OLD}/${BASE}.old
- fi
-
- ## These are live files, so use link rather than copy.
- for F in ${LIVEFILES} ; do
- if [ -f ${F} ]; then
- rm -f ${F}.old ${F}.new
- ln ${F} ${F}.old
- touch ${F}.new
- chmod 0660 ${F}.new
- mv ${F}.new ${F}
- fi
- done
-
- ## Tally control messages if we logged them.
- test -n "${CONTROL_DATA}" && cat ${CONTROL_DATA} | ${TALLY_CONTROL}
-
- ${PAUSED} && ctlinnd -s go "Flushing log and syslog files" 2>&1
-
- cd ${OLD}
- for F in ${LOGS}; do
- ## Process the current (just-flushed) log
- BASE=`basename ${F}`
- rm -f ${OLD}/${BASE}
- case ${F} in
- ${SYSLOG_CRIT}|${ERRLOG}|${EXPLOG}|${LOG}|${SYSLOG_NOTICE})
- ## Make a link that can be deleted (since if not rotating
- ## we delete the copy that is made in ${TMPDIR}).
- mv ${F}.old ${OLD}/${BASE}
- rm -f ${OLD}/${BASE}.0
- ln ${OLD}/${BASE} ${OLD}/${BASE}.0
- ;;
- ${ACTIVEFILE})
- mv ${BASE}.old ${OLD}/${BASE}
- ;;
- ${SYSLOG_ERR})
- mv ${F}.old ${OLD}/${BASE}
- ;;
- ${UNWANTED_LOG})
- ## Rotate and compress the file.
- BASE=`basename ${F}`
- if [ ! -f ${BASE} -a -f ../${BASE} ]; then
- cp ../${BASE} ${BASE}
- chmod 0440 ${BASE}
- fi
- if [ -f ${BASE} ]; then
- ${LOG_COMPRESS} <${BASE} >${BASE}.0${Z} && rm -f ${BASE}
- chmod 0440 ${BASE}.0${Z}
-
- ## Do rotation.
- if [ X${LOGCYCLES} = X ]; then
- LOGCYCLES=3
- fi
- EXT=${LOGCYCLES}
- rm -f ${BASE}.${LOGCYCLES}${Z}
- while [ ${EXT} -gt 0 ] ; do
- NEXT=${EXT}
- EXT=`expr ${EXT} - 1`
- test -f ${BASE}.${EXT}${Z} \
- && rm -f ${BASE}.${NEXT}${Z} \
- && mv ${BASE}.${EXT}${Z} ${BASE}.${NEXT}${Z}
- done
- fi
- ## Innreport assumes where unwanted.log exists, so leave it
- ## and process later.
- ;;
- *)
- if [ -f ${F}.old ]; then
- mv ${F}.old ${OLD}/${BASE}
- else
- rm -f ${OLD}/${BASE} ${F}.new
- touch ${F}.new
- chmod 0660 ${F}.new
- ln ${F} ${F}.old
- mv ${F}.new ${F}
- mv ${F}.old ${OLD}/${BASE}
- fi
- ;;
- esac
- done
- cd ${HERE}
-else
- ## Don't use the real OLD directory, instead use TMPDIR
- OLD=${TMPDIR}
-
- ## Make a snapshot of what we need for below.
- ctlinnd -s pause "Snapshot log and syslog files" 2>&1
- for F in ${SYSLOG_CRIT} ${ERRLOG} ${EXPLOG} ${LOG} ${SYSLOG_NOTICE} ; do
- BASE=`basename ${F}`
- rm -f ${OLD}/${BASE}.0
- cp ${F} ${OLD}/${BASE}.0
- done
- ctlinnd -s go "Snapshot log and syslog files" 2>&1
-fi
-
-##
-## We now (finally!) have copies of the log files where we need them.
-##
-
-## Display syslog critical messages.
-BASE=`basename ${SYSLOG_CRIT}`
-OLD_SYSLOG=${OLD}/${BASE}.0
-if [ -s ${OLD_SYSLOG} ] ; then
- echo Syslog critical messages:
- cat ${OLD_SYSLOG}
- echo ---------
- echo ''
-fi
-rm -f ${OLD_SYSLOG}
-
-## Display error log.
-BASE=`basename ${ERRLOG}`
-OLD_ERRLOG=${OLD}/${BASE}.0
-if [ -s ${OLD_ERRLOG} ] ; then
- echo Error log:
- cat ${OLD_ERRLOG}
- echo ---------
- echo ''
-fi
-rm -f ${OLD_ERRLOG}
-
-## Scan for various problems in articles we were offered or sent...
-BASE=`basename ${LOG}`
-OLD_LOG=${OLD}/${BASE}.0
-
-## and summarize syslog information.
-BASE=`basename ${SYSLOG_NOTICE}`
-OLD_SYSLOG=${OLD}/${BASE}.0
-if [ -s ${OLD_SYSLOG} -o -s ${OLD_LOG} ] ; then
- ${PATHBIN}/innreport -f ${PATHETC}/innreport.conf ${OLD_SYSLOG} ${OLD_LOG}
- echo ---------
- echo ''
-fi
-rm -f ${OLD_LOG} ${OLD_SYSLOG}
-if ${ROTATE} ; then
- BASE=`basename ${UNWANTED_LOG}`
- if [ -f ${UNWANTED_LOG}.old ]; then
- mv ${UNWANTED_LOG}.old ${OLD}/${BASE}
- else
- rm -f ${OLD}/${BASE}
- cp ${UNWANTED_LOG} ${OLD}/${BASE}
- chmod 0660 ${OLD}/${BASE}
- fi
-fi
-
-OLD_SYSLOG=${OLD}/${EXPLOG}.0
-rm -f ${EXPLOG}
-
-## Compress and rotate the logs.
-if ${ROTATE} ; then
- cd ${OLD}
- if [ X${LOGCYCLES} = X ]; then
- LOGCYCLES=3
- fi
- for F in ${LOGS} ; do
- ## Skip if it's unwanted.log, since it's already rotated
- if [ ${F} = ${UNWANTED_LOG} ]; then
- continue
- fi
- ## Skip if file doesn't exist.
- BASE=`basename ${F}`
- test -f ${BASE} || continue
-
- ## Compress the file.
- ${LOG_COMPRESS} <${BASE} >${BASE}.0${Z} && rm -f ${BASE}
- chmod 0440 ${BASE}.0${Z}
-
- ## Do rotation.
- EXT=${LOGCYCLES}
- rm -f ${BASE}.${LOGCYCLES}${Z}
- while [ ${EXT} -gt 0 ] ; do
- NEXT=${EXT}
- EXT=`expr ${EXT} - 1`
- test -f ${BASE}.${EXT}${Z} \
- && rm -f ${BASE}.${NEXT}${Z} \
- && mv ${BASE}.${EXT}${Z} ${BASE}.${NEXT}${Z}
- done
- done
-
- ## Remove lock.
- rm -f ${LOCK}
-fi
-
-## All done.
-exit 0
+++ /dev/null
-#! /usr/bin/perl -w
-
-# simpleftp - Rudimentary FTP client.
-#
-# Author: David Lawrence <tale@isc.org>.
-# Rewritten by Julien Elie <julien@trigofacile.com> to use Net::FTP.
-#
-# Fetch files to the local machine based on URLs on the command line.
-# INN's configure searches for ncftp, wget, linx, et caetera,
-# but they're all system add-ons, so this is provided.
-#
-# Perl 5 is already required by other parts of INN; it only took a half hour
-# to write this, so this was the easiest way to go for a backup plan.
-#
-# This script is nowhere near as flexible as libwww. If you really need
-# that kind of power, get libwww and use it. This is just sufficient for what
-# INN needed.
-
-use strict;
-use Net::FTP;
-use Sys::Hostname;
-
-$0 =~ s(.*/)();
-
-my $usage = "Usage: $0 ftp-URL ...\n";
-
-@ARGV
- or die $usage;
-
-for (@ARGV) {
- m(^ftp://)
- or die $usage;
-}
-
-my ($lasthost, $ftp);
-
-# This will keep track of how many _failed_.
-my $exit = @ARGV;
-
-for (@ARGV) {
- my ($host, $path) = m%^ftp://([^/]+)(/.+)%;
- my $user = 'anonymous';
- my $pass = (getpwuid($<))[0] . '@' . hostname;
- my $port = 21;
-
- unless (defined $host && defined $path) {
- warn "$0: bad URL: $_\n";
- next;
- }
-
- if ($host =~ /(.*):(.*)\@(.*)/) {
- $user = $1;
- $pass = $2;
- $host = $3;
- }
-
- if ($host =~ /(.*):(.*)/) {
- $port = $1;
- $host = $2;
- }
-
- if (defined $lasthost && $host ne $lasthost) {
- $ftp->quit;
- $lasthost = undef;
- }
-
- unless (defined $lasthost) {
- $ftp = Net::FTP->new($host, Port => $port)
- or next;
- $ftp->login($user, $pass)
- or next;
- }
-
- my $localfile = $path;
- $path =~ s([^/]+$)();
- $localfile =~ s(.*/)();
-
- $ftp->cwd($path)
- or next;
- $ftp->get($localfile)
- or next;
-
- $exit--;
- $lasthost = $host;
-}
-
-$ftp->quit
- if defined $lasthost;
-
-exit $exit;
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 2677 $
-## Tally/update the newgroup/rmgroup control log.
-## Merge in a log that contains newgroup/rmgroup control messages so that
-## the "control.log" file is updated to contain the new counts of how
-## often each group has been newgroup'd or rmgroup'd. This is run by
-## scanlogs, which prepares this from the control-message handlers if
-## control.ctl specifies logging.
-
-CONTROL=${MOST_LOGS}/control.log
-CONTROL_NEW=${CONTROL}.new
-CONTROL_OLD=${CONTROL}.old
-
-PROGNAME=`basename $0`
-LOCK=${LOCKS}/LOCK.${PROGNAME}
-
-## Lock.
-trap 'rm -f ${LOCK} ; exit 1' 1 2 3 15
-shlock -f ${LOCK} -p $$ || {
- echo "$0: cannot lock ${LOCK}" 1>&2
- exit 1
-}
-
-## Prepare the files.
-if [ ! -f ${CONTROL} ]; then
- touch ${CONTROL}
- chmod 0660 ${CONTROL}
-fi
-rm -f ${CONTROL_NEW} ${CONTROL_OLD}
-ln ${CONTROL} ${CONTROL_OLD}
-touch ${CONTROL_NEW}
-chmod 0660 ${CONTROL_NEW}
-
-## Grab the data.
-${SED} -n -e 's/[ ][ ]*/ /g' -e 's/^ \(Control:.*\)$/1 \1/p' \
- | cat - ${CONTROL} \
- | ${SED} -e 's/ /#/g' -e 's/\([0-9][0-9]*\)#\(.*\)/\1 \2/' \
- | ${AWK} 'BEGIN {
- ctl[0]=0;
- }
- {
- ctl[$2] += $1;
- }
- END {
- for (line in ctl) {
- if (line != 0) {
- print ctl[line], line;
- }
- }
- }' \
- | tr '#' ' ' \
- | sort -n -r >${CONTROL_NEW}
-mv -f ${CONTROL_NEW} ${CONTROL}
-
-## All done.
-rm -f ${LOCK}
-exit 0
+++ /dev/null
-#! /bin/sh
-# fixscript will replace this line with code to load innshellvars
-
-## $Revision: 2677 $
-## Write a log file entry, by either mailing it or writing it safely.
-## Usage:
-## writelog name text... <input
-## where
-## name is 'mail' to mail it, or filename to append to.
-
-MAXTRY=60
-
-## Parse arguments.
-if [ $# -lt 2 ] ; then
- echo "usage: $0 'logfile|mail' message ..." 1>&2
- exit 1
-fi
-LOGFILE="$1"
-shift
-MESSAGE="$@"
-
-## Handle the easy cases.
-case "X${LOGFILE}" in
-X/dev/null)
- exit 0
- ;;
-Xmail)
- sed -e 's/^~/~~/' | ${MAILCMD} -s "${MESSAGE}" ${NEWSMASTER}
- exit 0
- ;;
-esac
-
-## We're sending to a file.
-LOCK=${LOCKS}/LOCK.`basename ${LOGFILE}`
-
-## Remember our PID, in case while is a sub-shell.
-PID=$$
-TRY=0
-
-export LOCK MAXTRY PID LOGFILE ARTICLE MESSAGE TRY
-while [ ${TRY} -lt ${MAXTRY} ]; do
- shlock -p ${PID} -f ${LOCK} && break
- sleep 2
- TRY=`expr ${TRY} + 1`
-done
-
-## If we got the lock, update the file; otherwise, give up.
-if [ ${TRY} -lt ${MAXTRY} ]; then
- echo "${MESSAGE}" >>${LOGFILE}
- ${SED} -e 's/^/ /' >>${LOGFILE}
- echo "" >>${LOGFILE}
- rm -f ${LOCK}
-else
- ## This goes to errlog, usually.
- echo "$0: Cannot grab lock ${LOCK}, held by:" `cat ${LOCK}` 1>&2
-fi
+++ /dev/null
-## $Revision: 7907 $
-include ../Makefile.global
-top = ..
-
-## If you want to do ctlinnd pause/reload/go, uncomment these lines.
-#PAUSE = pause
-#RELOAD_AND_GO = reload go
-DIFF="diff"
-
-# Added a default rule for ".csh" because Digital UNIX has a builtin
-# rule which would overwite the innshellvars file.
-.csh:
-
-CTLINND = ${PATHBIN}/ctlinnd
-FILTBIN = ${PATHFILTER}
-PATH_PERL_STARTUP_INND = ${PATHFILTER}/startup_innd.pl
-PATH_PERL_FILTER_INND = ${PATHFILTER}/filter_innd.pl
-PATH_PERL_FILTER_NNRPD = ${PATHFILTER}/filter_nnrpd.pl
-PATH_TCL_STARTUP = ${PATHFILTER}/startup.tcl
-PATH_TCL_FILTER = ${PATHFILTER}/filter.tcl
-PATH_PYTHON_FILTER_INND = ${PATHFILTER}/filter_innd.py
-PATH_PYTHON_INN_MODULE = ${PATHFILTER}/INN.py
-PATH_PYTHON_NNRPD_MODULE= ${PATHFILTER}/nnrpd.py
-PATH_NNRPAUTH = ${PATHFILTER}/nnrpd_auth.pl
-PATH_NNRPYAUTH = ${PATHFILTER}/nnrpd_auth.py
-PATH_NNRPACCESS = ${PATHFILTER}/nnrpd_access.pl
-PATH_NNRPYACCESS = ${PATHFILTER}/nnrpd_access.py
-PATH_NNRPYDYNAMIC = ${PATHFILTER}/nnrpd_dynamic.py
-
-PATH_CONFIG = ${PATHETC}/inn.conf
-PATH_CONTROLCTL = ${PATHETC}/control.ctl
-PATH_EXPIRECTL = ${PATHETC}/expire.ctl
-PATH_INNDHOSTS = ${PATHETC}/incoming.conf
-PATH_MODERATORS = ${PATHETC}/moderators
-PATH_DISTPATS = ${PATHETC}/distrib.pats
-PATH_NEWSFEEDS = ${PATHETC}/newsfeeds
-PATH_READERSCONF = ${PATHETC}/readers.conf
-PATH_NNRPDTRACK = ${PATHETC}/nnrpd.track
-PATH_SCHEMA = ${PATHETC}/overview.fmt
-PATH_NNTPPASS = ${PATHETC}/passwd.nntp
-PATH_CTLWATCH = ${PATHETC}/innwatch.ctl
-PATH_ACTSYNC_IGN = ${PATHETC}/actsync.ign
-PATH_ACTSYNC_CFG = ${PATHETC}/actsync.cfg
-PATH_MOTD = ${PATHETC}/motd.news
-PATH_STORAGECONF = ${PATHETC}/storage.conf
-PATH_CYCBUFFCONFIG = ${PATHETC}/cycbuff.conf
-PATH_INNFEEDCTL = ${PATHETC}/innfeed.conf
-PATH_BUFFINDEXED = ${PATHETC}/buffindexed.conf
-PATH_RADIUS_CONF = ${PATHETC}/radius.conf
-PATH_OVDB_CONF = ${PATHETC}/ovdb.conf
-PATH_SASL_CONF = ${PATHETC}/sasl.conf
-PATH_SUBSCRIPTIONS = ${PATHETC}/subscriptions
-
-PATH_ACTIVE = ${PATHDB}/active
-PATH_ACTIVE_TIMES = ${PATHDB}/active.times
-PATH_HISTORY = ${PATHDB}/history
-PATH_NEWSGROUPS = ${PATHDB}/newsgroups
-
-## Scripts from above, plus site-specific config files.
-REST = \
- newsfeeds incoming.conf nnrpd.track passwd.nntp \
- inn.conf moderators innreport.conf \
- control.ctl expire.ctl nntpsend.ctl overview.fmt \
- innwatch.ctl distrib.pats actsync.cfg actsync.ign \
- motd.news storage.conf cycbuff.conf buffindexed.conf \
- innfeed.conf startup_innd.pl filter_innd.pl filter_nnrpd.pl \
- filter_innd.py INN.py nnrpd.py \
- startup.tcl filter.tcl nnrpd_auth.pl nnrpd_access.pl \
- nnrpd_access.py nnrpd_dynamic.py \
- news2mail.cf readers.conf \
- radius.conf nnrpd_auth.py ovdb.conf sasl.conf active.minimal \
- newsgroups.minimal subscriptions
-
-ALL = $(MOST) $(REST)
-
-REST_INSTALLED = \
- $D$(PATH_NEWSFEEDS) $D$(PATH_INNDHOSTS) \
- $D$(PATH_NNRPDTRACK) $D$(PATH_NNTPPASS) \
- $D$(PATH_CONFIG) $D$(PATH_MODERATORS) \
- $D$(PATH_CONTROLCTL) $D$(PATH_EXPIRECTL) $D$(PATHETC)/nntpsend.ctl \
- $D$(PATHETC)/innreport.conf \
- $D$(PATH_CTLWATCH) $D$(PATH_DISTPATS) $D$(PATH_SCHEMA) \
- $D$(PATH_ACTSYNC_CFG) $D$(PATH_ACTSYNC_IGN) \
- $D$(PATH_MOTD) $D$(PATH_STORAGECONF) \
- $D$(PATH_OVERVIEWCTL) $D$(PATH_CYCBUFFCONFIG) $D$(PATH_BUFFINDEXED) \
- $D$(PATH_INNFEEDCTL) $D$(PATH_PERL_STARTUP_INND) \
- $D$(PATH_PERL_FILTER_INND) $D$(PATH_PERL_FILTER_NNRPD) \
- $D$(PATH_PYTHON_FILTER_INND) $D$(PATH_PYTHON_INN_MODULE) \
- $D$(PATH_TCL_STARTUP) $D$(PATH_TCL_FILTER) $D$(PATH_PYTHON_NNRPD_MODULE) \
- $D$(PATH_NNRPAUTH) $D$(PATHETC)/news2mail.cf $D$(PATH_READERSCONF) \
- $D$(PATH_RADIUS_CONF) $D$(PATH_NNRPYAUTH) $D$(PATH_OVDB_CONF) \
- $D$(PATH_NNRPYACCESS) $D$(PATH_NNRPYDYNAMIC) \
- $D$(PATH_SASL_CONF) $D$(PATH_SUBSCRIPTIONS) $D$(PATH_NNRPACCESS)
-
-ALL_INSTALLED = $(MOST_INSTALLED) $(REST_INSTALLED)
-
-SPECIAL = $D$(PATH_ACTIVE) $D$(PATH_ACTIVE_TIMES) \
- $D$(PATH_NEWSGROUPS) $D$(PATH_HISTORY)
-
-## Get new versions of everything from samples directory.
-all: $(P) $(ALL) config
-
-## Get only scripts, not per-host config files.
-most: $(MOST)
-
-## Show changes between files here and ones in samples.
-diff:
- @$(MAKE) COPY=-${DIFF} all
-
-## Show changes between files here and installed versions.
-diff-installed:
- @$(MAKE) COPY_RPRI=-${DIFF} COPY_RPUB=-${DIFF} COPY_XPRI=-${DIFF} COPY_XPUB=-${DIFF} $(ALL_INSTALLED)
-
-## Show what would be copied from samples directory.
-what:
- @$(MAKE) -s 'COPY=@echo' $(ALL) | ${AWK} 'NF==2 { print $$2; }'
-
-config: $(ALL)
- date >config
-
-## Don't use parallel rules -- we want this to be viewed carefully.
-install: all $(PAUSE) install-config $(RELOAD_AND_GO)
-reload-install: all pause install-config reload go
-install-config: update $(REST_INSTALLED) #$(SPECIAL)
-
-## Install scripts, not per-host config files.
-update: all $(MOST_INSTALLED)
- @echo "" ; echo inn.conf in site directory may have newly added parameters
- @echo which installed inn.conf does not have. Check those parameters
- @echo before you run innd. ; echo ""
- date >update
-
-## Special rules for files that sould never be overwritten if they are
-## already installed. These are used only for the initial install of a
-## brand new server.
-$D$(PATH_ACTIVE): ; $(CP_DATA) active.minimal $@
-$D$(PATH_NEWSGROUPS): ; $(CP_DATA) newsgroups.minimal $@
-$D$(PATH_ACTIVE_TIMES):
- touch $@
- chown $(NEWSUSER) $@
- chgrp $(NEWSGROUP) $@
- chmod $(FILEMODE) $@
-$D$(PATH_HISTORY):
- touch $@
- chown $(NEWSUSER) $@
- chgrp $(NEWSGROUP) $@
- chmod $(FILEMODE) $@
- $(PATHBIN)/makedbz -i -o
-
-## Remove files that are unchanged from the release version.
-clean:
- @-for I in $(ALL) ; do \
- cmp -s $$I ../samples/$$I && echo rm -f $$I && rm -f $$I ; \
- done
-
-clobber distclean:
- rm -f $(ALL) tags profiled config update
-
-tags ctags:
- cp /dev/null tags
-
-profiled:
- cp /dev/null profiled
-
-depend:
-
-## Commands to make private or public, read or executable files.
-COPY_RPRI = $(CP_RPRI)
-COPY_RPUB = $(CP_RPUB)
-COPY_XPRI = $(CP_XPRI)
-COPY_XPUB = $(CP_XPUB)
-
-## Order: innd, control, expire, inews, sending, misc
-$D$(PATH_INNDHOSTS): incoming.conf ; $(COPY_RPRI) $? $@
-$D$(PATH_NEWSFEEDS): newsfeeds ; $(COPY_RPUB) $? $@
-$D$(PATH_READERSCONF): readers.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_RADIUS_CONF): radius.conf ; $(COPY_RPRI) $? $@
-$D$(PATH_NNRPDTRACK): nnrpd.track ; $(COPY_RPUB) $? $@
-$D$(PATH_SCHEMA): overview.fmt ; $(COPY_RPUB) $? $@
-$D$(PATH_CONTROLCTL): control.ctl ; $(COPY_RPUB) $? $@
-$D$(PATH_CTLWATCH): innwatch.ctl ; $(COPY_RPUB) $? $@
-$D$(PATH_EXPIRECTL): expire.ctl ; $(COPY_RPUB) $? $@
-$D$(PATH_CONFIG): inn.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_MODERATORS): moderators ; $(COPY_RPUB) $? $@
-$D$(PATH_DISTPATS): distrib.pats ; $(COPY_RPUB) $? $@
-$D$(PATH_NNTPPASS): passwd.nntp ; $(COPY_RPRI) $? $@
-$D$(PATHETC)/nntpsend.ctl: nntpsend.ctl ; $(COPY_RPUB) $? $@
-$D$(PATHETC)/news2mail.cf: news2mail.cf ; $(COPY_RPUB) $? $@
-$D$(PATHETC)/innreport.conf: innreport.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_STORAGECONF): storage.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_CYCBUFFCONFIG): cycbuff.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_BUFFINDEXED): buffindexed.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_OVDB_CONF): ovdb.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_PERL_STARTUP_INND): startup_innd.pl ; $(COPY_RPUB) $? $@
-$D$(PATH_PERL_FILTER_INND): filter_innd.pl ; $(COPY_RPUB) $? $@
-$D$(PATH_PERL_FILTER_NNRPD): filter_nnrpd.pl ; $(COPY_RPUB) $? $@
-$D$(PATH_PYTHON_FILTER_INND): filter_innd.py ; $(COPY_RPUB) $? $@
-$D$(PATH_PYTHON_INN_MODULE): INN.py ; $(COPY_RPUB) $? $@
-$D$(PATH_PYTHON_NNRPD_MODULE): nnrpd.py ; $(COPY_RPUB) $? $@
-$D$(PATH_TCL_STARTUP): startup.tcl ; $(COPY_RPUB) $? $@
-$D$(PATH_TCL_FILTER): filter.tcl ; $(COPY_RPUB) $? $@
-$D$(PATH_NNRPAUTH): nnrpd_auth.pl ; $(COPY_RPUB) $? $@
-$D$(PATH_NNRPACCESS): nnrpd_access.pl ; $(COPY_RPUB) $? $@
-$D$(PATH_NNRPYAUTH): nnrpd_auth.py ; $(COPY_RPUB) $? $@
-$D$(PATH_NNRPYACCESS): nnrpd_access.py ; $(COPY_RPUB) $? $@
-$D$(PATH_NNRPYDYNAMIC): nnrpd_dynamic.py ; $(COPY_RPUB) $? $@
-$D$(PATH_ACTSYNC_CFG): actsync.cfg ; $(COPY_RPUB) $? $@
-$D$(PATH_ACTSYNC_IGN): actsync.ign ; $(COPY_RPUB) $? $@
-$D$(PATH_MOTD): motd.news ; $(COPY_RPUB) $? $@
-$D$(PATH_INNFEEDCTL): innfeed.conf ; $(COPY_RPRI) $? $@
-$D$(PATH_SASL_CONF): sasl.conf ; $(COPY_RPUB) $? $@
-$D$(PATH_SUBSCRIPTIONS): subscriptions ; $(COPY_RPUB) $? $@
-
-REASON = 'Installing site config files from site/Makefile'
-go pause:
- -${CTLINND} $@ $(REASON)
-reload:
- -${CTLINND} reload all $(REASON)
-
-## Use this to just replace any changed files you might have made. Only
-## do this after you've examined the output of "make -n"!
-replace:
- $(MAKE) COPY=cp all
-
-## Get files from the samples directory.
-COPY = $(SHELL) ./getsafe.sh
-actsync.cfg: ../samples/actsync.cfg ; $(COPY) $? $@
-actsync.ign: ../samples/actsync.ign ; $(COPY) $? $@
-control.ctl: ../samples/control.ctl ; $(COPY) $? $@
-expire.ctl: ../samples/expire.ctl ; $(COPY) $? $@
-filter.tcl: ../samples/filter.tcl ; $(COPY) $? $@
-nnrpd_auth.pl: ../samples/nnrpd_auth.pl ; $(COPY) $? $@
-nnrpd_access.pl: ../samples/nnrpd_access.pl ; $(COPY) $? $@
-nnrpd_auth.py: ../samples/nnrpd_auth.py ; $(COPY) $? $@
-nnrpd_access.py: ../samples/nnrpd_access.py ; $(COPY) $? $@
-nnrpd_dynamic.py: ../samples/nnrpd_dynamic.py ; $(COPY) $? $@
-filter_innd.pl: ../samples/filter_innd.pl ; $(COPY) $? $@
-filter_nnrpd.pl: ../samples/filter_nnrpd.pl ; $(COPY) $? $@
-filter_innd.py: ../samples/filter_innd.py ; $(COPY) $? $@
-INN.py: ../samples/INN.py ; $(COPY) $? $@
-nnrpd.py: ../samples/nnrpd.py ; $(COPY) $? $@
-incoming.conf: ../samples/incoming.conf ; $(COPY) $? $@
-inn.conf: ../samples/inn.conf ; $(COPY) $? $@
-innreport.conf: ../samples/innreport.conf ; $(COPY) $? $@
-storage.conf: ../samples/storage.conf ; $(COPY) $? $@
-cycbuff.conf: ../samples/cycbuff.conf ; $(COPY) $? $@
-buffindexed.conf: ../samples/buffindexed.conf ; $(COPY) $? $@
-ovdb.conf: ../samples/ovdb.conf ; $(COPY) $? $@
-innwatch.ctl: ../samples/innwatch.ctl ; $(COPY) $? $@
-innfeed.conf: ../samples/innfeed.conf ; $(COPY) $? $@
-moderators: ../samples/moderators ; $(COPY) $? $@
-distrib.pats: ../samples/distrib.pats ; $(COPY) $? $@
-motd.news: ../samples/motd.news ; $(COPY) $? $@
-news2mail.cf: ../samples/news2mail.cf ; $(COPY) $? $@
-newsfeeds: ../samples/newsfeeds ; $(COPY) $? $@
-nnrpd.track: ../samples/nnrpd.track ; $(COPY) $? $@
-nntpsend.ctl: ../samples/nntpsend.ctl ; $(COPY) $? $@
-overview.fmt: ../samples/overview.fmt ; $(COPY) $? $@
-parsecontrol: ../samples/parsecontrol ; $(COPY) $? $@
-passwd.nntp: ../samples/passwd.nntp ; $(COPY) $? $@
-readers.conf: ../samples/readers.conf ; $(COPY) $? $@
-radius.conf: ../samples/radius.conf ; $(COPY) $? $@
-startup.tcl: ../samples/startup.tcl ; $(COPY) $? $@
-startup_innd.pl: ../samples/startup_innd.pl ; $(COPY) $? $@
-subscriptions: ../samples/subscriptions ; $(COPY) $? $@
-sasl.conf: ../samples/sasl.conf ; $(COPY) $? $@
-active.minimal: ../samples/active.minimal ; $(COPY) $? $@
-newsgroups.minimal: ../samples/newsgroups.minimal ; $(COPY) $? $@
+++ /dev/null
-#! /bin/sh
-## $Revision: 847 $
-##
-## Safely get a file from the samples directory. Usage:
-## getsafe <sample> <localfile>
-case $# in
-2)
- ;;
-*)
- echo "Can't get INN sample file: wrong number of arguments." 1>&2
- exit 1
- ;;
-esac
-
-SRC=$1
-DEST=$2
-
-## Try RCS.
-if [ -f RCS/${DEST},v ] ; then
- echo "Note: ${SRC} has changed; please compare."
- test -f ${DEST} && exit 0
- exec co -q ${DEST}
-fi
-
-## Try SCCS.
-if [ -f SCCS/s.${DEST} ] ; then
- echo "Note: ${SRC} has changed; please compare."
- test -f ${DEST} && exit 0
- exec sccs get -s ${DEST}
-fi
-
-## File exist locally?
-if [ -f ${DEST} ] ; then
- cmp ${SRC} ${DEST}
- if [ $? -eq 0 ] ; then
- touch ${DEST}
- exit 0
- fi
- echo "${SRC} has changed; please update ${DEST}"
- exit 1
-fi
-
-echo Using sample version of ${DEST}
-cp ${SRC} ${DEST}
-
-exit 0
+++ /dev/null
-# This file is automatically generated by buildconfig
-
-METHOD_SOURCES = buffindexed/buffindexed.c cnfs/cnfs.c ovdb/ovdb.c \
- timecaf/caf.c timecaf/timecaf.c timehash/timehash.c \
- tradindexed/tdx-cache.c tradindexed/tdx-data.c \
- tradindexed/tdx-group.c tradindexed/tradindexed.c \
- tradspool/tradspool.c trash/trash.c
-EXTRA_SOURCES = tradindexed/tdx-util.c
-PROGRAMS = tradindexed/tdx-util
-
-
-## Included from buffindexed/ovmethod.mk
-
-# This rule requires a compiler that supports -o with -c. Since it's normally
-# used by developers, that should be acceptable.
-buffindexed/buffindexed_d.o: buffindexed/buffindexed.c
- $(CC) $(CFLAGS) -DBUFF_DEBUG -c -o $@ buffindexed/buffindexed.c
-
-buffindexed/debug: buffindexed/buffindexed_d.o libstorage.$(EXTLIB) $(LIBHIST)
- $(LIBLD) $(LDFLAGS) -o $@ buffindexed/buffindexed_d.o \
- $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
-
-
-## Included from tradindexed/ovmethod.mk
-
-tradindexed/tdx-util.o: tradindexed/tdx-util.c
- $(CC) $(CFLAGS) -c -o $@ tradindexed/tdx-util.c
-
-tradindexed/tdx-util: tradindexed/tdx-util.o libstorage.$(EXTLIB) $(LIBHIST)
- $(LIBLD) $(LDFLAGS) -o $@ tradindexed/tdx-util.o \
- $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
+++ /dev/null
-## $Id: Makefile 7727 2008-04-06 07:59:46Z iulius $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) -I. $(BERKELEY_DB_CFLAGS)
-
-SOURCES = expire.c interface.c methods.c ov.c overdata.c ovmethods.c \
- $(METHOD_SOURCES)
-OBJECTS = $(SOURCES:.c=.o)
-LOBJECTS = $(OBJECTS:.o=.lo)
-
-.SUFFIXES: .lo
-
-all: library programs
-
-# Included here after the all target, since additional rules are defined in
-# Make.methods to be sure that we recurse properly to build the methods.
-include Make.methods
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' all
-
-install: all
- $(LI_XPUB) libstorage.$(EXTLIB) $D$(PATHLIB)/libstorage.$(EXTLIB)
- for F in $(PROGRAMS) ; do \
- $(LI_XPRI) $$F $D$(PATHBIN)/`basename $$F` ; \
- done
-
-library: libstorage.$(EXTLIB)
-
-programs: $(PROGRAMS)
-
-clobber clean distclean:
- rm -f *.o *.lo */*.o */*.lo libstorage.la libstorage.a
- rm -f $(PROGRAMS) libstorage_pure_*.a .pure
- rm -f buildconfig methods.c methods.h ovmethods.c ovmethods.h
- rm -f profiled libstorage$(PROFSUFFIX).a
- rm -rf .libs */.libs
-
-tags ctags: $(SOURCES)
- $(CTAGS) $(SOURCES) ../include/*.h ../include/inn/*.h
-
-$(FIXSCRIPT):
- @echo Run configure before running make. See INSTALL for details.
- @exit 1
-
-libstorage.la: $(OBJECTS) $(LIBINN)
- $(LIBLD) $(LDFLAGS) -o $@ $(LOBJECTS) \
- $(LIBINN) $(EXTSTORAGELIBS) $(LIBS) \
- -rpath $(PATHLIB) -version-info 2:0:0
-
-libstorage.a: $(OBJECTS)
- ar r $@ $(OBJECTS)
- $(RANLIB) libstorage.a
-
-# Make.methods is included in the distribution tarball since some non-GNU
-# makes can't deal with including a non-existent file, so don't depend on
-# it. The dependencies aren't entirely accurate; you really want to re-run
-# buildconfig each time a new subdirectory is added to the directory. But
-# adding a dependency on . is a bit too non-portable for my taste and causes
-# too many rebuilds.
-Make.methods methods.h ovmethods.c ovmethods.h methods.c: buildconfig
- ./buildconfig
-
-buildconfig: buildconfig.in $(FIXSCRIPT)
- $(FIXSCRIPT) -i buildconfig.in
-
-.c.o .c.lo:
- $(LIBCC) $(CFLAGS) $(CCOUTPUT)
-
-ovtest: ov.c libstorage.$(EXTLIB) $(LIBINN)
- $(CC) $(CFLAGS) -D_TEST_ -o ovtest ov.c \
- libstorage.$(EXTLIB) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
-
-$(LIBINN): ; (cd ../lib ; $(MAKE))
-$(LIBHIST): ; (cd ../history ; $(MAKE))
-
-
-## Profiling. The rules are a bit brute-force, but good enough.
-
-profiled: libstorage$(PROFSUFFIX).a
- date >$@
-
-libstorage$(PROFSUFFIX).a: $(SOURCES)
- rm -f $(OBJECTS)
- $(MAKEPROFILING) libstorage.a
- mv libstorage.a libstorage$(PROFSUFFIX).a
- $(RANLIB) libstorage$(PROFSUFFIX).a
- rm -f $(OBJECTS)
-
-
-## Dependencies. Default list, below, is probably good enough.
-
-depend: Makefile $(SOURCES) $(EXTRA_SOURCES)
- $(MAKEDEPEND) '$(CFLAGS)' $(SOURCES) $(EXTRA_SOURCES)
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
-expire.o: expire.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ovinterface.h ../include/storage.h ../include/inn/history.h \
- ../include/paths.h
-interface.o: interface.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/conffile.h ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/wire.h interface.h ../include/storage.h \
- ../include/libinn.h methods.h ../include/paths.h
-methods.o: methods.c interface.h ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/storage.h \
- ../include/config.h methods.h cnfs/cnfs.h timecaf/timecaf.h \
- ../include/config.h interface.h timehash/timehash.h ../include/config.h \
- interface.h tradspool/tradspool.h ../include/config.h interface.h \
- trash/trash.h ../include/config.h interface.h
-ov.o: ov.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ovinterface.h ../include/storage.h ../include/inn/history.h ovmethods.h
-overdata.o: overdata.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/inn/buffer.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h ../include/inn/qio.h \
- ../include/inn/wire.h ../include/inn/vector.h ../include/libinn.h \
- ovinterface.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../include/storage.h ../include/inn/history.h \
- ../include/paths.h
-ovmethods.o: ovmethods.c ovinterface.h ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/ov.h \
- ../include/storage.h ../include/config.h ../include/inn/history.h \
- ../include/inn/defines.h ../include/storage.h ../include/inn/history.h \
- buffindexed/buffindexed.h ovdb/ovdb.h tradindexed/tradindexed.h \
- ../include/config.h ../include/ov.h ../include/storage.h
-buffindexed/buffindexed.o: buffindexed/buffindexed.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/mmap.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ../include/paths.h ovinterface.h ../include/config.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ../include/storage.h \
- buffindexed/buffindexed.h
-cnfs/cnfs.o: cnfs/cnfs.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h \
- ../include/portable/time.h ../include/inn/innconf.h \
- ../include/inn/defines.h interface.h ../include/config.h \
- ../include/storage.h ../include/libinn.h methods.h interface.h \
- ../include/paths.h ../include/inn/wire.h ../include/inn/mmap.h \
- cnfs/cnfs.h cnfs/cnfs-private.h
-ovdb/ovdb.o: ovdb/ovdb.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/socket.h ../include/config.h \
- ../include/portable/time.h ../include/conffile.h \
- ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/paths.h \
- ../include/storage.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ovinterface.h ../include/config.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ovdb/ovdb.h ovdb/ovdb-private.h
-timecaf/caf.o: timecaf/caf.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h timecaf/caf.h
-timecaf/timecaf.o: timecaf/timecaf.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/portable/mmap.h ../include/config.h timecaf/caf.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/wire.h \
- ../include/libinn.h methods.h interface.h ../include/config.h \
- ../include/storage.h timecaf/timecaf.h interface.h ../include/paths.h
-timehash/timehash.o: timehash/timehash.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/mmap.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/wire.h \
- ../include/libinn.h methods.h interface.h ../include/config.h \
- ../include/storage.h ../include/paths.h timehash/timehash.h interface.h
-tradindexed/tdx-cache.o: tradindexed/tdx-cache.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/hashtab.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/storage.h \
- tradindexed/tdx-private.h
-tradindexed/tdx-data.o: tradindexed/tdx-data.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/mmap.h ../include/config.h \
- ../include/inn/history.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h \
- ../include/inn/mmap.h ../include/libinn.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ovinterface.h \
- ../include/config.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../include/storage.h tradindexed/tdx-private.h \
- tradindexed/tdx-structure.h
-tradindexed/tdx-group.o: tradindexed/tdx-group.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/mmap.h ../include/config.h \
- ../include/inn/hashtab.h ../include/inn/defines.h \
- ../include/inn/innconf.h ../include/inn/messages.h \
- ../include/inn/mmap.h ../include/inn/qio.h ../include/inn/vector.h \
- ../include/libinn.h ../include/paths.h tradindexed/tdx-private.h \
- ../include/storage.h tradindexed/tdx-structure.h
-tradindexed/tradindexed.o: tradindexed/tradindexed.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/innconf.h ../include/inn/defines.h \
- ../include/inn/messages.h ../include/libinn.h ../include/ov.h \
- ../include/storage.h ../include/inn/history.h ../include/storage.h \
- tradindexed/tdx-private.h tradindexed/tdx-structure.h \
- tradindexed/tradindexed.h
-tradspool/tradspool.o: tradspool/tradspool.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/portable/mmap.h ../include/config.h \
- ../include/inn/innconf.h ../include/inn/defines.h ../include/inn/qio.h \
- ../include/inn/wire.h ../include/libinn.h ../include/paths.h methods.h \
- interface.h ../include/config.h ../include/storage.h \
- tradspool/tradspool.h interface.h
-trash/trash.o: trash/trash.c ../include/config.h ../include/inn/defines.h \
- ../include/inn/system.h ../include/clibrary.h ../include/config.h \
- ../include/libinn.h methods.h interface.h ../include/config.h \
- ../include/storage.h trash/trash.h interface.h
-tradindexed/tdx-util.o: tradindexed/tdx-util.c ../include/config.h \
- ../include/inn/defines.h ../include/inn/system.h ../include/clibrary.h \
- ../include/config.h ../include/inn/buffer.h ../include/inn/defines.h \
- ../include/inn/history.h ../include/inn/innconf.h \
- ../include/inn/messages.h ../include/inn/vector.h ../include/libinn.h \
- ../include/ov.h ../include/storage.h ../include/inn/history.h \
- ovinterface.h ../include/config.h ../include/ov.h ../include/storage.h \
- ../include/inn/history.h ../include/paths.h tradindexed/tdx-private.h \
- ../include/storage.h tradindexed/tdx-structure.h
+++ /dev/null
-/* $Id: buffindexed.c 7602 2007-02-10 22:19:49Z eagle $
-**
-** Overview buffer and index method.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <syslog.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "ov.h"
-#include "paths.h"
-#include "ovinterface.h"
-#include "storage.h"
-
-#include "buffindexed.h"
-
-#define OVBUFF_MAGIC "ovbuff"
-
-/* ovbuff header */
-#define OVBUFFMASIZ 8
-#define OVBUFFNASIZ 16
-#define OVBUFFLASIZ 16
-#define OVBUFFPASIZ 64
-
-#define OVMAXCYCBUFFNAME 8
-
-#define OV_HDR_PAGESIZE 16384
-#define OV_BLOCKSIZE 8192
-#define OV_BEFOREBITF (1 * OV_BLOCKSIZE)
-#define OV_FUDGE 1024
-
-/* ovblock pointer */
-typedef struct _OV {
- unsigned int blocknum;
- short index;
-} OV;
-
-/* ovbuff header */
-typedef struct {
- char magic[OVBUFFMASIZ];
- char path[OVBUFFPASIZ];
- char indexa[OVBUFFLASIZ]; /* ASCII version of index */
- char lena[OVBUFFLASIZ]; /* ASCII version of len */
- char totala[OVBUFFLASIZ]; /* ASCII version of total */
- char useda[OVBUFFLASIZ]; /* ASCII version of used */
- char freea[OVBUFFLASIZ]; /* ASCII version of free */
- char updateda[OVBUFFLASIZ]; /* ASCII version of updated */
-} OVBUFFHEAD;
-
-/* ovbuff info */
-typedef struct _OVBUFF {
- unsigned int index; /* ovbuff index */
- char path[OVBUFFPASIZ]; /* Path to file */
- int magicver; /* Magic version number */
- int fd; /* file descriptor for this
- ovbuff */
- off_t len; /* Length of writable area, in
- bytes */
- off_t base; /* Offset (relative to byte
- 0 of file) to base block */
- unsigned int freeblk; /* next free block number no
- freeblk left if equals
- totalblk */
- unsigned int totalblk; /* number of total blocks */
- unsigned int usedblk; /* number of used blocks */
- time_t updated; /* Time of last update to
- header */
- void * bitfield; /* Bitfield for ovbuff block in
- use */
- bool needflush; /* true if OVBUFFHEAD is needed
- to be flushed */
- struct _OVBUFF *next; /* next ovbuff */
- int nextchunk; /* next chunk */
-#ifdef OV_DEBUG
- struct ov_trace_array *trace;
-#endif /* OV_DEBUG */
-} OVBUFF;
-
-typedef struct _OVINDEXHEAD {
- OV next; /* next block */
- ARTNUM low; /* lowest article number in the index */
- ARTNUM high; /* highest article number in the index */
-} OVINDEXHEAD;
-
-typedef struct _OVINDEX {
- ARTNUM artnum; /* article number */
- unsigned int blocknum; /* overview data block number */
- short index; /* overview data block index */
- TOKEN token; /* token for this article */
- off_t offset; /* offset from the top in the block */
- int len; /* length of the data */
- time_t arrived; /* arrived time of article */
- time_t expires; /* expire time of article */
-} OVINDEX;
-
-#define OVINDEXMAX ((OV_BLOCKSIZE-sizeof(OVINDEXHEAD))/sizeof(OVINDEX))
-
-typedef struct _OVBLOCK {
- OVINDEXHEAD ovindexhead; /* overview index header */
- OVINDEX ovindex[OVINDEXMAX]; /* overview index */
-} OVBLOCK;
-
-typedef struct _OVBLKS {
- OVBLOCK *ovblock;
- void * addr;
- int len;
- OV indexov;
-} OVBLKS;
-
-/* Data structure for specifying a location in the group index */
-typedef struct {
- int recno; /* Record number in group index */
-} GROUPLOC;
-
-#ifdef OV_DEBUG
-struct ov_trace {
- time_t occupied;
- time_t freed;
- GROUPLOC gloc;
-};
-
-#define OV_TRACENUM 10
-struct ov_trace_array {
- int max;
- int cur;
- struct ov_trace *ov_trace;
-};
-
-struct ov_name_table {
- char *name;
- int recno;
- struct ov_name_table *next;
-};
-
-static struct ov_name_table *name_table = NULL;
-#endif /* OV_DEBUG */
-
-#define GROUPHEADERHASHSIZE (16 * 1024)
-#define GROUPHEADERMAGIC (~(0xf1f0f33d))
-
-typedef struct {
- int magic;
- GROUPLOC hash[GROUPHEADERHASHSIZE];
- GROUPLOC freelist;
-} GROUPHEADER;
-
-/* The group is matched based on the MD5 of the grouname. This may prove to
- be inadequate in the future, if so, the right thing to do is to is
- probably just to add a SHA1 hash into here also. We get a really nice
- benefit from this being fixed length, we should try to keep it that way.
-*/
-typedef struct {
- HASH hash; /* MD5 hash of the group name */
- HASH alias; /* If not empty then this is the hash of the
- group that this group is an alias for */
- ARTNUM high; /* High water mark in group */
- ARTNUM low; /* Low water mark in group */
- int count; /* Number of articles in group */
- int flag; /* Posting/Moderation Status */
- time_t expired; /* When last expiry */
- time_t deleted; /* When this was deleted, 0 otherwise */
- GROUPLOC next; /* Next block in this chain */
- OV baseindex; /* base index buff */
- OV curindex; /* current index buff */
- int curindexoffset; /* current index offset for this ovbuff */
- ARTNUM curhigh; /* High water mark in group */
- ARTNUM curlow; /* Low water mark in group */
- OV curdata; /* current offset for this ovbuff */
- off_t curoffset; /* current offset for this ovbuff */
-} GROUPENTRY;
-
-typedef struct _GIBLIST {
- OV ov;
- struct _GIBLIST *next;
-} GIBLIST;
-
-typedef struct _GDB {
- OV datablk;
- void * addr;
- void * data;
- int len;
- bool mmapped;
- struct _GDB *next;
-} GROUPDATABLOCK;
-
-typedef struct {
- char *group;
- int lo;
- int hi;
- int cur;
- bool needov;
- GROUPLOC gloc;
- int count;
- GROUPDATABLOCK gdb; /* used for caching current block */
-} OVSEARCH;
-
-#define GROUPDATAHASHSIZE 25
-
-static GROUPDATABLOCK *groupdatablock[GROUPDATAHASHSIZE];
-
-typedef enum {PREPEND_BLK, APPEND_BLK} ADDINDEX;
-typedef enum {SRCH_FRWD, SRCH_BKWD} SRCH;
-
-#define _PATH_OVBUFFCONFIG "buffindexed.conf"
-
-static char LocalLogName[] = "buffindexed";
-static long pagesize = 0;
-static OVBUFF *ovbufftab;
-static int GROUPfd;
-static GROUPHEADER *GROUPheader = NULL;
-static GROUPENTRY *GROUPentries = NULL;
-static int GROUPcount = 0;
-static GROUPLOC GROUPemptyloc = { -1 };
-#define NULLINDEX (-1)
-static OV ovnull = { 0, NULLINDEX };
-typedef unsigned long ULONG;
-static ULONG onarray[64], offarray[64];
-static int longsize = sizeof(long);
-static bool Nospace;
-static bool Needunlink;
-static bool Cutofflow;
-static bool Cache;
-static OVSEARCH *Cachesearch;
-
-static int ovbuffmode;
-
-static GROUPLOC GROUPnewnode(void);
-static bool GROUPremapifneeded(GROUPLOC loc);
-static void GROUPLOCclear(GROUPLOC *loc);
-static bool GROUPLOCempty(GROUPLOC loc);
-static bool GROUPlockhash(enum inn_locktype type);
-static bool GROUPlock(GROUPLOC gloc, enum inn_locktype type);
-static off_t GROUPfilesize(int count);
-static bool GROUPexpand(int mode);
-static void *ovopensearch(char *group, int low, int high, bool needov);
-static void ovclosesearch(void *handle, bool freeblock);
-static OVINDEX *Gib;
-static GIBLIST *Giblist;
-static int Gibcount;
-
-#ifdef MMAP_MISSES_WRITES
-/* With HP/UX, you definitely do not want to mix mmap-accesses of
- a file with read()s and write()s of the same file */
-static off_t mmapwrite(int fd, void *buf, off_t nbyte, off_t offset) {
- int pagefudge, len;
- off_t mmapoffset;
- void * addr;
-
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- len = pagefudge + nbyte;
-
- if ((addr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, mmapoffset)) == MAP_FAILED) {
- return -1;
- }
- memcpy(addr+pagefudge, buf, nbyte);
- munmap(addr, len);
- return nbyte;
-}
-#endif /* MMAP_MISSES_WRITES */
-
-static bool ovparse_part_line(char *l) {
- char *p;
- struct stat sb;
- off_t len, base;
- int tonextblock;
- OVBUFF *ovbuff, *tmp = ovbufftab;
-
- /* ovbuff partition name */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > OVMAXCYCBUFFNAME - 1) {
- syslog(L_ERROR, "%s: bad index in line '%s'", LocalLogName, l);
- return false;
- }
- *p = '\0';
- ovbuff = xmalloc(sizeof(OVBUFF));
- ovbuff->index = strtoul(l, NULL, 10);
- for (; tmp != (OVBUFF *)NULL; tmp = tmp->next) {
- if (tmp->index == ovbuff->index) {
- syslog(L_ERROR, "%s: dupulicate index in line '%s'", LocalLogName, l);
- free(ovbuff);
- return false;
- }
- }
- l = ++p;
-
- /* Path to ovbuff partition */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > OVBUFFPASIZ - 1) {
- syslog(L_ERROR, "%s: bad pathname in line '%s'", LocalLogName, l);
- free(ovbuff);
- return false;
- }
- *p = '\0';
- memset(ovbuff->path, '\0', OVBUFFPASIZ);
- strlcpy(ovbuff->path, l, OVBUFFPASIZ);
- if (stat(ovbuff->path, &sb) < 0) {
- syslog(L_ERROR, "%s: file '%s' does not exist, ignoring '%d'",
- LocalLogName, ovbuff->path, ovbuff->index);
- free(ovbuff);
- return false;
- }
- l = ++p;
-
- /* Length/size of symbolic partition in KB */
- len = strtoul(l, NULL, 10) * (off_t) 1024;
- /*
- ** The minimum article offset will be the size of the bitfield itself,
- ** len / (blocksize * 8), plus however many additional blocks the OVBUFFHEAD
- ** external header occupies ... then round up to the next block.
- */
- base = len / (OV_BLOCKSIZE * 8) + OV_BEFOREBITF;
- tonextblock = OV_HDR_PAGESIZE - (base & (OV_HDR_PAGESIZE - 1));
- ovbuff->base = base + tonextblock;
- if (S_ISREG(sb.st_mode) && (len != sb.st_size || ovbuff->base > sb.st_size)) {
- if (len != sb.st_size)
- syslog(L_NOTICE, "%s: length mismatch '%lu' for index '%d' (%lu bytes)",
- LocalLogName, (unsigned long) len, ovbuff->index,
- (unsigned long) sb.st_size);
- if (ovbuff->base > sb.st_size)
- syslog(L_NOTICE, "%s: length must be at least '%lu' for index '%d' (%lu bytes)",
- LocalLogName, (unsigned long) ovbuff->base, ovbuff->index,
- (unsigned long) sb.st_size);
- free(ovbuff);
- return false;
- }
- ovbuff->len = len;
- ovbuff->fd = -1;
- ovbuff->next = (OVBUFF *)NULL;
- ovbuff->needflush = false;
- ovbuff->bitfield = NULL;
- ovbuff->nextchunk = 1;
-
- if (ovbufftab == (OVBUFF *)NULL)
- ovbufftab = ovbuff;
- else {
- for (tmp = ovbufftab; tmp->next != (OVBUFF *)NULL; tmp = tmp->next);
- tmp->next = ovbuff;
- }
- return true;
-}
-
-/*
-** ovbuffread_config() -- Read the overview partition/file configuration file.
-*/
-
-static bool ovbuffread_config(void) {
- char *path, *config, *from, *to, **ctab = (char **)NULL;
- int ctab_free = 0; /* Index to next free slot in ctab */
- int ctab_i;
-
- path = concatpath(innconf->pathetc, _PATH_OVBUFFCONFIG);
- config = ReadInFile(path, NULL);
- if (config == NULL) {
- syslog(L_ERROR, "%s: cannot read %s", LocalLogName, path);
- free(config);
- free(path);
- return false;
- }
- free(path);
- for (from = to = config; *from; ) {
- if (*from == '#') { /* Comment line? */
- while (*from && *from != '\n')
- from++; /* Skip past it */
- from++;
- continue; /* Back to top of loop */
- }
- if (*from == '\n') { /* End or just a blank line? */
- from++;
- continue; /* Back to top of loop */
- }
- if (ctab_free == 0)
- ctab = xmalloc(sizeof(char *));
- else
- ctab = xrealloc(ctab, (ctab_free + 1) * sizeof(char *));
- /* If we're here, we've got the beginning of a real entry */
- ctab[ctab_free++] = to = from;
- while (1) {
- if (*from && *from == '\\' && *(from + 1) == '\n') {
- from += 2; /* Skip past backslash+newline */
- while (*from && isspace((int)*from))
- from++;
- continue;
- }
- if (*from && *from != '\n')
- *to++ = *from++;
- if (*from == '\n') {
- *to++ = '\0';
- from++;
- break;
- }
- if (! *from)
- break;
- }
- }
- for (ctab_i = 0; ctab_i < ctab_free; ctab_i++) {
- if (!ovparse_part_line(ctab[ctab_i])) {
- free(config);
- free(ctab);
- return false;
- }
- }
- free(config);
- free(ctab);
- if (ovbufftab == (OVBUFF *)NULL) {
- syslog(L_ERROR, "%s: no buffindexed defined", LocalLogName);
- return false;
- }
- return true;
-}
-
-static char hextbl[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f'};
-
-static char *offt2hex(off_t offset, bool leadingzeros) {
- static char buf[24];
- char *p;
-
- if (sizeof(off_t) <= 4) {
- snprintf(buf, sizeof(buf), (leadingzeros) ? "%016lx" : "%lx", offset);
- } else {
- int i;
-
- for (i = 0; i < OVBUFFLASIZ; i++)
- buf[i] = '0'; /* Pad with zeros to start */
- for (i = OVBUFFLASIZ - 1; i >= 0; i--) {
- buf[i] = hextbl[offset & 0xf];
- offset >>= 4;
- }
- }
- if (!leadingzeros) {
- for (p = buf; *p == '0'; p++)
- ;
- if (*p != '\0')
- return p;
- else
- return p - 1; /* We converted a "0" and then bypassed all the zeros */
- } else
- return buf;
-}
-
-static off_t hex2offt(char *hex) {
- if (sizeof(off_t) <= 4) {
- unsigned long rpofft;
-
- sscanf(hex, "%lx", &rpofft);
- return rpofft;
- } else {
- char diff;
- off_t n = 0;
-
- for (; *hex != '\0'; hex++) {
- if (*hex >= '0' && *hex <= '9')
- diff = '0';
- else if (*hex >= 'a' && *hex <= 'f')
- diff = 'a' - 10;
- else if (*hex >= 'A' && *hex <= 'F')
- diff = 'A' - 10;
- else {
- /*
- ** We used to have a syslog() message here, but the case
- ** where we land here because of a ":" happens, er, often.
- */
- break;
- }
- n += (*hex - diff);
- if (isalnum((int)*(hex + 1)))
- n <<= 4;
- }
- return n;
- }
-}
-
-static void ovreadhead(OVBUFF *ovbuff) {
- OVBUFFHEAD rpx;
- char buff[OVBUFFLASIZ+1];
-
- memcpy(&rpx, ovbuff->bitfield, sizeof(OVBUFFHEAD));
- strncpy(buff, rpx.useda, OVBUFFLASIZ);
- buff[OVBUFFLASIZ] = '\0';
- ovbuff->usedblk = (unsigned int)hex2offt((char *)buff);
- strncpy(buff, rpx.freea, OVBUFFLASIZ);
- buff[OVBUFFLASIZ] = '\0';
- ovbuff->freeblk = (unsigned int)hex2offt((char *)buff);
- return;
-}
-
-static void ovflushhead(OVBUFF *ovbuff) {
- OVBUFFHEAD rpx;
-
- if (!ovbuff->needflush)
- return;
- memset(&rpx, 0, sizeof(OVBUFFHEAD));
- ovbuff->updated = time(NULL);
- strncpy(rpx.magic, OVBUFF_MAGIC, strlen(OVBUFF_MAGIC));
- strncpy(rpx.path, ovbuff->path, OVBUFFPASIZ);
- /* Don't use sprintf() directly ... the terminating '\0' causes grief */
- strncpy(rpx.indexa, offt2hex(ovbuff->index, true), OVBUFFLASIZ);
- strncpy(rpx.lena, offt2hex(ovbuff->len, true), OVBUFFLASIZ);
- strncpy(rpx.totala, offt2hex(ovbuff->totalblk, true), OVBUFFLASIZ);
- strncpy(rpx.useda, offt2hex(ovbuff->usedblk, true), OVBUFFLASIZ);
- strncpy(rpx.freea, offt2hex(ovbuff->freeblk, true), OVBUFFLASIZ);
- strncpy(rpx.updateda, offt2hex(ovbuff->updated, true), OVBUFFLASIZ);
- memcpy(ovbuff->bitfield, &rpx, sizeof(OVBUFFHEAD));
- mmap_flush(ovbuff->bitfield, ovbuff->base);
- ovbuff->needflush = false;
- return;
-}
-
-static bool ovlock(OVBUFF *ovbuff, enum inn_locktype type) {
- return inn_lock_range(ovbuff->fd, type, true, 0, sizeof(OVBUFFHEAD));
-}
-
-static bool ovbuffinit_disks(void) {
- OVBUFF *ovbuff = ovbufftab;
- char buf[64];
- OVBUFFHEAD *rpx;
- int i, fd;
- off_t tmpo;
-
- /*
- ** Discover the state of our ovbuffs. If any of them are in icky shape,
- ** duck shamelessly & return false.
- */
- for (; ovbuff != (OVBUFF *)NULL; ovbuff = ovbuff->next) {
- if (ovbuff->fd < 0) {
- if ((fd = open(ovbuff->path, ovbuffmode & OV_WRITE ? O_RDWR : O_RDONLY)) < 0) {
- syslog(L_ERROR, "%s: ERROR opening '%s' : %m", LocalLogName, ovbuff->path);
- return false;
- } else {
- close_on_exec(fd, true);
- ovbuff->fd = fd;
- }
- }
- if ((ovbuff->bitfield =
- mmap(NULL, ovbuff->base, ovbuffmode & OV_WRITE ? (PROT_READ | PROT_WRITE) : PROT_READ,
- MAP_SHARED, ovbuff->fd, (off_t) 0)) == MAP_FAILED) {
- syslog(L_ERROR,
- "%s: ovinitdisks: mmap for %s offset %d len %lu failed: %m",
- LocalLogName, ovbuff->path, 0, (unsigned long) ovbuff->base);
- return false;
- }
- rpx = (OVBUFFHEAD *)ovbuff->bitfield;
- ovlock(ovbuff, INN_LOCK_WRITE);
- if (strncmp(rpx->magic, OVBUFF_MAGIC, strlen(OVBUFF_MAGIC)) == 0) {
- ovbuff->magicver = 1;
- if (strncmp(rpx->path, ovbuff->path, OVBUFFPASIZ) != 0) {
- syslog(L_ERROR, "%s: Path mismatch: read %s for buffindexed %s",
- LocalLogName, rpx->path, ovbuff->path);
- ovbuff->needflush = true;
- }
- strncpy(buf, rpx->indexa, OVBUFFLASIZ);
- buf[OVBUFFLASIZ] = '\0';
- i = hex2offt(buf);
- if (i != ovbuff->index) {
- syslog(L_ERROR, "%s: Mismatch: index '%d' for buffindexed %s",
- LocalLogName, i, ovbuff->path);
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- return false;
- }
- strncpy(buf, rpx->lena, OVBUFFLASIZ);
- buf[OVBUFFLASIZ] = '\0';
- tmpo = hex2offt(buf);
- if (tmpo != ovbuff->len) {
- syslog(L_ERROR, "%s: Mismatch: read 0x%s length for buffindexed %s",
- LocalLogName, offt2hex(tmpo, false), ovbuff->path);
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- return false;
- }
- strncpy(buf, rpx->totala, OVBUFFLASIZ);
- buf[OVBUFFLASIZ] = '\0';
- ovbuff->totalblk = hex2offt(buf);
- strncpy(buf, rpx->useda, OVBUFFLASIZ);
- buf[OVBUFFLASIZ] = '\0';
- ovbuff->usedblk = hex2offt(buf);
- strncpy(buf, rpx->freea, OVBUFFLASIZ);
- buf[OVBUFFLASIZ] = '\0';
- ovbuff->freeblk = hex2offt(buf);
- ovflushhead(ovbuff);
- Needunlink = false;
- } else {
- ovbuff->totalblk = (ovbuff->len - ovbuff->base)/OV_BLOCKSIZE;
- if (ovbuff->totalblk < 1) {
- syslog(L_ERROR, "%s: too small length '%lu' for buffindexed %s",
- LocalLogName, (unsigned long) ovbuff->len, ovbuff->path);
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- return false;
- }
- ovbuff->magicver = 1;
- ovbuff->usedblk = 0;
- ovbuff->freeblk = 0;
- ovbuff->updated = 0;
- ovbuff->needflush = true;
- syslog(L_NOTICE,
- "%s: No magic cookie found for buffindexed %d, initializing",
- LocalLogName, ovbuff->index);
- ovflushhead(ovbuff);
- }
-#ifdef OV_DEBUG
- ovbuff->trace = xcalloc(ovbuff->totalblk, sizeof(ov_trace_array));
-#endif /* OV_DEBUG */
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- }
- return true;
-}
-
-static int ovusedblock(OVBUFF *ovbuff, int blocknum, bool set_operation, bool setbitvalue) {
- off_t longoffset;
- int bitoffset; /* From the 'left' side of the long */
- ULONG bitlong, mask;
-
- longoffset = blocknum / (sizeof(long) * 8);
- bitoffset = blocknum % (sizeof(long) * 8);
- bitlong = *((ULONG *) ovbuff->bitfield + (OV_BEFOREBITF / sizeof(long))
- + longoffset);
- if (set_operation) {
- if (setbitvalue) {
- mask = onarray[bitoffset];
- bitlong |= mask;
- } else {
- mask = offarray[bitoffset];
- bitlong &= mask;
- }
- *((ULONG *) ovbuff->bitfield + (OV_BEFOREBITF / sizeof(long))
- + longoffset) = bitlong;
- return 2; /* XXX Clean up return semantics */
- }
- /* It's a read operation */
- mask = onarray[bitoffset];
- /* return bitlong & mask; doesn't work if sizeof(ulong) > sizeof(int) */
- if ( bitlong & mask ) return 1; else return 0;
-}
-
-static void ovnextblock(OVBUFF *ovbuff) {
- int i, j, last, lastbit, left;
- ULONG mask = 0x80000000;
- ULONG *table;
-
- last = ovbuff->totalblk/(sizeof(long) * 8);
- if ((left = ovbuff->totalblk % (sizeof(long) * 8)) != 0) {
- last++;
- }
- table = ((ULONG *) ovbuff->bitfield + (OV_BEFOREBITF / sizeof(long)));
- for (i = ovbuff->nextchunk ; i < last ; i++) {
- if (i == last - 1 && left != 0) {
- for (j = 1 ; j < left ; j++) {
- mask |= mask >> 1;
- }
- if ((table[i] & mask) != mask)
- break;
- } else {
- if ((table[i] ^ ~0) != 0)
- break;
- }
- }
- if (i == last) {
- for (i = 0 ; i < ovbuff->nextchunk ; i++) {
- if ((table[i] ^ ~0) != 0)
- break;
- }
- if (i == ovbuff->nextchunk) {
- ovbuff->freeblk = ovbuff->totalblk;
- return;
- }
- }
- if ((i - 1) >= 0 && (last - 1 == i) && left != 0) {
- lastbit = left;
- } else {
- lastbit = sizeof(long) * 8;
- }
- for (j = 0 ; j < lastbit ; j++) {
- if ((table[i] & onarray[j]) == 0)
- break;
- }
- if (j == lastbit) {
- ovbuff->freeblk = ovbuff->totalblk;
- return;
- }
- ovbuff->freeblk = i * sizeof(long) * 8 + j;
- ovbuff->nextchunk = i + 1;
- if (i == last)
- ovbuff->nextchunk = 0;
- return;
-}
-
-static OVBUFF *getovbuff(OV ov) {
- OVBUFF *ovbuff = ovbufftab;
- for (; ovbuff != (OVBUFF *)NULL; ovbuff = ovbuff->next) {
- if (ovbuff->index == ov.index)
- return ovbuff;
- }
- return NULL;
-}
-
-#ifdef OV_DEBUG
-static OV ovblocknew(GROUPENTRY *ge) {
-#else
-static OV ovblocknew(void) {
-#endif /* OV_DEBUG */
- static OVBUFF *ovbuffnext = NULL;
- OVBUFF *ovbuff;
- OV ov;
-#ifdef OV_DEBUG
- int recno;
- struct ov_trace_array *trace;
-#endif /* OV_DEBUG */
-
- if (ovbuffnext == NULL)
- ovbuffnext = ovbufftab;
- for (ovbuff = ovbuffnext ; ovbuff != (OVBUFF *)NULL ; ovbuff = ovbuff->next) {
- ovlock(ovbuff, INN_LOCK_WRITE);
- ovreadhead(ovbuff);
- if (ovbuff->totalblk != ovbuff->usedblk && ovbuff->freeblk == ovbuff->totalblk) {
- ovnextblock(ovbuff);
- }
- if (ovbuff->totalblk == ovbuff->usedblk || ovbuff->freeblk == ovbuff->totalblk) {
- /* no space left for this ovbuff */
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- continue;
- }
- break;
- }
- if (ovbuff == NULL) {
- for (ovbuff = ovbufftab ; ovbuff != ovbuffnext ; ovbuff = ovbuff->next) {
- ovlock(ovbuff, INN_LOCK_WRITE);
- ovreadhead(ovbuff);
- if (ovbuff->totalblk == ovbuff->usedblk || ovbuff->freeblk == ovbuff->totalblk) {
- /* no space left for this ovbuff */
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- continue;
- }
- break;
- }
- if (ovbuff == ovbuffnext) {
- Nospace = true;
- return ovnull;
- }
- }
-#ifdef OV_DEBUG
- recno = ((char *)ge - (char *)&GROUPentries[0])/sizeof(GROUPENTRY);
- if (ovusedblock(ovbuff, ovbuff->freeblk, false, true)) {
- syslog(L_FATAL, "%s: 0x%08x trying to occupy new block(%d, %d), but already occupied", LocalLogName, recno, ovbuff->index, ovbuff->freeblk);
- buffindexed_close();
- abort();
- }
- trace = &ovbuff->trace[ovbuff->freeblk];
- if (trace->ov_trace == NULL) {
- trace->ov_trace = xcalloc(OV_TRACENUM, sizeof(struct ov_trace));
- trace->max = OV_TRACENUM;
- } else if (trace->cur + 1 == trace->max) {
- trace->max += OV_TRACENUM;
- trace->ov_trace = xrealloc(trace->ov_trace, trace->max * sizeof(struct ov_trace));
- memset(&trace->ov_trace[trace->cur], '\0', sizeof(struct ov_trace) * (trace->max - trace->cur));
- }
- if (trace->ov_trace[trace->cur].occupied != 0) {
- trace->cur++;
- }
- trace->ov_trace[trace->cur].gloc.recno = recno;
- trace->ov_trace[trace->cur].occupied = time(NULL);
-#endif /* OV_DEBUG */
- ov.index = ovbuff->index;
- ov.blocknum = ovbuff->freeblk;
- ovusedblock(ovbuff, ov.blocknum, true, true);
- ovnextblock(ovbuff);
- ovbuff->usedblk++;
- ovbuff->needflush = true;
- ovflushhead(ovbuff);
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- ovbuffnext = ovbuff->next;
- if (ovbuffnext == NULL)
- ovbuffnext = ovbufftab;
- return ov;
-}
-
-#ifdef OV_DEBUG
-static void ovblockfree(OV ov, GROUPENTRY *ge) {
-#else
-static void ovblockfree(OV ov) {
-#endif /* OV_DEBUG */
- OVBUFF *ovbuff;
-#ifdef OV_DEBUG
- int recno;
- struct ov_trace_array *trace;
-#endif /* OV_DEBUG */
-
- if (ov.index == NULLINDEX)
- return;
- if ((ovbuff = getovbuff(ov)) == NULL)
- return;
- ovlock(ovbuff, INN_LOCK_WRITE);
-#ifdef OV_DEBUG
- recno = ((char *)ge - (char *)&GROUPentries[0])/sizeof(GROUPENTRY);
- if (!ovusedblock(ovbuff, ov.blocknum, false, false)) {
- syslog(L_FATAL, "%s: 0x%08x trying to free block(%d, %d), but already freed", LocalLogName, recno, ov.index, ov.blocknum);
- buffindexed_close();
- abort();
- }
- trace = &ovbuff->trace[ov.blocknum];
- if (trace->ov_trace == NULL) {
- trace->ov_trace = xcalloc(OV_TRACENUM, sizeof(struct ov_trace));
- trace->max = OV_TRACENUM;
- } else if (trace->cur + 1 == trace->max) {
- trace->max += OV_TRACENUM;
- trace->ov_trace = xrealloc(trace->ov_trace, trace->max * sizeof(struct ov_trace));
- memset(&trace->ov_trace[trace->cur], '\0', sizeof(struct ov_trace) * (trace->max - trace->cur));
- }
- if (trace->ov_trace[trace->cur].freed != 0) {
- trace->cur++;
- }
- trace->ov_trace[trace->cur].freed = time(NULL);
- trace->ov_trace[trace->cur].gloc.recno = recno;
- trace->cur++;
-#endif /* OV_DEBUG */
- ovusedblock(ovbuff, ov.blocknum, true, false);
- ovreadhead(ovbuff);
- if (ovbuff->freeblk == ovbuff->totalblk)
- ovbuff->freeblk = ov.blocknum;
- ovbuff->usedblk--;
- ovbuff->needflush = true;
- ovflushhead(ovbuff);
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- return;
-}
-
-bool buffindexed_open(int mode) {
- char *groupfn;
- struct stat sb;
- int i, flag = 0;
- static int uninitialized = 1;
- ULONG on, off;
-
- if (uninitialized) {
- on = 1;
- off = on;
- off ^= ULONG_MAX;
- for (i = (longsize * 8) - 1; i >= 0; i--) {
- onarray[i] = on;
- offarray[i] = off;
- on <<= 1;
- off = on;
- off ^= ULONG_MAX;
- }
- uninitialized = 0;
- }
- ovbuffmode = mode;
- if (pagesize == 0) {
- pagesize = getpagesize();
- if (pagesize == -1) {
- syslog(L_ERROR, "%s: getpagesize failed: %m", LocalLogName);
- pagesize = 0;
- return false;
- }
- if ((pagesize > OV_HDR_PAGESIZE) || (OV_HDR_PAGESIZE % pagesize)) {
- syslog(L_ERROR, "%s: OV_HDR_PAGESIZE (%d) is not a multiple of pagesize (%ld)", LocalLogName, OV_HDR_PAGESIZE, pagesize);
- return false;
- }
- }
- memset(&groupdatablock, '\0', sizeof(groupdatablock));
- if (!ovbuffread_config()) {
- return false;
- }
- Needunlink = true;
- if (!ovbuffinit_disks()) {
- return false;
- }
-
- groupfn = concatpath(innconf->pathdb, "group.index");
- if (Needunlink && unlink(groupfn) == 0) {
- syslog(L_NOTICE, "%s: all buffers are brandnew, unlink '%s'", LocalLogName, groupfn);
- }
- GROUPfd = open(groupfn, ovbuffmode & OV_WRITE ? O_RDWR | O_CREAT : O_RDONLY, 0660);
- if (GROUPfd < 0) {
- syslog(L_FATAL, "%s: Could not create %s: %m", LocalLogName, groupfn);
- free(groupfn);
- return false;
- }
-
- if (fstat(GROUPfd, &sb) < 0) {
- syslog(L_FATAL, "%s: Could not fstat %s: %m", LocalLogName, groupfn);
- free(groupfn);
- close(GROUPfd);
- return false;
- }
- if (sb.st_size > sizeof(GROUPHEADER)) {
- if (mode & OV_READ)
- flag |= PROT_READ;
- if (mode & OV_WRITE) {
- /*
- * Note: below mapping of groupheader won't work unless we have
- * both PROT_READ and PROT_WRITE perms.
- */
- flag |= PROT_WRITE|PROT_READ;
- }
- GROUPcount = (sb.st_size - sizeof(GROUPHEADER)) / sizeof(GROUPENTRY);
- if ((GROUPheader = (GROUPHEADER *)mmap(0, GROUPfilesize(GROUPcount), flag,
- MAP_SHARED, GROUPfd, 0)) == (GROUPHEADER *) -1) {
- syslog(L_FATAL, "%s: Could not mmap %s in buffindexed_open: %m", LocalLogName, groupfn);
- free(groupfn);
- close(GROUPfd);
- return false;
- }
- GROUPentries = (GROUPENTRY *)((char *)GROUPheader + sizeof(GROUPHEADER));
- } else {
- GROUPcount = 0;
- if (!GROUPexpand(mode)) {
- free(groupfn);
- close(GROUPfd);
- return false;
- }
- }
- close_on_exec(GROUPfd, true);
-
- free(groupfn);
- Cutofflow = false;
-
- return true;
-}
-
-static GROUPLOC GROUPfind(char *group, bool Ignoredeleted) {
- HASH grouphash;
- unsigned int i;
- GROUPLOC loc;
-
- grouphash = Hash(group, strlen(group));
- memcpy(&i, &grouphash, sizeof(i));
-
- loc = GROUPheader->hash[i % GROUPHEADERHASHSIZE];
- GROUPremapifneeded(loc);
-
- while (!GROUPLOCempty(loc)) {
- if (GROUPentries[loc.recno].deleted == 0 || Ignoredeleted) {
- if (memcmp(&grouphash, &GROUPentries[loc.recno].hash, sizeof(HASH)) == 0) {
- return loc;
- }
- }
- loc = GROUPentries[loc.recno].next;
- }
- return GROUPemptyloc;
-}
-
-bool buffindexed_groupstats(char *group, int *lo, int *hi, int *count, int *flag) {
- GROUPLOC gloc;
-
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return false;
- }
- GROUPlock(gloc, INN_LOCK_READ);
- if (lo != NULL)
- *lo = GROUPentries[gloc.recno].low;
- if (hi != NULL)
- *hi = GROUPentries[gloc.recno].high;
- if (count != NULL)
- *count = GROUPentries[gloc.recno].count;
- if (flag != NULL)
- *flag = GROUPentries[gloc.recno].flag;
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return true;
-}
-
-static void setinitialge(GROUPENTRY *ge, HASH grouphash, char *flag, GROUPLOC next, ARTNUM lo, ARTNUM hi) {
- ge->hash = grouphash;
- if (lo != 0)
- ge->low = lo;
- ge->high = hi;
- ge->expired = ge->deleted = ge->count = 0;
- ge->flag = *flag;
- ge->baseindex = ge->curindex = ge->curdata = ovnull;
- ge->curindexoffset = ge->curoffset = 0;
- ge->next = next;
-}
-
-bool buffindexed_groupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag) {
- unsigned int i;
- HASH grouphash;
- GROUPLOC gloc;
- GROUPENTRY *ge;
-#ifdef OV_DEBUG
- struct ov_name_table *ntp;
-#endif /* OV_DEBUG */
-
- gloc = GROUPfind(group, true);
- if (!GROUPLOCempty(gloc)) {
- ge = &GROUPentries[gloc.recno];
- if (GROUPentries[gloc.recno].deleted != 0) {
- grouphash = Hash(group, strlen(group));
- setinitialge(ge, grouphash, flag, ge->next, lo, hi);
- } else {
- ge->flag = *flag;
- }
- return true;
- }
- grouphash = Hash(group, strlen(group));
- memcpy(&i, &grouphash, sizeof(i));
- i = i % GROUPHEADERHASHSIZE;
- GROUPlockhash(INN_LOCK_WRITE);
- gloc = GROUPnewnode();
- ge = &GROUPentries[gloc.recno];
- setinitialge(ge, grouphash, flag, GROUPheader->hash[i], lo, hi);
- GROUPheader->hash[i] = gloc;
-#ifdef OV_DEBUG
- ntp = xmalloc(sizeof(struct ov_name_table));
- memset(ntp, '\0', sizeof(struct ov_name_table));
- ntp->name = xstrdup(group);
- ntp->recno = gloc.recno;
- if (name_table == NULL)
- name_table = ntp;
- else {
- ntp->next = name_table;
- name_table = ntp;
- }
-#endif /* OV_DEBUG */
- GROUPlockhash(INN_LOCK_UNLOCK);
- return true;
-}
-
-static off_t GROUPfilesize(int count) {
- return ((off_t) count * sizeof(GROUPENTRY)) + sizeof(GROUPHEADER);
-}
-
-/* Check if the given GROUPLOC refers to GROUPENTRY that we don't have mmap'ed,
-** if so then see if the file has been grown by another writer and remmap
-*/
-static bool GROUPremapifneeded(GROUPLOC loc) {
- struct stat sb;
-
- if (loc.recno < GROUPcount)
- return true;
-
- if (fstat(GROUPfd, &sb) < 0)
- return false;
-
- if (GROUPfilesize(GROUPcount) >= sb.st_size)
- return true;
-
- if (GROUPheader) {
- if (munmap((void *)GROUPheader, GROUPfilesize(GROUPcount)) < 0) {
- syslog(L_FATAL, "%s: Could not munmap group.index in GROUPremapifneeded: %m", LocalLogName);
- return false;
- }
- }
-
- GROUPcount = (sb.st_size - sizeof(GROUPHEADER)) / sizeof(GROUPENTRY);
- GROUPheader = (GROUPHEADER *)mmap(0, GROUPfilesize(GROUPcount),
- PROT_READ | PROT_WRITE, MAP_SHARED, GROUPfd, 0);
- if (GROUPheader == (GROUPHEADER *) -1) {
- syslog(L_FATAL, "%s: Could not mmap group.index in GROUPremapifneeded: %m", LocalLogName);
- return false;
- }
- GROUPentries = (GROUPENTRY *)((char *)GROUPheader + sizeof(GROUPHEADER));
- return true;
-}
-
-/* This function does not need to lock because it's callers are expected to do so */
-static bool GROUPexpand(int mode) {
- int i;
- int flag = 0;
-
- if (GROUPheader) {
- if (munmap((void *)GROUPheader, GROUPfilesize(GROUPcount)) < 0) {
- syslog(L_FATAL, "%s: Could not munmap group.index in GROUPexpand: %m", LocalLogName);
- return false;
- }
- }
- GROUPcount += 1024;
- if (ftruncate(GROUPfd, GROUPfilesize(GROUPcount)) < 0) {
- syslog(L_FATAL, "%s: Could not extend group.index: %m", LocalLogName);
- return false;
- }
- if (mode & OV_READ)
- flag |= PROT_READ;
- if (mode & OV_WRITE) {
- /*
- * Note: below check of magic won't work unless we have both PROT_READ
- * and PROT_WRITE perms.
- */
- flag |= PROT_WRITE|PROT_READ;
- }
- GROUPheader = (GROUPHEADER *)mmap(0, GROUPfilesize(GROUPcount),
- flag, MAP_SHARED, GROUPfd, 0);
- if (GROUPheader == (GROUPHEADER *) -1) {
- syslog(L_FATAL, "%s: Could not mmap group.index in GROUPexpand: %m", LocalLogName);
- return false;
- }
- GROUPentries = (GROUPENTRY *)((char *)GROUPheader + sizeof(GROUPHEADER));
- if (GROUPheader->magic != GROUPHEADERMAGIC) {
- GROUPheader->magic = GROUPHEADERMAGIC;
- GROUPLOCclear(&GROUPheader->freelist);
- for (i = 0; i < GROUPHEADERHASHSIZE; i++)
- GROUPLOCclear(&GROUPheader->hash[i]);
- }
- /* Walk the new entries from the back to the front, adding them to the freelist */
- for (i = GROUPcount - 1; (GROUPcount - 1024) <= i; i--) {
- GROUPentries[i].next = GROUPheader->freelist;
- GROUPheader->freelist.recno = i;
- }
- return true;
-}
-
-static GROUPLOC GROUPnewnode(void) {
- GROUPLOC loc;
-
- /* If we didn't find any free space, then make some */
- if (GROUPLOCempty(GROUPheader->freelist)) {
- if (!GROUPexpand(ovbuffmode)) {
- return GROUPemptyloc;
- }
- }
- assert(!GROUPLOCempty(GROUPheader->freelist));
- loc = GROUPheader->freelist;
- GROUPheader->freelist = GROUPentries[GROUPheader->freelist.recno].next;
- return loc;
-}
-
-bool buffindexed_groupdel(char *group) {
- GROUPLOC gloc;
- GROUPENTRY *ge;
-
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return true;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- ge = &GROUPentries[gloc.recno];
- ge->deleted = time(NULL);
- HashClear(&ge->hash);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return true;
-}
-
-static void GROUPLOCclear(GROUPLOC *loc) {
- loc->recno = -1;
-}
-
-static bool GROUPLOCempty(GROUPLOC loc) {
- return (loc.recno < 0);
-}
-
-static bool GROUPlockhash(enum inn_locktype type) {
- return inn_lock_range(GROUPfd, type, true, 0, sizeof(GROUPHEADER));
-}
-
-static bool GROUPlock(GROUPLOC gloc, enum inn_locktype type) {
- return inn_lock_range(GROUPfd,
- type,
- true,
- sizeof(GROUPHEADER) + (sizeof(GROUPENTRY) * gloc.recno),
- sizeof(GROUPENTRY));
-}
-
-#ifdef OV_DEBUG
-static bool ovsetcurindexblock(GROUPENTRY *ge, GROUPENTRY *georig) {
-#else
-static bool ovsetcurindexblock(GROUPENTRY *ge) {
-#endif /* OV_DEBUG */
- OVBUFF *ovbuff;
- OV ov;
- OVINDEXHEAD ovindexhead;
-
- /* there is no index */
-#ifdef OV_DEBUG
- ov = ovblocknew(georig ? georig : ge);
-#else
- ov = ovblocknew();
-#endif /* OV_DEBUG */
- if (ov.index == NULLINDEX) {
- syslog(L_ERROR, "%s: ovsetcurindexblock could not get new block", LocalLogName);
- return false;
- }
- if ((ovbuff = getovbuff(ov)) == NULL) {
- syslog(L_ERROR, "%s: ovsetcurindexblock could not get ovbuff block for new, %d, %d", LocalLogName, ov.index, ov.blocknum);
- return false;
- }
- ovindexhead.next = ovnull;
- ovindexhead.low = 0;
- ovindexhead.high = 0;
-#ifdef MMAP_MISSES_WRITES
- if (mmapwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ov.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#else
- if (pwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ov.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#endif /* MMAP_MISSES_WRITES */
- syslog(L_ERROR, "%s: could not write index record index '%d', blocknum '%d': %m", LocalLogName, ge->curindex.index, ge->curindex.blocknum);
- return true;
- }
- if (ge->baseindex.index == NULLINDEX) {
- ge->baseindex = ov;
- } else {
- if ((ovbuff = getovbuff(ge->curindex)) == NULL)
- return false;
-#ifdef OV_DEBUG
- if (!ovusedblock(ovbuff, ge->curindex.blocknum, false, false)) {
- syslog(L_FATAL, "%s: block(%d, %d) not occupied (index)", LocalLogName, ovbuff->index, ge->curindex.blocknum);
- abort();
- }
-#endif /* OV_DEBUG */
- ovindexhead.next = ov;
- ovindexhead.low = ge->curlow;
- ovindexhead.high = ge->curhigh;
-#ifdef MMAP_MISSES_WRITES
- if (mmapwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#else
- if (pwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#endif /* MMAP_MISSES_WRITES */
- syslog(L_ERROR, "%s: could not write index record index '%d', blocknum '%d': %m", LocalLogName, ge->curindex.index, ge->curindex.blocknum);
- return false;
- }
- }
- ge->curindex = ov;
- ge->curindexoffset = 0;
- ge->curlow = 0;
- ge->curhigh = 0;
- return true;
-}
-
-#ifdef OV_DEBUG
-static bool ovaddrec(GROUPENTRY *ge, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires, GROUPENTRY *georig) {
-#else
-static bool ovaddrec(GROUPENTRY *ge, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires) {
-#endif /* OV_DEBUG */
- OV ov;
- OVINDEX ie;
- OVBUFF *ovbuff;
- OVINDEXHEAD ovindexhead;
- bool needupdate = false;
-#ifdef OV_DEBUG
- int recno;
-#endif /* OV_DEBUG */
-
- Nospace = false;
- if (OV_BLOCKSIZE < len) {
- syslog(L_ERROR, "%s: overview data must be under %d (%d)", LocalLogName, OV_BLOCKSIZE, len);
- return false;
- }
- if (ge->curdata.index == NULLINDEX) {
- /* no data block allocated */
-#ifdef OV_DEBUG
- ov = ovblocknew(georig ? georig : ge);
-#else
- ov = ovblocknew();
-#endif /* OV_DEBUG */
- if (ov.index == NULLINDEX) {
- syslog(L_ERROR, "%s: ovaddrec could not get new block", LocalLogName);
- return false;
- }
- if ((ovbuff = getovbuff(ov)) == NULL) {
- syslog(L_ERROR, "%s: ovaddrec could not get ovbuff block for new, %d, %d, %ld", LocalLogName, ov.index, ov.blocknum, artnum);
- return false;
- }
- ge->curdata = ov;
- ge->curoffset = 0;
- } else if ((ovbuff = getovbuff(ge->curdata)) == NULL)
- return false;
- else if (OV_BLOCKSIZE - ge->curoffset < len) {
- /* too short to store data, allocate new block */
-#ifdef OV_DEBUG
- ov = ovblocknew(georig ? georig : ge);
-#else
- ov = ovblocknew();
-#endif /* OV_DEBUG */
- if (ov.index == NULLINDEX) {
- syslog(L_ERROR, "%s: ovaddrec could not get new block", LocalLogName);
- return false;
- }
- if ((ovbuff = getovbuff(ov)) == NULL) {
- syslog(L_ERROR, "%s: ovaddrec could not get ovbuff block for new, %d, %d, %ld", LocalLogName, ov.index, ov.blocknum, artnum);
- return false;
- }
- ge->curdata = ov;
- ge->curoffset = 0;
- }
-#ifdef OV_DEBUG
- if (!ovusedblock(ovbuff, ge->curdata.blocknum, false, false)) {
- syslog(L_FATAL, "%s: block(%d, %d) not occupied", LocalLogName, ovbuff->index, ge->curdata.blocknum);
- buffindexed_close();
- abort();
- }
-#endif /* OV_DEBUG */
-#ifdef MMAP_MISSES_WRITES
- if (mmapwrite(ovbuff->fd, data, len, ovbuff->base + ge->curdata.blocknum * OV_BLOCKSIZE + ge->curoffset) != len) {
-#else
- if (pwrite(ovbuff->fd, data, len, ovbuff->base + ge->curdata.blocknum * OV_BLOCKSIZE + ge->curoffset) != len) {
-#endif /* MMAP_MISSES_WRITES */
- syslog(L_ERROR, "%s: could not append overview record index '%d', blocknum '%d': %m", LocalLogName, ge->curdata.index, ge->curdata.blocknum);
- return false;
- }
- memset(&ie, '\0', sizeof(ie));
- ie.artnum = artnum;
- ie.len = len;
- ie.index = ge->curdata.index;
- ie.blocknum = ge->curdata.blocknum;
- ie.offset = ge->curoffset;
- ie.token = token;
- ie.arrived = arrived;
- ie.expires = expires;
-
- if (ge->baseindex.index == NULLINDEX || ge->curindexoffset == OVINDEXMAX) {
-#ifdef OV_DEBUG
- if (!ovsetcurindexblock(ge, georig)) {
-#else
- if (!ovsetcurindexblock(ge)) {
-#endif /* OV_DEBUG */
- syslog(L_ERROR, "%s: could not set current index", LocalLogName);
- return false;
- }
- }
- if ((ovbuff = getovbuff(ge->curindex)) == NULL)
- return false;
-#ifdef OV_DEBUG
- if (!ovusedblock(ovbuff, ge->curindex.blocknum, false, false)) {
- syslog(L_FATAL, "%s: block(%d, %d) not occupied (index)", LocalLogName, ovbuff->index, ge->curindex.blocknum);
- buffindexed_close();
- abort();
- }
-#endif /* OV_DEBUG */
-#ifdef MMAP_MISSES_WRITES
- if (mmapwrite(ovbuff->fd, &ie, sizeof(ie), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE + sizeof(OVINDEXHEAD) + sizeof(ie) * ge->curindexoffset) != sizeof(ie)) {
-#else
- if (pwrite(ovbuff->fd, &ie, sizeof(ie), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE + sizeof(OVINDEXHEAD) + sizeof(ie) * ge->curindexoffset) != sizeof(ie)) {
-#endif /* MMAP_MISSES_WRITES */
- syslog(L_ERROR, "%s: could not write index record index '%d', blocknum '%d': %m", LocalLogName, ge->curindex.index, ge->curindex.blocknum);
- return true;
- }
- if ((ge->curlow <= 0) || (ge->curlow > artnum)) {
- ge->curlow = artnum;
- needupdate = true;
- }
- if ((ge->curhigh <= 0) || (ge->curhigh < artnum)) {
- ge->curhigh = artnum;
- needupdate = true;
- }
- if (needupdate) {
- ovindexhead.next = ovnull;
- ovindexhead.low = ge->curlow;
- ovindexhead.high = ge->curhigh;
-#ifdef MMAP_MISSES_WRITES
- if (mmapwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#else
- if (pwrite(ovbuff->fd, &ovindexhead, sizeof(OVINDEXHEAD), ovbuff->base + ge->curindex.blocknum * OV_BLOCKSIZE) != sizeof(OVINDEXHEAD)) {
-#endif /* MMAP_MISSES_WRITES */
- syslog(L_ERROR, "%s: could not write index record index '%d', blocknum '%d': %m", LocalLogName, ge->curindex.index, ge->curindex.blocknum);
- return true;
- }
- }
- if ((ge->low <= 0) || (ge->low > artnum))
- ge->low = artnum;
- if ((ge->high <= 0) || (ge->high < artnum))
- ge->high = artnum;
- ge->curindexoffset++;
- ge->curoffset += len;
- ge->count++;
- return true;
-}
-
-bool buffindexed_add(char *group, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires) {
- GROUPLOC gloc;
- GROUPENTRY *ge;
-
- if (len > OV_BLOCKSIZE) {
- syslog(L_ERROR, "%s: overview data is too large %d", LocalLogName, len);
- return true;
- }
-
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return true;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- /* prepend block(s) if needed. */
- ge = &GROUPentries[gloc.recno];
- if (Cutofflow && ge->low > artnum) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return true;
- }
-#ifdef OV_DEBUG
- if (!ovaddrec(ge, artnum, token, data, len, arrived, expires, NULL)) {
-#else
- if (!ovaddrec(ge, artnum, token, data, len, arrived, expires)) {
-#endif /* OV_DEBUG */
- if (Nospace) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- syslog(L_ERROR, "%s: no space left for buffer, adding '%s'", LocalLogName, group);
- return false;
- }
- syslog(L_ERROR, "%s: could not add overview for '%s'", LocalLogName, group);
- }
- GROUPlock(gloc, INN_LOCK_UNLOCK);
-
- return true;
-}
-
-bool buffindexed_cancel(TOKEN token UNUSED) {
- return true;
-}
-
-#ifdef OV_DEBUG
-static void freegroupblock(GROUPENTRY *ge) {
-#else
-static void freegroupblock(void) {
-#endif /* OV_DEBUG */
- GROUPDATABLOCK *gdb;
- int i;
- GIBLIST *giblist;
-
- for (giblist = Giblist ; giblist != NULL ; giblist = giblist->next) {
-#ifdef OV_DEBUG
- ovblockfree(giblist->ov, ge);
-#else
- ovblockfree(giblist->ov);
-#endif /* OV_DEBUG */
- }
- for (i = 0 ; i < GROUPDATAHASHSIZE ; i++) {
- for (gdb = groupdatablock[i] ; gdb != NULL ; gdb = gdb->next) {
-#ifdef OV_DEBUG
- ovblockfree(gdb->datablk, ge);
-#else
- ovblockfree(gdb->datablk);
-#endif /* OV_DEBUG */
- }
- }
-}
-
-static void ovgroupunmap(void) {
- GROUPDATABLOCK *gdb, *gdbnext;
- int i;
- GIBLIST *giblist, *giblistnext;
-
- for (i = 0 ; i < GROUPDATAHASHSIZE ; i++) {
- for (gdb = groupdatablock[i] ; gdb != NULL ; gdb = gdbnext) {
- gdbnext = gdb->next;
- free(gdb);
- }
- groupdatablock[i] = NULL;
- }
- for (giblist = Giblist ; giblist != NULL ; giblist = giblistnext) {
- giblistnext = giblist->next;
- free(giblist);
- }
- Giblist = NULL;
- if (!Cache && (Gib != NULL)) {
- free(Gib);
- Gib = NULL;
- if (Cachesearch != NULL) {
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- }
- }
-}
-
-static void insertgdb(OV *ov, GROUPDATABLOCK *gdb) {
- gdb->next = groupdatablock[(ov->index + ov->blocknum) % GROUPDATAHASHSIZE];
- groupdatablock[(ov->index + ov->blocknum) % GROUPDATAHASHSIZE] = gdb;
- return;
-}
-
-static GROUPDATABLOCK *searchgdb(OV *ov) {
- GROUPDATABLOCK *gdb;
-
- gdb = groupdatablock[(ov->index + ov->blocknum) % GROUPDATAHASHSIZE];
- for (; gdb != NULL ; gdb = gdb->next) {
- if (ov->index == gdb->datablk.index && ov->blocknum == gdb->datablk.blocknum)
- break;
- }
- return gdb;
-}
-
-static int INDEXcompare(const void *p1, const void *p2) {
- OVINDEX *oi1;
- OVINDEX *oi2;
-
- oi1 = (OVINDEX *)p1;
- oi2 = (OVINDEX *)p2;
- return oi1->artnum - oi2->artnum;
-}
-
-static bool ovgroupmmap(GROUPENTRY *ge, int low, int high, bool needov) {
- OV ov = ge->baseindex;
- OVBUFF *ovbuff;
- GROUPDATABLOCK *gdb;
- int pagefudge, limit, i, count, len;
- off_t offset, mmapoffset;
- OVBLOCK *ovblock;
- void * addr;
- GIBLIST *giblist;
-
- if (high - low < 0) {
- Gibcount = 0;
- return true;
- }
- Gibcount = ge->count;
- if (Gibcount == 0)
- return true;
- Gib = xmalloc(Gibcount * sizeof(OVINDEX));
- count = 0;
- while (ov.index != NULLINDEX) {
- ovbuff = getovbuff(ov);
- if (ovbuff == NULL) {
- syslog(L_ERROR, "%s: ovgroupmmap ovbuff is null(ovindex is %d, ovblock is %d", LocalLogName, ov.index, ov.blocknum);
- ovgroupunmap();
- return false;
- }
- offset = ovbuff->base + (ov.blocknum * OV_BLOCKSIZE);
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- len = pagefudge + OV_BLOCKSIZE;
- if ((addr = mmap(NULL, len, PROT_READ, MAP_SHARED, ovbuff->fd, mmapoffset)) == MAP_FAILED) {
- syslog(L_ERROR, "%s: ovgroupmmap could not mmap index block: %m", LocalLogName);
- ovgroupunmap();
- return false;
- }
- ovblock = (OVBLOCK *)((char *)addr + pagefudge);
- if (ov.index == ge->curindex.index && ov.blocknum == ge->curindex.blocknum) {
- limit = ge->curindexoffset;
- } else {
- limit = OVINDEXMAX;
- }
- for (i = 0 ; i < limit ; i++) {
- if (Gibcount == count) {
- Gibcount += OV_FUDGE;
- Gib = xrealloc(Gib, Gibcount * sizeof(OVINDEX));
- }
- Gib[count++] = ovblock->ovindex[i];
- }
- giblist = xmalloc(sizeof(GIBLIST));
- giblist->ov = ov;
- giblist->next = Giblist;
- Giblist = giblist;
- ov = ovblock->ovindexhead.next;
- munmap(addr, len);
- }
- Gibcount = count;
- qsort(Gib, Gibcount, sizeof(OVINDEX), INDEXcompare);
- /* Remove duplicates. */
- for (i = 0; i < Gibcount - 1; i++) {
- if (Gib[i].artnum == Gib[i+1].artnum) {
- /* lower position is removed */
- Gib[i].artnum = 0;
- }
- }
- if (!needov)
- return true;
- count = 0;
- for (i = 0 ; i < Gibcount ; i++) {
- if (Gib[i].artnum == 0 || Gib[i].artnum < low || Gib[i].artnum > high)
- continue;
- ov.index = Gib[i].index;
- ov.blocknum = Gib[i].blocknum;
- gdb = searchgdb(&ov);
- if (gdb != NULL)
- continue;
- ovbuff = getovbuff(ov);
- if (ovbuff == NULL)
- continue;
- gdb = xmalloc(sizeof(GROUPDATABLOCK));
- gdb->datablk = ov;
- gdb->next = NULL;
- gdb->mmapped = false;
- insertgdb(&ov, gdb);
- count++;
- }
- if (count == 0)
- return true;
- if (count * OV_BLOCKSIZE > innconf->keepmmappedthreshold * 1024)
- /* large retrieval, mmap is done in ovsearch() */
- return true;
- for (i = 0 ; i < GROUPDATAHASHSIZE ; i++) {
- for (gdb = groupdatablock[i] ; gdb != NULL ; gdb = gdb->next) {
- ov = gdb->datablk;
- ovbuff = getovbuff(ov);
- offset = ovbuff->base + (ov.blocknum * OV_BLOCKSIZE);
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- gdb->len = pagefudge + OV_BLOCKSIZE;
- if ((gdb->addr = mmap(NULL, gdb->len, PROT_READ, MAP_SHARED, ovbuff->fd, mmapoffset)) == MAP_FAILED) {
- syslog(L_ERROR, "%s: ovgroupmmap could not mmap data block: %m", LocalLogName);
- free(gdb);
- ovgroupunmap();
- return false;
- }
- gdb->data = (char *)gdb->addr + pagefudge;
- gdb->mmapped = true;
- }
- }
- return true;
-}
-
-static void *ovopensearch(char *group, int low, int high, bool needov) {
- GROUPLOC gloc;
- GROUPENTRY *ge;
- OVSEARCH *search;
-
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc))
- return NULL;
-
- ge = &GROUPentries[gloc.recno];
- if (low < ge->low)
- low = ge->low;
- if (high > ge->high)
- high = ge->high;
-
- if (!ovgroupmmap(ge, low, high, needov)) {
- return NULL;
- }
-
- search = xmalloc(sizeof(OVSEARCH));
- search->hi = high;
- search->lo = low;
- search->cur = 0;
- search->group = xstrdup(group);
- search->needov = needov;
- search->gloc = gloc;
- search->count = ge->count;
- search->gdb.mmapped = false;
- return (void *)search;
-}
-
-void *buffindexed_opensearch(char *group, int low, int high) {
- GROUPLOC gloc;
- void *handle;
-
- if (Gib != NULL) {
- free(Gib);
- Gib = NULL;
- if (Cachesearch != NULL) {
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- }
- }
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return NULL;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- if ((handle = ovopensearch(group, low, high, true)) == NULL)
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return(handle);
-}
-
-static bool ovsearch(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived, time_t *expires) {
- OVSEARCH *search = (OVSEARCH *)handle;
- OV srchov;
- GROUPDATABLOCK *gdb;
- off_t offset, mmapoffset;
- OVBUFF *ovbuff;
- int pagefudge;
- bool newblock;
-
- if (search->cur == Gibcount) {
- return false;
- }
- while (Gib[search->cur].artnum == 0 || Gib[search->cur].artnum < search->lo) {
- search->cur++;
- if (search->cur == Gibcount)
- return false;
- }
- if (Gib[search->cur].artnum > search->hi)
- return false;
-
- if (search->needov) {
- if (Gib[search->cur].index == NULLINDEX) {
- if (len)
- *len = 0;
- if (artnum)
- *artnum = Gib[search->cur].artnum;
- } else {
- if (artnum)
- *artnum = Gib[search->cur].artnum;
- if (len)
- *len = Gib[search->cur].len;
- if (arrived)
- *arrived = Gib[search->cur].arrived;
- if (expires)
- *expires = Gib[search->cur].expires;
- if (data) {
- srchov.index = Gib[search->cur].index;
- srchov.blocknum = Gib[search->cur].blocknum;
- gdb = searchgdb(&srchov);
- if (gdb == NULL) {
- if (len)
- *len = 0;
- search->cur++;
- return true;
- }
- if (!gdb->mmapped) {
- /* block needs to be mmapped */
- if (search->gdb.mmapped) {
- /* check previous mmapped area */
- if (search->gdb.datablk.blocknum != srchov.blocknum || search->gdb.datablk.index != srchov.index) {
- /* different one, release previous one */
- munmap(search->gdb.addr, search->gdb.len);
- newblock = true;
- } else
- newblock = false;
- } else
- newblock = true;
- if (newblock) {
- search->gdb.datablk.blocknum = srchov.blocknum;
- search->gdb.datablk.index = srchov.index;
- ovbuff = getovbuff(srchov);
- offset = ovbuff->base + (srchov.blocknum * OV_BLOCKSIZE);
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- search->gdb.len = pagefudge + OV_BLOCKSIZE;
- if ((search->gdb.addr = mmap(NULL, search->gdb.len, PROT_READ, MAP_SHARED, ovbuff->fd, mmapoffset)) == MAP_FAILED) {
- syslog(L_ERROR, "%s: ovsearch could not mmap data block: %m", LocalLogName);
- return false;
- }
- gdb->data = search->gdb.data = (char *)search->gdb.addr + pagefudge;
- search->gdb.mmapped = true;
- }
- }
- *data = (char *)gdb->data + Gib[search->cur].offset;
- }
- }
- }
- if (token) {
- if (Gib[search->cur].index == NULLINDEX && !search->needov) {
- search->cur++;
- return false;
- }
- *token = Gib[search->cur].token;
- }
- search->cur++;
- return true;
-}
-
-bool buffindexed_search(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived) {
- return(ovsearch(handle, artnum, data, len, token, arrived, NULL));
-}
-
-static void ovclosesearch(void *handle, bool freeblock) {
- OVSEARCH *search = (OVSEARCH *)handle;
- GROUPDATABLOCK *gdb;
- int i;
-#ifdef OV_DEBUG
- GROUPENTRY *ge;
- GROUPLOC gloc;
-#endif /* OV_DEBUG */
-
- for (i = 0 ; i < GROUPDATAHASHSIZE ; i++) {
- for (gdb = groupdatablock[i] ; gdb != NULL ; gdb = gdb->next) {
- if (gdb->mmapped)
- munmap(gdb->addr, gdb->len);
- }
- }
- if (search->gdb.mmapped)
- munmap(search->gdb.addr, search->gdb.len);
- if (freeblock) {
-#ifdef OV_DEBUG
- gloc = GROUPfind(search->group, false);
- if (!GROUPLOCempty(gloc)) {
- ge = &GROUPentries[gloc.recno];
- freegroupblock(ge);
- }
-#else
- freegroupblock();
-#endif /* OV_DEBUG */
- }
- ovgroupunmap();
- if (Cache) {
- Cachesearch = search;
- } else {
- free(search->group);
- free(search);
- }
- return;
-}
-
-void buffindexed_closesearch(void *handle) {
- OVSEARCH *search = (OVSEARCH *)handle;
- GROUPLOC gloc;
-
- gloc = search->gloc;
- ovclosesearch(handle, false);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
-}
-
-/* get token from sorted index */
-static bool gettoken(ARTNUM artnum, TOKEN *token) {
- int i, j, offset, limit;
- offset = 0;
- limit = Gibcount;
- for (i = (limit - offset) / 2 ; i > 0 ; i = (limit - offset) / 2) {
- if (Gib[offset + i].artnum == artnum) {
- *token = Gib[offset + i].token;
- return true;
- } else if (Gib[offset + i].artnum == 0) {
- /* case for duplicated index */
- for (j = offset + i - 1; j >= offset ; j --) {
- if (Gib[j].artnum != 0)
- break;
- }
- if (j < offset) {
- /* article not found */
- return false;
- }
- if (Gib[j].artnum == artnum) {
- *token = Gib[j].token;
- return true;
- } else if (Gib[j].artnum < artnum) {
- /* limit is not changed */
- offset += i + 1;
- } else {
- /* offset is not changed */
- limit = j;
- }
- } else if (Gib[offset + i].artnum < artnum) {
- /* limit is unchanged */
- offset += i + 1;
- } else {
- /* offset is unchanged */
- limit = offset + i;
- }
- }
- /* i == 0 */
- if (Gib[offset].artnum != artnum) {
- /* article not found */
- return false;
- }
- *token = Gib[offset].token;
- return true;
-}
-
-bool buffindexed_getartinfo(char *group, ARTNUM artnum, TOKEN *token) {
- GROUPLOC gloc;
- void *handle;
- bool retval, grouplocked = false;
-
- if (Gib != NULL) {
- if (Cachesearch != NULL && strcmp(Cachesearch->group, group) != 0) {
- free(Gib);
- Gib = NULL;
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- } else {
- if (gettoken(artnum, token))
- return true;
- else {
- /* examine to see if overview index are increased */
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return false;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- if ((Cachesearch != NULL) && (GROUPentries[gloc.recno].count == Cachesearch->count)) {
- /* no new overview data is stored */
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return false;
- } else {
- grouplocked = true;
- free(Gib);
- Gib = NULL;
- if (Cachesearch != NULL) {
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- }
- }
- }
- }
- }
- if (!grouplocked) {
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return false;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- }
- if (!(handle = ovopensearch(group, artnum, artnum, false))) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return false;
- }
- retval = buffindexed_search(handle, NULL, NULL, NULL, token, NULL);
- ovclosesearch(handle, false);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return retval;
-}
-
-bool buffindexed_expiregroup(char *group, int *lo, struct history *h) {
- void *handle;
- GROUPENTRY newge, *ge;
- GROUPLOC gloc, next;
- char *data;
- int i, j, len;
- TOKEN token;
- ARTNUM artnum, low, high;
- ARTHANDLE *ah;
- char flag;
- HASH hash;
- time_t arrived, expires;
-
- if (group == NULL) {
- for (i = 0 ; i < GROUPheader->freelist.recno ; i++) {
- gloc.recno = i;
- GROUPlock(gloc, INN_LOCK_WRITE);
- ge = &GROUPentries[gloc.recno];
- if (ge->expired >= OVrealnow || ge->count == 0) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- continue;
- }
- if (!ovgroupmmap(ge, ge->low, ge->high, true)) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- syslog(L_ERROR, "%s: could not mmap overview for hidden groups(%d)", LocalLogName, i);
- continue;
- }
- for (j = 0 ; j < Gibcount ; j++) {
- if (Gib[j].artnum == 0)
- continue;
- /* this may be duplicated, but ignore it in this case */
- OVEXPremove(Gib[j].token, true, NULL, 0);
- }
-#ifdef OV_DEBUG
- freegroupblock(ge);
-#else
- freegroupblock();
-#endif
- ovgroupunmap();
- ge->expired = time(NULL);
- ge->count = 0;
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- }
- return true;
- }
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- return false;
- }
- GROUPlock(gloc, INN_LOCK_WRITE);
- ge = &GROUPentries[gloc.recno];
- if (ge->count == 0) {
- if (lo)
- *lo = ge->low;
- ge->expired = time(NULL);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return true;
- }
- flag = ge->flag;
- hash = ge->hash;
- next = ge->next;
- low = ge->low;
- high = ge->high;
-
- newge.low = 0;
- setinitialge(&newge, hash, &flag, next, 0, high);
- if ((handle = ovopensearch(group, low, high, true)) == NULL) {
- ge->expired = time(NULL);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- syslog(L_ERROR, "%s: could not open overview for '%s'", LocalLogName, group);
- return false;
- }
- while (ovsearch(handle, &artnum, &data, &len, &token, &arrived, &expires)) {
- ah = NULL;
- if (len == 0)
- continue;
- if (!SMprobe(EXPENSIVESTAT, &token, NULL) || OVstatall) {
- if ((ah = SMretrieve(token, RETR_STAT)) == NULL)
- continue;
- SMfreearticle(ah);
- } else {
- if (!OVhisthasmsgid(h, data))
- continue;
- }
- if (innconf->groupbaseexpiry && OVgroupbasedexpire(token, group, data, len, arrived, expires))
- continue;
-#ifdef OV_DEBUG
- if (!ovaddrec(&newge, artnum, token, data, len, arrived, expires, ge)) {
-#else
- if (!ovaddrec(&newge, artnum, token, data, len, arrived, expires)) {
-#endif /* OV_DEBUG */
- ovclosesearch(handle, true);
- ge->expired = time(NULL);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- syslog(L_ERROR, "%s: could not add new overview for '%s'", LocalLogName, group);
- return false;
- }
- }
- if (newge.low == 0)
- /* no article for the group */
- newge.low = newge.high;
- *ge = newge;
- if (lo) {
- if (ge->count == 0)
- /* lomark should be himark + 1, if no article for the group */
- *lo = ge->low + 1;
- else
- *lo = ge->low;
- }
- ovclosesearch(handle, true);
- ge->expired = time(NULL);
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- return true;
-}
-
-bool buffindexed_ctl(OVCTLTYPE type, void *val) {
- int total, used, *i, j;
- OVBUFF *ovbuff = ovbufftab;
- OVSORTTYPE *sorttype;
- bool *boolval;
- GROUPDATABLOCK *gdb;
-
- switch (type) {
- case OVSPACE:
- for (total = used = 0 ; ovbuff != (OVBUFF *)NULL ; ovbuff = ovbuff->next) {
- ovlock(ovbuff, INN_LOCK_READ);
- ovreadhead(ovbuff);
- total += ovbuff->totalblk;
- used += ovbuff->usedblk;
- ovlock(ovbuff, INN_LOCK_UNLOCK);
- }
- i = (int *)val;
- *i = (used * 100) / total;
- return true;
- case OVSORT:
- sorttype = (OVSORTTYPE *)val;
- *sorttype = OVNOSORT;
- return true;
- case OVCUTOFFLOW:
- Cutofflow = *(bool *)val;
- return true;
- case OVSTATICSEARCH:
- i = (int *)val;
- *i = true;
- for (j = 0 ; j < GROUPDATAHASHSIZE ; j++) {
- for (gdb = groupdatablock[j] ; gdb != NULL ; gdb = gdb->next) {
- if (gdb->mmapped) {
- *i = false;
- return true;
- }
- }
- }
- return true;
- case OVCACHEKEEP:
- Cache = *(bool *)val;
- return true;
- case OVCACHEFREE:
- boolval = (bool *)val;
- *boolval = true;
- if (Gib != NULL) {
- free(Gib);
- Gib = NULL;
- if (Cachesearch != NULL) {
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- }
- }
- return true;
- default:
- return false;
- }
-}
-
-void buffindexed_close(void) {
- struct stat sb;
- OVBUFF *ovbuffnext, *ovbuff = ovbufftab;
-#ifdef OV_DEBUG
- FILE *F = NULL;
- pid_t pid;
- char *path = NULL;
- int i,j;
- struct ov_trace_array *trace;
- struct ov_name_table *ntp;
- size_t length;
-#endif /* OV_DEBUG */
-
-#ifdef OV_DEBUG
- for (; ovbuff != (OVBUFF *)NULL; ovbuff = ovbuff->next) {
- for (i = 0 ; i < ovbuff->totalblk ; i++) {
- trace = &ovbuff->trace[i];
- if (trace->ov_trace == NULL)
- continue;
- for (j = 0 ; j <= trace->cur && j < trace->max ; j++) {
- if (trace->ov_trace[j].occupied != 0 ||
- trace->ov_trace[j].freed != 0) {
- if (F == NULL) {
- length = strlen(innconf->pathtmp) + 11;
- path = xmalloc(length);
- pid = getpid();
- snprintf(path, length, "%s/%d", innconf->pathtmp, pid);
- if ((F = fopen(path, "w")) == NULL) {
- syslog(L_ERROR, "%s: could not open %s: %m", LocalLogName, path);
- break;
- }
- }
- fprintf(F, "%d: % 6d, % 2d: 0x%08x, % 10d, % 10d\n", ovbuff->index, i, j,
- trace->ov_trace[j].gloc.recno,
- trace->ov_trace[j].occupied,
- trace->ov_trace[j].freed);
- }
- }
- }
- }
- if ((ntp = name_table) != NULL) {
- if (F == NULL) {
- length = strlen(innconf->pathtmp) + 11;
- path = xmalloc(length);
- pid = getpid();
- sprintf(path, length, "%s/%d", innconf->pathtmp, pid);
- if ((F = fopen(path, "w")) == NULL) {
- syslog(L_ERROR, "%s: could not open %s: %m", LocalLogName, path);
- }
- }
- if (F != NULL) {
- while(ntp) {
- fprintf(F, "0x%08x: %s\n", ntp->recno, ntp->name);
- ntp = ntp->next;
- }
- }
- }
- if (F != NULL)
- fclose(F);
- if (path != NULL)
- free(path);
-#endif /* OV_DEBUG */
- if (Gib != NULL) {
- free(Gib);
- Gib = NULL;
- if (Cachesearch != NULL) {
- free(Cachesearch->group);
- free(Cachesearch);
- Cachesearch = NULL;
- }
- }
- if (fstat(GROUPfd, &sb) < 0)
- return;
- close(GROUPfd);
-
- if (GROUPheader) {
- if (munmap((void *)GROUPheader, GROUPfilesize(GROUPcount)) < 0) {
- syslog(L_FATAL, "%s: could not munmap group.index in buffindexed_close: %m", LocalLogName);
- return;
- }
- }
- for (; ovbuff != (OVBUFF *)NULL; ovbuff = ovbuffnext) {
- ovbuffnext = ovbuff->next;
- free(ovbuff);
- }
- ovbufftab = NULL;
-}
-
-#ifdef BUFF_DEBUG
-static int countgdb(void) {
- int i, count = 0;
- GROUPDATABLOCK *gdb;
-
- for (i = 0 ; i < GROUPDATAHASHSIZE ; i++) {
- for (gdb = groupdatablock[i] ; gdb != NULL ; gdb = gdb->next)
- count++;
- }
- return count;
-}
-
-main(int argc, char **argv) {
- char *group, flag[2], buff[OV_BLOCKSIZE];
- int lo, hi, count, flags, i;
- OVSEARCH *search;
- OVBLOCK *ovblock;
- OVINDEX *ovindex;
- OVBUFF *ovbuff;
- GROUPENTRY *ge;
- GROUPLOC gloc;
- GIBLIST *giblist;
-
- if (argc != 2) {
- fprintf(stderr, "only one argument can be specified\n");
- exit(1);
- }
- /* if innconf isn't already read in, do so. */
- if (innconf == NULL) {
- if (!innconf_read(NULL)) {
- fprintf(stderr, "reading inn.conf failed\n");
- exit(1);
- }
- }
- if (!buffindexed_open(OV_READ)) {
- fprintf(stderr, "buffindexed_open failed\n");
- exit(1);
- }
- fprintf(stdout, "GROUPheader->freelist.recno is %d(0x%08x)\n", GROUPheader->freelist.recno, GROUPheader->freelist.recno);
- group = argv[1];
- if (isdigit(*group)) {
- gloc.recno = atoi(group);
- ge = &GROUPentries[gloc.recno];
- fprintf(stdout, "left articles are %d for %d, last expiry is %d\n", ge->count, gloc.recno, ge->expired);
- if (ge->count == 0) {
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- exit(0);
- }
- if (!ovgroupmmap(ge, ge->low, ge->high, true)) {
- fprintf(stderr, "ovgroupmmap failed\n");
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- }
- for (giblist = Giblist, i = 0 ; giblist != NULL ; giblist = giblist->next, i++);
- fprintf(stdout, "%d index block(s)\n", i);
- fprintf(stdout, "%d data block(s)\n", countgdb());
- for (giblist = Giblist ; giblist != NULL ; giblist = giblist->next) {
- fprintf(stdout, " % 8d(% 5d)\n", giblist->ov.blocknum, giblist->ov.index);
- }
- for (i = 0 ; i < Gibcount ; i++) {
- if (Gib[i].artnum == 0)
- continue;
- if (Gib[i].index == NULLINDEX)
- fprintf(stdout, " %d empty\n");
- else {
- fprintf(stdout, " %d %d\n", Gib[i].offset, Gib[i].len);
- }
- }
- ovgroupunmap();
- GROUPlock(gloc, INN_LOCK_UNLOCK);
- exit(0);
- }
- gloc = GROUPfind(group, false);
- if (GROUPLOCempty(gloc)) {
- fprintf(stderr, "gloc is null\n");
- }
- GROUPlock(gloc, INN_LOCK_READ);
- ge = &GROUPentries[gloc.recno];
- fprintf(stdout, "base %d(%d), cur %d(%d), expired at %s\n", ge->baseindex.blocknum, ge->baseindex.index, ge->curindex.blocknum, ge->curindex.index, ge->expired == 0 ? "none\n" : ctime(&ge->expired));
- if (!buffindexed_groupstats(group, &lo, &hi, &count, &flags)) {
- fprintf(stderr, "buffindexed_groupstats failed for group %s\n", group);
- exit(1);
- }
- flag[0] = (char)flags;
- flag[1] = '\0';
- fprintf(stdout, "%s: low is %d, high is %d, count is %d, flag is '%s'\n", group, lo, hi, count, flag);
- if ((search = (OVSEARCH *)ovopensearch(group, lo, hi, true)) == NULL) {
- fprintf(stderr, "ovopensearch failed for group %s\n", group);
- exit(1);
- }
- fprintf(stdout, " gloc is %d(0x%08x)\n", search->gloc.recno, search->gloc.recno);
- for (giblist = Giblist, i = 0 ; giblist != NULL ; giblist = giblist->next, i++);
- fprintf(stdout, "%d index block(s)\n", i);
- fprintf(stdout, "%d data block(s)\n", countgdb());
- for (giblist = Giblist ; giblist != NULL ; giblist = giblist->next) {
- fprintf(stdout, " % 8d(% 5d)\n", giblist->ov.blocknum, giblist->ov.index);
- }
- for (i = 0 ; i < Gibcount ; i++) {
- if (Gib[i].artnum == 0)
- continue;
- if (Gib[i].index == NULLINDEX)
- fprintf(stdout, " %d empty\n");
- else {
- fprintf(stdout, " %d %d\n", Gib[i].offset, Gib[i].len);
- }
- }
- {
- ARTNUM artnum;
- char *data;
- int len;
- TOKEN token;
- while (buffindexed_search((void *)search, &artnum, &data, &len, &token, NULL)) {
- if (len == 0)
- fprintf(stdout, "%d: len is 0\n", artnum);
- else {
- memcpy(buff, data, len);
- buff[len] = '\0';
- fprintf(stdout, "%d: %s\n", artnum, buff);
- }
- }
- }
-}
-#endif /* BUFF_DEBUG */
+++ /dev/null
-#ifndef _BUFFINDEXED_H_
-#define _BUFFINDEXED_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-bool buffindexed_open(int mode);
-bool buffindexed_groupstats(char *group, int *lo, int *hi, int *count, int *flag);
-bool buffindexed_groupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag);
-bool buffindexed_groupdel(char *group);
-bool buffindexed_add(char *group, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires);
-bool buffindexed_cancel(TOKEN token);
-void *buffindexed_opensearch(char *group, int low, int high);
-bool buffindexed_search(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived);
-void buffindexed_closesearch(void *handle);
-bool buffindexed_getartinfo(char *group, ARTNUM artnum, TOKEN *token);
-bool buffindexed_expiregroup(char *group, int *lo, struct history *h);
-bool buffindexed_ctl(OVCTLTYPE type, void *val);
-void buffindexed_close(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _BUFFINDEXED_H_ */
+++ /dev/null
-name = buffindexed
-number = 3
-sources = buffindexed.c
+++ /dev/null
-# This rule requires a compiler that supports -o with -c. Since it's normally
-# used by developers, that should be acceptable.
-buffindexed/buffindexed_d.o: buffindexed/buffindexed.c
- $(CC) $(CFLAGS) -DBUFF_DEBUG -c -o $@ buffindexed/buffindexed.c
-
-buffindexed/debug: buffindexed/buffindexed_d.o libstorage.$(EXTLIB) $(LIBHIST)
- $(LIBLD) $(LDFLAGS) -o $@ buffindexed/buffindexed_d.o \
- $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
+++ /dev/null
-#! /usr/bin/perl
-
-## $Id: buildconfig.in 6806 2004-05-18 01:18:57Z rra $
-##
-## Generate linkage code and makefiles for storage and overview methods.
-##
-## Goes through all subdirectories of the current directory and finds
-## directories that are either storage methods or overview methods. Builds
-## methods.[ch] and ovmethods.[ch] as well as makefile stubs.
-
-require 5.003;
-
-use strict;
-use vars qw(@OVERVIEW @STORAGE);
-
-# Storage API functions.
-@STORAGE = qw(init store retrieve next freearticle cancel ctl flushcacheddata
- printfiles shutdown);
-
-# Overview API functions.
-@OVERVIEW = qw(open groupstats groupadd groupdel add cancel opensearch search
- closesearch getartinfo expiregroup ctl close);
-
-# Used to make heredocs more readable.
-sub unquote { my ($string) = @_; $string =~ s/^:( {0,7}|\t)//gm; $string }
-
-# Parse a method.config file for a storage method, putting information about
-# that storage method into the given hash ref.
-sub parse_config {
- my ($dir, $file, $config) = @_;
- local $_;
- $$config{sources} ||= [];
- $$config{extra} ||= [];
- $$config{programs} ||= [];
- $$config{makefiles} ||= [];
- open (CONFIG, "$dir/$file") or die "Can't open $dir/$file: $!\n";
- while (<CONFIG>) {
- s/^\s+//;
- s/\s+$//;
- if (/^name\s*=\s*(\S+)$/) {
- my $method = $1;
- die "$dir/$file: $method has already been defined\n"
- if (defined $$config{method}{$method});
- $$config{method}{$method} = $dir;
- } elsif (/^number\s*=\s*(\d+)$/) {
- my $number = $1;
- if (defined $$config{number}{$number}) {
- die "$dir/$file: method number $number was already "
- . "allocated in $$config{number}{$number}\n";
- }
- $$config{number}{$dir} = $number;
- } elsif (/^sources\s*=\s*(.*)/) {
- my $sources = $1;
- my @sources = split (' ', $sources);
- push (@{ $$config{sources} }, map { "$dir/$_" } @sources);
- } elsif (/^extra-sources\s*=\s*(.*)/) {
- my $extra = $1;
- my @extra = split (' ', $extra);
- push (@{ $$config{extra} }, map { "$dir/$_" } @extra);
- } elsif (/^programs\s*=\s*(.*)/) {
- my $programs = $1;
- my @programs = split (' ', $programs);
- push (@{ $$config{programs} }, map { "$dir/$_" } @programs);
- } else {
- warn "$dir/$file: ignoring unknown line: $_\n";
- }
- }
-
- # If there is a makefile fragment in the directory, note it.
- if (-f "$dir/method.mk") {
- push (@{ $$config{makefiles} }, "$dir/method.mk");
- } elsif (-f "$dir/ovmethod.mk") {
- push (@{ $$config{makefiles} }, "$dir/ovmethod.mk");
- }
-}
-
-# Write out include directives for a list of files.
-sub write_includes {
- my ($fh, $config) = @_;
- my $method;
- for $method (sort keys %{ $$config{method} }) {
- my $path = $$config{method}{$method};
- print $fh qq(\#include "$path/$method.h"\n);
- }
-}
-
-# Write out the method struct.
-sub write_methods {
- my ($fh, $config, $prefix, @funcs) = @_;
- my ($notfirst, $method);
- for $method (sort keys %{ $$config{method} }) {
- print $fh "\n},\n" if $notfirst;
- print $fh qq(\{\n "$method");
- print $fh ', ', $prefix, '_', uc ($method) if $prefix;
- for (@funcs) {
- print $fh ",\n ${method}_$_";
- }
- $notfirst++;
- }
- print $fh "\n}\n};\n\n";
-}
-
-# Write out the constant defines for methods.
-sub write_constants {
- my ($fh, $config, $prefix) = @_;
- my $method;
- for $method (sort keys %{ $$config{method} }) {
- printf $fh "#define ${prefix}_%-30s%d\n", uc ($method),
- $$config{number}{$$config{method}{$method}};
- }
-}
-
-# Write out methods.c and methods.h for the interface to the storage
-# methods.
-sub write_storage {
- my $storage = shift;
- open (DEF, '> methods.c.new') or die "Can't create methods.c.new: $!\n";
- print DEF unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig. */
-:
-: #include "interface.h"
-: #include "methods.h"
-EOE
- my $method;
- write_includes (\*DEF, $storage);
- print DEF "\nSTORAGE_METHOD storage_methods[",
- scalar (keys %{ $$storage{method} }), "] = {\n";
- write_methods (\*DEF, $storage, 'TOKEN', @STORAGE);
- close DEF;
- rename ('methods.c.new', 'methods.c');
-
- open (H, '> methods.h.new') or die "Can't open methods.h.new: $!\n";
- print H unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig */
-:
-: #ifndef METHODS_H
-: #define METHODS_H 1
-:
-: #include "interface.h"
-:
-EOE
- print H '#define NUM_STORAGE_METHODS ',
- scalar (keys %{ $$storage{method} }), "\n\n";
- write_constants (\*H, $storage, 'TOKEN');
- print H unquote (<<'EOE');
-:
-: extern STORAGE_METHOD storage_methods[NUM_STORAGE_METHODS];
-:
-: #endif /* METHODS_H */
-EOE
- close H;
- rename ('methods.h.new', 'methods.h');
-}
-
-# Write out ovmethods.c and ovmethods.h for the interface to the overview
-# methods.
-sub write_overview {
- my $overview = shift;
- open (DEF, '> ovmethods.c.new')
- or die "Can't create ovmethods.c.new: $!\n";
- print DEF unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig. */
-:
-: #include "ovinterface.h"
-EOE
- write_includes (\*DEF, $overview);
- print DEF "\nOV_METHOD ov_methods[",
- scalar (keys %{ $$overview{method} }), "] = {\n";
- write_methods (\*DEF, $overview, undef, @OVERVIEW);
- close DEF;
- rename ('ovmethods.c.new', 'ovmethods.c');
-
- open (H, '> ovmethods.h.new') or die "Can't open ovmethods.h.new: $!\n";
- print H unquote (<<'EOE');
-: /* This file is automatically generated by buildconfig */
-:
-: #ifndef OVMETHODS_H
-: #define OVMETHODS_H 1
-:
-: #include "ovinterface.h"
-:
-EOE
- print H '#define NUM_OV_METHODS ',
- scalar (keys %{ $$overview{method} }), "\n";
- print H unquote (<<'EOE');
-:
-: extern OV_METHOD ov_methods[NUM_OV_METHODS];
-:
-: #endif /* OVMETHODS_H */
-EOE
- close H;
- rename ('ovmethods.h.new', 'ovmethods.h');
-}
-
-# Return a string setting a makefile variable. Tab over the = properly and
-# wrap to fit our coding standards.
-sub makefile_var {
- my ($variable, @values) = @_;
- my $output;
- $output = sprintf ("%-15s =", $variable);
- my $column = 17;
- for (@values) {
- if ($column > 17 && 77 - $column < length ($_)) {
- $output .= " \\\n" . ' ' x 17;
- $column = 17;
- }
- $output .= " $_";
- $column += 1 + length ($_);
- }
- $output .= "\n";
- return $output;
-}
-
-# Write out the makefile fragment for overview and storage methods.
-sub write_makefile {
- my ($dirs, $sources, $extra, $programs, $makefiles) = @_;
- open (MAKE, '> Make.methods.new')
- or die "Can't create Make.methods.new: $!\n";
- print MAKE "# This file is automatically generated by buildconfig\n\n";
- print MAKE makefile_var ('METHOD_SOURCES', @$sources);
- print MAKE makefile_var ('EXTRA_SOURCES', @$extra);
- print MAKE makefile_var ('PROGRAMS', @$programs);
- for (@$makefiles) {
- print MAKE "\n\n## Included from $_\n\n";
- open (FRAG, $_) or die "Can't open $_: $!\n";
- print MAKE <FRAG>;
- close FRAG;
- }
- rename ('Make.methods.new', 'Make.methods');
-}
-
-my ($dir, %storage, %overview);
-if (!-d 'cnfs') {
- if (-d 'storage/cnfs') {
- chdir 'storage' or die "Can't chdir to storage: $!\n";
- } else {
- die "Can't find storage directory (looking for storage/cnfs)\n";
- }
-}
-opendir (D, ".") or die "Can't open current directory: $!\n";
-my @dirs = sort readdir D;
-for $dir (@dirs) {
- if (-e "$dir/method.config") {
- parse_config ($dir, 'method.config', \%storage);
- }
- if (-e "$dir/ovmethod.config") {
- parse_config ($dir, 'ovmethod.config', \%overview);
- }
-}
-write_storage (\%storage);
-write_overview (\%overview);
-@dirs = (sort values %{ $storage{method} },
- sort values %{ $overview{method} });
-my @sources = (sort @{ $storage{sources} }, sort @{ $overview{sources} });
-my @extra = (sort @{ $storage{extra} }, sort @{ $overview{extra} });
-my @programs = sort (@{ $storage{programs} }, @{ $overview{programs} });
-my @makefiles = sort (@{ $storage{makefiles} }, @{ $overview{makefiles} });
-write_makefile (\@dirs, \@sources, \@extra, \@programs, \@makefiles);
+++ /dev/null
-/* $Id: cnfs-private.h 5975 2002-12-11 04:51:43Z rra $
-**
-** CNFS disk/file mode header file.
-*/
-
-#ifndef CNFS_PRIVATE_H
-#define CNFS_PRIVATE_H 1
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#define _PATH_CYCBUFFCONFIG "cycbuff.conf"
-
-/* Page boundary on which to mmap() the CNFS article usage header. Should be
- a multiple of the pagesize for all the architectures you expect might need
- access to your CNFS buffer. If you don't expect to share your buffer
- across several platforms, you can use 'pagesize' here. */
-#define CNFS_HDR_PAGESIZE 16384
-
-#define CNFS_MAGICV1 "Cycbuff" /* CNFSMASIZ bytes */
-#define CNFS_MAGICV2 "CBuf1" /* CNFSMASIZ bytes */
-#define CNFS_MAGICV3 "CBuf3" /* CNFSMASIZ bytes */
-#define CNFS_BLOCKSIZE 512 /* Unit block size we'll work with */
-
-/* Amount of data stored at beginning of CYCBUFF before the bitfield */
-#define CNFS_BEFOREBITF (1 * CNFS_BLOCKSIZE)
-
-struct metacycbuff; /* Definition comes below */
-
-#define CNFSMAXCYCBUFFNAME 8
-#define CNFSMASIZ 8
-#define CNFSNASIZ 16 /* Effective size is 9, not 16 */
-#define CNFSPASIZ 64
-#define CNFSLASIZ 16 /* Match length of ASCII hex off_t
- representation */
-
-typedef struct _CYCBUFF {
- char name[CNFSNASIZ];/* Symbolic name */
- char path[CNFSPASIZ];/* Path to file */
- off_t len; /* Length of writable area, in bytes */
- off_t free; /* Offset (relative to byte 0 of file) to first
- freely available byte */
- time_t updated; /* Time of last update to header */
- int fd; /* file descriptor for this cycbuff */
- uint32_t cyclenum; /* Number of current cycle, 0 = invalid */
- int magicver; /* Magic version number */
- void * bitfield; /* Bitfield for article in use */
- off_t minartoffset; /* The minimum offset allowed for article
- storage */
- bool needflush; /* true if CYCBUFFEXTERN is needed to be
- flushed */
- struct _CYCBUFF *next;
- bool currentbuff; /* true if this cycbuff is currently used */
- char metaname[CNFSNASIZ];/* Symbolic name of meta */
- int order; /* Order in meta, start from 1 not 0 */
-} CYCBUFF;
-
-/*
-** A structure suitable for thwapping onto disk in a quasi-portable way.
-** We assume that sizeof(CYCBUFFEXTERN) < CNFS_BLOCKSIZE.
-*/
-typedef struct {
- char magic[CNFSMASIZ];
- char name[CNFSNASIZ];
- char path[CNFSPASIZ];
- char lena[CNFSLASIZ]; /* ASCII version of len */
- char freea[CNFSLASIZ]; /* ASCII version of free */
- char updateda[CNFSLASIZ]; /* ASCII version of updated */
- char cyclenuma[CNFSLASIZ]; /* ASCII version of cyclenum */
- char metaname[CNFSNASIZ];
- char orderinmeta[CNFSLASIZ];
- char currentbuff[CNFSMASIZ];
-} CYCBUFFEXTERN;
-
-#define METACYCBUFF_UPDATE 25
-#define REFRESH_INTERVAL 30
-
-typedef enum {INTERLEAVE, SEQUENTIAL} METAMODE;
-
-typedef struct metacycbuff {
- char *name; /* Symbolic name of the pool */
- int count; /* Number of files/devs in this pool */
- CYCBUFF **members; /* Member cycbuffs */
- int memb_next; /* Index to next member to write onto */
- unsigned long write_count; /* Number of writes since last header flush */
- struct metacycbuff *next;
- METAMODE metamode;
-} METACYCBUFF;
-
-typedef struct _CNFSEXPIRERULES {
- STORAGECLASS class;
- METACYCBUFF *dest;
- struct _CNFSEXPIRERULES *next;
-} CNFSEXPIRERULES;
-
-typedef struct {
- long size; /* Size of the article */
- time_t arrived; /* This is the time when article arrived */
- STORAGECLASS class; /* storage class */
-} CNFSARTHEADER;
-
-/* uncomment below for old cnfs spool */
-/* #ifdef OLD_CNFS */
-typedef struct {
- long zottf; /* This should always be 0x01234*/
- long size; /* Size of the article */
- char m_id[64]; /* We'll only store up to 63 bytes of the
- Message-ID, that should be good enough */
-} oldCNFSARTHEADER;
-
-#endif /* !CNFS_PRIVATE_H */
+++ /dev/null
-/* $Id: cnfs.c 7412 2005-10-09 03:44:35Z eagle $
-**
-** Cyclic News File System.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <netinet/in.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include "inn/innconf.h"
-#include "interface.h"
-#include "libinn.h"
-#include "methods.h"
-#include "paths.h"
-#include "inn/wire.h"
-#include "inn/mmap.h"
-
-#include "cnfs.h"
-#include "cnfs-private.h"
-
-/* Temporary until cnfs_mapcntl is handled like mapcntl. Make MS_ASYNC
- disappear on platforms that don't have it. */
-#ifndef MS_ASYNC
-# define MS_ASYNC 0
-#endif
-
-/* We can give a more descriptive error below about not having largefile support if the platform has EOVERFLOW; on other platforms some other
- * errno will be used and so we won't know when to give the descriptive
- * error. Oh well. */
-#ifndef EOVERFLOW
-# define EOVERFLOW 0
-#endif
-
-typedef struct {
- /**** Stuff to be cleaned up when we're done with the article */
- char *base; /* Base of mmap()ed art */
- int len; /* Length of article (and thus
- mmap()ed art */
- CYCBUFF *cycbuff; /* pointer to current CYCBUFF */
- off_t offset; /* offset to current article */
- bool rollover; /* true if the search is rollovered */
-} PRIV_CNFS;
-
-static char LocalLogName[] = "CNFS-sm";
-static CYCBUFF *cycbufftab = (CYCBUFF *)NULL;
-static METACYCBUFF *metacycbufftab = (METACYCBUFF *)NULL;
-static CNFSEXPIRERULES *metaexprulestab = (CNFSEXPIRERULES *)NULL;
-static long pagesize = 0;
-static int metabuff_update = METACYCBUFF_UPDATE;
-static int refresh_interval = REFRESH_INTERVAL;
-
-static TOKEN CNFSMakeToken(char *cycbuffname, off_t offset,
- uint32_t cycnum, STORAGECLASS class) {
- TOKEN token;
- int32_t int32;
-
- /*
- ** XXX We'll assume that TOKENSIZE is 16 bytes and that we divvy it
- ** up as: 8 bytes for cycbuffname, 4 bytes for offset, 4 bytes
- ** for cycnum. See also: CNFSBreakToken() for hard-coded constants.
- */
- token.type = TOKEN_CNFS;
- token.class = class;
- memcpy(token.token, cycbuffname, CNFSMAXCYCBUFFNAME);
- int32 = htonl(offset / CNFS_BLOCKSIZE);
- memcpy(&token.token[8], &int32, sizeof(int32));
- int32 = htonl(cycnum);
- memcpy(&token.token[12], &int32, sizeof(int32));
- return token;
-}
-
-/*
-** NOTE: We assume that cycbuffname is 9 bytes long.
-*/
-
-static bool CNFSBreakToken(TOKEN token, char *cycbuffname,
- off_t *offset, uint32_t *cycnum) {
- int32_t int32;
-
- if (cycbuffname == NULL || offset == NULL || cycnum == NULL) {
- syslog(L_ERROR, "%s: BreakToken: invalid argument: %s",
- LocalLogName, cycbuffname);
- SMseterror(SMERR_INTERNAL, "BreakToken: invalid argument");
- return false;
- }
- memcpy(cycbuffname, token.token, CNFSMAXCYCBUFFNAME);
- *(cycbuffname + CNFSMAXCYCBUFFNAME) = '\0'; /* Just to be paranoid */
- memcpy(&int32, &token.token[8], sizeof(int32));
- *offset = (off_t)ntohl(int32) * (off_t)CNFS_BLOCKSIZE;
- memcpy(&int32, &token.token[12], sizeof(int32));
- *cycnum = ntohl(int32);
- return true;
-}
-
-static char hextbl[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'a', 'b', 'c', 'd', 'e', 'f'};
-
-/*
-** CNFSofft2hex -- Given an argument of type off_t, return
-** a static ASCII string representing its value in hexadecimal.
-**
-** If "leadingzeros" is true, the number returned will have leading 0's.
-*/
-
-static char * CNFSofft2hex(off_t offset, bool leadingzeros) {
- static char buf[24];
- char *p;
-
- if (sizeof(off_t) <= 4) {
- snprintf(buf, sizeof(buf), (leadingzeros) ? "%016lx" : "%lx", offset);
- } else {
- int i;
-
- for (i = 0; i < CNFSLASIZ; i++)
- buf[i] = '0'; /* Pad with zeros to start */
- for (i = CNFSLASIZ - 1; i >= 0; i--) {
- buf[i] = hextbl[offset & 0xf];
- offset >>= 4;
- }
- }
- if (! leadingzeros) {
- for (p = buf; *p == '0'; p++)
- ;
- if (*p != '\0')
- return p;
- else
- return p - 1; /* We converted a "0" and then bypassed all
- the zeros */
- } else
- return buf;
-}
-
-/*
-** CNFShex2offt -- Given an ASCII string containing a hexadecimal representation
-** of a off_t, return a off_t.
-*/
-
-static off_t CNFShex2offt(char *hex) {
- if (sizeof(off_t) <= 4) {
- unsigned long rpofft;
- /* I'm lazy */
- sscanf(hex, "%lx", &rpofft);
- return rpofft;
- } else {
- char diff;
- off_t n = 0;
-
- for (; *hex != '\0'; hex++) {
- if (*hex >= '0' && *hex <= '9')
- diff = '0';
- else if (*hex >= 'a' && *hex <= 'f')
- diff = 'a' - 10;
- else if (*hex >= 'A' && *hex <= 'F')
- diff = 'A' - 10;
- else {
- /*
- ** We used to have a syslog() message here, but the case
- ** where we land here because of a ":" happens, er, often.
- */
- break;
- }
- n += (*hex - diff);
- if (isalnum((int)*(hex + 1)))
- n <<= 4;
- }
- return n;
- }
-}
-
-static bool CNFSflushhead(CYCBUFF *cycbuff) {
- CYCBUFFEXTERN rpx;
-
- if (!cycbuff->needflush)
- return true;
- if (!SMopenmode) {
- syslog(L_ERROR, "%s: CNFSflushhead: attempted flush whilst read only",
- LocalLogName);
- return false;
- }
- memset(&rpx, 0, sizeof(CYCBUFFEXTERN));
- if (cycbuff->magicver == 3) {
- cycbuff->updated = time(NULL);
- strncpy(rpx.magic, CNFS_MAGICV3, strlen(CNFS_MAGICV3));
- strncpy(rpx.name, cycbuff->name, CNFSNASIZ);
- strncpy(rpx.path, cycbuff->path, CNFSPASIZ);
- /* Don't use sprintf() directly ... the terminating '\0' causes grief */
- strncpy(rpx.lena, CNFSofft2hex(cycbuff->len, true), CNFSLASIZ);
- strncpy(rpx.freea, CNFSofft2hex(cycbuff->free, true), CNFSLASIZ);
- strncpy(rpx.cyclenuma, CNFSofft2hex(cycbuff->cyclenum, true), CNFSLASIZ);
- strncpy(rpx.updateda, CNFSofft2hex(cycbuff->updated, true), CNFSLASIZ);
- strncpy(rpx.metaname, cycbuff->metaname, CNFSNASIZ);
- strncpy(rpx.orderinmeta, CNFSofft2hex(cycbuff->order, true), CNFSLASIZ);
- if (cycbuff->currentbuff) {
- strncpy(rpx.currentbuff, "TRUE", CNFSMASIZ);
- } else {
- strncpy(rpx.currentbuff, "FALSE", CNFSMASIZ);
- }
- memcpy(cycbuff->bitfield, &rpx, sizeof(CYCBUFFEXTERN));
- msync(cycbuff->bitfield, cycbuff->minartoffset, MS_ASYNC);
- cycbuff->needflush = false;
- } else {
- syslog(L_ERROR, "%s: CNFSflushhead: bogus magicver for %s: %d",
- LocalLogName, cycbuff->name, cycbuff->magicver);
- return false;
- }
- return true;
-}
-
-static void CNFSshutdowncycbuff(CYCBUFF *cycbuff) {
- if (cycbuff == (CYCBUFF *)NULL)
- return;
- if (cycbuff->needflush) {
- syslog(L_NOTICE, "%s: CNFSshutdowncycbuff: flushing %s", LocalLogName, cycbuff->name);
- CNFSflushhead(cycbuff);
- }
- if (cycbuff->bitfield != NULL) {
- munmap(cycbuff->bitfield, cycbuff->minartoffset);
- cycbuff->bitfield = NULL;
- }
- if (cycbuff->fd >= 0)
- close(cycbuff->fd);
- cycbuff->fd = -1;
-}
-
-static void CNFScleancycbuff(void) {
- CYCBUFF *cycbuff, *nextcycbuff;
-
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL;) {
- CNFSshutdowncycbuff(cycbuff);
- nextcycbuff = cycbuff->next;
- free(cycbuff);
- cycbuff = nextcycbuff;
- }
- cycbufftab = (CYCBUFF *)NULL;
-}
-
-static void CNFScleanmetacycbuff(void) {
- METACYCBUFF *metacycbuff, *nextmetacycbuff;
-
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL;) {
- nextmetacycbuff = metacycbuff->next;
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- metacycbuff = nextmetacycbuff;
- }
- metacycbufftab = (METACYCBUFF *)NULL;
-}
-
-static void CNFScleanexpirerule(void) {
- CNFSEXPIRERULES *metaexprule, *nextmetaexprule;
-
- for (metaexprule = metaexprulestab; metaexprule != (CNFSEXPIRERULES *)NULL;) {
- nextmetaexprule = metaexprule->next;
- free(metaexprule);
- metaexprule = nextmetaexprule;
- }
- metaexprulestab = (CNFSEXPIRERULES *)NULL;
-}
-
-static CYCBUFF *CNFSgetcycbuffbyname(char *name) {
- CYCBUFF *cycbuff;
-
- if (name == NULL)
- return NULL;
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next)
- if (strcmp(name, cycbuff->name) == 0)
- return cycbuff;
- return NULL;
-}
-
-static METACYCBUFF *CNFSgetmetacycbuffbyname(char *name) {
- METACYCBUFF *metacycbuff;
-
- if (name == NULL)
- return NULL;
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL; metacycbuff = metacycbuff->next)
- if (strcmp(name, metacycbuff->name) == 0)
- return metacycbuff;
- return NULL;
-}
-
-static void CNFSflushallheads(void) {
- CYCBUFF *cycbuff;
-
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- if (cycbuff->needflush)
- syslog(L_NOTICE, "%s: CNFSflushallheads: flushing %s", LocalLogName, cycbuff->name);
- CNFSflushhead(cycbuff);
- }
-}
-
-/*
-** CNFSReadFreeAndCycle() -- Read from disk the current values of CYCBUFF's
-** free pointer and cycle number. Return 1 on success, 0 otherwise.
-*/
-
-static void CNFSReadFreeAndCycle(CYCBUFF *cycbuff) {
- CYCBUFFEXTERN rpx;
- char buf[64];
-
- memcpy(&rpx, cycbuff->bitfield, sizeof(CYCBUFFEXTERN));
- /* Sanity checks are not needed since CNFSinit_disks() has already done. */
- strncpy(buf, rpx.freea, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->free = CNFShex2offt(buf);
- strncpy(buf, rpx.updateda, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->updated = CNFShex2offt(buf);
- strncpy(buf, rpx.cyclenuma, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->cyclenum = CNFShex2offt(buf);
- return;
-}
-
-static bool CNFSparse_part_line(char *l) {
- char *p;
- struct stat sb;
- off_t len, minartoffset;
- int tonextblock;
- CYCBUFF *cycbuff, *tmp;
-
- /* Symbolic cnfs partition name */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > CNFSMAXCYCBUFFNAME - 1) {
- syslog(L_ERROR, "%s: bad cycbuff name in line '%s'", LocalLogName, l);
- return false;
- }
- *p = '\0';
- if (CNFSgetcycbuffbyname(l) != NULL) {
- *p = ':';
- syslog(L_ERROR, "%s: duplicate cycbuff name in line '%s'", LocalLogName, l);
- return false;
- }
- cycbuff = xmalloc(sizeof(CYCBUFF));
- memset(cycbuff->name, '\0', CNFSNASIZ);
- strlcpy(cycbuff->name, l, CNFSNASIZ);
- l = ++p;
-
- /* Path to cnfs partition */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0 || p - l > CNFSPASIZ - 1) {
- syslog(L_ERROR, "%s: bad pathname in line '%s'", LocalLogName, l);
- free(cycbuff);
- return false;
- }
- *p = '\0';
- memset(cycbuff->path, '\0', CNFSPASIZ);
- strlcpy(cycbuff->path, l, CNFSPASIZ);
- if (stat(cycbuff->path, &sb) < 0) {
- if (errno == EOVERFLOW) {
- syslog(L_ERROR, "%s: file '%s' : %s, ignoring '%s' cycbuff",
- LocalLogName, cycbuff->path,
- "Overflow (probably >2GB without largefile support)",
- cycbuff->name);
- } else {
- syslog(L_ERROR, "%s: file '%s' : %m, ignoring '%s' cycbuff",
- LocalLogName, cycbuff->path, cycbuff->name);
- }
- free(cycbuff);
- return false;
- }
- l = ++p;
-
- /* Length/size of symbolic partition */
- len = strtoul(l, NULL, 10) * (off_t)1024; /* This value in KB in decimal */
- if (S_ISREG(sb.st_mode) && len != sb.st_size) {
- if (sizeof(CYCBUFFEXTERN) > (size_t) sb.st_size) {
- syslog(L_NOTICE, "%s: length must be at least '%lu' for '%s' cycbuff(%lu bytes)",
- LocalLogName, (unsigned long) sizeof(CYCBUFFEXTERN), cycbuff->name,
- (unsigned long) sb.st_size);
- free(cycbuff);
- return false;
- }
- }
- cycbuff->len = len;
- cycbuff->fd = -1;
- cycbuff->next = (CYCBUFF *)NULL;
- cycbuff->needflush = false;
- cycbuff->bitfield = NULL;
- /*
- ** The minimum article offset will be the size of the bitfield itself,
- ** len / (blocksize * 8), plus however many additional blocks the CYCBUFF
- ** external header occupies ... then round up to the next block.
- */
- minartoffset =
- cycbuff->len / (CNFS_BLOCKSIZE * 8) + CNFS_BEFOREBITF;
- tonextblock = CNFS_HDR_PAGESIZE - (minartoffset & (CNFS_HDR_PAGESIZE - 1));
- cycbuff->minartoffset = minartoffset + tonextblock;
-
- if (cycbufftab == (CYCBUFF *)NULL)
- cycbufftab = cycbuff;
- else {
- for (tmp = cycbufftab; tmp->next != (CYCBUFF *)NULL; tmp = tmp->next);
- tmp->next = cycbuff;
- }
- /* Done! */
- return true;
-}
-
-static bool CNFSparse_metapart_line(char *l) {
- char *p, *cycbuff, *q = l;
- CYCBUFF *rp;
- METACYCBUFF *metacycbuff, *tmp;
-
- /* Symbolic metacycbuff name */
- if ((p = strchr(l, ':')) == NULL || p - l <= 0) {
- syslog(L_ERROR, "%s: bad partition name in line '%s'", LocalLogName, l);
- return false;
- }
- *p = '\0';
- if (CNFSgetmetacycbuffbyname(l) != NULL) {
- *p = ':';
- syslog(L_ERROR, "%s: duplicate metabuff name in line '%s'", LocalLogName, l);
- return false;
- }
- metacycbuff = xmalloc(sizeof(METACYCBUFF));
- metacycbuff->members = (CYCBUFF **)NULL;
- metacycbuff->count = 0;
- metacycbuff->name = xstrdup(l);
- metacycbuff->next = (METACYCBUFF *)NULL;
- metacycbuff->metamode = INTERLEAVE;
- l = ++p;
-
- if ((p = strchr(l, ':')) != NULL) {
- if (p - l <= 0) {
- syslog(L_ERROR, "%s: bad mode in line '%s'", LocalLogName, q);
- return false;
- }
- if (strcmp(++p, "INTERLEAVE") == 0)
- metacycbuff->metamode = INTERLEAVE;
- else if (strcmp(p, "SEQUENTIAL") == 0)
- metacycbuff->metamode = SEQUENTIAL;
- else {
- syslog(L_ERROR, "%s: unknown mode in line '%s'", LocalLogName, q);
- return false;
- }
- *--p = '\0';
- }
- /* Cycbuff list */
- while ((p = strchr(l, ',')) != NULL && p - l > 0) {
- *p = '\0';
- cycbuff = l;
- l = ++p;
- if ((rp = CNFSgetcycbuffbyname(cycbuff)) == NULL) {
- syslog(L_ERROR, "%s: bogus cycbuff '%s' (metacycbuff '%s')",
- LocalLogName, cycbuff, metacycbuff->name);
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- }
- if (metacycbuff->count == 0)
- metacycbuff->members = xmalloc(sizeof(CYCBUFF *));
- else
- metacycbuff->members = xrealloc(metacycbuff->members, (metacycbuff->count + 1) * sizeof(CYCBUFF *));
- metacycbuff->members[metacycbuff->count++] = rp;
- }
- /* Gotta deal with the last cycbuff on the list */
- cycbuff = l;
- if ((rp = CNFSgetcycbuffbyname(cycbuff)) == NULL) {
- syslog(L_ERROR, "%s: bogus cycbuff '%s' (metacycbuff '%s')",
- LocalLogName, cycbuff, metacycbuff->name);
- free(metacycbuff->members);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- } else {
- if (metacycbuff->count == 0)
- metacycbuff->members = xmalloc(sizeof(CYCBUFF *));
- else
- metacycbuff->members = xrealloc(metacycbuff->members, (metacycbuff->count + 1) * sizeof(CYCBUFF *));
- metacycbuff->members[metacycbuff->count++] = rp;
- }
-
- if (metacycbuff->count == 0) {
- syslog(L_ERROR, "%s: no cycbuffs assigned to cycbuff '%s'",
- LocalLogName, metacycbuff->name);
- free(metacycbuff->name);
- free(metacycbuff);
- return false;
- }
- if (metacycbufftab == (METACYCBUFF *)NULL)
- metacycbufftab = metacycbuff;
- else {
- for (tmp = metacycbufftab; tmp->next != (METACYCBUFF *)NULL; tmp = tmp->next);
- tmp->next = metacycbuff;
- }
- /* DONE! */
- return true;
-}
-
-static bool CNFSparse_groups_line(void) {
- METACYCBUFF *mrp;
- STORAGE_SUB *sub = (STORAGE_SUB *)NULL;
- CNFSEXPIRERULES *metaexprule, *tmp;
-
- sub = SMGetConfig(TOKEN_CNFS, sub);
- for (;sub != (STORAGE_SUB *)NULL; sub = SMGetConfig(TOKEN_CNFS, sub)) {
- if (sub->options == (char *)NULL) {
- syslog(L_ERROR, "%s: storage.conf options field is missing",
- LocalLogName);
- CNFScleanexpirerule();
- return false;
- }
- if ((mrp = CNFSgetmetacycbuffbyname(sub->options)) == NULL) {
- syslog(L_ERROR, "%s: storage.conf options field '%s' undefined",
- LocalLogName, sub->options);
- CNFScleanexpirerule();
- return false;
- }
- metaexprule = xmalloc(sizeof(CNFSEXPIRERULES));
- metaexprule->class = sub->class;
- metaexprule->dest = mrp;
- metaexprule->next = (CNFSEXPIRERULES *)NULL;
- if (metaexprulestab == (CNFSEXPIRERULES *)NULL)
- metaexprulestab = metaexprule;
- else {
- for (tmp = metaexprulestab; tmp->next != (CNFSEXPIRERULES *)NULL; tmp = tmp->next);
- tmp->next = metaexprule;
- }
- }
- /* DONE! */
- return true;
-}
-
-/*
-** CNFSinit_disks -- Finish initializing cycbufftab
-** Called by "innd" only -- we open (and keep) a read/write
-** file descriptor for each CYCBUFF.
-**
-** Calling this function repeatedly shouldn't cause any harm
-** speed-wise or bug-wise, as long as the caller is accessing the
-** CYCBUFFs _read-only_. If innd calls this function repeatedly,
-** bad things will happen.
-*/
-
-static bool CNFSinit_disks(CYCBUFF *cycbuff) {
- char buf[64];
- CYCBUFFEXTERN *rpx;
- int fd;
- off_t tmpo;
- bool oneshot;
-
- /*
- ** Discover the state of our cycbuffs. If any of them are in icky shape,
- ** duck shamelessly & return false.
- */
-
- if (cycbuff != (CYCBUFF *)NULL)
- oneshot = true;
- else {
- oneshot = false;
- cycbuff = cycbufftab;
- }
- for (; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- if (strcmp(cycbuff->path, "/dev/null") == 0) {
- syslog(L_ERROR, "%s: ERROR opening '%s' is not available",
- LocalLogName, cycbuff->path);
- return false;
- }
- if (cycbuff->fd < 0) {
- if ((fd = open(cycbuff->path, SMopenmode ? O_RDWR : O_RDONLY)) < 0) {
- syslog(L_ERROR, "%s: ERROR opening '%s' O_RDONLY : %m",
- LocalLogName, cycbuff->path);
- return false;
- } else {
- close_on_exec(fd, true);
- cycbuff->fd = fd;
- }
- }
- errno = 0;
- cycbuff->bitfield = mmap(NULL, cycbuff->minartoffset,
- SMopenmode ? (PROT_READ | PROT_WRITE) : PROT_READ,
- MAP_SHARED, cycbuff->fd, 0);
- if (cycbuff->bitfield == MAP_FAILED || errno != 0) {
- syslog(L_ERROR,
- "%s: CNFSinitdisks: mmap for %s offset %d len %ld failed: %m",
- LocalLogName, cycbuff->path, 0, (long) cycbuff->minartoffset);
- cycbuff->bitfield = NULL;
- return false;
- }
-
- /*
- ** Much of this checking from previous revisions is (probably) bogus
- ** & buggy & particularly icky & unupdated. Use at your own risk. :-)
- */
- rpx = (CYCBUFFEXTERN *)cycbuff->bitfield;
- if (strncmp(rpx->magic, CNFS_MAGICV3, strlen(CNFS_MAGICV3)) == 0) {
- cycbuff->magicver = 3;
- if (strncmp(rpx->name, cycbuff->name, CNFSNASIZ) != 0) {
- syslog(L_ERROR, "%s: Mismatch 3: read %s for cycbuff %s", LocalLogName,
- rpx->name, cycbuff->name);
- return false;
- }
- if (strncmp(rpx->path, cycbuff->path, CNFSPASIZ) != 0) {
- syslog(L_ERROR, "%s: Path mismatch: read %s for cycbuff %s",
- LocalLogName, rpx->path, cycbuff->path);
- }
- strncpy(buf, rpx->lena, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- tmpo = CNFShex2offt(buf);
- if (tmpo != cycbuff->len) {
- syslog(L_ERROR, "%s: Mismatch: read 0x%s length for cycbuff %s",
- LocalLogName, CNFSofft2hex(tmpo, false), cycbuff->path);
- return false;
- }
- strncpy(buf, rpx->freea, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->free = CNFShex2offt(buf);
- strncpy(buf, rpx->updateda, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->updated = CNFShex2offt(buf);
- strncpy(buf, rpx->cyclenuma, CNFSLASIZ);
- buf[CNFSLASIZ] = '\0';
- cycbuff->cyclenum = CNFShex2offt(buf);
- strncpy(cycbuff->metaname, rpx->metaname, CNFSLASIZ);
- strncpy(buf, rpx->orderinmeta, CNFSLASIZ);
- cycbuff->order = CNFShex2offt(buf);
- if (strncmp(rpx->currentbuff, "TRUE", CNFSMASIZ) == 0) {
- cycbuff->currentbuff = true;
- } else
- cycbuff->currentbuff = false;
- } else {
- syslog(L_NOTICE,
- "%s: No magic cookie found for cycbuff %s, initializing",
- LocalLogName, cycbuff->name);
- cycbuff->magicver = 3;
- cycbuff->free = cycbuff->minartoffset;
- cycbuff->updated = 0;
- cycbuff->cyclenum = 1;
- cycbuff->currentbuff = true;
- cycbuff->order = 0; /* to indicate this is newly added cycbuff */
- cycbuff->needflush = true;
- memset(cycbuff->metaname, '\0', CNFSLASIZ);
- if (!CNFSflushhead(cycbuff))
- return false;
- }
- if (oneshot)
- break;
- }
- return true;
-}
-
-static bool CNFS_setcurrent(METACYCBUFF *metacycbuff) {
- CYCBUFF *cycbuff;
- int i, currentcycbuff = 0, order = -1;
- bool foundcurrent = false;
- for (i = 0 ; i < metacycbuff->count ; i++) {
- cycbuff = metacycbuff->members[i];
- if (strncmp(cycbuff->metaname, metacycbuff->name, CNFSNASIZ) != 0) {
- /* this cycbuff is moved from other metacycbuff , or is new */
- cycbuff->order = i + 1;
- cycbuff->currentbuff = false;
- strncpy(cycbuff->metaname, metacycbuff->name, CNFSLASIZ);
- cycbuff->needflush = true;
- continue;
- }
- if (foundcurrent == false && cycbuff->currentbuff == true) {
- currentcycbuff = i;
- foundcurrent = true;
- }
- if (foundcurrent == false || order == -1 || order > cycbuff->order) {
- /* this cycbuff is a candidate for current cycbuff */
- currentcycbuff = i;
- order = cycbuff->order;
- }
- if (cycbuff->order != i + 1) {
- /* cycbuff order seems to be changed */
- cycbuff->order = i + 1;
- cycbuff->needflush = true;
- }
- }
- /* If no current cycbuff found (say, all our cycbuffs are new) default to 0 */
- if (foundcurrent == false) {
- currentcycbuff = 0;
- }
- for (i = 0 ; i < metacycbuff->count ; i++) {
- cycbuff = metacycbuff->members[i];
- if (currentcycbuff == i && cycbuff->currentbuff == false) {
- cycbuff->currentbuff = true;
- cycbuff->needflush = true;
- }
- if (currentcycbuff != i && cycbuff->currentbuff == true) {
- cycbuff->currentbuff = false;
- cycbuff->needflush = true;
- }
- if (cycbuff->needflush == true && !CNFSflushhead(cycbuff))
- return false;
- }
- metacycbuff->memb_next = currentcycbuff;
- return true;
-}
-
-/*
-** CNFSread_config() -- Read the cnfs partition/file configuration file.
-**
-** Oh, for the want of Perl! My parser probably shows that I don't use
-** C all that often anymore....
-*/
-
-static bool CNFSread_config(void) {
- char *path, *config, *from, *to, **ctab = (char **)NULL;
- int ctab_free = 0; /* Index to next free slot in ctab */
- int ctab_i;
- bool metacycbufffound = false;
- bool cycbuffupdatefound = false;
- bool refreshintervalfound = false;
- int update, refresh;
-
- path = concatpath(innconf->pathetc, _PATH_CYCBUFFCONFIG);
- config = ReadInFile(path, NULL);
- if (config == NULL) {
- syslog(L_ERROR, "%s: cannot read %s", LocalLogName, path);
- free(config);
- free(path);
- return false;
- }
- free(path);
- for (from = to = config; *from; ) {
- if (*from == '#') { /* Comment line? */
- while (*from && *from != '\n')
- from++; /* Skip past it */
- from++;
- continue; /* Back to top of loop */
- }
- if (*from == '\n') { /* End or just a blank line? */
- from++;
- continue; /* Back to top of loop */
- }
- if (ctab_free == 0)
- ctab = xmalloc(sizeof(char *));
- else
- ctab = xrealloc(ctab, (ctab_free + 1) * sizeof(char *));
- /* If we're here, we've got the beginning of a real entry */
- ctab[ctab_free++] = to = from;
- while (1) {
- if (*from && *from == '\\' && *(from + 1) == '\n') {
- from += 2; /* Skip past backslash+newline */
- while (*from && isspace((int)*from))
- from++;
- continue;
- }
- if (*from && *from != '\n')
- *to++ = *from++;
- if (*from == '\n') {
- *to++ = '\0';
- from++;
- break;
- }
- if (! *from)
- break;
- }
- }
-
- for (ctab_i = 0; ctab_i < ctab_free; ctab_i++) {
- if (strncmp(ctab[ctab_i], "cycbuff:", 8) == 0) {
- if (metacycbufffound) {
- syslog(L_ERROR, "%s: all cycbuff entries shoud be before metacycbuff entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (!CNFSparse_part_line(ctab[ctab_i] + 8)) {
- free(config);
- free(ctab);
- return false;
- }
- } else if (strncmp(ctab[ctab_i], "metacycbuff:", 12) == 0) {
- metacycbufffound = true;
- if (!CNFSparse_metapart_line(ctab[ctab_i] + 12)) {
- free(config);
- free(ctab);
- return false;
- }
- } else if (strncmp(ctab[ctab_i], "cycbuffupdate:", 14) == 0) {
- if (cycbuffupdatefound) {
- syslog(L_ERROR, "%s: duplicate cycbuffupdate entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- cycbuffupdatefound = true;
- update = atoi(ctab[ctab_i] + 14);
- if (update < 0) {
- syslog(L_ERROR, "%s: invalid cycbuffupdate", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (update == 0)
- metabuff_update = METACYCBUFF_UPDATE;
- else
- metabuff_update = update;
- } else if (strncmp(ctab[ctab_i], "refreshinterval:", 16) == 0) {
- if (refreshintervalfound) {
- syslog(L_ERROR, "%s: duplicate refreshinterval entries", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- refreshintervalfound = true;
- refresh = atoi(ctab[ctab_i] + 16);
- if (refresh < 0) {
- syslog(L_ERROR, "%s: invalid refreshinterval", LocalLogName);
- free(config);
- free(ctab);
- return false;
- }
- if (refresh == 0)
- refresh_interval = REFRESH_INTERVAL;
- else
- refresh_interval = refresh;
- } else {
- syslog(L_ERROR, "%s: Bogus metacycbuff config line '%s' ignored",
- LocalLogName, ctab[ctab_i]);
- }
- }
- free(config);
- free(ctab);
- if (!CNFSparse_groups_line()) {
- return false;
- }
- if (cycbufftab == (CYCBUFF *)NULL) {
- syslog(L_ERROR, "%s: zero cycbuffs defined", LocalLogName);
- return false;
- }
- if (metacycbufftab == (METACYCBUFF *)NULL) {
- syslog(L_ERROR, "%s: zero metacycbuffs defined", LocalLogName);
- return false;
- }
- return true;
-}
-
-/* Figure out what page an address is in and flush those pages */
-static void
-cnfs_mapcntl(void *p, size_t length, int flags)
-{
- char *start, *end;
-
- start = (char *)((size_t)p & ~(size_t)(pagesize - 1));
- end = (char *)((size_t)((char *)p + length + pagesize) &
- ~(size_t)(pagesize - 1));
- if (flags == MS_INVALIDATE) {
- msync(start, end - start, flags);
- } else {
- static char *sstart, *send;
-
- /* Don't thrash the system with msync()s - keep the last value
- * and check each time, only if the pages which we should
- * flush change actually flush the previous ones. Calling
- * cnfs_mapcntl(NULL, 0, MS_ASYNC) then flushes the final
- * piece */
- if (start != sstart || end != send) {
- if (sstart != NULL && send != NULL) {
- msync(sstart, send - sstart, flags);
- }
- sstart = start;
- send = send;
- }
- }
-}
-
-/*
-** Bit arithmetic by brute force.
-**
-** XXXYYYXXX WARNING: the code below is not endian-neutral!
-*/
-
-typedef unsigned long ULONG;
-
-static int CNFSUsedBlock(CYCBUFF *cycbuff, off_t offset,
- bool set_operation, bool setbitvalue) {
- off_t blocknum;
- off_t longoffset;
- int bitoffset; /* From the 'left' side of the long */
- static int uninitialized = 1;
- static int longsize = sizeof(long);
- int i;
- ULONG bitlong, on, off, mask;
- static ULONG onarray[64], offarray[64];
- ULONG *where;
-
- if (uninitialized) {
- on = 1;
- off = on;
- off ^= ULONG_MAX;
- for (i = (longsize * 8) - 1; i >= 0; i--) {
- onarray[i] = on;
- offarray[i] = off;
- on <<= 1;
- off = on;
- off ^= ULONG_MAX;
- }
- uninitialized = 0;
- }
-
- /* We allow bit-setting under minartoffset, but it better be false */
- if ((offset < cycbuff->minartoffset && setbitvalue) ||
- offset > cycbuff->len) {
- char bufoff[64], bufmin[64], bufmax[64];
- SMseterror(SMERR_INTERNAL, NULL);
- strlcpy(bufoff, CNFSofft2hex(offset, false), sizeof(bufoff));
- strlcpy(bufmin, CNFSofft2hex(cycbuff->minartoffset, false),
- sizeof(bufmin));
- strlcpy(bufmax, CNFSofft2hex(cycbuff->len, false), sizeof(bufmax));
- syslog(L_ERROR,
- "%s: CNFSUsedBlock: invalid offset %s, min = %s, max = %s",
- LocalLogName, bufoff, bufmin, bufmax);
- return 0;
- }
- if (offset % CNFS_BLOCKSIZE != 0) {
- SMseterror(SMERR_INTERNAL, NULL);
- syslog(L_ERROR,
- "%s: CNFSsetusedbitbyrp: offset %s not on %d-byte block boundary",
- LocalLogName, CNFSofft2hex(offset, false), CNFS_BLOCKSIZE);
- return 0;
- }
- blocknum = offset / CNFS_BLOCKSIZE;
- longoffset = blocknum / (longsize * 8);
- bitoffset = blocknum % (longsize * 8);
- where = (ULONG *)cycbuff->bitfield + (CNFS_BEFOREBITF / longsize)
- + longoffset;
- bitlong = *where;
- if (set_operation) {
- if (setbitvalue) {
- mask = onarray[bitoffset];
- bitlong |= mask;
- } else {
- mask = offarray[bitoffset];
- bitlong &= mask;
- }
- *where = bitlong;
- if (innconf->nfswriter) {
- cnfs_mapcntl(where, sizeof *where, MS_ASYNC);
- }
- return 2; /* XXX Clean up return semantics */
- }
- /* It's a read operation */
- mask = onarray[bitoffset];
-
-/*
- * return bitlong & mask; doesn't work if sizeof(ulong) > sizeof(int)
- */
- if ( bitlong & mask ) return 1; else return 0;
-
-}
-
-static int CNFSArtMayBeHere(CYCBUFF *cycbuff, off_t offset, uint32_t cycnum) {
- static time_t lastupdate = 0;
- CYCBUFF *tmp;
-
- if (SMpreopen && !SMopenmode) {
- if ((time(NULL) - lastupdate) > refresh_interval) { /* XXX Changed to refresh every 30sec - cmo*/
- for (tmp = cycbufftab; tmp != (CYCBUFF *)NULL; tmp = tmp->next) {
- CNFSReadFreeAndCycle(tmp);
- }
- lastupdate = time(NULL);
- } else if (cycnum == cycbuff->cyclenum + 1) { /* rollover ? */
- CNFSReadFreeAndCycle(cycbuff);
- }
- }
- /*
- ** The current cycle number may have advanced since the last time we
- ** checked it, so use a ">=" check instead of "==". Our intent is
- ** avoid a false negative response, *not* a false positive response.
- */
- if (! (cycnum == cycbuff->cyclenum ||
- (cycnum == cycbuff->cyclenum - 1 && offset > cycbuff->free) ||
- (cycnum + 1 == 0 && cycbuff->cyclenum == 2 && offset > cycbuff->free))) {
- /* We've been overwritten */
- return 0;
- }
- return CNFSUsedBlock(cycbuff, offset, false, false);
-}
-
-bool cnfs_init(SMATTRIBUTE *attr) {
- METACYCBUFF *metacycbuff;
- CYCBUFF *cycbuff;
-
- if (attr == NULL) {
- syslog(L_ERROR, "%s: attr is NULL", LocalLogName);
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- attr->selfexpire = true;
- attr->expensivestat = false;
- if (innconf == NULL) {
- if (!innconf_read(NULL)) {
- syslog(L_ERROR, "%s: innconf_read failed", LocalLogName);
- SMseterror(SMERR_INTERNAL, "ReadInnConf() failed");
- return false;
- }
- }
- if (pagesize == 0) {
- pagesize = getpagesize();
- if (pagesize == -1) {
- syslog(L_ERROR, "%s: getpagesize failed: %m", LocalLogName);
- SMseterror(SMERR_INTERNAL, "getpagesize failed");
- pagesize = 0;
- return false;
- }
- if ((pagesize > CNFS_HDR_PAGESIZE) || (CNFS_HDR_PAGESIZE % pagesize)) {
- syslog(L_ERROR, "%s: CNFS_HDR_PAGESIZE (%d) is not a multiple of pagesize (%ld)", LocalLogName, CNFS_HDR_PAGESIZE, pagesize);
- SMseterror(SMERR_INTERNAL, "CNFS_HDR_PAGESIZE not multiple of pagesize");
- return false;
- }
- }
- if (STORAGE_TOKEN_LENGTH < 16) {
- syslog(L_ERROR, "%s: token length is less than 16 bytes", LocalLogName);
- SMseterror(SMERR_TOKENSHORT, NULL);
- return false;
- }
-
- if (!CNFSread_config()) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- if (!CNFSinit_disks(NULL)) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- for (metacycbuff = metacycbufftab; metacycbuff != (METACYCBUFF *)NULL; metacycbuff = metacycbuff->next) {
- metacycbuff->memb_next = 0;
- metacycbuff->write_count = 0; /* Let's not forget this */
- if (metacycbuff->metamode == SEQUENTIAL)
- /* mark current cycbuff */
- if (CNFS_setcurrent(metacycbuff) == false) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- }
- if (!SMpreopen) {
- for (cycbuff = cycbufftab; cycbuff != (CYCBUFF *)NULL; cycbuff = cycbuff->next) {
- CNFSshutdowncycbuff(cycbuff);
- }
- }
- return true;
-}
-
-TOKEN cnfs_store(const ARTHANDLE article, const STORAGECLASS class) {
- TOKEN token;
- CYCBUFF *cycbuff = NULL;
- METACYCBUFF *metacycbuff = NULL;
- int i;
- static char buf[1024];
- static char alignbuf[CNFS_BLOCKSIZE];
- char *artcycbuffname;
- off_t artoffset, middle;
- uint32_t artcyclenum;
- CNFSARTHEADER cah;
- static struct iovec *iov;
- static int iovcnt;
- int tonextblock;
- CNFSEXPIRERULES *metaexprule;
- off_t left;
- size_t totlen;
-
- for (metaexprule = metaexprulestab; metaexprule != (CNFSEXPIRERULES *)NULL; metaexprule = metaexprule->next) {
- if (metaexprule->class == class)
- break;
- }
- if (metaexprule == (CNFSEXPIRERULES *)NULL) {
- SMseterror(SMERR_INTERNAL, "no rules match");
- syslog(L_ERROR, "%s: no matches for group '%s'",
- LocalLogName, buf);
- token.type = TOKEN_EMPTY;
- return token;
- }
- metacycbuff = metaexprule->dest;
-
- cycbuff = metacycbuff->members[metacycbuff->memb_next];
- if (cycbuff == NULL) {
- SMseterror(SMERR_INTERNAL, "no cycbuff found");
- syslog(L_ERROR, "%s: no cycbuff found for %d", LocalLogName, metacycbuff->memb_next);
- token.type = TOKEN_EMPTY;
- return token;
- } else if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- token.type = TOKEN_EMPTY;
- return token;
- }
-
- /* cycbuff->free should have already been aligned by the last write, but
- realign it just to be sure. */
- tonextblock = CNFS_BLOCKSIZE - (cycbuff->free & (CNFS_BLOCKSIZE - 1));
- if (tonextblock != CNFS_BLOCKSIZE)
- cycbuff->free += tonextblock;
-
- /* Article too big? */
- if (cycbuff->len - cycbuff->free < CNFS_BLOCKSIZE + 1)
- left = 0;
- else
- left = cycbuff->len - cycbuff->free - CNFS_BLOCKSIZE - 1;
- if (article.len > left) {
- for (middle = cycbuff->free ;middle < cycbuff->len - CNFS_BLOCKSIZE - 1;
- middle += CNFS_BLOCKSIZE) {
- CNFSUsedBlock(cycbuff, middle, true, false);
- }
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- cycbuff->free = cycbuff->minartoffset;
- cycbuff->cyclenum++;
- if (cycbuff->cyclenum == 0)
- cycbuff->cyclenum += 2; /* cnfs_next() needs this */
- cycbuff->needflush = true;
- if (metacycbuff->metamode == INTERLEAVE) {
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- syslog(L_NOTICE, "%s: cycbuff %s rollover to cycle 0x%x... remain calm",
- LocalLogName, cycbuff->name, cycbuff->cyclenum);
- } else {
- /* SEQUENTIAL */
- cycbuff->currentbuff = false;
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- metacycbuff->memb_next = (metacycbuff->memb_next + 1) % metacycbuff->count;
- cycbuff = metacycbuff->members[metacycbuff->memb_next];
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- token.type = TOKEN_EMPTY;
- return token;
- }
- syslog(L_NOTICE, "%s: metacycbuff %s cycbuff is moved to %s remain calm",
- LocalLogName, metacycbuff->name, cycbuff->name);
- cycbuff->currentbuff = true;
- cycbuff->needflush = true;
- CNFSflushhead(cycbuff); /* Flush, just for giggles */
- }
- }
-
- /* Ah, at least we know all three important data */
- artcycbuffname = cycbuff->name;
- artoffset = cycbuff->free;
- artcyclenum = cycbuff->cyclenum;
-
- memset(&cah, 0, sizeof(cah));
- cah.size = htonl(article.len);
- if (article.arrived == (time_t)0)
- cah.arrived = htonl(time(NULL));
- else
- cah.arrived = htonl(article.arrived);
- cah.class = class;
-
- if (lseek(cycbuff->fd, artoffset, SEEK_SET) < 0) {
- SMseterror(SMERR_INTERNAL, "lseek failed");
- syslog(L_ERROR, "%s: lseek failed for '%s' offset 0x%s: %m",
- LocalLogName, cycbuff->name, CNFSofft2hex(artoffset, false));
- token.type = TOKEN_EMPTY;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return token;
- }
- if (iovcnt == 0) {
- iov = xmalloc((article.iovcnt + 2) * sizeof(struct iovec));
- iovcnt = article.iovcnt + 2;
- } else if (iovcnt < article.iovcnt + 2) {
- iov = xrealloc(iov, (article.iovcnt + 2) * sizeof(struct iovec));
- iovcnt = article.iovcnt + 2;
- }
- iov[0].iov_base = (char *) &cah;
- iov[0].iov_len = sizeof(cah);
- totlen = iov[0].iov_len;
- for (i = 1; i <= article.iovcnt; i++) {
- iov[i].iov_base = article.iov[i-1].iov_base;
- iov[i].iov_len = article.iov[i-1].iov_len;
- totlen += iov[i].iov_len;
- }
- if ((totlen & (CNFS_BLOCKSIZE - 1)) != 0) {
- /* Want to xwritev an exact multiple of CNFS_BLOCKSIZE */
- iov[i].iov_base = alignbuf;
- iov[i].iov_len = CNFS_BLOCKSIZE - (totlen & (CNFS_BLOCKSIZE - 1));
- totlen += iov[i].iov_len;
- i++;
- }
- if (xwritev(cycbuff->fd, iov, i) < 0) {
- SMseterror(SMERR_INTERNAL, "cnfs_store() xwritev() failed");
- syslog(L_ERROR,
- "%s: cnfs_store xwritev failed for '%s' offset 0x%s: %m",
- LocalLogName, artcycbuffname, CNFSofft2hex(artoffset, false));
- token.type = TOKEN_EMPTY;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return token;
- }
- cycbuff->needflush = true;
-
- /* Now that the article is written, advance the free pointer & flush */
- cycbuff->free += totlen;
-
- /*
- ** If cycbuff->free > cycbuff->len, don't worry. The next cnfs_store()
- ** will detect the situation & wrap around correctly.
- */
- if (metacycbuff->metamode == INTERLEAVE)
- metacycbuff->memb_next = (metacycbuff->memb_next + 1) % metacycbuff->count;
- if (++metacycbuff->write_count % metabuff_update == 0) {
- for (i = 0; i < metacycbuff->count; i++) {
- CNFSflushhead(metacycbuff->members[i]);
- }
- }
- CNFSUsedBlock(cycbuff, artoffset, true, true);
- for (middle = artoffset + CNFS_BLOCKSIZE; middle < cycbuff->free;
- middle += CNFS_BLOCKSIZE) {
- CNFSUsedBlock(cycbuff, middle, true, false);
- }
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return CNFSMakeToken(artcycbuffname, artoffset, artcyclenum, class);
-}
-
-ARTHANDLE *cnfs_retrieve(const TOKEN token, const RETRTYPE amount) {
- char cycbuffname[9];
- off_t offset;
- uint32_t cycnum;
- CYCBUFF *cycbuff;
- ARTHANDLE *art;
- CNFSARTHEADER cah;
- PRIV_CNFS *private;
- char *p;
- long pagefudge;
- off_t mmapoffset;
- static TOKEN ret_token;
- static bool nomessage = false;
- int plusoffset = 0;
-
- if (token.type != TOKEN_CNFS) {
- SMseterror(SMERR_INTERNAL, NULL);
- return NULL;
- }
- if (! CNFSBreakToken(token, cycbuffname, &offset, &cycnum)) {
- /* SMseterror() should have already been called */
- return NULL;
- }
- if ((cycbuff = CNFSgetcycbuffbyname(cycbuffname)) == NULL) {
- SMseterror(SMERR_NOENT, NULL);
- if (!nomessage) {
- syslog(L_ERROR, "%s: cnfs_retrieve: token %s: bogus cycbuff name: %s:0x%s:%d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- nomessage = true;
- }
- return NULL;
- }
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- return NULL;
- }
- if (! CNFSArtMayBeHere(cycbuff, offset, cycnum)) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
-
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_CNFS;
- if (amount == RETR_STAT) {
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- ret_token = token;
- art->token = &ret_token;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- /*
- ** Because we don't know the length of the article (yet), we'll
- ** just mmap() a chunk of memory which is guaranteed to be larger
- ** than the largest article can be.
- ** XXX Because the max article size can be changed, we could get into hot
- ** XXX water here. So, to be safe, we double MAX_ART_SIZE and add enough
- ** XXX extra for the pagesize fudge factor and CNFSARTHEADER structure.
- */
- if (pread(cycbuff->fd, &cah, sizeof(cah), offset) != sizeof(cah)) {
- SMseterror(SMERR_UNDEFINED, "read failed");
- syslog(L_ERROR, "%s: could not read token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
-#ifdef OLD_CNFS
- if(cah.size == htonl(0x1234) && ntohl(cah.arrived) < time(NULL)-10*365*24*3600) {
- oldCNFSARTHEADER cahh;
- *(CNFSARTHEADER *)&cahh = cah;
- if(pread(cycbuff->fd, ((char *)&cahh)+sizeof(CNFSARTHEADER), sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER), offset+sizeof(cah)) != sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER)) {
- SMseterror(SMERR_UNDEFINED, "read2 failed");
- syslog(L_ERROR, "%s: could not read2 token %s %s:0x%s:%ld: %m",
- LocalLogName, TokenToText(token), cycbuffname,
- CNFSofft2hex(offset, false), cycnum);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- cah.size = cahh.size;
- cah.arrived = htonl(time(NULL));
- cah.class = 0;
- plusoffset = sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER);
- }
-#endif /* OLD_CNFS */
- if (offset > cycbuff->len - CNFS_BLOCKSIZE - (off_t) ntohl(cah.size) - 1) {
- if (!SMpreopen) {
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER size overflow");
- syslog(L_ERROR, "%s: could not match article size token %s %s:0x%s:%d: %d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum, ntohl(cah.size));
- free(art);
- CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- CNFSReadFreeAndCycle(cycbuff);
- if (offset > cycbuff->len - CNFS_BLOCKSIZE - (off_t) ntohl(cah.size) - 1) {
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER size overflow");
- syslog(L_ERROR, "%s: could not match article size token %s %s:0x%s:%d: %d",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum, ntohl(cah.size));
- free(art);
- return NULL;
- }
- }
- /* checking the bitmap to ensure cah.size is not broken was dropped */
- if (innconf->cnfscheckfudgesize != 0 && innconf->maxartsize != 0 &&
- (ntohl(cah.size) > (size_t) innconf->maxartsize + innconf->cnfscheckfudgesize)) {
- char buf1[24];
- strlcpy(buf1, CNFSofft2hex(cycbuff->free, false), sizeof(buf1));
- SMseterror(SMERR_UNDEFINED, "CNFSARTHEADER fudge size overflow");
- syslog(L_ERROR, "%s: fudge size overflows bitmaps %s %s:0x%s: %u",
- LocalLogName, TokenToText(token), cycbuffname, buf1, ntohl(cah.size));
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- free(art);
- return NULL;
- }
- private = xmalloc(sizeof(PRIV_CNFS));
- art->private = (void *)private;
- art->arrived = ntohl(cah.arrived);
- offset += sizeof(cah) + plusoffset;
- if (innconf->articlemmap) {
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- private->len = pagefudge + ntohl(cah.size);
- if ((private->base = mmap(NULL, private->len, PROT_READ,
- MAP_SHARED, cycbuff->fd, mmapoffset)) == MAP_FAILED) {
- SMseterror(SMERR_UNDEFINED, "mmap failed");
- syslog(L_ERROR, "%s: could not mmap token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- mmap_invalidate(private->base, private->len);
- if (amount == RETR_ALL)
- madvise(private->base, private->len, MADV_WILLNEED);
- else
- madvise(private->base, private->len, MADV_SEQUENTIAL);
- } else {
- private->base = xmalloc(ntohl(cah.size));
- pagefudge = 0;
- if (pread(cycbuff->fd, private->base, ntohl(cah.size), offset) < 0) {
- SMseterror(SMERR_UNDEFINED, "read failed");
- syslog(L_ERROR, "%s: could not read token %s %s:0x%s:%d: %m",
- LocalLogName, TokenToText(token), cycbuffname, CNFSofft2hex(offset, false), cycnum);
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- }
- ret_token = token;
- art->token = &ret_token;
- art->len = ntohl(cah.size);
- if (amount == RETR_ALL) {
- art->data = innconf->articlemmap ? private->base + pagefudge : private->base;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if ((p = wire_findbody(innconf->articlemmap ? private->base + pagefudge : private->base, art->len)) == NULL) {
- SMseterror(SMERR_NOBODY, NULL);
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
- }
- if (amount == RETR_HEAD) {
- if (innconf->articlemmap) {
- art->data = private->base + pagefudge;
- art->len = p - private->base - pagefudge;
- } else {
- art->data = private->base;
- art->len = p - private->base;
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_BODY) {
- art->data = p;
- if (innconf->articlemmap)
- art->len = art->len - (p - private->base - pagefudge);
- else
- art->len = art->len - (p - private->base);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- SMseterror(SMERR_UNDEFINED, "Invalid retrieve request");
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return NULL;
-}
-
-void cnfs_freearticle(ARTHANDLE *article) {
- PRIV_CNFS *private;
-
- if (!article)
- return;
-
- if (article->private) {
- private = (PRIV_CNFS *)article->private;
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(private);
- }
- free(article);
-}
-
-bool cnfs_cancel(TOKEN token) {
- char cycbuffname[9];
- off_t offset;
- uint32_t cycnum;
- CYCBUFF *cycbuff;
-
- if (token.type != TOKEN_CNFS) {
- SMseterror(SMERR_INTERNAL, NULL);
- return false;
- }
- if (! CNFSBreakToken(token, cycbuffname, &offset, &cycnum)) {
- SMseterror(SMERR_INTERNAL, NULL);
- /* SMseterror() should have already been called */
- return false;
- }
- if ((cycbuff = CNFSgetcycbuffbyname(cycbuffname)) == NULL) {
- SMseterror(SMERR_INTERNAL, "bogus cycbuff name");
- return false;
- }
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- syslog(L_ERROR, "%s: cycbuff '%s' initialization fail", LocalLogName, cycbuff->name);
- return false;
- }
- if (! (cycnum == cycbuff->cyclenum ||
- (cycnum == cycbuff->cyclenum - 1 && offset > cycbuff->free) ||
- (cycnum + 1 == 0 && cycbuff->cyclenum == 2 && offset > cycbuff->free))) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return false;
- }
- if (CNFSUsedBlock(cycbuff, offset, false, false) == 0) {
- SMseterror(SMERR_NOENT, NULL);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return false;
- }
- CNFSUsedBlock(cycbuff, offset, true, false);
- if (innconf->nfswriter) {
- cnfs_mapcntl(NULL, 0, MS_ASYNC);
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return true;
-}
-
-ARTHANDLE *cnfs_next(const ARTHANDLE *article, const RETRTYPE amount) {
- ARTHANDLE *art;
- CYCBUFF *cycbuff;
- PRIV_CNFS priv, *private;
- off_t middle = 0, limit;
- CNFSARTHEADER cah;
- off_t offset;
- long pagefudge, blockfudge;
- static TOKEN token;
- int tonextblock;
- off_t mmapoffset;
- char *p;
- int plusoffset = 0;
-
- if (article == (ARTHANDLE *)NULL) {
- if ((cycbuff = cycbufftab) == (CYCBUFF *)NULL)
- return (ARTHANDLE *)NULL;
- priv.offset = 0;
- priv.rollover = false;
- } else {
- priv = *(PRIV_CNFS *)article->private;
- free(article->private);
- free((void *)article);
- if (innconf->articlemmap)
- munmap(priv.base, priv.len);
- else {
- /* In the case we return art->data = NULL, we
- * must not free an already stale pointer.
- -mibsoft@mibsoftware.com
- */
- if (priv.base) {
- free(priv.base);
- priv.base = 0;
- }
- }
- cycbuff = priv.cycbuff;
- }
-
- for (;cycbuff != (CYCBUFF *)NULL;
- cycbuff = cycbuff->next,
- priv.offset = 0) {
-
- if (!SMpreopen && !CNFSinit_disks(cycbuff)) {
- SMseterror(SMERR_INTERNAL, "cycbuff initialization fail");
- continue;
- }
- if (priv.rollover && priv.offset >= cycbuff->free) {
- priv.offset = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- continue;
- }
- if (priv.offset == 0) {
- if (cycbuff->cyclenum == 1) {
- priv.offset = cycbuff->minartoffset;
- priv.rollover = true;
- } else {
- priv.offset = cycbuff->free;
- priv.rollover = false;
- }
- }
- if (!priv.rollover) {
- for (middle = priv.offset ;middle < cycbuff->len - CNFS_BLOCKSIZE - 1;
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- break;
- }
- if (middle >= cycbuff->len - CNFS_BLOCKSIZE - 1) {
- priv.rollover = true;
- middle = cycbuff->minartoffset;
- }
- break;
- } else {
- for (middle = priv.offset ;middle < cycbuff->free;
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- break;
- }
- if (middle >= cycbuff->free) {
- middle = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- continue;
- } else
- break;
- }
- }
- if (cycbuff == (CYCBUFF *)NULL)
- return (ARTHANDLE *)NULL;
-
- offset = middle;
- if (pread(cycbuff->fd, &cah, sizeof(cah), offset) != sizeof(cah)) {
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return (ARTHANDLE *)NULL;
- }
-#ifdef OLD_CNFS
- if(cah.size == htonl(0x1234) && ntohl(cah.arrived) < time(NULL)-10*365*24*3600) {
- oldCNFSARTHEADER cahh;
- *(CNFSARTHEADER *)&cahh = cah;
- if(pread(cycbuff->fd, ((char *)&cahh)+sizeof(CNFSARTHEADER), sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER), offset+sizeof(cah)) != sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER)) {
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return (ARTHANDLE *)NULL;
- }
- cah.size = cahh.size;
- cah.arrived = htonl(time(NULL));
- cah.class = 0;
- plusoffset = sizeof(oldCNFSARTHEADER)-sizeof(CNFSARTHEADER);
- }
-#endif /* OLD_CNFS */
- art = xmalloc(sizeof(ARTHANDLE));
- private = xmalloc(sizeof(PRIV_CNFS));
- art->private = (void *)private;
- art->type = TOKEN_CNFS;
- *private = priv;
- private->cycbuff = cycbuff;
- private->offset = middle;
- if (cycbuff->len - cycbuff->free < (off_t) ntohl(cah.size) + CNFS_BLOCKSIZE + 1) {
- private->offset += CNFS_BLOCKSIZE;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- /* check the bitmap to ensure cah.size is not broken */
- blockfudge = (sizeof(cah) + plusoffset + ntohl(cah.size)) % CNFS_BLOCKSIZE;
- limit = private->offset + sizeof(cah) + plusoffset + ntohl(cah.size) - blockfudge + CNFS_BLOCKSIZE;
- if (offset < cycbuff->free) {
- for (middle = offset + CNFS_BLOCKSIZE; (middle < cycbuff->free) && (middle < limit);
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- /* Bitmap set. This article assumes to be broken */
- break;
- }
- if ((middle > cycbuff->free) || (middle != limit)) {
- private->offset = middle;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- } else {
- for (middle = offset + CNFS_BLOCKSIZE; (middle < cycbuff->len) && (middle < limit);
- middle += CNFS_BLOCKSIZE) {
- if (CNFSUsedBlock(cycbuff, middle, false, false) != 0)
- /* Bitmap set. This article assumes to be broken */
- break;
- }
- if ((middle >= cycbuff->len) || (middle != limit)) {
- private->offset = middle;
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- }
- if (innconf->cnfscheckfudgesize != 0 && innconf->maxartsize != 0 &&
- ((off_t) ntohl(cah.size) > innconf->maxartsize + innconf->cnfscheckfudgesize)) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- private->base = 0;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
-
- private->offset += (off_t) ntohl(cah.size) + sizeof(cah) + plusoffset;
- tonextblock = CNFS_BLOCKSIZE - (private->offset & (CNFS_BLOCKSIZE - 1));
- private->offset += (off_t) tonextblock;
- art->arrived = ntohl(cah.arrived);
- token = CNFSMakeToken(cycbuff->name, offset, (offset > cycbuff->free) ? cycbuff->cyclenum - 1 : cycbuff->cyclenum, cah.class);
- art->token = &token;
- offset += sizeof(cah) + plusoffset;
- if (innconf->articlemmap) {
- pagefudge = offset % pagesize;
- mmapoffset = offset - pagefudge;
- private->len = pagefudge + ntohl(cah.size);
- if ((private->base = mmap(0, private->len, PROT_READ,
- MAP_SHARED, cycbuff->fd, mmapoffset)) == MAP_FAILED) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- mmap_invalidate(private->base, private->len);
- madvise(private->base, private->len, MADV_SEQUENTIAL);
- } else {
- private->base = xmalloc(ntohl(cah.size));
- pagefudge = 0;
- if (pread(cycbuff->fd, private->base, ntohl(cah.size), offset) < 0) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- free(private->base);
- private->base = 0;
- return art;
- }
- }
- art->len = ntohl(cah.size);
- if (amount == RETR_ALL) {
- art->data = innconf->articlemmap ? private->base + pagefudge : private->base;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if ((p = wire_findbody(innconf->articlemmap ? private->base + pagefudge : private->base, art->len)) == NULL) {
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_HEAD) {
- if (innconf->articlemmap) {
- art->data = private->base + pagefudge;
- art->len = p - private->base - pagefudge;
- } else {
- art->data = private->base;
- art->len = p - private->base;
- }
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- if (amount == RETR_BODY) {
- art->data = p;
- if (innconf->articlemmap)
- art->len = art->len - (p - private->base - pagefudge);
- else
- art->len = art->len - (p - private->base);
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
- }
- art->data = NULL;
- art->len = 0;
- art->token = NULL;
- if (!SMpreopen) CNFSshutdowncycbuff(cycbuff);
- return art;
-}
-
-bool cnfs_ctl(PROBETYPE type, TOKEN *token UNUSED, void *value) {
- struct artngnum *ann;
-
- switch (type) {
- case SMARTNGNUM:
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- /* make SMprobe() call cnfs_retrieve() */
- ann->artnum = 0;
- return true;
- default:
- return false;
- }
-}
-
-bool cnfs_flushcacheddata(FLUSHTYPE type) {
- if (type == SM_ALL || type == SM_HEAD)
- CNFSflushallheads();
- return true;
-}
-
-void
-cnfs_printfiles(FILE *file, TOKEN token, char **xref UNUSED,
- int ngroups UNUSED)
-{
- fprintf(file, "%s\n", TokenToText(token));
-}
-
-void cnfs_shutdown(void) {
- CNFScleancycbuff();
- CNFScleanmetacycbuff();
- CNFScleanexpirerule();
-}
+++ /dev/null
-/* $Id: cnfs.h 4266 2001-01-04 06:01:36Z rra $
-**
-** cyclic news file system header
-*/
-
-#ifndef __CNFS_H__
-#define __CNFS_H__
-
-bool cnfs_init(SMATTRIBUTE *attr);
-TOKEN cnfs_store(const ARTHANDLE article, const STORAGECLASS class);
-ARTHANDLE *cnfs_retrieve(const TOKEN token, const RETRTYPE amount);
-ARTHANDLE *cnfs_next(const ARTHANDLE *article, const RETRTYPE amount);
-void cnfs_freearticle(ARTHANDLE *article);
-bool cnfs_cancel(TOKEN token);
-bool cnfs_ctl(PROBETYPE type, TOKEN *token, void *value);
-bool cnfs_flushcacheddata(FLUSHTYPE type);
-void cnfs_printfiles(FILE *file, TOKEN token, char **xref, int ngroups);
-void cnfs_shutdown(void);
-
-#endif
+++ /dev/null
-name = cnfs
-number = 3
-sources = cnfs.c
+++ /dev/null
-/* $Id: expire.c 6775 2004-05-17 06:23:42Z rra $
-**
-** Code for overview-driven expiration.
-**
-** In order to expire on a per-newsgroup (instead of per-storage-class)
-** basis, one has to use overview-driven expiration. This contains all of
-** the code to do that. It provides OVgroupbasedexpire, OVhisthasmsgid, and
-** OVgroupmatch for the use of various overview methods.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "ov.h"
-#include "ovinterface.h"
-#include "paths.h"
-#include "storage.h"
-
-enum KRP {Keep, Remove, Poison};
-
-/* Statistics */
-static long EXPprocessed;
-static long EXPunlinked;
-static long EXPoverindexdrop;
-
-#define NGH_HASH(Name, p, j) \
- for (p = Name, j = 0; *p; ) j = (j << 5) + j + *p++
-#define NGH_SIZE 2048
-#define NGH_BUCKET(j) &NGHtable[j & (NGH_SIZE - 1)]
-
-#define OVFMT_UNINIT -2
-#define OVFMT_NODATE -1
-#define OVFMT_NOXREF -1
-
-static int Dateindex = OVFMT_UNINIT;
-static int Xrefindex = OVFMT_UNINIT;
-static int Messageidindex = OVFMT_UNINIT;
-
-typedef struct _NEWSGROUP {
- char *Name;
- char *Rest;
- unsigned long Last;
- unsigned long Lastpurged;
- /* These fields are new. */
- time_t Keep;
- time_t Default;
- time_t Purge;
- /* X flag => remove entire article when it expires in this group */
- bool Poison;
-} NEWSGROUP;
-
-typedef struct _NGHASH {
- int Size;
- int Used;
- NEWSGROUP **Groups;
-} NGHASH;
-
-#define MAGIC_TIME 49710.
-
-typedef struct _BADGROUP {
- struct _BADGROUP *Next;
- char *Name;
-} BADGROUP;
-
-/*
-** Information about the schema of the news overview files.
-*/
-typedef struct _ARTOVERFIELD {
- char *Header;
- int Length;
- bool HasHeader;
- bool NeedsHeader;
-} ARTOVERFIELD;
-
-static BADGROUP *EXPbadgroups;
-static int nGroups;
-static NEWSGROUP *Groups;
-static NEWSGROUP EXPdefault;
-static NGHASH NGHtable[NGH_SIZE];
-
-static char **arts;
-static enum KRP *krps;
-
-static ARTOVERFIELD * ARTfields;
-static int ARTfieldsize;
-static bool ReadOverviewfmt = false;
-
-
-/* FIXME: The following variables are shared between this file and ov.c.
- This should be cleaned up with a better internal interface. */
-extern time_t OVnow;
-extern char * ACTIVE;
-extern FILE * EXPunlinkfile;
-extern bool OVignoreselfexpire;
-extern bool OVusepost;
-extern bool OVkeep;
-extern bool OVearliest;
-extern bool OVquiet;
-extern int OVnumpatterns;
-extern char ** OVpatterns;
-
-
-/*
-** Hash a newsgroup and see if we get it.
-*/
-static NEWSGROUP *
-NGfind(char *Name)
-{
- char *p;
- int i;
- unsigned int j;
- NEWSGROUP **ngp;
- char c;
- NGHASH *htp;
-
- NGH_HASH(Name, p, j);
- htp = NGH_BUCKET(j);
- for (c = *Name, ngp = htp->Groups, i = htp->Used; --i >= 0; ngp++)
- if (c == ngp[0]->Name[0] && strcmp(Name, ngp[0]->Name) == 0)
- return ngp[0];
- return NULL;
-}
-
-/*
-** Sorting predicate to put newsgroups in rough order of their activity.
-*/
-static int
-NGcompare(const void *p1, const void *p2)
-{
- const NEWSGROUP * const * ng1 = p1;
- const NEWSGROUP * const * ng2 = p2;
-
- return ng1[0]->Last - ng2[0]->Last;
-}
-
-/*
-** Split a line at a specified field separator into a vector and return
-** the number of fields found, or -1 on error.
-*/
-static int
-EXPsplit(char *p, char sep, char **argv, int count)
-{
- int i;
-
- if (!p)
- return 0;
-
- while (*p == sep)
- ++p;
-
- if (!*p)
- return 0;
-
- if (!p)
- return 0;
-
- while (*p == sep)
- ++p;
-
- if (!*p)
- return 0;
-
- for (i = 1, *argv++ = p; *p; )
- if (*p++ == sep) {
- p[-1] = '\0';
- for (; *p == sep; p++);
- if (!*p)
- return i;
- if (++i == count)
- /* Overflow. */
- return -1;
- *argv++ = p;
- }
- return i;
-}
-
-/*
-** Build the newsgroup structures from the active file.
-*/
-static void
-BuildGroups(char *active)
-{
- NGHASH *htp;
- NEWSGROUP *ngp;
- char *p;
- char *q;
- int i;
- unsigned j;
- int lines;
- int NGHbuckets;
- char *fields[5];
-
- /* Count the number of groups. */
- for (p = active, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)
- continue;
- nGroups = i;
- Groups = xmalloc(i * sizeof(NEWSGROUP));
-
- /* Set up the default hash buckets. */
- NGHbuckets = i / NGH_SIZE;
- if (NGHbuckets == 0)
- NGHbuckets = 1;
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++) {
- htp->Size = NGHbuckets;
- htp->Groups = xmalloc(htp->Size * sizeof(NEWSGROUP *));
- htp->Used = 0;
- }
-
- /* Fill in the array. */
- lines = 0;
- for (p = active, ngp = Groups, i = nGroups; --i >= 0; ngp++, p = q + 1) {
- lines++;
- if ((q = strchr(p, '\n')) == NULL) {
- fprintf(stderr, "%s: line %d missing newline\n", ACTIVE, lines);
- exit(1);
- }
- if (*p == '.')
- continue;
- *q = '\0';
- if (EXPsplit(p, ' ', fields, ARRAY_SIZE(fields)) != 4) {
- fprintf(stderr, "%s: line %d wrong number of fields\n", ACTIVE, lines);
- exit(1);
- }
- ngp->Name = fields[0];
- ngp->Last = atol(fields[1]);
- ngp->Rest = fields[3];
-
- /* Find the right bucket for the group, make sure there is room. */
- NGH_HASH(ngp->Name, p, j);
- htp = NGH_BUCKET(j);
- if (htp->Used >= htp->Size) {
- htp->Size += NGHbuckets;
- htp->Groups = xrealloc(htp->Groups, htp->Size * sizeof(NEWSGROUP *));
- }
- htp->Groups[htp->Used++] = ngp;
- }
-
- /* Sort each hash bucket. */
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++)
- if (htp->Used > 1)
- qsort(htp->Groups, htp->Used, sizeof htp->Groups[0], NGcompare);
-
- /* Ok, now change our use of the Last field. Set them all to maxint. */
- for (i = NGH_SIZE, htp = NGHtable; --i >= 0; htp++) {
- NEWSGROUP **ngpa;
- int k;
-
- for (ngpa = htp->Groups, k = htp->Used; --k >= 0; ngpa++) {
- ngpa[0]->Last = ~(unsigned long) 0;
- ngpa[0]->Lastpurged = 0;
- }
- }
-}
-
-/*
-** Parse a number field converting it into a "when did this start?".
-** This makes the "keep it" tests fast, but inverts the logic of
-** just about everything you expect. Print a message and return false
-** on error.
-*/
-static bool
-EXPgetnum(int line, char *word, time_t *v, const char *name)
-{
- char *p;
- bool SawDot;
- double d;
-
- if (strcasecmp(word, "never") == 0) {
- *v = (time_t)0;
- return true;
- }
-
- /* Check the number. We don't have strtod yet. */
- for (p = word; ISWHITE(*p); p++)
- continue;
- if (*p == '+' || *p == '-')
- p++;
- for (SawDot = false; *p; p++)
- if (*p == '.') {
- if (SawDot)
- break;
- SawDot = true;
- }
- else if (!CTYPE(isdigit, (int)*p))
- break;
- if (*p) {
- fprintf(stderr, "Line %d, bad `%c' character in %s field\n",
- line, *p, name);
- return false;
- }
- d = atof(word);
- if (d > MAGIC_TIME)
- *v = (time_t)0;
- else
- *v = OVnow - (time_t)(d * 86400.);
- return true;
-}
-
-/*
-** Set the expiration fields for all groups that match this pattern.
-*/
-static void
-EXPmatch(char *p, NEWSGROUP *v, char mod)
-{
- NEWSGROUP *ngp;
- int i;
- bool negate;
-
- negate = *p == '!';
- if (negate)
- p++;
- for (ngp = Groups, i = nGroups; --i >= 0; ngp++)
- if (negate ? !uwildmat(ngp->Name, p) : uwildmat(ngp->Name, p))
- if (mod == 'a'
- || (mod == 'm' && ngp->Rest[0] == NF_FLAG_MODERATED)
- || (mod == 'u' && ngp->Rest[0] != NF_FLAG_MODERATED)) {
- ngp->Keep = v->Keep;
- ngp->Default = v->Default;
- ngp->Purge = v->Purge;
- ngp->Poison = v->Poison;
- }
-}
-
-/*
-** Parse the expiration control file. Return true if okay.
-*/
-static bool
-EXPreadfile(FILE *F)
-{
- char *p;
- int i;
- int j;
- int k;
- char mod;
- NEWSGROUP v;
- bool SawDefault;
- char buff[BUFSIZ];
- char *fields[7];
- char **patterns;
-
- /* Scan all lines. */
- SawDefault = false;
- patterns = xmalloc(nGroups * sizeof(char *));
-
- for (i = 1; fgets(buff, sizeof buff, F) != NULL; i++) {
- if ((p = strchr(buff, '\n')) == NULL) {
- fprintf(stderr, "Line %d too long\n", i);
- free(patterns);
- return false;
- }
- *p = '\0';
- p = strchr(buff, '#');
- if (p)
- *p = '\0';
- else
- p = buff + strlen(buff);
- while (--p >= buff) {
- if (isspace((int)*p))
- *p = '\0';
- else
- break;
- }
- if (buff[0] == '\0')
- continue;
- if ((j = EXPsplit(buff, ':', fields, ARRAY_SIZE(fields))) == -1) {
- fprintf(stderr, "Line %d too many fields\n", i);
- free(patterns);
- return false;
- }
-
- /* Expired-article remember line? */
- if (strcmp(fields[0], "/remember/") == 0) {
- continue;
- }
-
- /* Regular expiration line -- right number of fields? */
- if (j != 5) {
- fprintf(stderr, "Line %d bad format\n", i);
- free(patterns);
- return false;
- }
-
- /* Parse the fields. */
- if (strchr(fields[1], 'M') != NULL)
- mod = 'm';
- else if (strchr(fields[1], 'U') != NULL)
- mod = 'u';
- else if (strchr(fields[1], 'A') != NULL)
- mod = 'a';
- else {
- fprintf(stderr, "Line %d bad modflag\n", i);
- free(patterns);
- return false;
- }
- v.Poison = (strchr(fields[1], 'X') != NULL);
- if (!EXPgetnum(i, fields[2], &v.Keep, "keep")
- || !EXPgetnum(i, fields[3], &v.Default, "default")
- || !EXPgetnum(i, fields[4], &v.Purge, "purge")) {
- free(patterns);
- return false;
- }
- /* These were turned into offsets, so the test is the opposite
- * of what you think it should be. If Purge isn't forever,
- * make sure it's greater then the other two fields. */
- if (v.Purge) {
- /* Some value not forever; make sure other values are in range. */
- if (v.Keep && v.Keep < v.Purge) {
- fprintf(stderr, "Line %d keep>purge\n", i);
- free(patterns);
- return false;
- }
- if (v.Default && v.Default < v.Purge) {
- fprintf(stderr, "Line %d default>purge\n", i);
- free(patterns);
- return false;
- }
- }
-
- /* Is this the default line? */
- if (fields[0][0] == '*' && fields[0][1] == '\0' && mod == 'a') {
- if (SawDefault) {
- fprintf(stderr, "Line %d duplicate default\n", i);
- free(patterns);
- return false;
- }
- EXPdefault.Keep = v.Keep;
- EXPdefault.Default = v.Default;
- EXPdefault.Purge = v.Purge;
- EXPdefault.Poison = v.Poison;
- SawDefault = true;
- }
-
- /* Assign to all groups that match the pattern and flags. */
- if ((j = EXPsplit(fields[0], ',', patterns, nGroups)) == -1) {
- fprintf(stderr, "Line %d too many patterns\n", i);
- free(patterns);
- return false;
- }
- for (k = 0; k < j; k++)
- EXPmatch(patterns[k], &v, mod);
- }
- free(patterns);
-
- return true;
-}
-
-/*
-** Handle a newsgroup that isn't in the active file.
-*/
-static NEWSGROUP *
-EXPnotfound(char *Entry)
-{
- static NEWSGROUP Removeit;
- BADGROUP *bg;
-
- /* See if we already know about this group. */
- for (bg = EXPbadgroups; bg; bg = bg->Next)
- if (strcmp(Entry, bg->Name) == 0)
- break;
- if (bg == NULL) {
- bg = xmalloc(sizeof(BADGROUP));
- bg->Name = xstrdup(Entry);
- bg->Next = EXPbadgroups;
- EXPbadgroups = bg;
- }
- /* remove it all now. */
- if (Removeit.Keep == 0) {
- Removeit.Keep = OVnow;
- Removeit.Default = OVnow;
- Removeit.Purge = OVnow;
- }
- return &Removeit;
-}
-
-/*
-** Should we keep the specified article?
-*/
-static enum KRP
-EXPkeepit(char *Entry, time_t when, time_t expires)
-{
- NEWSGROUP *ngp;
- enum KRP retval = Remove;
-
- if ((ngp = NGfind(Entry)) == NULL)
- ngp = EXPnotfound(Entry);
-
- /* Bad posting date? */
- if (when > OVrealnow + 86400) {
- /* Yes -- force the article to go right now. */
- when = expires ? ngp->Purge : ngp->Default;
- }
-
- /* If no expiration, make sure it wasn't posted before the default. */
- if (expires == 0) {
- if (when >= ngp->Default)
- retval = Keep;
-
- /* Make sure it's not posted before the purge cut-off and
- * that it's not due to expire. */
- } else {
- if (when >= ngp->Purge && (expires >= OVnow || when >= ngp->Keep))
- retval = Keep;
- }
- if (retval == Keep) {
- return Keep;
- } else {
- return ngp->Poison ? Poison : Remove;
- }
-}
-
-/*
-** An article can be removed. Either print a note, or actually remove it.
-** Takes in the Xref information so that it can pass this to the storage
-** API callback used to generate the list of files to remove.
-*/
-void
-OVEXPremove(TOKEN token, bool deletedgroups, char **xref, int ngroups)
-{
- EXPunlinked++;
- if (deletedgroups) {
- EXPprocessed++;
- EXPoverindexdrop++;
- }
- if (EXPunlinkfile && xref != NULL) {
- SMprintfiles(EXPunlinkfile, token, xref, ngroups);
- if (!ferror(EXPunlinkfile))
- return;
- fprintf(stderr, "Can't write to -z file, %s\n", strerror(errno));
- fprintf(stderr, "(Will ignore it for rest of run.)\n");
- fclose(EXPunlinkfile);
- EXPunlinkfile = NULL;
- }
- if (!SMcancel(token) && SMerrno != SMERR_NOENT && SMerrno != SMERR_UNINIT)
- fprintf(stderr, "Can't unlink %s: %s\n", TokenToText(token),
- SMerrorstr);
-}
-
-/*
-** Read the overview schema.
-*/
-static void
-ARTreadschema(void)
-{
- FILE *F;
- char *p;
- char *path;
- ARTOVERFIELD *fp;
- int i;
- char buff[SMBUF];
- bool foundxref = false;
- bool foundxreffull = false;
-
- /* Open file, count lines. */
- path = concatpath(innconf->pathetc, _PATH_SCHEMA);
- F = fopen(path, "r");
- if (F == NULL)
- return;
- for (i = 0; fgets(buff, sizeof buff, F) != NULL; i++)
- continue;
- fseeko(F, 0, SEEK_SET);
- ARTfields = xmalloc((i + 1) * sizeof(ARTOVERFIELD));
-
- /* Parse each field. */
- for (fp = ARTfields; fgets(buff, sizeof buff, F) != NULL; ) {
- /* Ignore blank and comment lines. */
- if ((p = strchr(buff, '\n')) != NULL)
- *p = '\0';
- if ((p = strchr(buff, '#')) != NULL)
- *p = '\0';
- if (buff[0] == '\0')
- continue;
- if ((p = strchr(buff, ':')) != NULL) {
- *p++ = '\0';
- fp->NeedsHeader = (strcmp(p, "full") == 0);
- }
- else
- fp->NeedsHeader = false;
- fp->HasHeader = false;
- fp->Header = xstrdup(buff);
- fp->Length = strlen(buff);
- if (strcasecmp(buff, "Xref") == 0) {
- foundxref = true;
- foundxreffull = fp->NeedsHeader;
- }
- fp++;
- }
- ARTfieldsize = fp - ARTfields;
- fclose(F);
- if (!foundxref || !foundxreffull) {
- fprintf(stderr, "'Xref:full' must be included in %s", path);
- exit(1);
- }
- free(path);
-}
-
-/*
-** Return a field from the overview line or NULL on error. Return a copy
-** since we might be re-using the line later.
-*/
-static char *
-OVERGetHeader(const char *p, int field)
-{
- static char *buff;
- static int buffsize;
- int i;
- ARTOVERFIELD *fp;
- char *next;
-
- fp = &ARTfields[field];
-
- /* Skip leading headers. */
- for (; field-- >= 0 && *p; p++)
- if ((p = strchr(p, '\t')) == NULL)
- return NULL;
- if (*p == '\0')
- return NULL;
-
- if (fp->HasHeader)
- p += fp->Length + 2;
-
- if (fp->NeedsHeader) { /* find an exact match */
- while (strncmp(fp->Header, p, fp->Length) != 0) {
- if ((p = strchr(p, '\t')) == NULL)
- return NULL;
- p++;
- }
- p += fp->Length + 2;
- }
-
- /* Figure out length; get space. */
- if ((next = strpbrk(p, "\n\r\t")) != NULL) {
- i = next - p;
- } else {
- i = strlen(p);
- }
- if (buffsize == 0) {
- buffsize = i;
- buff = xmalloc(buffsize + 1);
- }
- else if (buffsize < i) {
- buffsize = i;
- buff = xrealloc(buff, buffsize + 1);
- }
-
- strncpy(buff, p, i);
- buff[i] = '\0';
- return buff;
-}
-
-/*
-** Read overview.fmt and find index for headers
-*/
-static void
-OVfindheaderindex(void)
-{
- FILE *F;
- char *active;
- char *path;
- int i;
-
- if (ReadOverviewfmt)
- return;
- if (innconf->groupbaseexpiry) {
- ACTIVE = concatpath(innconf->pathdb, _PATH_ACTIVE);
- if ((active = ReadInFile(ACTIVE, (struct stat *)NULL)) == NULL) {
- fprintf(stderr, "Can't read %s, %s\n",
- ACTIVE, strerror(errno));
- exit(1);
- }
- BuildGroups(active);
- arts = xmalloc(nGroups * sizeof(char *));
- krps = xmalloc(nGroups * sizeof(enum KRP));
- path = concatpath(innconf->pathetc, _PATH_EXPIRECTL);
- F = fopen(path, "r");
- free(path);
- if (!EXPreadfile(F)) {
- fclose(F);
- fprintf(stderr, "Format error in expire.ctl\n");
- exit(1);
- }
- fclose(F);
- }
- ARTreadschema();
- if (Dateindex == OVFMT_UNINIT) {
- for (Dateindex = OVFMT_NODATE, i = 0; i < ARTfieldsize; i++) {
- if (strcasecmp(ARTfields[i].Header, "Date") == 0) {
- Dateindex = i;
- } else if (strcasecmp(ARTfields[i].Header, "Xref") == 0) {
- Xrefindex = i;
- } else if (strcasecmp(ARTfields[i].Header, "Message-ID") == 0) {
- Messageidindex = i;
- }
- }
- }
- ReadOverviewfmt = true;
- return;
-}
-
-/*
-** Do the work of expiring one line. Assumes article still exists in the
-** spool. Returns true if article should be purged, or return false.
-*/
-bool
-OVgroupbasedexpire(TOKEN token, const char *group, const char *data,
- int len UNUSED, time_t arrived, time_t expires)
-{
- static char *Group = NULL;
- char *p;
- int i;
- int count;
- time_t when;
- bool poisoned;
- bool keeper;
- bool delete;
- bool purge;
- char *Xref;
-
- if (SMprobe(SELFEXPIRE, &token, NULL)) {
- if (!OVignoreselfexpire)
- /* this article should be kept */
- return false;
- }
- if (!ReadOverviewfmt) {
- OVfindheaderindex();
- }
-
- if (OVusepost) {
- if ((p = OVERGetHeader(data, Dateindex)) == NULL) {
- EXPoverindexdrop++;
- return true;
- }
- if ((when = parsedate(p, NULL)) == -1) {
- EXPoverindexdrop++;
- return true;
- }
- } else {
- when = arrived;
- }
- if ((Xref = OVERGetHeader(data, Xrefindex)) == NULL) {
- if (Group != NULL) {
- free(Group);
- }
- Group = concat(group, ":", (char *) 0);
- Xref = Group;
- } else {
- if ((Xref = strchr(Xref, ' ')) == NULL) {
- EXPoverindexdrop++;
- return true;
- }
- for (Xref++; *Xref == ' '; Xref++)
- ;
- }
- if ((count = EXPsplit(Xref, ' ', arts, nGroups)) == -1) {
- EXPoverindexdrop++;
- return true;
- }
-
- /* arts is now an array of strings, each of which is a group name, a
- colon, and an article number. EXPkeepit wants just pure group names,
- so replace the colons with nuls (deleting the overview entry if it
- isn't in the expected form). */
- for (i = 0; i < count; i++) {
- p = strchr(arts[i], ':');
- if (p == NULL) {
- fflush(stdout);
- fprintf(stderr, "Bad entry, \"%s\"\n", arts[i]);
- EXPoverindexdrop++;
- return true;
- }
- *p = '\0';
- }
-
- /* First check all postings */
- poisoned = false;
- keeper = false;
- delete = false;
- purge = true;
- for (i = 0; i < count; ++i) {
- if ((krps[i] = EXPkeepit(arts[i], when, expires)) == Poison)
- poisoned = true;
- if (OVkeep && (krps[i] == Keep))
- keeper = true;
- if ((krps[i] == Remove) && strcmp(group, arts[i]) == 0)
- delete = true;
- if ((krps[i] == Keep))
- purge = false;
- }
- EXPprocessed++;
-
- if (OVearliest) {
- if (delete || poisoned || token.type == TOKEN_EMPTY) {
- /* delete article if this is first entry */
- if (strcmp(group, arts[0]) == 0) {
- for (i = 0; i < count; i++)
- arts[i][strlen(arts[i])] = ':';
- OVEXPremove(token, false, arts, count);
- }
- EXPoverindexdrop++;
- return true;
- }
- } else { /* not earliest mode */
- if ((!keeper && delete) || token.type == TOKEN_EMPTY) {
- /* delete article if purge is set, indicating that it has
- expired out of every group to which it was posted */
- if (purge) {
- for (i = 0; i < count; i++)
- arts[i][strlen(arts[i])] = ':';
- OVEXPremove(token, false, arts, count);
- }
- EXPoverindexdrop++;
- return true;
- }
- }
-
- /* this article should be kept */
- return false;
-}
-
-bool
-OVhisthasmsgid(struct history *h, const char *data)
-{
- char *p;
-
- if (!ReadOverviewfmt) {
- OVfindheaderindex();
- }
- if ((p = OVERGetHeader(data, Messageidindex)) == NULL)
- return false;
- return HISlookup(h, p, NULL, NULL, NULL, NULL);
-}
-
-bool
-OVgroupmatch(const char *group)
-{
- int i;
- bool wanted = false;
-
- if (OVnumpatterns == 0 || group == NULL)
- return true;
- for (i = 0; i < OVnumpatterns; i++) {
- switch (OVpatterns[i][0]) {
- case '!':
- if (!wanted && uwildmat(group, &OVpatterns[i][1]))
- break;
- case '@':
- if (uwildmat(group, &OVpatterns[i][1])) {
- return false;
- }
- break;
- default:
- if (uwildmat(group, OVpatterns[i]))
- wanted = true;
- }
- }
- return wanted;
-}
-
-void
-OVEXPcleanup(void)
-{
- int i;
- BADGROUP *bg, *bgnext;
- ARTOVERFIELD *fp;
- NGHASH *htp;
-
- if (EXPprocessed != 0) {
- if (!OVquiet) {
- printf(" Article lines processed %8ld\n", EXPprocessed);
- printf(" Articles dropped %8ld\n", EXPunlinked);
- printf(" Overview index dropped %8ld\n", EXPoverindexdrop);
- }
- EXPprocessed = EXPunlinked = EXPoverindexdrop = 0;
- }
- if (innconf->ovgrouppat != NULL) {
- for (i = 0 ; i < OVnumpatterns ; i++)
- free(OVpatterns[i]);
- free(OVpatterns);
- }
- for (bg = EXPbadgroups; bg; bg = bgnext) {
- bgnext = bg->Next;
- free(bg->Name);
- free(bg);
- }
- for (fp = ARTfields, i = 0; i < ARTfieldsize ; i++, fp++) {
- free(fp->Header);
- }
- free(ARTfields);
- if (ACTIVE != NULL) {
- free(ACTIVE);
- ACTIVE = NULL;
- }
- if (Groups != NULL) {
- free(Groups);
- Groups = NULL;
- }
- for (i = 0, htp = NGHtable ; i < NGH_SIZE ; i++, htp++) {
- if (htp->Groups != NULL) {
- free(htp->Groups);
- htp->Groups = NULL;
- }
- }
-}
+++ /dev/null
-/* $Id: interface.c 7277 2005-06-07 04:40:16Z eagle $
-**
-** Storage Manager interface
-*/
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "conffile.h"
-#include "inn/innconf.h"
-#include "inn/wire.h"
-#include "interface.h"
-#include "libinn.h"
-#include "methods.h"
-#include "paths.h"
-
-typedef enum {INIT_NO, INIT_DONE, INIT_FAIL} INITTYPE;
-typedef struct {
- INITTYPE initialized;
- bool configured;
- bool selfexpire;
- bool expensivestat;
-} METHOD_DATA;
-
-METHOD_DATA method_data[NUM_STORAGE_METHODS];
-
-static STORAGE_SUB *subscriptions = NULL;
-static unsigned int typetoindex[256];
-int SMerrno;
-char *SMerrorstr = NULL;
-static bool ErrorAlloc = false;
-static bool Initialized = false;
-bool SMopenmode = false;
-bool SMpreopen = false;
-
-/*
-** Checks to see if the token is valid
-*/
-bool IsToken(const char *text) {
- const char *p;
-
- if (!text)
- return false;
-
- if (strlen(text) != (sizeof(TOKEN) * 2) + 2)
- return false;
-
- if (text[0] != '@')
- return false;
-
- if (text[(sizeof(TOKEN) * 2) + 1] != '@')
- return false;
-
- for (p = text + 1; *p != '@'; p++)
- if (!isxdigit((int)*p))
- return false;
-
- return true;
-}
-
-/*
-** Converts a token to a textual representation for error messages
-** and the like.
-*/
-char *
-TokenToText(const TOKEN token)
-{
- static const char hex[] = "0123456789ABCDEF";
- static char result[(sizeof(TOKEN) * 2) + 3];
- const char *p;
- char *q;
- size_t i;
-
-
- result[0] = '@';
- for (q = result + 1, p = (const char *) &token, i = 0; i < sizeof(TOKEN);
- i++, p++) {
- *q++ = hex[(*p & 0xF0) >> 4];
- *q++ = hex[*p & 0x0F];
- }
- *q++ = '@';
- *q++ = '\0';
- return result;
-
-}
-
-/*
-** Converts a hex digit and converts it to a int
-*/
-static int hextodec(const int c) {
- return isdigit(c) ? (c - '0') : ((c - 'A') + 10);
-}
-
-/*
-** Converts a textual representation of a token back to a native
-** representation
-*/
-TOKEN TextToToken(const char *text) {
- const char *p;
- char *q;
- int i;
- TOKEN token;
-
- if (text[0] == '@')
- p = &text[1];
- else
- p = text;
-
- for (q = (char *)&token, i = 0; i != sizeof(TOKEN); i++) {
- q[i] = (hextodec(*p) << 4) + hextodec(*(p + 1));
- p += 2;
- }
- return token;
-}
-
-/*
-** Given an article and length in non-wire format, return a malloced region
-** containing the article in wire format. Set *newlen to the length of the
-** new article.
-*/
-char *
-ToWireFmt(const char *article, size_t len, size_t *newlen)
-{
- size_t bytes;
- char *newart;
- const char *p;
- char *dest;
- bool atstartofline=true;
-
- /* First go thru article and count number of bytes we need. */
- for (bytes = 0, p=article ; p < &article[len] ; ++p) {
- if (*p == '.' && atstartofline) ++bytes; /* 1 byte for escaping . */
- ++bytes;
- if (*p == '\n') {
- ++bytes; /* need another byte for CR */
- atstartofline = true; /* next char starts new line */
- } else {
- atstartofline = false;
- }
- }
- bytes += 3; /* for .\r\n */
- newart = xmalloc(bytes + 1);
- *newlen = bytes;
-
- /* now copy the article, making changes */
- atstartofline = true;
- for (p=article, dest=newart ; p < &article[len] ; ++p) {
- if (*p == '\n') {
- *dest++ = '\r';
- *dest++ = '\n';
- atstartofline = true;
- } else {
- if (atstartofline && *p == '.') *dest++ = '.'; /* add extra . */
- *dest++ = *p;
- atstartofline = false;
- }
- }
- *dest++ = '.';
- *dest++ = '\r';
- *dest++ = '\n';
- *dest = '\0';
- return newart;
-}
-
-char *
-FromWireFmt(const char *article, size_t len, size_t *newlen)
-{
- size_t bytes;
- char *newart;
- const char *p;
- char *dest;
- bool atstartofline = true;
-
- /* First go thru article and count number of bytes we need */
- for (bytes = 0, p=article ; p < &article[len] ; ) {
- /* check for terminating .\r\n and if so break */
- if (p == &article[len-3] && *p == '.' && p[1] == '\r' && p[2] == '\n')
- break;
- /* check for .. at start-of-line */
- if (atstartofline && p < &article[len-1] && *p == '.' && p[1] == '.') {
- bytes++; /* only output 1 byte */
- p+=2;
- atstartofline = false;
- } else if (p < &article[len-1] && *p == '\r' && p[1] == '\n') {
- bytes++; /* \r\n counts as only one byte in output */
- p += 2;
- atstartofline = true;
- } else {
- bytes++;
- p++;
- atstartofline = false;
- }
- }
- newart = xmalloc(bytes + 1);
- *newlen = bytes;
- for (p = article, dest = newart ; p < &article[len]; ) {
- /* check for terminating .\r\n and if so break */
- if (p == &article[len-3] && *p == '.' && p[1] == '\r' && p[2] == '\n')
- break;
- if (atstartofline && p < &article[len-1] && *p == '.' && p[1] == '.') {
- *dest++ = '.';
- p += 2;
- atstartofline = false;
- } else if (p < &article[len-1] && *p == '\r' && p[1] == '\n') {
- *dest++ = '\n';
- p += 2;
- atstartofline = true;
- } else {
- *dest++ = *p++;
- atstartofline = false;
- }
- }
- *dest = '\0';
- return newart;
-}
-
-/*
-** get Xref header without pathhost
-*/
-static char *
-GetXref(ARTHANDLE *art)
-{
- const char *p, *p1;
- const char *q;
- char *buff;
- bool Nocr = false;
-
- p = wire_findheader(art->data, art->len, "xref");
- if (p == NULL)
- return NULL;
- q = p;
- for (p1 = NULL; p < art->data + art->len; p++) {
- if (p1 != (char *)NULL && *p1 == '\r' && *p == '\n') {
- Nocr = false;
- break;
- }
- if (*p == '\n') {
- Nocr = true;
- break;
- }
- p1 = p;
- }
- if (p >= art->data + art->len)
- return NULL;
- if (!Nocr)
- p = p1;
- /* skip pathhost */
- for (; (*q == ' ') && (q < p); q++);
- if (q == p)
- return NULL;
- if ((q = memchr(q, ' ', p - q)) == NULL)
- return NULL;
- for (q++; (*q == ' ') && (q < p); q++);
- if (q == p)
- return NULL;
- buff = xmalloc(p - q + 1);
- memcpy(buff, q, p - q);
- buff[p - q] = '\0';
- return buff;
-}
-
-/*
-** Split newsgroup and returns artnum
-** or 0 if there are no newsgroup.
-*/
-static ARTNUM GetGroups(char *Xref) {
- char *p;
-
- if ((p = strchr(Xref, ':')) == NULL)
- return 0;
- *p++ = '\0';
- return ((ARTNUM)atoi(p));
-}
-
-STORAGE_SUB *SMGetConfig(STORAGETYPE type, STORAGE_SUB *sub) {
- if (sub == (STORAGE_SUB *)NULL)
- sub = subscriptions;
- else
- sub = sub->next;
- for (;sub != NULL; sub = sub->next) {
- if (sub->type == type) {
- return sub;
- }
- }
- return (STORAGE_SUB *)NULL;
-}
-
-static time_t ParseTime(char *tmbuf)
-{
- char *startnum;
- time_t ret;
- int tmp;
-
- ret = 0;
- startnum = tmbuf;
- while (*tmbuf) {
- if (!isdigit((int)*tmbuf)) {
- tmp = atol(startnum);
- switch (*tmbuf) {
- case 'M':
- ret += tmp*60*60*24*31;
- break;
- case 'd':
- ret += tmp*60*60*24;
- break;
- case 'h':
- ret += tmp*60*60;
- break;
- case 'm':
- ret += tmp*60;
- break;
- case 's':
- ret += tmp;
- break;
- default:
- return(0);
- }
- startnum = tmbuf+1;
- }
- tmbuf++;
- }
- return(ret);
-}
-
-#define SMlbrace 1
-#define SMrbrace 2
-#define SMmethod 10
-#define SMgroups 11
-#define SMsize 12
-#define SMclass 13
-#define SMexpire 14
-#define SMoptions 15
-#define SMexactmatch 16
-
-static CONFTOKEN smtoks[] = {
- { SMlbrace, "{" },
- { SMrbrace, "}" },
- { SMmethod, "method" },
- { SMgroups, "newsgroups:" },
- { SMsize, "size:" },
- { SMclass, "class:" },
- { SMexpire, "expires:" },
- { SMoptions, "options:" },
- { SMexactmatch, "exactmatch:" },
- { 0, 0 }
-};
-
-/* Open the config file and parse it, generating the policy data */
-static bool
-SMreadconfig(void)
-{
- CONFFILE *f;
- CONFTOKEN *tok;
- int type;
- int i;
- char *p;
- char *q;
- char *path;
- char *method = NULL;
- char *pattern = NULL;
- size_t minsize = 0;
- size_t maxsize = 0;
- time_t minexpire = 0;
- time_t maxexpire = 0;
- int class = 0;
- STORAGE_SUB *sub = NULL;
- STORAGE_SUB *prev = NULL;
- char *options = 0;
- int inbrace;
- bool exactmatch = false;
-
- /* if innconf isn't already read in, do so. */
- if (innconf == NULL) {
- if (!innconf_read(NULL)) {
- SMseterror(SMERR_INTERNAL, "ReadInnConf() failed");
- return false;
- }
- }
-
- for (i = 0; i < NUM_STORAGE_METHODS; i++) {
- method_data[i].initialized = INIT_NO;
- method_data[i].configured = false;
- }
- path = concatpath(innconf->pathetc, _PATH_STORAGECTL);
- f = CONFfopen(path);
- if (f == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "SM Could not open %s: %m", path);
- free(path);
- return false;
- }
- free(path);
-
- inbrace = 0;
- while ((tok = CONFgettoken(smtoks, f)) != NULL) {
- if (!inbrace) {
- if (tok->type != SMmethod) {
- SMseterror(SMERR_CONFIG, "Expected 'method' keyword");
- syslog(L_ERROR, "SM expected 'method' keyword, line %d", f->lineno);
- return false;
- }
- if ((tok = CONFgettoken(0, f)) == NULL) {
- SMseterror(SMERR_CONFIG, "Expected method name");
- syslog(L_ERROR, "SM expected method name, line %d", f->lineno);
- return false;
- }
- method = xstrdup(tok->name);
- if ((tok = CONFgettoken(smtoks, f)) == NULL || tok->type != SMlbrace) {
- SMseterror(SMERR_CONFIG, "Expected '{'");
- syslog(L_ERROR, "SM Expected '{', line %d", f->lineno);
- return false;
- }
- inbrace = 1;
- /* initialize various params to defaults. */
- minsize = 0;
- maxsize = 0; /* zero means no limit */
- class = 0;
- pattern = NULL;
- options = NULL;
- minexpire = 0;
- maxexpire = 0;
- exactmatch = false;
-
- } else {
- type = tok->type;
- if (type == SMrbrace)
- inbrace = 0;
- else {
- if ((tok = CONFgettoken(0, f)) == NULL) {
- SMseterror(SMERR_CONFIG, "Keyword with no value");
- syslog(L_ERROR, "SM keyword with no value, line %d", f->lineno);
- return false;
- }
- p = tok->name;
- switch(type) {
- case SMgroups:
- if (pattern)
- free(pattern);
- pattern = xstrdup(tok->name);
- break;
- case SMsize:
- minsize = strtoul(p, NULL, 10);
- if ((p = strchr(p, ',')) != NULL) {
- p++;
- maxsize = strtoul(p, NULL, 10);
- }
- break;
- case SMclass:
- class = atoi(p);
- if (class > NUM_STORAGE_CLASSES) {
- SMseterror(SMERR_CONFIG, "Storage class too large");
- warn("SM: storage class larger than %d, line %d",
- NUM_STORAGE_CLASSES, f->lineno);
- return false;
- }
- break;
- case SMexpire:
- q = strchr(p, ',');
- if (q)
- *q++ = 0;
- minexpire = ParseTime(p);
- if (q)
- maxexpire = ParseTime(q);
- break;
- case SMoptions:
- if (options)
- free(options);
- options = xstrdup(p);
- break;
- case SMexactmatch:
- if (strcasecmp(p, "true") == 0
- || strcasecmp(p, "yes") == 0
- || strcasecmp(p, "on") == 0)
- exactmatch = true;
- break;
- default:
- SMseterror(SMERR_CONFIG, "Unknown keyword in method declaration");
- syslog(L_ERROR, "SM Unknown keyword in method declaration, line %d: %s", f->lineno, tok->name);
- free(method);
- return false;
- break;
- }
- }
- }
- if (!inbrace) {
- /* just finished a declaration */
- sub = xmalloc(sizeof(STORAGE_SUB));
- sub->type = TOKEN_EMPTY;
- for (i = 0; i < NUM_STORAGE_METHODS; i++) {
- if (!strcasecmp(method, storage_methods[i].name)) {
- sub->type = storage_methods[i].type;
- method_data[i].configured = true;
- break;
- }
- }
- if (sub->type == TOKEN_EMPTY) {
- SMseterror(SMERR_CONFIG, "Invalid storage method name");
- syslog(L_ERROR, "SM no configured storage methods are named '%s'", method);
- free(options);
- free(sub);
- return false;
- }
- if (!pattern) {
- SMseterror(SMERR_CONFIG, "pattern not defined");
- syslog(L_ERROR, "SM no pattern defined");
- free(options);
- free(sub);
- return false;
- }
- sub->pattern = pattern;
- sub->minsize = minsize;
- sub->maxsize = maxsize;
- sub->class = class;
- sub->options = options;
- sub->minexpire = minexpire;
- sub->maxexpire = maxexpire;
- sub->exactmatch = exactmatch;
-
- free(method);
- method = 0;
-
- if (!prev)
- subscriptions = sub;
- if (prev)
- prev->next = sub;
- prev = sub;
- sub->next = NULL;
- }
- }
-
- CONFfclose(f);
-
- return true;
-}
-
-/*
-** setup storage api environment (open mode etc.)
-*/
-bool SMsetup(SMSETUP type, void *value) {
- if (Initialized)
- return false;
- switch (type) {
- case SM_RDWR:
- SMopenmode = *(bool *)value;
- break;
- case SM_PREOPEN:
- SMpreopen = *(bool *)value;
- break;
- default:
- return false;
- }
- return true;
-}
-
-/*
-** Calls the setup function for all of the configured methods and returns
-** true if they all initialize ok, false if they don't
-*/
-bool SMinit(void) {
- int i;
- bool allok = true;
- static bool once = false;
- SMATTRIBUTE smattr;
-
- if (Initialized)
- return true;
-
- Initialized = true;
-
- if (!SMreadconfig()) {
- SMshutdown();
- Initialized = false;
- return false;
- }
-
- for (i = 0; i < NUM_STORAGE_METHODS; i++) {
- if (method_data[i].configured) {
- if (method_data[i].configured && storage_methods[i].init(&smattr)) {
- method_data[i].initialized = INIT_DONE;
- method_data[i].selfexpire = smattr.selfexpire;
- method_data[i].expensivestat = smattr.expensivestat;
- } else {
- method_data[i].initialized = INIT_FAIL;
- method_data[i].selfexpire = false;
- method_data[i].expensivestat = true;
- syslog(L_ERROR, "SM storage method '%s' failed initialization", storage_methods[i].name);
- allok = false;
- }
- }
- typetoindex[storage_methods[i].type] = i;
- }
- if (!allok) {
- SMshutdown();
- Initialized = false;
- SMseterror(SMERR_UNDEFINED, "one or more storage methods failed initialization");
- syslog(L_ERROR, "SM one or more storage methods failed initialization");
- return false;
- }
- if (!once && atexit(SMshutdown) < 0) {
- SMshutdown();
- Initialized = false;
- SMseterror(SMERR_UNDEFINED, NULL);
- return false;
- }
- once = true;
- return true;
-}
-
-static bool InitMethod(STORAGETYPE method) {
- SMATTRIBUTE smattr;
-
- if (!Initialized)
- if (!SMreadconfig()) {
- Initialized = false;
- return false;
- }
- Initialized = true;
-
- if (method_data[method].initialized == INIT_DONE)
- return true;
-
- if (method_data[method].initialized == INIT_FAIL)
- return false;
-
- if (!method_data[method].configured) {
- method_data[method].initialized = INIT_FAIL;
- SMseterror(SMERR_UNDEFINED, "storage method is not configured.");
- return false;
- }
- if (!storage_methods[method].init(&smattr)) {
- method_data[method].initialized = INIT_FAIL;
- method_data[method].selfexpire = false;
- method_data[method].expensivestat = true;
- SMseterror(SMERR_UNDEFINED, "Could not initialize storage method late.");
- return false;
- }
- method_data[method].initialized = INIT_DONE;
- method_data[method].selfexpire = smattr.selfexpire;
- method_data[method].expensivestat = smattr.expensivestat;
- return true;
-}
-
-static bool
-MatchGroups(const char *g, int len, const char *pattern, bool exactmatch)
-{
- char *group, *groups, *q;
- int i, lastwhite;
- enum uwildmat matched;
- bool wanted = false;
-
- q = groups = xmalloc(len + 1);
- for (lastwhite = -1, i = 0 ; i < len ; i++) {
- /* trim white chars */
- if (g[i] == '\r' || g[i] == '\n' || g[i] == ' ' || g[i] == '\t') {
- if (lastwhite + 1 != i)
- *q++ = ' ';
- lastwhite = i;
- } else
- *q++ = g[i];
- }
- *q = '\0';
-
- group = strtok(groups, " ,");
- while (group != NULL) {
- q = strchr(group, ':');
- if (q != NULL)
- *q = '\0';
- matched = uwildmat_poison(group, pattern);
- if (matched == UWILDMAT_POISON || (exactmatch && !matched)) {
- free(groups);
- return false;
- }
- if (matched == UWILDMAT_MATCH)
- wanted = true;
- group = strtok(NULL, " ,");
- }
-
- free(groups);
- return wanted;
-}
-
-STORAGE_SUB *SMgetsub(const ARTHANDLE article) {
- STORAGE_SUB *sub;
-
- if (article.len == 0) {
- SMseterror(SMERR_BADHANDLE, NULL);
- return NULL;
- }
-
- if (article.groups == NULL)
- return NULL;
-
- for (sub = subscriptions; sub != NULL; sub = sub->next) {
- if (!(method_data[typetoindex[sub->type]].initialized == INIT_FAIL) &&
- (article.len >= sub->minsize) &&
- (!sub->maxsize || (article.len <= sub->maxsize)) &&
- (!sub->minexpire || article.expires >= sub->minexpire) &&
- (!sub->maxexpire || (article.expires <= sub->maxexpire)) &&
- MatchGroups(article.groups, article.groupslen, sub->pattern,
- sub->exactmatch)) {
- if (InitMethod(typetoindex[sub->type]))
- return sub;
- }
- }
- errno = 0;
- SMseterror(SMERR_NOMATCH, "no matching entry in storage.conf");
- return NULL;
-}
-
-TOKEN SMstore(const ARTHANDLE article) {
- STORAGE_SUB *sub;
- TOKEN result;
-
- if (!SMopenmode) {
- result.type = TOKEN_EMPTY;
- SMseterror(SMERR_INTERNAL, "read only storage api");
- return result;
- }
- result.type = TOKEN_EMPTY;
- if ((sub = SMgetsub(article)) == NULL) {
- return result;
- }
- return storage_methods[typetoindex[sub->type]].store(article, sub->class);
-}
-
-ARTHANDLE *SMretrieve(const TOKEN token, const RETRTYPE amount) {
- ARTHANDLE *art;
-
- if (method_data[typetoindex[token.type]].initialized == INIT_FAIL) {
- SMseterror(SMERR_UNINIT, NULL);
- return NULL;
- }
- if (method_data[typetoindex[token.type]].initialized == INIT_NO && !InitMethod(typetoindex[token.type])) {
- syslog(L_ERROR, "SM could not find token type or method was not initialized (%d)",
- token.type);
- SMseterror(SMERR_UNINIT, NULL);
- return NULL;
- }
- art = storage_methods[typetoindex[token.type]].retrieve(token, amount);
- if (art)
- art->nextmethod = 0;
- return art;
-
-}
-
-ARTHANDLE *SMnext(const ARTHANDLE *article, const RETRTYPE amount) {
- unsigned char i;
- int start;
- ARTHANDLE *newart;
-
- if (article == NULL)
- start = 0;
- else
- start= article->nextmethod;
-
- if (method_data[start].initialized == INIT_FAIL) {
- SMseterror(SMERR_UNINIT, NULL);
- return NULL;
- }
- if (method_data[start].initialized == INIT_NO && method_data[start].configured
- && !InitMethod(start)) {
- SMseterror(SMERR_UNINIT, NULL);
- return NULL;
- }
-
- for (i = start, newart = NULL; i < NUM_STORAGE_METHODS; i++) {
- if (method_data[i].configured && (newart = storage_methods[i].next(article, amount)) != (ARTHANDLE *)NULL) {
- newart->nextmethod = i;
- break;
- } else
- article = NULL;
- }
-
- return newart;
-}
-
-void SMfreearticle(ARTHANDLE *article) {
- if (method_data[typetoindex[article->type]].initialized == INIT_FAIL) {
- return;
- }
- if (method_data[typetoindex[article->type]].initialized == INIT_NO && !InitMethod(typetoindex[article->type])) {
- syslog(L_ERROR, "SM can't free article with uninitialized method");
- return;
- }
- storage_methods[typetoindex[article->type]].freearticle(article);
-}
-
-bool SMcancel(TOKEN token) {
- if (!SMopenmode) {
- SMseterror(SMERR_INTERNAL, "read only storage api");
- return false;
- }
- if (method_data[typetoindex[token.type]].initialized == INIT_FAIL) {
- SMseterror(SMERR_UNINIT, NULL);
- return false;
- }
- if (method_data[typetoindex[token.type]].initialized == INIT_NO && !InitMethod(typetoindex[token.type])) {
- SMseterror(SMERR_UNINIT, NULL);
- syslog(L_ERROR, "SM can't cancel article with uninitialized method");
- return false;
- }
- return storage_methods[typetoindex[token.type]].cancel(token);
-}
-
-bool SMprobe(PROBETYPE type, TOKEN *token, void *value) {
- struct artngnum *ann;
- ARTHANDLE *art;
-
- switch (type) {
- case SELFEXPIRE:
- return (method_data[typetoindex[token->type]].selfexpire);
- case SMARTNGNUM:
- if (method_data[typetoindex[token->type]].initialized == INIT_FAIL) {
- SMseterror(SMERR_UNINIT, NULL);
- return false;
- }
- if (method_data[typetoindex[token->type]].initialized == INIT_NO && !InitMethod(typetoindex[token->type])) {
- SMseterror(SMERR_UNINIT, NULL);
- syslog(L_ERROR, "SM can't cancel article with uninitialized method");
- return false;
- }
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- ann->groupname = NULL;
- if (storage_methods[typetoindex[token->type]].ctl(type, token, value)) {
- if (ann->artnum != 0) {
- /* set by storage method */
- return true;
- } else {
- art = storage_methods[typetoindex[token->type]].retrieve(*token, RETR_HEAD);
- if (art == NULL) {
- if (ann->groupname != NULL)
- free(ann->groupname);
- storage_methods[typetoindex[token->type]].freearticle(art);
- return false;
- }
- if ((ann->groupname = GetXref(art)) == NULL) {
- if (ann->groupname != NULL)
- free(ann->groupname);
- storage_methods[typetoindex[token->type]].freearticle(art);
- return false;
- }
- storage_methods[typetoindex[token->type]].freearticle(art);
- if ((ann->artnum = GetGroups(ann->groupname)) == 0) {
- if (ann->groupname != NULL)
- free(ann->groupname);
- return false;
- }
- return true;
- }
- } else {
- return false;
- }
- case EXPENSIVESTAT:
- return (method_data[typetoindex[token->type]].expensivestat);
- default:
- return false;
- }
-}
-
-bool SMflushcacheddata(FLUSHTYPE type) {
- int i;
-
- for (i = 0; i < NUM_STORAGE_METHODS; i++) {
- if (method_data[i].initialized == INIT_DONE &&
- !storage_methods[i].flushcacheddata(type))
- syslog(L_ERROR, "SM can't flush cached data method '%s'", storage_methods[i].name);
- }
- return true;
-}
-
-void SMprintfiles(FILE *file, TOKEN token, char **xref, int ngroups) {
- if (method_data[typetoindex[token.type]].initialized == INIT_FAIL)
- return;
- if (method_data[typetoindex[token.type]].initialized == INIT_NO
- && !InitMethod(typetoindex[token.type])) {
- SMseterror(SMERR_UNINIT, NULL);
- syslog(L_ERROR, "SM can't print files for article with uninitialized method");
- return;
- }
- storage_methods[typetoindex[token.type]].printfiles(file, token, xref, ngroups);
-}
-
-void SMshutdown(void) {
- int i;
- STORAGE_SUB *old;
-
- if (!Initialized)
- return;
-
- for (i = 0; i < NUM_STORAGE_METHODS; i++)
- if (method_data[i].initialized == INIT_DONE) {
- storage_methods[i].shutdown();
- method_data[i].initialized = INIT_NO;
- method_data[i].configured = false;
- }
- while (subscriptions) {
- old = subscriptions;
- subscriptions = subscriptions->next;
- free(old->pattern);
- free(old->options);
- free(old);
- }
- Initialized = false;
-}
-
-void SMseterror(int errornum, char *error) {
- if (ErrorAlloc)
- free(SMerrorstr);
-
- ErrorAlloc = false;
-
- if ((errornum == SMERR_UNDEFINED) && (errno == ENOENT))
- errornum = SMERR_NOENT;
-
- SMerrno = errornum;
-
- if (error == NULL) {
- switch (SMerrno) {
- case SMERR_UNDEFINED:
- SMerrorstr = xstrdup(strerror(errno));
- ErrorAlloc = true;
- break;
- case SMERR_INTERNAL:
- SMerrorstr = "Internal error";
- break;
- case SMERR_NOENT:
- SMerrorstr = "Token not found";
- break;
- case SMERR_TOKENSHORT:
- SMerrorstr = "Configured token size too small";
- break;
- case SMERR_NOBODY:
- SMerrorstr = "No article body found";
- break;
- case SMERR_UNINIT:
- SMerrorstr = "Storage manager is not initialized";
- break;
- case SMERR_CONFIG:
- SMerrorstr = "Error reading config file";
- break;
- case SMERR_BADHANDLE:
- SMerrorstr = "Bad article handle";
- break;
- case SMERR_BADTOKEN:
- SMerrorstr = "Bad token";
- break;
- case SMERR_NOMATCH:
- SMerrorstr = "No matching entry in storage.conf";
- break;
- default:
- SMerrorstr = "Undefined error";
- }
- } else {
- SMerrorstr = xstrdup(error);
- ErrorAlloc = true;
- }
-}
-
+++ /dev/null
-/* $Id: interface.h 5933 2002-12-07 09:47:17Z rra $
-**
-** Storage Manager interface header
-*/
-
-#ifndef __INTERFACE_H__
-#define __INTERFACE_H__
-
-#include "config.h"
-#include "storage.h"
-#include <stdio.h>
-
-typedef struct {
- bool selfexpire;
- bool expensivestat;
-} SMATTRIBUTE;
-
-typedef struct {
- const char *name;
- unsigned char type;
- bool (*init)(SMATTRIBUTE *attr);
- TOKEN (*store)(const ARTHANDLE article, const STORAGECLASS storageclass);
- ARTHANDLE *(*retrieve)(const TOKEN token, const RETRTYPE amount);
- ARTHANDLE *(*next)(const ARTHANDLE *article, const RETRTYPE amount);
- void (*freearticle)(ARTHANDLE *article);
- bool (*cancel)(TOKEN token);
- bool (*ctl)(PROBETYPE type, TOKEN *token, void *value);
- bool (*flushcacheddata)(FLUSHTYPE type);
- void (*printfiles)(FILE *, TOKEN, char **xref, int ngroups);
- void (*shutdown)(void);
-} STORAGE_METHOD;
-
-typedef struct __S_SUB__ {
- int type; /* Index into storage_methods of the one to use */
- size_t minsize; /* Minimum size to send to this method */
- size_t maxsize; /* Maximum size to send to this method */
- time_t minexpire; /* Minimum expire offset to send method */
- time_t maxexpire; /* Maximum expire offset to send method */
- int numpatterns; /* Number of patterns in patterns */
- int class; /* Number of the storage class for this subscription */
- char *pattern; /* Wildmat pattern to check against the
- groups to determine if the article
- should go to this method */
- char *options; /* additional options specific to the
- method */
- bool exactmatch; /* all newsgroups to which article belongs
- should match the patterns */
- struct __S_SUB__ *next;
-} STORAGE_SUB;
-
-extern bool SMopenmode;
-extern bool SMpreopen;
-char *SMFindBody(char *article, int len);
-STORAGE_SUB *SMGetConfig(STORAGETYPE type, STORAGE_SUB *sub);
-STORAGE_SUB *SMgetsub(const ARTHANDLE article);
-void SMseterror(int errorno, char *error);
-
-#endif /* __INTERFACE_H__ */
+++ /dev/null
-/* $Id: ov.c 6135 2003-01-19 01:15:40Z rra $
-**
-** The implementation of the overview API.
-**
-** This code handles calls to the overview API by passing them along to the
-** appropriate underlying overview method, as well as implementing those
-** portions of the overview subsystem that are independent of storage
-** method.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <syslog.h>
-
-#include "inn/innconf.h"
-#include "libinn.h"
-#include "ov.h"
-#include "ovinterface.h"
-#include "ovmethods.h"
-
-/* FIXME: The following variables are shared between this file and expire.c.
- This should be cleaned up with a better internal interface. */
-static bool OVdelayrm;
-static OV_METHOD ov;
-
-bool
-OVopen(int mode)
-{
- int i;
- bool val;
- char *p;
-
- if (ov.open)
- /* already opened */
- return true;
-
- /* if innconf isn't already read in, do so. */
- if (innconf == NULL)
- if (!innconf_read(NULL))
- return false;
- if (!innconf->enableoverview) {
- syslog(L_FATAL, "enableoverview is not true");
- fprintf(stderr, "enableoverview is not true\n");
- return false;
- }
- if (innconf->ovmethod == NULL) {
- syslog(L_FATAL, "ovmethod is not defined");
- fprintf(stderr, "ovmethod is not defined\n");
- return false;
- }
- for (i=0;i<NUM_OV_METHODS;i++) {
- if (!strcmp(innconf->ovmethod, ov_methods[i].name))
- break;
- }
- if (i == NUM_OV_METHODS) {
- syslog(L_FATAL, "%s is not found for ovmethod", innconf->ovmethod);
- fprintf(stderr, "%s is not found for ovmethod\n", innconf->ovmethod);
- return false;
- }
- ov = ov_methods[i];
- val = (*ov.open)(mode);
- if (atexit(OVclose) < 0) {
- OVclose();
- return false;
- }
- if (innconf->ovgrouppat != NULL) {
- for (i = 1, p = innconf->ovgrouppat; *p && (p = strchr(p+1, ',')); i++);
- OVnumpatterns = i;
- OVpatterns = xmalloc(OVnumpatterns * sizeof(char *));
- for (i = 0, p = strtok(innconf->ovgrouppat, ","); p != NULL && i <= OVnumpatterns ; i++, p = strtok(NULL, ","))
- OVpatterns[i] = xstrdup(p);
- if (i != OVnumpatterns) {
- syslog(L_FATAL, "extra ',' in pattern");
- fprintf(stderr, "extra ',' in pattern");
- return false;
- }
- }
- return val;
-}
-
-bool
-OVgroupstats(char *group, int *lo, int *hi, int *count, int *flag)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.groupstats)(group, lo, hi, count, flag));
-}
-
-bool
-OVgroupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag)
-{
- /* lomark should never be changed in each ovmethod if lo is 0 */
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.groupadd)(group, lo, hi, flag));
-}
-
-bool
-OVgroupdel(char *group)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.groupdel)(group));
-}
-
-OVADDRESULT
-OVadd(TOKEN token, char *data, int len, time_t arrived, time_t expires)
-{
- char *next, *nextcheck;
- static char *xrefdata, *patcheck, *overdata;
- char *xrefstart = NULL;
- char *xrefend;
- static int xrefdatalen = 0, overdatalen = 0;
- bool found = false;
- int xreflen;
- int i;
- char *group;
- ARTNUM artnum;
-
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return OVADDFAILED;
- }
-
- /*
- * find last Xref: in the overview line. Note we need to find the *last*
- * Xref:, since there have been corrupted articles on Usenet with Xref:
- * fragments stuck in other header lines. The last Xref: is guaranteed
- * to be from our server.
- */
-
- for (next = data; ((len - (next - data)) > 6 ) && ((next = memchr(next, 'X', len - (next - data))) != NULL); ) {
- if (memcmp(next, "Xref: ", 6) == 0) {
- found = true;
- xrefstart = next;
- }
- next++;
- }
-
- if (!found)
- return OVADDFAILED;
-
- next = xrefstart;
- for (i = 0; (i < 2) && (next < (data + len)); i++) {
- if ((next = memchr(next, ' ', len - (next - data))) == NULL)
- return OVADDFAILED;
- next++;
- }
- xreflen = len - (next - data);
-
- /*
- * If there are other fields beyond Xref in overview, then
- * we must find Xref's end, or data following is misinterpreted.
- */
- if ((xrefend = memchr(next, '\t', xreflen)) != NULL)
- xreflen = xrefend - next;
-
- if (xrefdatalen == 0) {
- xrefdatalen = BIG_BUFFER;
- xrefdata = xmalloc(xrefdatalen);
- if (innconf->ovgrouppat != NULL)
- patcheck = xmalloc(xrefdatalen);
- }
- if (xreflen > xrefdatalen) {
- xrefdatalen = xreflen;
- xrefdata = xrealloc(xrefdata, xrefdatalen + 1);
- if (innconf->ovgrouppat != NULL)
- patcheck = xrealloc(patcheck, xrefdatalen + 1);
- }
- if (overdatalen == 0) {
- overdatalen = BIG_BUFFER;
- overdata = xmalloc(overdatalen);
- }
- if (len + 16 > overdatalen) {
- overdatalen = len + 16;
- overdata = xrealloc(overdata, overdatalen);
- }
-
- if (innconf->ovgrouppat != NULL) {
- memcpy(patcheck, next, xreflen);
- patcheck[xreflen] = '\0';
- for (group = patcheck; group && *group; group = memchr(nextcheck, ' ', xreflen - (nextcheck - patcheck))) {
- while (isspace((int)*group))
- group++;
- if ((nextcheck = memchr(group, ':', xreflen - (patcheck - group))) == NULL)
- return OVADDFAILED;
- *nextcheck++ = '\0';
- if (!OVgroupmatch(group)) {
- if (!SMprobe(SELFEXPIRE, &token, NULL) && innconf->groupbaseexpiry)
- /* this article will never be expired, since it does not
- have self expiry function in stored method and
- groupbaseexpiry is true */
- return OVADDFAILED;
- return OVADDGROUPNOMATCH;
- }
- }
- }
- memcpy(xrefdata, next, xreflen);
- xrefdata[xreflen] = '\0';
- for (group = xrefdata; group && *group; group = memchr(next, ' ', xreflen - (next - xrefdata))) {
- /* Parse the xref part into group name and article number */
- while (isspace((int)*group))
- group++;
- if ((next = memchr(group, ':', xreflen - (group - xrefdata))) == NULL)
- return OVADDFAILED;
- *next++ = '\0';
- artnum = atoi(next);
- if (artnum <= 0)
- continue;
-
- sprintf(overdata, "%ld\t", artnum);
- i = strlen(overdata);
- memcpy(overdata + i, data, len);
- i += len;
- memcpy(overdata + i, "\r\n", 2);
- i += 2;
-
- if(! (*ov.add)(group, artnum, token, overdata, i, arrived, expires))
- return OVADDFAILED;
- }
-
- return OVADDCOMPLETED;
-}
-
-bool
-OVcancel(TOKEN token)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.cancel)(token));
-}
-
-void *
-OVopensearch(char *group, int low, int high)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.opensearch)(group, low, high));
-}
-
-bool
-OVsearch(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token,
- time_t *arrived)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.search)(handle, artnum, data, len, token, arrived));
-}
-
-void
-OVclosesearch(void *handle)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return;
- }
- (*ov.closesearch)(handle);
- return;
-}
-
-bool
-OVgetartinfo(char *group, ARTNUM artnum, TOKEN *token)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.getartinfo)(group, artnum, token));
-}
-
-bool
-OVexpiregroup(char *group, int *lo, struct history *h)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- return ((*ov.expiregroup)(group, lo, h));
-}
-
-bool
-OVctl(OVCTLTYPE type, void *val)
-{
- if (!ov.open) {
- /* must be opened */
- syslog(L_ERROR, "ovopen must be called first");
- fprintf(stderr, "ovopen must be called first");
- return false;
- }
- switch (type) {
- case OVGROUPBASEDEXPIRE:
- if (!innconf->groupbaseexpiry) {
- syslog(L_ERROR, "OVGROUPBASEDEXPIRE is not allowed if groupbaseexpiry if false");
- fprintf(stderr, "OVGROUPBASEDEXPIRE is not allowed if groupbaseexpiry if false");
- return false;
- }
- if (((OVGE *)val)->delayrm) {
- if ((((OVGE *)val)->filename == NULL) || (strlen(((OVGE *)val)->filename) == 0)) {
- syslog(L_ERROR, "file name must be specified");
- fprintf(stderr, "file name must be specified");
- return false;
- }
- if ((EXPunlinkfile = fopen(((OVGE *)val)->filename, "w")) == NULL) {
- syslog(L_ERROR, "fopen: %s failed: %m", ((OVGE *)val)->filename);
- fprintf(stderr, "fopen: %s failed: %s", ((OVGE *)val)->filename,
- strerror(errno));
- return false;
- }
- }
- OVdelayrm = ((OVGE *)val)->delayrm;
- OVusepost = ((OVGE *)val)->usepost;
- OVrealnow = ((OVGE *)val)->now;
- OVnow = ((OVGE *)val)->now + (time_t)((OVGE *)val)->timewarp;
- OVquiet = ((OVGE *)val)->quiet;
- OVkeep = ((OVGE *)val)->keep;
- OVearliest = ((OVGE *)val)->earliest;
- OVignoreselfexpire = ((OVGE *)val)->ignoreselfexpire;
- return true;
- case OVSTATALL:
- OVstatall = *(bool *)val;
- return true;
- default:
- return ((*ov.ctl)(type, val));
- }
-}
-
-void
-OVclose(void)
-{
- if (!ov.open)
- return;
- (*ov.close)();
- memset(&ov, '\0', sizeof(ov));
- OVEXPcleanup();
-}
+++ /dev/null
-#ifdef USE_BERKELEY_DB
-
-#include <db.h>
-
-#if DB_VERSION_MAJOR == 2
-#if DB_VERSION_MINOR < 6
-#error "Need BerkeleyDB 2.6.x, 2.7.x, 3.x or 4.x"
-#endif
-#else
-#if DB_VERSION_MAJOR < 3 || DB_VERSION_MAJOR > 4
-#error "Need BerkeleyDB 2.6.x, 2.7.x, 3.x or 4.x"
-#endif
-#endif
-
-/*
- * How data is stored:
- *
- * Each group is assigned an integer ID. The mapping between a group name
- * and its ID is stored in the groupinfo DB. Overview data itself
- * is stored in one or more btree DBs. The specific DB file that is used
- * to store data for a certain group is chosen by taking the hash of the
- * group name, copying the first bytes of the hash into an int, and then
- * modding the int value to the number of DBs.
- *
- * Each group has one groupinfo structure in the groupinfo DB, whose key
- * is the newsgroup name. The overview records for the group have a
- * 'struct datakey' as their keys, which consists of the group ID (in
- * native byteorder) followed by the article number in network byteorder.
- * The reason for storing the article number in net byte order (big-endian)
- * is that the keys will sort correctly using BerkeleyDB's default sort
- * function (basically, a memcmp).
- *
- * The overview records consist of a 'struct ovdata' followed by the actual
- * overview data. The struct ovdata contains the token and arrival time.
- */
-
-struct ovdb_conf {
- char *home; /* path to directory where db files are stored */
- int txn_nosync; /* whether to pass DB_TXN_NOSYNC to db_appinit */
- int numdbfiles;
- size_t cachesize;
- size_t pagesize;
- int minkey;
- int maxlocks;
- int nocompact;
- int readserver;
- int numrsprocs;
- int maxrsconn;
- int useshm;
- int shmkey;
-};
-
-typedef u_int32_t group_id_t;
-
-struct groupinfo {
- ARTNUM low;
- ARTNUM high;
- int count;
- int flag;
- time_t expired; /* when this group was last touched by expiregroup */
- group_id_t current_gid; /* group ID */
- group_id_t new_gid; /* pending ID (expireover) */
- int current_db; /* which DB file the records are in */
- int new_db; /* pending DB file */
- pid_t expiregrouppid; /* PID of expireover process */
- int status;
-};
-#define GROUPINFO_DELETED 1
-#define GROUPINFO_EXPIRING (1<<1)
-#define GROUPINFO_MOVING (1<<2)
-#define GROUPINFO_MOVE_REQUESTED (1<<3) /*NYI*/
-
-struct datakey {
- group_id_t groupnum; /* must be the first member of this struct */
- u_int32_t artnum;
-};
-
-struct ovdata {
- TOKEN token;
- time_t arrived;
- time_t expires;
-};
-
-
-#define DATA_VERSION 2
-
-extern struct ovdb_conf ovdb_conf;
-extern DB_ENV *OVDBenv;
-
-#define OVDB_ERR_NONE 0
-#define OVDB_ERR_SYSLOG 1 /* default */
-#define OVDB_ERR_STDERR 2
-extern int ovdb_errmode;
-
-void read_ovdb_conf(void);
-int ovdb_open_berkeleydb(int mode, int flags);
-void ovdb_close_berkeleydb(void);
-int ovdb_getgroupinfo(char *group, struct groupinfo *gi, int ignoredeleted, DB_TXN *tid, int getflags);
-
-#define OVDB_RECOVER 1
-#define OVDB_UPGRADE 2
-
-#define OVDB_LOCK_NORMAL 0
-#define OVDB_LOCK_ADMIN 1
-#define OVDB_LOCK_EXCLUSIVE 2
-
-bool ovdb_getlock(int mode);
-bool ovdb_releaselock(void);
-bool ovdb_check_pidfile(char *file);
-bool ovdb_check_user(void);
-
-#define OVDB_LOCKFN "ovdb.sem"
-#define OVDB_MONITOR_PIDFILE "ovdb_monitor.pid"
-#define OVDB_SERVER_PIDFILE "ovdb_server.pid"
-#define SPACES " "
-
-/* read server stuff */
-#define CMD_QUIT 0x01
-#define CMD_GROUPSTATS 0x02
-#define CMD_OPENSRCH 0x03
-#define CMD_SRCH 0x04
-#define CMD_CLOSESRCH 0x05
-#define CMD_ARTINFO 0x06
-#define CMD_MASK 0x0F
-#define RPLY_OK 0x00
-#define RPLY_ERROR 0x10
-#define OVDB_SERVER (1<<4)
-#define OVDB_SERVER_BANNER "ovdb read protocol 1"
-#define OVDB_SERVER_PORT 32323 /* only used if don't have unix domain sockets */
-#define OVDB_SERVER_SOCKET "ovdb.server"
-
-struct rs_cmd {
- uint32_t what;
- uint32_t grouplen;
- uint32_t artlo;
- uint32_t arthi;
- void * handle;
-};
-
-struct rs_groupstats {
- uint32_t status;
- int lo;
- int hi;
- int count;
- int flag;
- uint32_t aliaslen;
- /* char alias */
-};
-
-struct rs_opensrch {
- uint32_t status;
- void * handle;
-};
-
-struct rs_srch {
- uint32_t status;
- ARTNUM artnum;
- TOKEN token;
- time_t arrived;
- int len;
- /* char data */
-};
-
-struct rs_artinfo {
- uint32_t status;
- TOKEN token;
-};
-
-
-#if DB_VERSION_MAJOR == 2
-char *db_strerror(int err);
-
-#define TXN_START(label, tid) \
-label: { \
- int txn_ret; \
- txn_ret = txn_begin(OVDBenv->tx_info, NULL, &tid); \
- if (txn_ret != 0) { \
- syslog(L_ERROR, "OVDB: " #label " txn_begin: %s", db_strerror(ret)); \
- tid = NULL; \
- } \
-}
-
-#define TXN_RETRY(label, tid) \
-{ txn_abort(tid); goto label; }
-
-#define TXN_ABORT(label, tid) txn_abort(tid)
-#define TXN_COMMIT(label, tid) txn_commit(tid)
-
-#define TRYAGAIN EAGAIN
-
-#elif DB_VERSION_MAJOR == 3
-
-#define TXN_START(label, tid) \
-label: { \
- int txn_ret; \
- txn_ret = txn_begin(OVDBenv, NULL, &tid, 0); \
- if (txn_ret != 0) { \
- syslog(L_ERROR, "OVDB: " #label " txn_begin: %s", db_strerror(ret)); \
- tid = NULL; \
- } \
-}
-
-#define TXN_RETRY(label, tid) \
-{ txn_abort(tid); goto label; }
-
-#define TXN_ABORT(label, tid) txn_abort(tid)
-#define TXN_COMMIT(label, tid) txn_commit(tid, 0)
-
-#define TRYAGAIN DB_LOCK_DEADLOCK
-
-#else /* DB_VERSION_MAJOR == 4 */
-
-#define TXN_START(label, tid) \
-label: { \
- int txn_ret; \
- txn_ret = OVDBenv->txn_begin(OVDBenv, NULL, &tid, 0); \
- if (txn_ret != 0) { \
- syslog(L_ERROR, "OVDB: " #label " txn_begin: %s", db_strerror(ret)); \
- tid = NULL; \
- } \
-}
-
-#define TXN_RETRY(label, tid) \
-{ (tid)->abort(tid); goto label; }
-
-#define TXN_ABORT(label, tid) (tid)->abort(tid)
-#define TXN_COMMIT(label, tid) (tid)->commit(tid, 0)
-
-#define TRYAGAIN DB_LOCK_DEADLOCK
-
-#endif /* DB_VERSION_MAJOR == 4 */
-
-#endif /* USE_BERKELEY_DB */
+++ /dev/null
-/*
- * ovdb.c
- * ovdb 2.00
- * Overview storage using BerkeleyDB 2.x/3.x/4.x
- *
- * 2004-02-17 : Need to track search cursors, since it's possible that
- * ovdb_closesearch does not get called. We now close
- * any cursors still open in ovdb_close, or they'd be in
- * the database indefinitely causing deadlocks.
- * 2002-08-13 : Change BOOL to bool, remove portability to < 2.4.
- * 2002-08-11 : Cleaned up use of sprintf and fixed a bunch of warnings.
- * 2002-02-28 : Update getartinfo for the overview API change in 2.4. This
- * breaks compatibility with INN 2.3.x....
- * 2000-12-12 : Add support for BerkeleyDB DB_SYSTEM_MEM option, controlled
- * : by ovdb.conf 'useshm' and 'shmkey'
- * 2000-11-27 : Update for DB 3.2.x compatibility
- * 2000-11-13 : New 'readserver' feature
- * 2000-10-10 : ovdb_search now closes the cursor right after the last
- * record is read.
- * 2000-10-05 : artnum member of struct datakey changed from ARTNUM to u_int32_t.
- * OS's where sizeof(long)==8 will have to rebuild their databases
- * after this update.
- * 2000-10-05 : from Dan Riley: struct datakey needs to be zero'd, for
- * 64-bit OSs where the struct has internal padding bytes.
- * 2000-09-29 : ovdb_expiregroup can now fix incorrect counts; use new
- * inn/version.h so can have same ovdb.c for 2.3.0, 2.3.1, and 2.4
- * 2000-09-28 : low mark in ovdb_expiregroup still wasn't right
- * 2000-09-27 : Further improvements to ovdb_expiregroup: restructured the
- * loop; now updates groupinfo as it goes along rather than
- * counting records at the end, which prevents a possible
- * deadlock.
- * 2000-09-19 : *lo wasn't being set in ovdb_expiregroup
- * 2000-09-15 : added ovdb_check_user(); tweaked some error msgs; fixed an
- * improper use of RENEW
- * 2000-08-28: New major release: version 2.00 (beta)
- * + "groupsbyname" and "groupstats" databases replaced with "groupinfo".
- * + ovdb_recover, ovdb_upgrade, and dbprocs are now deprecated; their
- * functionality is now in ovdb_init and ovdb_monitor.
- * + ovdb_init can upgrade a database from the old version of ovdb to
- * work with this version.
- * + Rewrote ovdb_expiregroup(); it can now re-write OV data rather
- * than simply deleting old keys (which can leave 'holes' that result
- * in inefficient disk-space use).
- * + Add "nocompact" to ovdb.conf, which controls whether ovdb_expiregroup()
- * rewrites OV data.
- * + No longer needs the BerkeleyDB tools db_archive, db_checkpoint, and
- * db_deadlock. That functionality is now in ovdb_monitor.
- * + ovdb_open() won't succeed if ovdb_monitor is not running. This will
- * prevent the problems that happen if the database is not regularly
- * checkpointed and deadlock-tested.
- * + Internal group IDs (32-bit ints) are now reused.
- * + Add "maxlocks" to ovdb.conf, which will set the DB lk_max parameter.
- * + Pull "test" code out into ovdb_stat. ovdb_stat will also provide
- * functionality similar to the BerkeleyDB "db_stat" command.
- * + Update docs: write man pages for the new ovdb_* commands; update
- * ovdb.pod
- *
- * 2000-07-11 : fix possible alignment problem; add test code
- * 2000-07-07 : bugfix: timestamp handling
- * 2000-06-10 : Modified groupnum() interface; fix ovdb_add() to return false
- * for certain groupnum() errors
- * 2000-06-08 : Added BerkeleyDB 3.1.x compatibility
- * 2000-04-09 : Tweak some default parameters; store aliased group info
- * 2000-03-29 : Add DB_RMW flag to the 'get' of get-modify-put sequences
- * 2000-02-17 : Update expire behavior to be consistent with current
- * ov3 and buffindexed
- * 2000-01-13 : Fix to make compatible with unmodified nnrpd/article.c
- * 2000-01-04 : Added data versioning
- * 1999-12-20 : Added BerkeleyDB 3.x compatibility
- * 1999-12-06 : First Release -- H. Kehoe <hakehoe@avalon.net>
- */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/socket.h"
-#include "portable/time.h"
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_LIMITS_H
-# include <limits.h>
-#endif
-#include <pwd.h>
-#include <signal.h>
-#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
-#include <syslog.h>
-
-#include "conffile.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "paths.h"
-#include "storage.h"
-
-#include "ov.h"
-#include "ovinterface.h"
-#include "ovdb.h"
-#include "ovdb-private.h"
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
-# include <sys/un.h>
-#endif
-
-#ifndef USE_BERKELEY_DB
-
-/* Provide stub functions if we don't have db */
-
-bool ovdb_open(int mode UNUSED)
-{
- syslog(L_FATAL, "OVDB: ovdb support not enabled");
- return false;
-}
-
-bool ovdb_groupstats(char *group UNUSED, int *lo UNUSED, int *hi UNUSED, int *count UNUSED, int *flag UNUSED)
-{ return false; }
-
-bool ovdb_groupadd(char *group UNUSED, ARTNUM lo UNUSED, ARTNUM hi UNUSED, char *flag UNUSED)
-{ return false; }
-
-bool ovdb_groupdel(char *group UNUSED)
-{ return false; }
-
-bool ovdb_add(char *group UNUSED, ARTNUM artnum UNUSED, TOKEN token UNUSED, char *data UNUSED, int len UNUSED, time_t arrived UNUSED, time_t expires UNUSED)
-{ return false; }
-
-bool ovdb_cancel(TOKEN token UNUSED)
-{ return false; }
-
-void *ovdb_opensearch(char *group UNUSED, int low UNUSED, int high UNUSED)
-{ return NULL; }
-
-bool ovdb_search(void *handle UNUSED, ARTNUM *artnum UNUSED, char **data UNUSED, int *len UNUSED, TOKEN *token UNUSED, time_t *arrived UNUSED)
-{ return false; }
-
-void ovdb_closesearch(void *handle UNUSED) { }
-
-bool ovdb_getartinfo(char *group UNUSED, ARTNUM artnum UNUSED, TOKEN *token UNUSED)
-{ return false; }
-
-bool ovdb_expiregroup(char *group UNUSED, int *lo UNUSED, struct history *h UNUSED)
-{ return false; }
-
-bool ovdb_ctl(OVCTLTYPE type UNUSED, void *val UNUSED)
-{ return false; }
-
-void ovdb_close(void) { }
-
-#else /* USE_BERKELEY_DB */
-
-#define EXPIREGROUP_TXN_SIZE 100
-#define DELETE_TXN_SIZE 500
-
-struct ovdb_conf ovdb_conf;
-DB_ENV *OVDBenv = NULL;
-int ovdb_errmode = OVDB_ERR_SYSLOG;
-
-static int OVDBmode;
-static bool Cutofflow;
-static DB **dbs = NULL;
-static int oneatatime = 0;
-static int current_db = -1;
-static time_t eo_start = 0;
-static int clientmode = 0;
-
-static DB *groupinfo = NULL;
-static DB *groupaliases = NULL;
-
-#define OVDBtxn_nosync 1
-#define OVDBnumdbfiles 2
-#define OVDBpagesize 3
-#define OVDBcachesize 4
-#define OVDBminkey 5
-#define OVDBmaxlocks 6
-#define OVDBnocompact 7
-#define OVDBreadserver 8
-#define OVDBnumrsprocs 9
-#define OVDBmaxrsconn 10
-#define OVDBuseshm 11
-#define OVDBshmkey 12
-
-static CONFTOKEN toks[] = {
- { OVDBtxn_nosync, "txn_nosync" },
- { OVDBnumdbfiles, "numdbfiles" },
- { OVDBpagesize, "pagesize" },
- { OVDBcachesize, "cachesize" },
- { OVDBminkey, "minkey" },
- { OVDBmaxlocks, "maxlocks" },
- { OVDBnocompact, "nocompact" },
- { OVDBreadserver, "readserver" },
- { OVDBnumrsprocs, "numrsprocs" },
- { OVDBmaxrsconn, "maxrsconn" },
- { OVDBuseshm, "useshm" },
- { OVDBshmkey, "shmkey" },
- { 0, NULL },
-};
-
-#define _PATH_OVDBCONF "ovdb.conf"
-
-/*********** readserver functions ***********/
-
-static int clientfd = -1;
-
-/* read client send and recieve functions. */
-
-static int
-csend(void *data, int n)
-{
- ssize_t status;
-
- if (n == 0)
- return 0;
- status = xwrite(clientfd, data, n);
- if (status < 0)
- syswarn("OVDB: rc: cant write");
- return status;
-}
-
-static int crecv(void *data, int n)
-{
- int r, p = 0;
-
- if(n == 0)
- return 0;
-
- while(p < n) {
- r = read(clientfd, (char *)data + p, n - p);
- if(r <= 0) {
- if(r < 0 && errno == EINTR)
- continue;
- syslog(LOG_ERR, "OVDB: rc: cant read: %m");
- clientfd = -1;
- exit(1);
- }
- p+= r;
- }
- return p;
-}
-
-/* Attempt to connect to the readserver. If anything fails, we
- return -1 so that ovdb_open can open the database directly. */
-
-static int client_connect()
-{
- ssize_t r;
- size_t p = 0;
- char *path;
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- struct sockaddr_un sa;
-#else
- struct sockaddr_in sa;
-#endif
- char banner[sizeof(OVDB_SERVER_BANNER)];
- fd_set fds;
- struct timeval timeout;
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- clientfd = socket(AF_UNIX, SOCK_STREAM, 0);
-#else
- clientfd = socket(AF_INET, SOCK_STREAM, 0);
-#endif
- if(clientfd < 0) {
- syslog(LOG_ERR, "OVDB: rc: socket: %m");
- return -1;
- }
-
-#ifdef HAVE_UNIX_DOMAIN_SOCKETS
- sa.sun_family = AF_UNIX;
- path = concatpath(innconf->pathrun, OVDB_SERVER_SOCKET);
- strlcpy(sa.sun_path, path, sizeof(sa.sun_path));
- free(path);
-#else
- sa.sin_family = AF_INET;
- sa.sin_port = 0;
- sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- bind(clientfd, (struct sockaddr *) &sa, sizeof sa);
- sa.sin_port = htons(OVDB_SERVER_PORT);
-#endif
- if((r = connect(clientfd, (struct sockaddr *) &sa, sizeof sa)) != 0) {
- syslog(LOG_ERR, "OVDB: rc: cant connect to server: %m");
- close(clientfd);
- clientfd = -1;
- return -1;
- }
-
- while(p < sizeof(OVDB_SERVER_BANNER)) {
- FD_ZERO(&fds);
- FD_SET(clientfd, &fds);
- timeout.tv_sec = 30;
- timeout.tv_usec = 0;
-
- r = select(clientfd+1, &fds, NULL, NULL, &timeout);
-
- if(r < 0) {
- if(errno == EINTR)
- continue;
- syslog(LOG_ERR, "OVDB: rc: select: %m");
- close(clientfd);
- clientfd = -1;
- return -1;
- }
- if(r == 0) {
- syslog(LOG_ERR, "OVDB: rc: timeout waiting for server");
- close(clientfd);
- clientfd = -1;
- return -1;
- }
-
- r = read(clientfd, banner + p, sizeof(OVDB_SERVER_BANNER) - p);
- if(r <= 0) {
- if(r < 0 && errno == EINTR)
- continue;
- syslog(LOG_ERR, "OVDB: rc: cant read: %m");
- close(clientfd);
- clientfd = -1;
- return -1;
- }
- p+= r;
- }
-
- if(memcmp(banner, OVDB_SERVER_BANNER, sizeof(OVDB_SERVER_BANNER))) {
- syslog(LOG_ERR, "OVDB: rc: unknown reply from server");
- close(clientfd);
- clientfd = -1;
- return -1;
- }
- return 0;
-}
-
-static void
-client_disconnect(void)
-{
- struct rs_cmd rs;
-
- if (clientfd != -1) {
- rs.what = CMD_QUIT;
- csend(&rs, sizeof(rs));
- }
- clientfd = -1;
-}
-
-
-/*********** internal functions ***********/
-
-#if DB_VERSION_MAJOR == 2
-char *db_strerror(int err)
-{
- switch(err) {
- case DB_RUNRECOVERY:
- return "Recovery Needed";
- default:
- return strerror(err);
- }
-}
-#endif /* DB_VERSION_MAJOR == 2 */
-
-
-static bool conf_bool_val(char *str, bool *value)
-{
- if(strcasecmp(str, "on") == 0
- || strcasecmp(str, "true") == 0
- || strcasecmp(str, "yes") == 0) {
- *value = true;
- return true;
- }
- if(strcasecmp(str, "off") == 0
- || strcasecmp(str, "false") == 0
- || strcasecmp(str, "no") == 0) {
- *value = false;
- return true;
- }
- return false;
-}
-
-static bool conf_long_val(char *str, long *value)
-{
- long v;
-
- errno = 0;
- v = strtol(str, NULL, 10);
- if(v == 0 && errno != 0) {
- return false;
- }
- *value = v;
- return true;
-}
-
-void read_ovdb_conf(void)
-{
- static int confread = 0;
- int done = 0;
- char *path;
- CONFFILE *f;
- CONFTOKEN *tok;
- bool b;
- long l;
-
- if(confread)
- return;
-
- /* defaults */
- ovdb_conf.home = innconf->pathoverview;
- ovdb_conf.txn_nosync = 1;
- ovdb_conf.numdbfiles = 32;
- ovdb_conf.pagesize = 8192;
- ovdb_conf.cachesize = 8000 * 1024;
- ovdb_conf.minkey = 0;
- ovdb_conf.maxlocks = 4000;
- ovdb_conf.nocompact = 1;
- ovdb_conf.readserver = 0;
- ovdb_conf.numrsprocs = 5;
- ovdb_conf.maxrsconn = 0;
- ovdb_conf.useshm = 0;
- ovdb_conf.shmkey = 6400;
-
- path = concatpath(innconf->pathetc, _PATH_OVDBCONF);
- f = CONFfopen(path);
- free(path);
-
- if(f) {
- while(!done && (tok = CONFgettoken(toks, f))) {
- switch(tok->type) {
- case OVDBtxn_nosync:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_bool_val(tok->name, &b)) {
- ovdb_conf.txn_nosync = b;
- }
- break;
- case OVDBnumdbfiles:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 0) {
- ovdb_conf.numdbfiles = l;
- }
- break;
- case OVDBpagesize:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 0) {
- ovdb_conf.pagesize = l;
- }
- break;
- case OVDBcachesize:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 0) {
- ovdb_conf.cachesize = l * 1024;
- }
- break;
- case OVDBminkey:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 1) {
- ovdb_conf.minkey = l;
- }
- break;
- case OVDBmaxlocks:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 0) {
- ovdb_conf.maxlocks = l;
- }
- break;
- case OVDBnocompact:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l >= 0) {
- ovdb_conf.nocompact = l;
- }
- break;
- case OVDBreadserver:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_bool_val(tok->name, &b)) {
- ovdb_conf.readserver = b;
- }
- break;
- case OVDBnumrsprocs:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l > 0) {
- ovdb_conf.numrsprocs = l;
- }
- break;
- case OVDBmaxrsconn:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l >= 0) {
- ovdb_conf.maxrsconn = l;
- }
- break;
- case OVDBuseshm:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_bool_val(tok->name, &b)) {
- ovdb_conf.useshm = b;
- }
- break;
- case OVDBshmkey:
- tok = CONFgettoken(0, f);
- if(!tok) {
- done = 1;
- continue;
- }
- if(conf_long_val(tok->name, &l) && l >= 0) {
- ovdb_conf.shmkey = l;
- }
- break;
- }
- }
- CONFfclose(f);
- }
-
- /* If user did not specify minkey, choose one based on pagesize */
- if(ovdb_conf.minkey == 0) {
- ovdb_conf.minkey = ovdb_conf.pagesize / 2048 - 1;
- if(ovdb_conf.minkey < 2)
- ovdb_conf.minkey = 2;
- }
-
- confread = 1;
-}
-
-
-/* Function that db will use to report errors */
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
-static void OVDBerror(const DB_ENV *dbenv UNUSED, const char *db_errpfx UNUSED, const char *buffer)
-#else
-static void OVDBerror(const char *db_errpfx UNUSED, char *buffer)
-#endif
-{
- switch(ovdb_errmode) {
- case OVDB_ERR_SYSLOG:
- syslog(L_ERROR, "OVDB: %s", buffer);
- break;
- case OVDB_ERR_STDERR:
- fprintf(stderr, "OVDB: %s\n", buffer);
- break;
- }
-}
-
-static u_int32_t _db_flags = 0;
-#if DB_VERSION_MAJOR == 2
-static DB_INFO _dbinfo;
-#endif
-
-static int open_db_file(int which)
-{
- int ret;
- char name[10];
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- DB_TXN *tid;
-#endif
-
- if(dbs[which] != NULL)
- return 0;
-
- snprintf(name, sizeof(name), "ov%05d", which);
-
-#if DB_VERSION_MAJOR == 2
- ret = db_open(name, DB_BTREE, _db_flags, 0666, OVDBenv, &_dbinfo,
- &(dbs[which]));
- if (ret != 0) {
- dbs[which] = NULL;
- return ret;
- }
-#else
- ret = db_create(&(dbs[which]), OVDBenv, 0);
- if (ret != 0)
- return ret;
-
- if(ovdb_conf.minkey > 0)
- (dbs[which])->set_bt_minkey(dbs[which], ovdb_conf.minkey);
- if(ovdb_conf.pagesize > 0)
- (dbs[which])->set_pagesize(dbs[which], ovdb_conf.pagesize);
-
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- TXN_START(t_open_db_file, tid);
- ret = (dbs[which])->open(dbs[which], tid, name, NULL, DB_BTREE, _db_flags,
- 0666);
- if (ret == 0)
- TXN_COMMIT(t_open_db_file, tid);
-#else
- ret = (dbs[which])->open(dbs[which], name, NULL, DB_BTREE, _db_flags,
- 0666);
-#endif
- if (ret != 0) {
- (dbs[which])->close(dbs[which], 0);
- dbs[which] = NULL;
- return ret;
- }
-#endif
- return 0;
-}
-
-static void close_db_file(int which)
-{
- if(which == -1 || dbs[which] == NULL)
- return;
-
- dbs[which]->close(dbs[which], 0);
- dbs[which] = NULL;
-}
-
-static int which_db(char *group)
-{
- HASH grouphash;
- unsigned int i;
-
- grouphash = Hash(group, strlen(group));
- memcpy(&i, &grouphash, sizeof(i));
- return i % ovdb_conf.numdbfiles;
-}
-
-static DB *get_db_bynum(int which)
-{
- int ret;
- if(which >= ovdb_conf.numdbfiles)
- return NULL;
- if(oneatatime) {
- if(which != current_db && current_db != -1)
- close_db_file(current_db);
-
- ret = open_db_file(which);
- if (ret != 0)
- syslog(L_ERROR, "OVDB: open_db_file failed: %s", db_strerror(ret));
-
- current_db = which;
- }
- return(dbs[which]);
-}
-
-
-int ovdb_getgroupinfo(char *group, struct groupinfo *gi, int ignoredeleted, DB_TXN *tid, int getflags)
-{
- int ret;
- DBT key, val;
-
- if(group == NULL) /* just in case */
- return DB_NOTFOUND;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- key.data = group;
- key.size = strlen(group);
- val.data = gi;
- val.ulen = sizeof(struct groupinfo);
- val.flags = DB_DBT_USERMEM;
-
- ret = groupinfo->get(groupinfo, tid, &key, &val, getflags);
- if (ret != 0)
- return ret;
-
- if(val.size != sizeof(struct groupinfo)) {
- syslog(L_ERROR, "OVDB: wrong size for %s groupinfo (%u)",
- group, val.size);
- return DB_NOTFOUND;
- }
-
- if(ignoredeleted && (gi->status & GROUPINFO_DELETED))
- return DB_NOTFOUND;
-
- return 0;
-}
-
-#define GROUPID_MAX_FREELIST 10240
-#define GROUPID_MIN_FREELIST 100
-
-/* allocate a new group ID and return in gno */
-/* must be used in a transaction */
-static int groupid_new(group_id_t *gno, DB_TXN *tid)
-{
- DBT key, val;
- int ret, n;
- group_id_t newgno, *freelist, one;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- key.data = (char *) "!groupid_freelist";
- key.size = sizeof("!groupid_freelist");
-
- ret = groupinfo->get(groupinfo, tid, &key, &val, DB_RMW);
- if (ret != 0) {
- if(ret == DB_NOTFOUND) {
- val.size = sizeof(group_id_t);
- val.data = &one;
- one = 1;
- } else {
- return ret;
- }
- }
-
- if(val.size % sizeof(group_id_t)) {
- syslog(L_ERROR, "OVDB: invalid size (%d) for !groupid_freelist",
- val.size);
- return EINVAL;
- }
-
- n = val.size / sizeof(group_id_t);
- freelist = xmalloc(n * sizeof(group_id_t));
- memcpy(freelist, val.data, val.size);
- if(n <= GROUPID_MIN_FREELIST ) {
- newgno = freelist[n-1];
- (freelist[n-1])++;
- val.data = freelist;
- } else {
- newgno = freelist[0];
- val.data = &(freelist[1]);
- val.size -= sizeof(group_id_t);
- }
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- if (ret != 0) {
- free(freelist);
- return ret;
- }
-
- free(freelist);
- *gno = newgno;
- return 0;
-}
-
-/* mark given group ID as "unused" */
-/* must be used in a transaction */
-static int groupid_free(group_id_t gno, DB_TXN *tid)
-{
- DBT key, val;
- int ret, n, i;
- group_id_t *freelist;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- key.data = (char *) "!groupid_freelist";
- key.size = sizeof("!groupid_freelist");
-
- ret = groupinfo->get(groupinfo, tid, &key, &val, DB_RMW);
- if (ret != 0) {
- return ret;
- }
-
- if(val.size % sizeof(group_id_t)) {
- syslog(L_ERROR, "OVDB: invalid size (%d) for !groupid_freelist",
- val.size);
- return EINVAL;
- }
-
- n = val.size / sizeof(group_id_t);
- if(n > GROUPID_MAX_FREELIST)
- return 0;
- freelist = xmalloc((n + 1) * sizeof(group_id_t));
- memcpy(freelist, val.data, val.size);
-
- if(gno >= freelist[n-1]) { /* shouldn't happen */
- free(freelist);
- return 0;
- }
- for(i = 0; i < n-1; i++) {
- if(gno == freelist[i]) { /* already on freelist */
- free(freelist);
- return 0;
- }
- }
-
- freelist[n] = freelist[n-1];
- freelist[n-1] = gno;
- val.data = freelist;
- val.size += sizeof(group_id_t);
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
-
- free(freelist);
- return ret;
-}
-
-/* Must be called outside of a transaction because it makes its own
- transactions */
-static int delete_all_records(int whichdb, group_id_t gno)
-{
- DB *db;
- DBC *dbcursor;
- DBT key, val;
- struct datakey dk;
- int count;
- int ret;
- DB_TXN *tid;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- memset(&dk, 0, sizeof dk);
-
- db = get_db_bynum(whichdb);
- if(db == NULL)
- return DB_NOTFOUND;
-
- dk.groupnum = gno;
- dk.artnum = 0;
-
- while(1) {
- TXN_START(t_del, tid);
-
- /* get a cursor to traverse the ov records and delete them */
- ret = db->cursor(db, tid, &dbcursor, 0);
- switch(ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_del, tid);
- default:
- TXN_ABORT(t_del, tid);
- syslog(L_ERROR, "OVDB: delete_all_records: db->cursor: %s", db_strerror(ret));
- return ret;
- }
-
- key.data = &dk;
- key.size = sizeof dk;
- val.flags = DB_DBT_PARTIAL;
-
- for(count = 0; count < DELETE_TXN_SIZE; count++) {
- ret = dbcursor->c_get(dbcursor, &key, &val,
- count ? DB_NEXT : DB_SET_RANGE);
- switch (ret)
- {
- case 0:
- break;
- case DB_NOTFOUND:
- dbcursor->c_close(dbcursor);
- TXN_COMMIT(t_del, tid);
- return 0;
- case TRYAGAIN:
- dbcursor->c_close(dbcursor);
- TXN_RETRY(t_del, tid);
- default:
- warn("OVDB: delete_all_records: DBcursor->c_get: %s",
- db_strerror(ret));
- dbcursor->c_close(dbcursor);
- TXN_ABORT(t_del, tid);
- return ret;
- }
-
- if(key.size == sizeof dk
- && memcmp(key.data, &gno, sizeof gno)) {
- break;
- }
-
- ret = dbcursor->c_del(dbcursor, 0);
- switch (ret) {
- case 0:
- case DB_KEYEMPTY:
- break;
- case TRYAGAIN:
- dbcursor->c_close(dbcursor);
- TXN_RETRY(t_del, tid);
- default:
- warn("OVDB: delete_all_records: DBcursor->c_del: %s",
- db_strerror(ret));
- dbcursor->c_close(dbcursor);
- TXN_ABORT(t_del, tid);
- return ret;
- }
- }
- dbcursor->c_close(dbcursor);
- TXN_COMMIT(t_del, tid);
- if(count < DELETE_TXN_SIZE) {
- break;
- }
- }
- return 0;
-}
-
-/* Make a temporary groupinfo key using the given db number and group ID.
- Must be called in a transaction */
-static int
-mk_temp_groupinfo(int whichdb, group_id_t gno, DB_TXN *tid)
-{
- char keystr[1 + sizeof gno];
- DBT key, val;
- struct groupinfo gi;
- int ret;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- memset(&gi, 0, sizeof gi);
-
- keystr[0] = 0;
- memcpy(keystr + 1, &gno, sizeof gno);
-
- gi.current_db = whichdb;
- gi.current_gid = gno;
- gi.status = GROUPINFO_DELETED;
-
- key.data = keystr;
- key.size = sizeof keystr;
- val.data = &gi;
- val.size = sizeof gi;
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- switch (ret) {
- case 0:
- break;
- default:
- syslog(L_ERROR, "OVDB: mk_temp_groupinfo: groupinfo->put: %s", db_strerror(ret));
- case TRYAGAIN:
- return ret;
- }
-
- return 0;
-}
-
-/* Delete a temporary groupinfo key created by mk_temp_groupid, then
- frees the group id.
- Must NOT be called within a transaction. */
-static int
-rm_temp_groupinfo(group_id_t gno)
-{
- char keystr[1 + sizeof gno];
- DB_TXN *tid;
- DBT key;
- int ret;
-
- memset(&key, 0, sizeof key);
-
- keystr[0] = 0;
- memcpy(keystr + 1, &gno, sizeof gno);
-
- key.data = keystr;
- key.size = sizeof keystr;
-
- TXN_START(t_tmp, tid);
-
- ret = groupinfo->del(groupinfo, tid, &key, 0);
- switch(ret) {
- case 0:
- case DB_NOTFOUND:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_tmp, tid);
- default:
- TXN_ABORT(t_tmp, tid);
- syslog(L_ERROR, "OVDB: rm_temp_groupinfo: groupinfo->del: %s", db_strerror(ret));
- return ret;
- }
-
- switch(groupid_free(gno, tid)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_tmp, tid);
- default:
- TXN_ABORT(t_tmp, tid);
- syslog(L_ERROR, "OVDB: rm_temp_groupinfo: groupid_free: %s", db_strerror(ret));
- return ret;
- }
-
- TXN_COMMIT(t_tmp, tid);
- return 0;
-}
-
-/* This function deletes overview records for deleted or forgotton groups */
-/* argument: 0 = process deleted groups 1 = process forgotton groups */
-static bool delete_old_stuff(int forgotton)
-{
- DBT key, val;
- DBC *cursor;
- DB_TXN *tid;
- struct groupinfo gi;
- char **dellist = NULL;
- size_t *dellistsz = NULL;
- int listlen, listcount;
- int i, ret;
-
- TXN_START(t_dellist, tid);
- if (dellist != NULL) {
- for (i = 0; i < listcount; ++i)
- free(dellist[i]);
- free(dellist);
- }
- if (dellistsz != NULL)
- free(dellistsz);
- listlen = 20;
- listcount = 0;
- dellist = xmalloc(listlen * sizeof(char *));
- dellistsz = xmalloc(listlen * sizeof(size_t));
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- val.data = &gi;
- val.ulen = val.dlen = sizeof gi;
- val.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
-
- /* get a cursor to traverse all of the groupinfo records */
- ret = groupinfo->cursor(groupinfo, tid, &cursor, 0);
- if (ret != 0) {
- syslog(L_ERROR, "OVDB: delete_old_stuff: groupinfo->cursor: %s", db_strerror(ret));
- free(dellist);
- free(dellistsz);
- return false;
- }
-
- while((ret = cursor->c_get(cursor, &key, &val, DB_NEXT)) == 0) {
- if(key.size == sizeof("!groupid_freelist") &&
- !strcmp("!groupid_freelist", key.data))
- continue;
- if(val.size != sizeof(struct groupinfo)) {
- syslog(L_ERROR, "OVDB: delete_old_stuff: wrong size for groupinfo record");
- continue;
- }
- if((!forgotton && (gi.status & GROUPINFO_DELETED))
- || (forgotton && (gi.expired < eo_start))) {
- dellist[listcount] = xmalloc(key.size);
- memcpy(dellist[listcount], key.data, key.size);
- dellistsz[listcount] = key.size;
- listcount++;
- if(listcount >= listlen) {
- listlen += 20;
- dellist = xrealloc(dellist, listlen * sizeof(char *));
- dellistsz = xrealloc(dellistsz, listlen * sizeof(size_t));
- }
- }
- }
- cursor->c_close(cursor);
- switch (ret) {
- case 0:
- case DB_NOTFOUND:
- TXN_COMMIT(t_dellist, tid);
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dellist, tid);
- default:
- TXN_ABORT(t_dellist, tid);
- syslog(L_ERROR, "OVDB: delete_old_stuff: cursor->c_get: %s", db_strerror(ret));
- for (i = 0; i < listcount; ++i)
- free(dellist[i]);
- free(dellist);
- free(dellistsz);
- return false;
- }
-
- for(i = 0; i < listcount; i++) {
- TXN_START(t_dos, tid);
-
- /* Can't use ovdb_getgroupinfo here */
- key.data = dellist[i];
- key.size = dellistsz[i];
- val.data = &gi;
- val.ulen = sizeof(struct groupinfo);
- val.flags = DB_DBT_USERMEM;
-
- ret = groupinfo->get(groupinfo, tid, &key, &val, 0);
-
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dos, tid);
- case DB_NOTFOUND:
- TXN_ABORT(t_dos, tid);
- continue;
- default:
- syslog(L_ERROR, "OVDB: delete_old_stuff: groupinfo->get: %s\n", db_strerror(ret));
- TXN_ABORT(t_dos, tid);
- continue;
- }
- if(val.size != sizeof(struct groupinfo)) {
- TXN_ABORT(t_dos, tid);
- continue;
- }
-
- /* This if() is true if this ISN'T a key created by mk_temp_groupinfo */
- if(*((char *)key.data) != 0 || key.size != 1 + sizeof(group_id_t)) {
-
- switch(mk_temp_groupinfo(gi.current_db, gi.current_gid, tid)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dos, tid);
- default:
- TXN_ABORT(t_dos, tid);
- continue;
- }
- if(gi.status & GROUPINFO_MOVING) {
- switch(mk_temp_groupinfo(gi.new_db, gi.new_gid, tid)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dos, tid);
- default:
- TXN_ABORT(t_dos, tid);
- continue;
- }
- }
-
- /* delete the corresponding groupaliases record (if exists) */
- switch(groupaliases->del(groupaliases, tid, &key, 0)) {
- case 0:
- case DB_NOTFOUND:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dos, tid);
- default:
- TXN_ABORT(t_dos, tid);
- continue;
- }
-
- switch(groupinfo->del(groupinfo, tid, &key, 0)) {
- case 0:
- case DB_NOTFOUND:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_dos, tid);
- default:
- TXN_ABORT(t_dos, tid);
- continue;
- }
- }
-
- TXN_COMMIT(t_dos, tid);
-
- if(delete_all_records(gi.current_db, gi.current_gid) == 0) {
- rm_temp_groupinfo(gi.current_gid);
- }
- if(gi.status & GROUPINFO_MOVING) {
- if(delete_all_records(gi.new_db, gi.new_gid) == 0) {
- rm_temp_groupinfo(gi.new_gid);
- }
- }
- }
-out:
- for(i = 0; i < listcount; i++)
- free(dellist[i]);
- free(dellist);
- free(dellistsz);
- return true;
-}
-
-static int count_records(struct groupinfo *gi)
-{
- int ret;
- DB *db;
- DBC *cursor;
- DBT key, val;
- struct datakey dk;
- u_int32_t artnum, newlow = 0;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- memset(&dk, 0, sizeof dk);
-
- db = get_db_bynum(gi->current_db);
- if(db == NULL)
- return DB_NOTFOUND;
-
- dk.groupnum = gi->current_gid;
- dk.artnum = 0;
- key.data = &dk;
- key.size = key.ulen = sizeof dk;
- key.flags = DB_DBT_USERMEM;
- val.flags = DB_DBT_PARTIAL;
-
- gi->count = 0;
-
- ret = db->cursor(db, NULL, &cursor, 0);
- if (ret)
- return ret;
-
- ret = cursor->c_get(cursor, &key, &val, DB_SET_RANGE);
- switch (ret)
- {
- case 0:
- case DB_NOTFOUND:
- break;
- default:
- cursor->c_close(cursor);
- return ret;
- }
- while(ret == 0 && key.size == sizeof(dk) && dk.groupnum == gi->current_gid) {
- artnum = ntohl(dk.artnum);
- if(newlow == 0 || newlow > artnum)
- newlow = artnum;
- if(artnum > gi->high)
- gi->high = artnum;
- gi->count++;
-
- ret = cursor->c_get(cursor, &key, &val, DB_NEXT);
- }
- cursor->c_close(cursor);
- if(gi->count == 0)
- gi->low = gi->high + 1;
- else
- gi->low = newlow;
-
- if(ret == DB_NOTFOUND)
- return 0;
- return ret;
-}
-
-
-/*
- * Locking: OVopen() calls ovdb_getlock(OVDB_LOCK_NORMAL). This
- * aquires a read (shared) lock on the lockfile. Multiple processes
- * can have this file locked at the same time. That way, if there
- * are any processes that are using the database, the lock file will
- * have one or more shared locks on it.
- *
- * ovdb_init, when starting, calls ovdb_getlock(OVDB_LOCK_EXCLUSIVE).
- * This tries to get a write (exclusive) lock, which will fail if
- * anyone has a shared lock. This way, ovdb_init can tell if there
- * are any processes using the database. If not, and the excl. lock
- * succeeds, ovdb_init is free to do DB_RUNRECOVER.
- *
- * ovdb_getlock() in the "normal" lock mode calls ovdb_check_monitor,
- * which looks for the OVDB_MONITOR_PIDFILE. If said file does not
- * exist, or the PID in it does not exist, it will fail. This will
- * prevent OVopen() from opening the database if ovdb_monitor is not running.
- *
- * The OVDB_LOCK_ADMIN mode is used by ovdb_monitor to get a shared lock
- * without testing the pidfile.
- */
-static int lockfd = -1;
-bool ovdb_getlock(int mode)
-{
- if(lockfd == -1) {
- char *lockfn = concatpath(innconf->pathrun, OVDB_LOCKFN);
- lockfd = open(lockfn,
- mode == OVDB_LOCK_NORMAL ? O_RDWR : O_CREAT|O_RDWR, 0660);
- if(lockfd == -1) {
- free(lockfn);
- if(errno == ENOENT)
- syslog(L_FATAL, "OVDB: can not open database unless ovdb_monitor is running.");
- return false;
- }
- close_on_exec(lockfd, true);
- free(lockfn);
- } else
- return true;
-
- if(mode == OVDB_LOCK_NORMAL) {
- if(!ovdb_check_pidfile(OVDB_MONITOR_PIDFILE)) {
- syslog(L_FATAL, "OVDB: can not open database unless ovdb_monitor is running.");
- return false;
- }
- }
- if(mode == OVDB_LOCK_EXCLUSIVE) {
- if(!inn_lock_file(lockfd, INN_LOCK_WRITE, false)) {
- close(lockfd);
- lockfd = -1;
- return false;
- }
- return true;
- } else {
- if(!inn_lock_file(lockfd, INN_LOCK_READ, false)) {
- close(lockfd);
- lockfd = -1;
- return false;
- }
- return true;
- }
-}
-
-bool ovdb_releaselock(void)
-{
- bool r;
- if(lockfd == -1)
- return true;
- r = inn_lock_file(lockfd, INN_LOCK_UNLOCK, false);
- close(lockfd);
- lockfd = -1;
- return r;
-}
-
-bool ovdb_check_pidfile(char *file)
-{
- int f, pid;
- char buf[SMBUF];
- char *pidfn = concatpath(innconf->pathrun, file);
-
- f = open(pidfn, O_RDONLY);
- if(f == -1) {
- if(errno != ENOENT)
- syslog(L_FATAL, "OVDB: can't open %s: %m", pidfn);
- free(pidfn);
- return false;
- }
- memset(buf, 0, SMBUF);
- if(read(f, buf, SMBUF-1) < 0) {
- syslog(L_FATAL, "OVDB: can't read from %s: %m", pidfn);
- free(pidfn);
- close(f);
- return false;
- }
- close(f);
- free(pidfn);
- pid = atoi(buf);
- if(pid <= 1) {
- return false;
- }
- if(kill(pid, 0) < 0 && errno == ESRCH) {
- return false;
- }
- return true;
-}
-
-/* make sure the effective uid is that of NEWSUSER */
-bool ovdb_check_user(void)
-{
- struct passwd *p;
- static int result = -1;
-
- if(result == -1) {
- p = getpwnam(NEWSUSER);
- if(!p) {
- syslog(L_FATAL, "OVDB: getpwnam(" NEWSUSER ") failed: %m");
- return false;
- }
- result = (p->pw_uid == geteuid());
- }
- return result;
-}
-
-static int check_version(void)
-{
- int ret;
- DB *vdb;
- DBT key, val;
- u_int32_t dv;
-
-#if DB_VERSION_MAJOR == 2
- DB_INFO dbinfo;
- memset(&dbinfo, 0, sizeof dbinfo);
-
- ret = db_open("version", DB_BTREE, _db_flags, 0666, OVDBenv, &dbinfo,
- &vdb);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: db_open failed: %s", db_strerror(ret));
- return ret;
- }
-#else
- /* open version db */
- ret = db_create(&vdb, OVDBenv, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open: db_create: %s", db_strerror(ret));
- return ret;
- }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- ret = vdb->open(vdb, NULL, "version", NULL, DB_BTREE, _db_flags, 0666);
-#else
- ret = vdb->open(vdb, "version", NULL, DB_BTREE, _db_flags, 0666);
-#endif
- if (ret != 0) {
- vdb->close(vdb, 0);
- syslog(L_FATAL, "OVDB: open: version->open: %s", db_strerror(ret));
- return ret;
- }
-#endif
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- key.data = (char *) "dataversion";
- key.size = sizeof("dataversion");
- ret = vdb->get(vdb, NULL, &key, &val, 0);
- if (ret != 0) {
- if(ret != DB_NOTFOUND) {
- syslog(L_FATAL, "OVDB: open: can't retrieve version: %s", db_strerror(ret));
- vdb->close(vdb, 0);
- return ret;
- }
- }
- if(ret == DB_NOTFOUND || val.size != sizeof dv) {
- dv = DATA_VERSION;
- if(!(OVDBmode & OV_WRITE)) {
- vdb->close(vdb, 0);
- return EACCES;
- }
- val.data = &dv;
- val.size = sizeof dv;
- ret = vdb->put(vdb, NULL, &key, &val, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open: can't store version: %s", db_strerror(ret));
- vdb->close(vdb, 0);
- return ret;
- }
- } else
- memcpy(&dv, val.data, sizeof dv);
-
- if(dv > DATA_VERSION) {
- syslog(L_FATAL, "OVDB: can't open database: unknown version %d", dv);
- vdb->close(vdb, 0);
- return EINVAL;
- }
- if(dv < DATA_VERSION) {
- syslog(L_FATAL, "OVDB: database is an old version, please run ovdb_init");
- vdb->close(vdb, 0);
- return EINVAL;
- }
-
- /* The version db also stores some config values, which will override the
- corresponding ovdb.conf setting. */
-
- key.data = (char *) "numdbfiles";
- key.size = sizeof("numdbfiles");
- ret = vdb->get(vdb, NULL, &key, &val, 0);
- if (ret != 0) {
- if(ret != DB_NOTFOUND) {
- syslog(L_FATAL, "OVDB: open: can't retrieve numdbfiles: %s", db_strerror(ret));
- vdb->close(vdb, 0);
- return ret;
- }
- }
- if(ret == DB_NOTFOUND || val.size != sizeof(ovdb_conf.numdbfiles)) {
- if(!(OVDBmode & OV_WRITE)) {
- vdb->close(vdb, 0);
- return EACCES;
- }
- val.data = &(ovdb_conf.numdbfiles);
- val.size = sizeof(ovdb_conf.numdbfiles);
- ret = vdb->put(vdb, NULL, &key, &val, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open: can't store numdbfiles: %s", db_strerror(ret));
- vdb->close(vdb, 0);
- return ret;
- }
- } else {
- memcpy(&(ovdb_conf.numdbfiles), val.data, sizeof(ovdb_conf.numdbfiles));
- }
-
- vdb->close(vdb, 0);
- return 0;
-}
-
-
-int ovdb_open_berkeleydb(int mode, int flags)
-{
- int ret;
- u_int32_t ai_flags = DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_MPOOL|DB_INIT_TXN;
-
- OVDBmode = mode;
- read_ovdb_conf();
-
- if(OVDBenv != NULL)
- return 0; /* already opened */
-
- if(OVDBmode & OV_WRITE) {
- _db_flags |= DB_CREATE;
- ai_flags |= DB_CREATE;
- } else {
- _db_flags |= DB_RDONLY;
- }
- if(flags & OVDB_RECOVER)
- ai_flags |= DB_RECOVER;
-
-#if DB_VERSION_MAJOR == 2 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 2)
- if(ovdb_conf.txn_nosync)
- ai_flags |= DB_TXN_NOSYNC;
-#endif
-
-#if DB_VERSION_MAJOR == 2
-
- OVDBenv = xcalloc(1, sizeof(DB_ENV));
-
- OVDBenv->db_errcall = OVDBerror;
- OVDBenv->mp_size = ovdb_conf.cachesize;
- OVDBenv->lk_max = ovdb_conf.maxlocks;
-
- /* initialize environment */
- ret = db_appinit(ovdb_conf.home, NULL, OVDBenv, ai_flags);
- if (ret != 0) {
- free(OVDBenv);
- OVDBenv = NULL;
- syslog(L_FATAL, "OVDB: db_appinit failed: %s", db_strerror(ret));
- return ret;
- }
-#else
- ret = db_env_create(&OVDBenv, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: db_env_create: %s", db_strerror(ret));
- return ret;
- }
-
- if((flags & (OVDB_UPGRADE | OVDB_RECOVER)) == (OVDB_UPGRADE | OVDB_RECOVER))
- ai_flags |= DB_PRIVATE;
- if(!(ai_flags & DB_PRIVATE)) {
- if(ovdb_conf.useshm)
- ai_flags |= DB_SYSTEM_MEM;
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 0)
- OVDBenv->set_shm_key(OVDBenv, ovdb_conf.shmkey);
-#endif
- }
-
- OVDBenv->set_errcall(OVDBenv, OVDBerror);
- OVDBenv->set_cachesize(OVDBenv, 0, ovdb_conf.cachesize, 1);
-#if DB_VERSION_MAJOR >= 4
- OVDBenv->set_lk_max_locks(OVDBenv, ovdb_conf.maxlocks);
- OVDBenv->set_lk_max_lockers(OVDBenv, ovdb_conf.maxlocks);
- OVDBenv->set_lk_max_objects(OVDBenv, ovdb_conf.maxlocks);
-#else
- OVDBenv->set_lk_max(OVDBenv, ovdb_conf.maxlocks);
-#endif
-
-#if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
- if(ovdb_conf.txn_nosync)
- OVDBenv->set_flags(OVDBenv, DB_TXN_NOSYNC, 1);
-#endif
-
- if((flags & (OVDB_UPGRADE | OVDB_RECOVER)) != OVDB_UPGRADE) {
-#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
- ret = OVDBenv->open(OVDBenv, ovdb_conf.home, NULL, ai_flags, 0666);
-#else
- ret = OVDBenv->open(OVDBenv, ovdb_conf.home, ai_flags, 0666);
-#endif
- if (ret != 0) {
- OVDBenv->close(OVDBenv, 0);
- OVDBenv = NULL;
- syslog(L_FATAL, "OVDB: OVDBenv->open: %s", db_strerror(ret));
- return ret;
- }
- }
-#endif /* DB_VERSION_MAJOR == 2 */
-
- return 0;
-}
-
-bool ovdb_open(int mode)
-{
- int i, ret;
-#if DB_VERSION_MAJOR == 2
- DB_INFO dbinfo;
-#else
- DB_TXN *tid;
-#endif
-
- if(OVDBenv != NULL || clientmode) {
- syslog(L_ERROR, "OVDB: ovdb_open called more than once");
- return false;
- }
-
- read_ovdb_conf();
- if(ovdb_conf.readserver && mode == OV_READ)
- clientmode = 1;
-
- if(mode & OVDB_SERVER)
- clientmode = 0;
-
- if(clientmode) {
- if(client_connect() == 0)
- return true;
- clientmode = 0;
- }
- if(!ovdb_check_user()) {
- syslog(L_FATAL, "OVDB: must be running as " NEWSUSER " to access overview.");
- return false;
- }
- if(!ovdb_getlock(OVDB_LOCK_NORMAL)) {
- syslog(L_FATAL, "OVDB: ovdb_getlock failed: %m");
- return false;
- }
-
- if(ovdb_open_berkeleydb(mode, 0) != 0)
- return false;
-
- if(check_version() != 0)
- return false;
-
- if(mode & OV_WRITE || mode & OVDB_SERVER) {
- oneatatime = 0;
- } else {
- oneatatime = 1;
- }
-
-#if DB_VERSION_MAJOR == 2
- memset(&_dbinfo, 0, sizeof _dbinfo);
- _dbinfo.db_pagesize = ovdb_conf.pagesize;
- _dbinfo.bt_minkey = ovdb_conf.minkey;
-#endif
-
- dbs = xcalloc(ovdb_conf.numdbfiles, sizeof(DB *));
-
- if(!oneatatime) {
- for(i = 0; i < ovdb_conf.numdbfiles; i++) {
- ret = open_db_file(i);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open_db_file failed: %s", db_strerror(ret));
- return false;
- }
- }
- }
-
-#if DB_VERSION_MAJOR == 2
- memset(&dbinfo, 0, sizeof dbinfo);
-
- ret = db_open("groupinfo", DB_BTREE, _db_flags, 0666, OVDBenv,
- &dbinfo, &groupinfo);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: db_open failed: %s", db_strerror(ret));
- return false;
- }
-
- ret = db_open("groupaliases", DB_HASH, _db_flags, 0666, OVDBenv,
- &dbinfo, &groupaliases);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: db_open failed: %s", db_strerror(ret));
- return false;
- }
-#else
- ret = db_create(&groupinfo, OVDBenv, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open: db_create: %s", db_strerror(ret));
- return false;
- }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- TXN_START(t_open_groupinfo, tid);
- ret = groupinfo->open(groupinfo, tid, "groupinfo", NULL, DB_BTREE,
- _db_flags, 0666);
- if (ret == 0)
- TXN_COMMIT(t_open_groupinfo, tid);
-#else
- ret = groupinfo->open(groupinfo, "groupinfo", NULL, DB_BTREE,
- _db_flags, 0666);
-#endif
- if (ret != 0) {
- groupinfo->close(groupinfo, 0);
- syslog(L_FATAL, "OVDB: open: groupinfo->open: %s", db_strerror(ret));
- return false;
- }
- ret = db_create(&groupaliases, OVDBenv, 0);
- if (ret != 0) {
- syslog(L_FATAL, "OVDB: open: db_create: %s", db_strerror(ret));
- return false;
- }
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
- TXN_START(t_open_groupaliases, tid);
- ret = groupaliases->open(groupaliases, tid, "groupaliases", NULL, DB_HASH,
- _db_flags, 0666);
- if (ret == 0)
- TXN_COMMIT(t_open_groupaliases, tid);
-#else
- ret = groupaliases->open(groupaliases, "groupaliases", NULL, DB_HASH,
- _db_flags, 0666);
-#endif
- if (ret != 0) {
- groupaliases->close(groupaliases, 0);
- syslog(L_FATAL, "OVDB: open: groupaliases->open: %s", db_strerror(ret));
- return false;
- }
-#endif
-
- Cutofflow = false;
- return true;
-}
-
-
-bool
-ovdb_groupstats(char *group, int *lo, int *hi, int *count, int *flag)
-{
- int ret;
- struct groupinfo gi;
-
- if (clientmode) {
- struct rs_cmd rs;
- struct rs_groupstats repl;
-
- rs.what = CMD_GROUPSTATS;
- rs.grouplen = strlen(group)+1;
-
- if (csend(&rs, sizeof(rs)) < 0)
- return false;
- if (csend(group, rs.grouplen) < 0)
- return false;
- crecv(&repl, sizeof(repl));
-
- if(repl.status != CMD_GROUPSTATS)
- return false;
-
- /* we don't use the alias yet, but the OV API will be extended
- at some point so that the alias is returned also */
- if(repl.aliaslen != 0) {
- char *buf = xmalloc(repl.aliaslen);
- crecv(buf, repl.aliaslen);
- free(buf);
- }
-
- if(lo)
- *lo = repl.lo;
- if(hi)
- *hi = repl.hi;
- if(count)
- *count = repl.count;
- if(flag)
- *flag = repl.flag;
- return true;
- }
-
- ret = ovdb_getgroupinfo(group, &gi, true, NULL, 0);
- switch (ret)
- {
- case 0:
- break;
- case DB_NOTFOUND:
- return false;
- default:
- syslog(L_ERROR, "OVDB: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- return false;
- }
-
- if(lo != NULL)
- *lo = gi.low;
- if(hi != NULL)
- *hi = gi.high;
- if(count != NULL)
- *count = gi.count;
- if(flag != NULL)
- *flag = gi.flag;
- return true;
-}
-
-bool ovdb_groupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag)
-{
- DBT key, val;
- struct groupinfo gi;
- DB_TXN *tid;
- int ret = 0;
- int new;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- TXN_START(t_groupadd, tid);
-
- if(tid==NULL)
- return false;
-
- new = 0;
- ret = ovdb_getgroupinfo(group, &gi, false, tid, DB_RMW);
- switch (ret)
- {
- case DB_NOTFOUND:
- new = 1;
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- return false;
- }
-
- if(!new && (gi.status & GROUPINFO_DELETED)
- && !(gi.status & GROUPINFO_EXPIRING)
- && !(gi.status & GROUPINFO_MOVING)) {
- int s, c = 0;
- char g[MAXHEADERSIZE];
-
- strlcpy(g, group, sizeof(g));
- s = strlen(g) + 1;
- key.data = g;
- key.size = s + sizeof(int);
- do {
- c++;
- memcpy(g+s, &c, sizeof(int));
- ret = groupinfo->get(groupinfo, tid, &key, &val, 0);
- } while(ret == 0);
- if(ret == TRYAGAIN) {
- TXN_RETRY(t_groupadd, tid);
- }
- val.data = &gi;
- val.size = sizeof(gi);
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
- key.data = group;
- key.size = strlen(group);
- ret = groupinfo->del(groupinfo, tid, &key, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: groupinfo->del: %s", db_strerror(ret));
- return false;
- }
- new = 1;
- }
-
- if(new) {
- ret = groupid_new(&gi.current_gid, tid);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: groupid_new: %s", db_strerror(ret));
- return false;
- }
- gi.low = lo ? lo : 1;
- gi.high = hi;
- gi.count = 0;
- gi.flag = *flag;
- gi.expired = time(NULL);
- gi.expiregrouppid = 0;
- gi.current_db = gi.new_db = which_db(group);
- gi.new_gid = gi.current_gid;
- gi.status = 0;
- } else {
- gi.flag = *flag;
- }
-
- key.data = group;
- key.size = strlen(group);
- val.data = &gi;
- val.size = sizeof gi;
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- switch (ret) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: groupadd: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
-
- if(*flag == '=') {
- key.data = group;
- key.size = strlen(group);
- val.data = flag + 1;
- val.size = strcspn(flag, "\n") - 1;
-
- switch(ret = groupaliases->put(groupaliases, tid, &key, &val, 0)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupadd, tid);
- default:
- TXN_ABORT(t_groupadd, tid);
- syslog(L_ERROR, "OVDB: groupadd: groupaliases->put: %s", db_strerror(ret));
- return false;
- }
- }
-
- TXN_COMMIT(t_groupadd, tid);
- return true;
-}
-
-bool ovdb_groupdel(char *group)
-{
- DBT key, val;
- struct groupinfo gi;
- DB_TXN *tid;
- int ret = 0;
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- /* We only need to set the deleted flag in groupinfo to prevent readers
- from seeing this group. The actual overview records aren't deleted
- now, since that could take a significant amount of time (and innd
- is who normally calls this function). The expireover run will
- clean up the deleted groups. */
-
- TXN_START(t_groupdel, tid);
-
- if(tid==NULL)
- return false;
-
- ret = ovdb_getgroupinfo(group, &gi, true, tid, DB_RMW);
- switch (ret)
- {
- case DB_NOTFOUND:
- return true;
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupdel, tid);
- default:
- syslog(L_ERROR, "OVDB: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- TXN_ABORT(t_groupdel, tid);
- return false;
- }
-
- gi.status |= GROUPINFO_DELETED;
-
- key.data = group;
- key.size = strlen(group);
- val.data = &gi;
- val.size = sizeof gi;
-
- switch(ret = groupinfo->put(groupinfo, tid, &key, &val, 0)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupdel, tid);
- default:
- TXN_ABORT(t_groupdel, tid);
- syslog(L_ERROR, "OVDB: groupadd: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
-
- switch(ret = groupaliases->del(groupaliases, tid, &key, 0)) {
- case 0:
- case DB_NOTFOUND:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_groupdel, tid);
- default:
- syslog(L_ERROR, "OVDB: groupdel: groupaliases->del: %s", db_strerror(ret));
- TXN_ABORT(t_groupdel, tid);
- return false;
- }
-
- TXN_COMMIT(t_groupdel, tid);
- return true;
-}
-
-bool ovdb_add(char *group, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires)
-{
- static size_t databuflen = 0;
- static char *databuf;
- DB *db;
- DBT key, val;
- DB_TXN *tid;
- struct groupinfo gi;
- struct datakey dk;
- int ret = 0;
-
- memset(&dk, 0, sizeof dk);
-
- if(databuflen == 0) {
- databuflen = BIG_BUFFER;
- databuf = xmalloc(databuflen);
- }
- if(databuflen < len + sizeof(struct ovdata)) {
- databuflen = len + sizeof(struct ovdata);
- databuf = xrealloc(databuf, databuflen);
- }
-
- /* hmm... BerkeleyDB needs something like a 'struct iovec' so that we don't
- have to make a new buffer and copy everything in to it */
-
- ((struct ovdata *)databuf)->token = token;
- ((struct ovdata *)databuf)->arrived = arrived;
- ((struct ovdata *)databuf)->expires = expires;
- memcpy(databuf + sizeof(struct ovdata), data, len);
- len += sizeof(struct ovdata);
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- /* start the transaction */
- TXN_START(t_add, tid);
-
- if(tid==NULL)
- return false;
-
- /* first, retrieve groupinfo */
- ret = ovdb_getgroupinfo(group, &gi, true, tid, DB_RMW);
- switch (ret)
- {
- case 0:
- break;
- case DB_NOTFOUND:
- TXN_ABORT(t_add, tid);
- return true;
- case TRYAGAIN:
- TXN_RETRY(t_add, tid);
- default:
- TXN_ABORT(t_add, tid);
- syslog(L_ERROR, "OVDB: add: ovdb_getgroupinfo: %s", db_strerror(ret));
- return false;
- }
-
- /* adjust groupinfo */
- if(Cutofflow && gi.low > artnum) {
- TXN_ABORT(t_add, tid);
- return true;
- }
- if(gi.low == 0 || gi.low > artnum)
- gi.low = artnum;
- if(gi.high < artnum)
- gi.high = artnum;
- gi.count++;
-
- /* store groupinfo */
- key.data = group;
- key.size = strlen(group);
- val.data = &gi;
- val.size = sizeof gi;
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_add, tid);
- default:
- TXN_ABORT(t_add, tid);
- syslog(L_ERROR, "OVDB: add: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
-
- /* store overview */
- db = get_db_bynum(gi.current_db);
- if(db == NULL) {
- TXN_ABORT(t_add, tid);
- return false;
- }
- dk.groupnum = gi.current_gid;
- dk.artnum = htonl((u_int32_t)artnum);
-
- key.data = &dk;
- key.size = sizeof dk;
- val.data = databuf;
- val.size = len;
-
- ret = db->put(db, tid, &key, &val, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_add, tid);
- default:
- TXN_ABORT(t_add, tid);
- syslog(L_ERROR, "OVDB: add: db->put: %s", db_strerror(ret));
- return false;
- }
-
- if(artnum < gi.high && gi.status & GROUPINFO_MOVING) {
- /* If the GROUPINFO_MOVING flag is set, then expireover
- is writing overview records under a new groupid.
- If this overview record is not at the highmark,
- we need to also store it under the new groupid */
- db = get_db_bynum(gi.new_db);
- if(db == NULL) {
- TXN_ABORT(t_add, tid);
- return false;
- }
- dk.groupnum = gi.new_gid;
-
- ret = db->put(db, tid, &key, &val, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_add, tid);
- default:
- TXN_ABORT(t_add, tid);
- syslog(L_ERROR, "OVDB: add: db->put: %s", db_strerror(ret));
- return false;
- }
- }
-
- TXN_COMMIT(t_add, tid);
- return true;
-}
-
-bool ovdb_cancel(TOKEN token UNUSED)
-{
- return true;
-}
-
-struct ovdbsearch {
- DBC *cursor;
- group_id_t gid;
- u_int32_t firstart;
- u_int32_t lastart;
- int state;
-};
-
-/* Even though nnrpd only does one search at a time, a read server process could
- do many concurrent searches; hence we must keep track of an arbitrary number of
- open searches */
-static struct ovdbsearch **searches = NULL;
-static int nsearches = 0;
-static int maxsearches = 0;
-
-void *
-ovdb_opensearch(char *group, int low, int high)
-{
- DB *db;
- struct ovdbsearch *s;
- struct groupinfo gi;
- int ret;
-
- if(clientmode) {
- struct rs_cmd rs;
- struct rs_opensrch repl;
-
- rs.what = CMD_OPENSRCH;
- rs.grouplen = strlen(group)+1;
- rs.artlo = low;
- rs.arthi = high;
-
- if (csend(&rs, sizeof(rs)) < 0)
- return NULL;
- if (csend(group, rs.grouplen) < 0)
- return NULL;
- crecv(&repl, sizeof(repl));
-
- if(repl.status != CMD_OPENSRCH)
- return NULL;
-
- return repl.handle;
- }
-
- ret = ovdb_getgroupinfo(group, &gi, true, NULL, 0);
- switch (ret)
- {
- case 0:
- break;
- case DB_NOTFOUND:
- return NULL;
- default:
- syslog(L_ERROR, "OVDB: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- return NULL;
- }
-
- s = xmalloc(sizeof(struct ovdbsearch));
- db = get_db_bynum(gi.current_db);
- if(db == NULL) {
- free(s);
- return NULL;
- }
-
- ret = db->cursor(db, NULL, &(s->cursor), 0);
- if (ret != 0) {
- syslog(L_ERROR, "OVDB: opensearch: s->db->cursor: %s", db_strerror(ret));
- free(s);
- return NULL;
- }
-
- s->gid = gi.current_gid;
- s->firstart = low;
- s->lastart = high;
- s->state = 0;
-
- if(searches == NULL) {
- nsearches = 0;
- maxsearches = 50;
- searches = xmalloc(sizeof(struct ovdbsearch *) * maxsearches);
- }
- if(nsearches == maxsearches) {
- maxsearches += 50;
- searches = xrealloc(searches, sizeof(struct ovdbsearch *) * maxsearches);
- }
- searches[nsearches] = s;
- nsearches++;
-
- return (void *)s;
-}
-
-bool
-ovdb_search(void *handle, ARTNUM *artnum, char **data, int *len,
- TOKEN *token, time_t *arrived)
-{
- struct ovdbsearch *s = (struct ovdbsearch *)handle;
- DBT key, val;
- u_int32_t flags;
- struct ovdata ovd;
- struct datakey dk;
- int ret;
-
- if (clientmode) {
- struct rs_cmd rs;
- struct rs_srch repl;
- static char *databuf;
- static int buflen = 0;
-
- rs.what = CMD_SRCH;
- rs.handle = handle;
-
- if (csend(&rs, sizeof(rs)) < 0)
- return false;
- if (crecv(&repl, sizeof(repl)) < 0)
- return false;
-
- if(repl.status != CMD_SRCH)
- return false;
- if(repl.len > buflen) {
- if(buflen == 0) {
- buflen = repl.len + 512;
- databuf = xmalloc(buflen);
- } else {
- buflen = repl.len + 512;
- databuf = xrealloc(databuf, buflen);
- }
- }
- crecv(databuf, repl.len);
-
- if(artnum)
- *artnum = repl.artnum;
- if(token)
- *token = repl.token;
- if(arrived)
- *arrived = repl.arrived;
- if(len)
- *len = repl.len;
- if(data)
- *data = databuf;
- return true;
- }
-
- switch(s->state) {
- case 0:
- flags = DB_SET_RANGE;
- memset(&dk, 0, sizeof dk);
- dk.groupnum = s->gid;
- dk.artnum = htonl(s->firstart);
- s->state = 1;
- break;
- case 1:
- flags = DB_NEXT;
- break;
- case 2:
- s->state = 3;
- return false;
- default:
- syslog(L_ERROR, "OVDB: OVsearch called again after false return");
- return false;
- }
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
- key.data = &dk;
- key.size = key.ulen = sizeof(struct datakey);
- key.flags = DB_DBT_USERMEM;
-
- if(!data && !len) {
- /* caller doesn't need data, so we don't have to retrieve it all */
- val.flags |= DB_DBT_PARTIAL;
-
- if(token || arrived)
- val.dlen = sizeof(struct ovdata);
- }
-
- switch(ret = s->cursor->c_get(s->cursor, &key, &val, flags)) {
- case 0:
- break;
- case DB_NOTFOUND:
- s->state = 3;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- return false;
- default:
- syslog(L_ERROR, "OVDB: search: c_get: %s", db_strerror(ret));
- s->state = 3;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- return false;
- }
-
- if(key.size != sizeof(struct datakey)) {
- s->state = 3;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- return false;
- }
-
- if(dk.groupnum != s->gid || ntohl(dk.artnum) > s->lastart) {
- s->state = 3;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- return false;
- }
-
- if( ((len || data) && val.size <= sizeof(struct ovdata))
- || ((token || arrived) && val.size < sizeof(struct ovdata)) ) {
- syslog(L_ERROR, "OVDB: search: bad value length");
- s->state = 3;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- return false;
- }
-
- if(ntohl(dk.artnum) == s->lastart) {
- s->state = 2;
- s->cursor->c_close(s->cursor);
- s->cursor = NULL;
- }
-
- if(artnum)
- *artnum = ntohl(dk.artnum);
-
- if(token || arrived)
- memcpy(&ovd, val.data, sizeof(struct ovdata));
- if(token)
- *token = ovd.token;
- if(arrived)
- *arrived = ovd.arrived;
-
- if(len)
- *len = val.size - sizeof(struct ovdata);
- if(data)
- *data = (char *)val.data + sizeof(struct ovdata);
-
- return true;
-}
-
-void ovdb_closesearch(void *handle)
-{
- int i;
- if(clientmode) {
- struct rs_cmd rs;
-
- rs.what = CMD_CLOSESRCH;
- rs.handle = handle;
- csend(&rs, sizeof(rs));
- /* no reply is sent for a CMD_CLOSESRCH */
- } else {
- struct ovdbsearch *s = (struct ovdbsearch *)handle;
-
- if(s->cursor)
- s->cursor->c_close(s->cursor);
-
- for(i = 0; i < nsearches; i++) {
- if(s == searches[i]) {
- break;
- }
- }
- nsearches--;
- for( ; i < nsearches; i++) {
- searches[i] = searches[i+1];
- }
-
- free(handle);
- }
-}
-
-bool ovdb_getartinfo(char *group, ARTNUM artnum, TOKEN *token)
-{
- int ret, cdb = 0;
- group_id_t cgid = 0;
- DB *db;
- DBT key, val;
- struct ovdata ovd;
- struct datakey dk;
- struct groupinfo gi;
- int pass = 0;
-
- if(clientmode) {
- struct rs_cmd rs;
- struct rs_artinfo repl;
-
- rs.what = CMD_ARTINFO;
- rs.grouplen = strlen(group)+1;
- rs.artlo = artnum;
-
- if (csend(&rs, sizeof(rs)) < 0)
- return false;
- if (csend(group, rs.grouplen) < 0)
- return false;
- crecv(&repl, sizeof(repl));
-
- if(repl.status != CMD_ARTINFO)
- return false;
-
- if(token)
- *token = repl.token;
-
- return true;
- }
-
- while(1) {
- ret = ovdb_getgroupinfo(group, &gi, true, NULL, 0);
- switch (ret)
- {
- case 0:
- break;
- case DB_NOTFOUND:
- return false;
- default:
- syslog(L_ERROR, "OVDB: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- return false;
- }
-
- if(pass) {
- /* This was our second groupinfo retrieval; because the article
- retrieval came up empty. If the group ID hasn't changed
- since the first groupinfo retrieval, we can assume the article
- is definitely not there. Otherwise, we'll try to retrieve
- it the article again. */
- if(cdb == gi.current_db && cgid == gi.current_gid)
- return false;
- }
-
- db = get_db_bynum(gi.current_db);
- if(db == NULL)
- return false;
-
- memset(&dk, 0, sizeof dk);
- dk.groupnum = gi.current_gid;
- dk.artnum = htonl((u_int32_t)artnum);
-
- memset(&key, 0, sizeof key);
- memset(&val, 0, sizeof val);
-
- key.data = &dk;
- key.size = sizeof dk;
-
- /* caller doesn't need data, so we don't have to retrieve it all */
- val.flags = DB_DBT_PARTIAL;
-
- if(token)
- val.dlen = sizeof(struct ovdata);
-
- switch(ret = db->get(db, NULL, &key, &val, 0)) {
- case 0:
- case DB_NOTFOUND:
- break;
- default:
- syslog(L_ERROR, "OVDB: getartinfo: db->get: %s", db_strerror(ret));
- return false;
- }
-
- if(ret == DB_NOTFOUND) {
- /* If the group is being moved (i.e., its group ID is going
- to change), there's a chance the article is now under the
- new ID. So we'll grab the groupinfo again to check for
- that. */
- if(!pass && (gi.status & GROUPINFO_MOVING)) {
- cdb = gi.current_db;
- cgid = gi.current_gid;
- pass++;
- continue;
- }
- return false;
- }
- break;
- }
-
- if(token && val.size < sizeof(struct ovdata)) {
- syslog(L_ERROR, "OVDB: getartinfo: data too short");
- return false;
- }
-
- if(token) {
- memcpy(&ovd, val.data, sizeof(struct ovdata));
- *token = ovd.token;
- }
- return true;
-}
-
-bool ovdb_expiregroup(char *group, int *lo, struct history *h)
-{
- DB *db, *ndb = NULL;
- DBT key, val, nkey, gkey, gval;
- DB_TXN *tid;
- DBC *cursor = NULL;
- int ret = 0, delete, old_db = 0, cleanup;
- struct groupinfo gi;
- struct ovdata ovd;
- struct datakey dk, ndk;
- group_id_t old_gid = 0;
- ARTHANDLE *ah;
- u_int32_t artnum = 0, currentart, lowest;
- int i, compact, done, currentcount, newcount;
-
- if(eo_start == 0) {
- eo_start = time(NULL);
- delete_old_stuff(0); /* remove deleted groups first */
- }
-
- /* Special case: when called with NULL group, we're to clean out
- * records for forgotton groups (groups removed from the active file
- * but not from overview).
- * This happens at the end of the expireover run, and only if all
- * of the groups in the active file have been processed.
- * delete_old_stuff(1) will remove groups that are in ovdb but
- * have not been processed during this run.
- */
-
- if(group == NULL)
- return delete_old_stuff(1);
-
- memset(&key, 0, sizeof key);
- memset(&nkey, 0, sizeof nkey);
- memset(&val, 0, sizeof val);
- memset(&dk, 0, sizeof dk);
- memset(&ndk, 0, sizeof ndk);
-
- TXN_START(t_expgroup_1, tid);
-
- if(tid==NULL)
- return false;
-
- cleanup = 0;
-
- ret = ovdb_getgroupinfo(group, &gi, true, tid, DB_RMW);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_1, tid);
- default:
- syslog(L_ERROR, "OVDB: expiregroup: ovdb_getgroupinfo failed: %s", db_strerror(ret));
- case DB_NOTFOUND:
- TXN_ABORT(t_expgroup_1, tid);
- return false;
- }
-
- if(gi.status & GROUPINFO_EXPIRING) {
- /* is there another expireover working on this group? */
- ret = kill(gi.expiregrouppid, 0);
- switch(ret)
- {
- case 0:
- case EPERM:
- TXN_ABORT(t_expgroup_1, tid);
- return false;
- }
-
- /* a previous expireover run must've died. We'll clean
- up after it */
- if(gi.status & GROUPINFO_MOVING) {
- cleanup = 1;
- old_db = gi.new_db;
- old_gid = gi.new_gid;
-
- ret = mk_temp_groupinfo(old_db, old_gid, tid);
- switch(ret) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_1, tid);
- default:
- TXN_ABORT(t_expgroup_1, tid);
- return false;
- }
- gi.status &= ~GROUPINFO_MOVING;
- }
- }
-
- if(gi.count < ovdb_conf.nocompact || ovdb_conf.nocompact == 0)
- compact = 1;
- else
- compact = 0;
-
- if(gi.count == 0)
- compact = 0;
-
- db = get_db_bynum(gi.current_db);
- if(db == NULL) {
- TXN_ABORT(t_expgroup_1, tid);
- return false;
- }
-
- gi.status |= GROUPINFO_EXPIRING;
- gi.expiregrouppid = getpid();
- if(compact) {
- gi.status |= GROUPINFO_MOVING;
- gi.new_db = gi.current_db;
- ndb = db;
- ret = groupid_new(&gi.new_gid, tid);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_1, tid);
- default:
- TXN_ABORT(t_expgroup_1, tid);
- syslog(L_ERROR, "OVDB: expiregroup: groupid_new: %s", db_strerror(ret));
- return false;
- }
- }
-
- key.data = group;
- key.size = strlen(group);
- val.data = &gi;
- val.size = sizeof gi;
-
- ret = groupinfo->put(groupinfo, tid, &key, &val, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_1, tid);
- default:
- TXN_ABORT(t_expgroup_1, tid);
- syslog(L_ERROR, "OVDB: expiregroup: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
- TXN_COMMIT(t_expgroup_1, tid);
-
- if(cleanup) {
- if(delete_all_records(old_db, old_gid) == 0) {
- rm_temp_groupinfo(old_gid);
- }
- }
-
- /*
- * The following loop iterates over the OV records for the group in
- * "batches", to limit transaction sizes.
- *
- * loop {
- * start transaction
- * get groupinfo
- * process EXPIREGROUP_TXN_SIZE records
- * write updated groupinfo
- * commit transaction
- * }
- */
- currentart = 0;
- lowest = currentcount = 0;
-
- memset(&gkey, 0, sizeof gkey);
- memset(&gval, 0, sizeof gval);
- gkey.data = group;
- gkey.size = strlen(group);
- gval.data = &gi;
- gval.size = sizeof gi;
-
- while(1) {
- TXN_START(t_expgroup_loop, tid);
- if(tid==NULL)
- return false;
- done = 0;
- newcount = 0;
-
- ret = ovdb_getgroupinfo(group, &gi, false, tid, DB_RMW);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: ovdb_getgroupinfo: %s", db_strerror(ret));
- return false;
- }
-
- ret = db->cursor(db, tid, &cursor, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: db->cursor: %s", db_strerror(ret));
- return false;
- }
-
- dk.groupnum = gi.current_gid;
- dk.artnum = htonl(currentart);
- key.data = &dk;
- key.size = key.ulen = sizeof dk;
- key.flags = DB_DBT_USERMEM;
-
- for(i=0; i < EXPIREGROUP_TXN_SIZE; i++) {
- ret = cursor->c_get(cursor, &key, &val,
- i == 0 ? DB_SET_RANGE : DB_NEXT);
- switch (ret)
- {
- case 0:
- case DB_NOTFOUND:
- break;
- case TRYAGAIN:
- cursor->c_close(cursor);
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- cursor->c_close(cursor);
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: c_get: %s", db_strerror(ret));
- return false;
- }
-
- /* stop if: there are no more keys, an unknown key is reached,
- or reach a different group */
-
- if(ret == DB_NOTFOUND
- || key.size != sizeof dk
- || dk.groupnum != gi.current_gid) {
- done++;
- break;
- }
-
- artnum = ntohl(dk.artnum);
-
- delete = 0;
- if(val.size < sizeof ovd) {
- delete = 1; /* must be corrupt, just delete it */
- } else {
- memcpy(&ovd, val.data, sizeof ovd);
-
- ah = NULL;
- if (!SMprobe(EXPENSIVESTAT, &ovd.token, NULL) || OVstatall) {
- if((ah = SMretrieve(ovd.token, RETR_STAT)) == NULL) {
- delete = 1;
- } else
- SMfreearticle(ah);
- } else {
- if (!OVhisthasmsgid(h, (char *)val.data + sizeof(ovd))) {
- delete = 1;
- }
- }
- if (!delete && innconf->groupbaseexpiry &&
- OVgroupbasedexpire(ovd.token, group,
- (char *)val.data + sizeof(ovd),
- val.size - sizeof(ovd),
- ovd.arrived, ovd.expires)) {
- delete = 1;
- }
- }
-
- if(delete) {
- if(!compact) {
- switch(ret = cursor->c_del(cursor, 0)) {
- case 0:
- case DB_NOTFOUND:
- case DB_KEYEMPTY:
- break;
- case TRYAGAIN:
- cursor->c_close(cursor);
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- cursor->c_close(cursor);
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: c_del: %s", db_strerror(ret));
- return false;
- }
- }
- if(gi.count > 0)
- gi.count--;
- } else {
- if(compact) {
- ndk.groupnum = gi.new_gid;
- ndk.artnum = dk.artnum;
- nkey.data = &ndk;
- nkey.size = sizeof ndk;
-
- switch(ret = ndb->put(ndb, tid, &nkey, &val, 0)) {
- case 0:
- break;
- case TRYAGAIN:
- cursor->c_close(cursor);
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- cursor->c_close(cursor);
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: ndb->put: %s", db_strerror(ret));
- return false;
- }
- }
- newcount++;
- if(lowest != -1 && (lowest == 0 || artnum < lowest))
- lowest = artnum;
- }
- }
- /* end of for loop */
-
- if(cursor->c_close(cursor) == TRYAGAIN) {
- TXN_RETRY(t_expgroup_loop, tid);
- }
-
- if(lowest != 0 && lowest != -1)
- gi.low = lowest;
-
- if(done) {
- if(compact) {
- old_db = gi.current_db;
- gi.current_db = gi.new_db;
- old_gid = gi.current_gid;
- gi.current_gid = gi.new_gid;
- gi.status &= ~GROUPINFO_MOVING;
-
- ret = mk_temp_groupinfo(old_db, old_gid, tid);
- switch(ret) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- TXN_ABORT(t_expgroup_loop, tid);
- return false;
- }
- }
-
- gi.status &= ~GROUPINFO_EXPIRING;
- gi.expired = time(NULL);
- if(gi.count == 0 && lowest == 0)
- gi.low = gi.high+1;
- }
-
- ret = groupinfo->put(groupinfo, tid, &gkey, &gval, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_loop, tid);
- default:
- TXN_ABORT(t_expgroup_loop, tid);
- syslog(L_ERROR, "OVDB: expiregroup: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
- TXN_COMMIT(t_expgroup_loop, tid);
-
- currentcount += newcount;
- if(lowest != 0)
- lowest = -1;
-
- if(done)
- break;
-
- currentart = artnum+1;
- }
-
- if(compact) {
- if(delete_all_records(old_db, old_gid) == 0) {
- rm_temp_groupinfo(old_gid);
- }
- }
-
- if(currentcount != gi.count) {
- syslog(L_NOTICE, "OVDB: expiregroup: recounting %s", group);
-
- TXN_START(t_expgroup_recount, tid);
- if(tid == NULL)
- return false;
-
- switch(ret = ovdb_getgroupinfo(group, &gi, false, tid, DB_RMW)) {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_recount, tid);
- default:
- TXN_ABORT(t_expgroup_recount, tid);
- syslog(L_ERROR, "OVDB: expiregroup: ovdb_getgroupinfo: %s", db_strerror(ret));
- return false;
- }
-
- if(count_records(&gi) != 0) {
- TXN_ABORT(t_expgroup_recount, tid);
- return false;
- }
-
- ret = groupinfo->put(groupinfo, tid, &gkey, &gval, 0);
- switch (ret)
- {
- case 0:
- break;
- case TRYAGAIN:
- TXN_RETRY(t_expgroup_recount, tid);
- default:
- TXN_ABORT(t_expgroup_recount, tid);
- syslog(L_ERROR, "OVDB: expiregroup: groupinfo->put: %s", db_strerror(ret));
- return false;
- }
- TXN_COMMIT(t_expgroup_recount, tid);
- }
-
- if(lo)
- *lo = gi.low;
- return true;
-}
-
-bool ovdb_ctl(OVCTLTYPE type, void *val)
-{
- int *i;
- OVSORTTYPE *sorttype;
- bool *boolval;
-
- switch (type) {
- case OVSPACE:
- i = (int *)val;
- *i = -1;
- return true;
- case OVSORT:
- sorttype = (OVSORTTYPE *)val;
- *sorttype = OVNEWSGROUP;
- return true;
- case OVCUTOFFLOW:
- Cutofflow = *(bool *)val;
- return true;
- case OVSTATICSEARCH:
- i = (int *)val;
- *i = true;
- return true;
- case OVCACHEKEEP:
- case OVCACHEFREE:
- boolval = (bool *)val;
- *boolval = false;
- return true;
- default:
- return false;
- }
-}
-
-void ovdb_close_berkeleydb(void)
-{
- if(OVDBenv) {
- /* close db environment */
-#if DB_VERSION_MAJOR == 2
- db_appexit(OVDBenv);
- free(OVDBenv);
-#else
- OVDBenv->close(OVDBenv, 0);
-#endif
- OVDBenv = NULL;
- }
-}
-
-void ovdb_close(void)
-{
- int i;
-
- if(clientmode) {
- client_disconnect();
- return;
- }
-
- while(searches != NULL && nsearches) {
- ovdb_closesearch(searches[0]);
- }
- if(searches != NULL) {
- free(searches);
- searches = NULL;
- }
-
- if(dbs) {
- /* close databases */
- for(i = 0; i < ovdb_conf.numdbfiles; i++)
- close_db_file(i);
-
- free(dbs);
- dbs = NULL;
- }
- if(groupinfo) {
- groupinfo->close(groupinfo, 0);
- groupinfo = NULL;
- }
- if(groupaliases) {
- groupaliases->close(groupaliases, 0);
- groupaliases = NULL;
- }
-
- ovdb_close_berkeleydb();
- ovdb_releaselock();
-}
-
-
-#endif /* USE_BERKELEY_DB */
-
+++ /dev/null
-#ifndef _OVDB_H_
-#define _OVDB_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-bool ovdb_open(int mode);
-bool ovdb_groupstats(char *group, int *lo, int *hi, int *count, int *flag);
-bool ovdb_groupadd(char *group, ARTNUM lo, ARTNUM hi, char *flag);
-bool ovdb_groupdel(char *group);
-bool ovdb_add(char *group, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires);
-bool ovdb_cancel(TOKEN token);
-void *ovdb_opensearch(char *group, int low, int high);
-bool ovdb_search(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived);
-void ovdb_closesearch(void *handle);
-bool ovdb_getartinfo(char *group, ARTNUM artnum, TOKEN *token);
-bool ovdb_expiregroup(char *group, int *lo, struct history *h);
-bool ovdb_ctl(OVCTLTYPE type, void *val);
-void ovdb_close(void);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _OVDB_H_ */
+++ /dev/null
-name = ovdb
-number = 4
-sources = ovdb.c
+++ /dev/null
-/* $Id: overdata.c 7477 2005-12-24 21:34:38Z eagle $
-**
-** Overview data processing.
-**
-** Here be routines for creating and checking the overview data, the
-** tab-separated list of overview fields.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-
-#include "inn/buffer.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "inn/wire.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "ovinterface.h"
-#include "paths.h"
-
-
-/* The standard overview fields. */
-static const char * const fields[] = {
- "Subject", "From", "Date", "Message-ID", "References", "Bytes", "Lines"
-};
-
-
-/*
-** Return a vector of the standard overview fields. Note there is no
-** way to free up the resulting data structure.
-*/
-const struct cvector *
-overview_fields(void)
-{
- static struct cvector *list = NULL;
-
- if (list == NULL) {
- unsigned int field;
-
- list = cvector_new();
- cvector_resize(list, ARRAY_SIZE(fields));
-
- for (field = 0; field < ARRAY_SIZE(fields); ++field) {
- cvector_add(list, fields[field]);
- }
- }
- return list;
-}
-
-/*
-** Parse the overview schema and return a vector of the additional fields
-** over the standard ones. Caller is responsible for freeing the vector.
-*/
-struct vector *
-overview_extra_fields(void)
-{
- struct vector *list = NULL;
- struct vector *result = NULL;
- char *schema = NULL;
- char *line, *p;
- QIOSTATE *qp = NULL;
- unsigned int field;
- bool full = false;
-
- schema = concatpath(innconf->pathetc, _PATH_SCHEMA);
- qp = QIOopen(schema);
- if (qp == NULL) {
- syswarn("cannot open %s", schema);
- goto done;
- }
- list = vector_new();
- for (field = 0, line = QIOread(qp); line != NULL; line = QIOread(qp)) {
- while (ISWHITE(*line))
- line++;
- p = strchr(line, '#');
- if (p != NULL)
- *p = '\0';
- p = strchr(line, '\n');
- if (p != NULL)
- *p = '\0';
- if (*line == '\0')
- continue;
- p = strchr(line, ':');
- if (p != NULL) {
- *p++ = '\0';
- full = (strcmp(p, "full") == 0);
- }
- if (field >= ARRAY_SIZE(fields)) {
- if (!full)
- warn("additional field %s not marked with :full", line);
- vector_add(list, line);
- } else {
- if (strcasecmp(line, fields[field]) != 0)
- warn("field %d is %s, should be %s", field, line,
- fields[field]);
- }
- field++;
- }
- if (QIOerror(qp)) {
- if (QIOtoolong(qp)) {
- warn("line too long in %s", schema);
- } else {
- syswarn("error while reading %s", schema);
- }
- }
- result = list;
-
-done:
- if (schema != NULL)
- free(schema);
- if (qp != NULL)
- QIOclose(qp);
- if (result == NULL && list != NULL)
- vector_free(list);
- return result;
-}
-
-
-/*
-** Given an article, its length, the name of a header, and a buffer to append
-** the data to, append header data for that header to the overview data
-** that's being constructed. Doesn't append any data if the header isn't
-** found.
-*/
-static void
-build_header(const char *article, size_t length, const char *header,
- struct buffer *overview)
-{
- ptrdiff_t size;
- size_t offset;
- const char *data, *end, *p;
-
- data = wire_findheader(article, length, header);
- if (data == NULL)
- return;
- end = wire_endheader(data, article + length - 1);
- if (end == NULL)
- return;
-
- /* Someone managed to break their server so that they were appending
- multiple Xref headers, and INN had a bug where it wouldn't notice this
- and reject the article. Just in case, see if there are multiple Xref
- headers and use the last one. */
- if (strcasecmp(header, "xref") == 0) {
- const char *next = end + 1;
-
- while (next != NULL) {
- next = wire_findheader(next, length - (next - article), header);
- if (next != NULL) {
- data = next;
- end = wire_endheader(data, article + length - 1);
- if (end == NULL)
- return;
- }
- }
- }
-
- size = end - data + 1;
- offset = overview->used + overview->left;
- buffer_resize(overview, offset + size);
-
- for (p = data; p <= end; p++) {
- if (*p == '\r' && p[1] == '\n') {
- p++;
- continue;
- }
- if (*p == '\0' || *p == '\t' || *p == '\n' || *p == '\r')
- overview->data[offset++] = ' ';
- else
- overview->data[offset++] = *p;
- overview->left++;
- }
-}
-
-
-/*
-** Given an article number, an article, and a vector of additional headers,
-** generate overview data into the provided buffer. If the buffer parameter
-** is NULL, a new buffer is allocated. The article should be in wire format.
-** Returns the buffer containing the overview data.
-*/
-struct buffer *
-overview_build(ARTNUM number, const char *article, size_t length,
- const struct vector *extra, struct buffer *overview)
-{
- unsigned int field;
- char buffer[32];
-
- snprintf(buffer, sizeof(buffer), "%lu", number);
- if (overview == NULL)
- overview = buffer_new();
- buffer_set(overview, buffer, strlen(buffer));
- for (field = 0; field < ARRAY_SIZE(fields); field++) {
- buffer_append(overview, "\t", 1);
- if (field == 5) {
- snprintf(buffer, sizeof(buffer), "%lu", (unsigned long) length);
- buffer_append(overview, buffer, strlen(buffer));
- } else
- build_header(article, length, fields[field], overview);
- }
- for (field = 0; field < extra->count; field++) {
- buffer_append(overview, "\t", 1);
- buffer_append(overview, extra->strings[field],
- strlen(extra->strings[field]));
- buffer_append(overview, ": ", 2);
- build_header(article, length, extra->strings[field], overview);
- }
- buffer_append(overview, "\r\n", 2);
- return overview;
-}
-
-
-/*
-** Check whether a given string is a valid number.
-*/
-static bool
-valid_number(const char *string)
-{
- const char *p;
-
- for (p = string; *p != '\0'; p++)
- if (!CTYPE(isdigit, *p))
- return false;
- return true;
-}
-
-
-/*
-** Check whether a given string is a valid overview string (doesn't contain
-** CR or LF, and if the second argument is true must be preceeded by a header
-** name, colon, and space). Allow CRLF at the end of the data, but don't
-** require it.
-*/
-static bool
-valid_overview_string(const char *string, bool full)
-{
- const unsigned char *p;
-
- /* RFC 2822 says that header fields must consist of printable ASCII
- characters (characters between 33 and 126, inclusive) excluding colon.
- We also allow high-bit characters, just in case, but not DEL. */
- p = (const unsigned char *) string;
- if (full) {
- for (; *p != '\0' && *p != ':'; p++)
- if (*p < 33 || *p == 127)
- return false;
- if (*p != ':')
- return false;
- p++;
- if (*p != ' ')
- return false;
- }
- for (p++; *p != '\0'; p++) {
- if (*p == '\015' && p[1] == '\012' && p[2] == '\0')
- break;
- if (*p == '\015' || *p == '\012')
- return false;
- }
- return true;
-}
-
-
-/*
-** Check the given overview data and make sure it's well-formed. Extension
-** headers are not checked against overview.fmt (having a different set of
-** extension headers doesn't make the data invalid), but the presence of the
-** standard fields is checked. Also checked is whether the article number in
-** the data matches the passed article number. Returns true if the data is
-** okay, false otherwise.
-*/
-bool
-overview_check(const char *data, size_t length, ARTNUM article)
-{
- char *copy;
- struct cvector *overview;
- ARTNUM overnum;
- size_t i;
-
- copy = xstrndup(data, length);
- overview = cvector_split(copy, '\t', NULL);
-
- /* The actual checks. We don't verify all of the data, since that data
- may be malformed in the article, but we do check to be sure that the
- fields that should be numbers are numbers. That should catch most
- positional errors. We can't check Lines yet since right now INN is
- still accepting the value from the post verbatim. */
- if (overview->count < 8)
- goto fail;
- if (!valid_number(overview->strings[0]))
- goto fail;
- overnum = strtoul(overview->strings[0], NULL, 10);
- if (overnum != article)
- goto fail;
- if (!valid_number(overview->strings[6]))
- goto fail;
- for (i = 1; i < 6; i++)
- if (!valid_overview_string(overview->strings[i], false))
- goto fail;
- for (i = 8; i < overview->count; i++)
- if (!valid_overview_string(overview->strings[i], true))
- goto fail;
- cvector_free(overview);
- free(copy);
- return true;
-
- fail:
- cvector_free(overview);
- free(copy);
- return false;
-}
-
-
-/*
-** Given an overview header, return the offset of the field within
-** the overview data, or -1 if the field is not present in the
-** overview schema for this installation.
-*/
-int
-overview_index(const char *field, const struct vector *extra)
-{
- int i;
-
- for (i = 0; i < (sizeof fields / sizeof fields[0]); ++i) {
- if (strcasecmp(field, fields[i]) == 0)
- return i;
- }
- for (i = 0; i < extra->count; i++) {
- if (strcasecmp(field, extra->strings[i]) == 0)
- return i + (sizeof fields / sizeof fields[0]);
- }
- return -1;
-}
-
-
-/*
-** Given an overview header line, split out a vector pointing at each
-** of the components (within line), returning a pointer to the
-** vector. If the vector initially passed in is NULL a new vector is
-** created, else the existing one is filled in.
-**
-** A member `n' of the vector is of length (vector->strings[n+1] -
-** vector->strings[n] - 1). Note that the last member of the vector
-** will always point beyond (line + length).
-*/
-struct cvector *
-overview_split(const char *line, size_t length, ARTNUM *number,
- struct cvector *vector)
-{
- const char *p = NULL;
-
- if (vector == NULL) {
- vector = cvector_new();
- } else {
- cvector_clear(vector);
- }
- while (line != NULL) {
- /* the first field is the article number */
- if (p == NULL) {
- if (number != NULL) {
- *number = atoi(line);
- }
- } else {
- cvector_add(vector, line);
- }
- p = memchr(line, '\t', length);
- if (p != NULL) {
- /* skip over the tab */
- ++p;
- /* and calculate the remaining length */
- length -= (p - line);
- } else {
- /* add in a pointer to beyond the end of the final
- * component, so you can always calculate the length.
- * overview lines are always terminated with \r\n, so the
- * -1 ends up chopping those off */
- cvector_add(vector, line + length - 1);
- }
- line = p;
- }
- return vector;
-}
-
-/*
-** Given an overview vector (from overview_split), return a copy of
-** the member which the caller is interested in (and must free).
-*/
-char *
-overview_getheader(const struct cvector *vector, int element,
- const struct vector *extra)
-{
- char *field = NULL;
- size_t len;
- const char *p;
-
- if ((element + 1) >= vector->count ||
- (element >= ARRAY_SIZE(fields) &&
- (element - ARRAY_SIZE(fields)) >= extra->count)) {
- warn("request for invalid overview field %d", element);
- return NULL;
- }
- /* Note... this routine does not synthesise Newsgroups: on behalf
- * of the caller... */
- if (element >= ARRAY_SIZE(fields)) {
- /* +2 for `: ' */
- p = vector->strings[element] +
- strlen(extra->strings[element - ARRAY_SIZE(fields)]) + 2;
- len = vector->strings[element + 1] - p - 1;
- } else {
- p = vector->strings[element];
- len = vector->strings[element + 1] - vector->strings[element] - 1;
- }
- field = xstrndup(p, len);
- return field;
-}
+++ /dev/null
-/* $Id: ovinterface.h 6113 2003-01-04 16:29:56Z kondou $
-**
-** Overview interface header
-*/
-
-#ifndef __OVINTERFACE_H__
-#define __OVINTERFACE_H__
-
-#include "config.h"
-#include "ov.h"
-#include "storage.h"
-#include "inn/history.h"
-
-struct buffer;
-struct vector;
-
-typedef struct {
- const char *name;
- bool (*open)(int mode);
- bool (*groupstats)(char *group, int *lo, int *hi, int *count, int *flag);
- bool (*groupadd)(char *group, ARTNUM lo, ARTNUM hi, char *flag);
- bool (*groupdel)(char *group);
- bool (*add)(char *group, ARTNUM artnum, TOKEN token, char *data, int len, time_t arrived, time_t expires);
- bool (*cancel)(TOKEN token);
- void *(*opensearch)(char *group, int low, int high);
- bool (*search)(void *handle, ARTNUM *artnum, char **data, int *len, TOKEN *token, time_t *arrived);
- void (*closesearch)(void *handle);
- bool (*getartinfo)(char *group, ARTNUM artnum, TOKEN *token);
- bool (*expiregroup)(char *group, int *lo, struct history *h);
- bool (*ctl)(OVCTLTYPE type, void *val);
- void (*close)(void);
-} OV_METHOD;
-
-extern time_t OVrealnow;
-bool OVgroupbasedexpire(TOKEN token, const char *group, const char *data,
- int len, time_t arrived, time_t expires);
-bool OVgroupmatch(const char *group);
-bool OVhisthasmsgid(struct history *, const char *data);
-void OVEXPremove(TOKEN token, bool deletedgroups, char **xref, int ngroups);
-void OVEXPcleanup(void);
-bool OVstatall;
-time_t OVnow;
-char *ACTIVE;
-FILE *EXPunlinkfile;
-bool OVignoreselfexpire;
-bool OVusepost;
-bool OVkeep;
-bool OVearliest;
-bool OVquiet;
-int OVnumpatterns;
-char **OVpatterns;
-time_t OVrealnow;
-
-#define DEFAULT_MAX_XREF_LEN 8192
-
-#endif /* __OVINTERFACE_H__ */
+++ /dev/null
-The timecaf storage manager is like the timehash storage manager, except that
-it stores multiple articles in one file. The file format is called CAF
-(for "crunched article file", putting multiple articles together into one big
-file), and uses a library 'caf.c' dating back from the pre-storage manager
-days when I made a locally-hacked version of INN1.5 that used this
-code in order to boost performance on my system. Originally I had planned to
-do one big file per newsgroup, but it turns out that a time-based file layout
-rather than newsgroup-name-based is a. more efficient and b. much easier to
-fit into the current storage manager interface paradigm. Anyway, the
-pathnames for the files are of the form
- <patharticles>/timecaf-nn/bb/aacc.CF
-where 'nn' is the numeric storage class (same as in 'timehash') and the
-file contains all articles written during the interval from
-(time_t) 0xaabbcc00 to 0xaabbccFF.
-
- The way expiration works on the 'timecaf' storage manager is a bit
-complicated. When articles are expired or cancelled (via SMcancel())
-they are at first just marked as expired in the .CF file -- no actual
-disk space is freed at first. But if fastrm/SMcancel() notices that a
-certain amount of space has been marked as free, then it will do a
-sort of garbage collection pass on the file, writing out a new file
-containing only the articles from the old file that have not yet
-expired and removing the old file. If fastrm notices that *all* the
-articles in a file have been expired, it just deletes the file and
-doesn't create a new one. This means that if your setup has
-newsgroups with differing expiration lengths put in the same timecaf
-storage class, everything will work ok but your expire runs will spend
-some extra time copying files about. In my experience this hasn't been too
-much of a problem. If you find that it is a problem, you may wish to
-consider dividing up your spool layout so each storage class gets newsgroups
-that expire at more-or-less the same time, or putting *.binaries in their own
-storage class.
-
-Some advantages and disadvantages compared to the 'timehash' and
-'CNFS' storage methods:
-
- timecaf is somewhat faster than timehash in writing articles (the tests
-I did on the old news.ecn.uoknor.edu showed a roughly 4x improvement in
-artwrite speed). This is presumably due to improved locality of reference and
-not having to open/close article files all the time but only every 4 minutes or
-so. Artcancel speed, on the other hand, is not much different, because
-cancel requests have terrible locality of reference. Expire times seem
-to be generally somewhat faster than timehash as well, even given the
-extra copying overhead mentioned above.
-
- Timecaf is probably slower than CNFS, but I haven't had a chance
-to do any comparison tests. Timecaf does share the feature with timehash
-that you can get much more fine-tuned control of your expire times (on a
-group-by-group basis, if needed) than you can with CNFS.
-
-Down below is an old README telling more about the implementation details
-of the CAF file format. Most people won't care about this, but if you're
-curious, read on; it also tells some of the historical developments that
-went on in this code. I've been running some version of this code off and
-on for the past two years, and have been running it as a storage manager
-module for the past few months, so I'm pretty sure of it's stability.
-
- Richard Todd
- (rmtodd@mailhost.ecn.ou.edu/rmtodd@servalan.servalan.com)
-
-\f
-Implementation details (format of a CAF file) and some design rationale:
-
- Look at include/caf.h for the details, but basically, the layout is
-something like this. Each CAF file has a blocksize associated with it
-(usually 512 bytes, but it can vary). The layout of a CAF file is as
-follows:
- 1. Header (~52 bytes) containing information like low and high
-article numbers, amount of free space, blocksize.
- 2. Free space bitmap (size given by the FreeZoneTabSize field of the
-header).
- 3. CAFTOCENTs (CAF Table of Contents Entries), 1/article storable
-in the file. Each CAFTOCENT gives the article's size, creation time,
-and offset in the CAF file. Usually space is alloted in the CAF file
-for 64K CAFTOCENTs, even if the # of articles in the CAF file is
-nowhere near that amount. The unused CAFTOCENTs are all zeros, and
-this means CAF files are almost always sparse.
- 4. Articles, always stored starting at blocksize boundaries.
-
-When fastrm is told to remove an article, the article is not actually
-removed as such, it is merely marked as non-existent (the CAFTOCENT is
-zeroed), and the blocks taken up by the article are marked as 'free'
-in the free space bitmap. When innd writes an article to a CAF file,
-it first looks to see if the CAF file has any free blocks in a
-contiguous chunk large enough to handle the article, and if so writes
-the article into those blocks and marks those blocks as being in use.
-If there is no suitable free space chunk in the CAF file, then innd
-merely appends the article to the end of the CAF file and records the
-article's position in the TOC. [Given the way the CAF code is currently
-used by the timecaf storage manager, it's almost always the case that we're
-appending to the end of the file.]
-
- A note on the free bitmap portion of the CAF file: it's not just a simple
-bitmap (each bit of the bitmap tells whether a data block is in use or free.)
-First there is an 'index' bitmap which tells which blocks of the 'main' bitmap
-have free blocks listed in them, and then a 'main' bitmap which tells whether
-the data blocks are in use or free. This setup means that we can have
-bitmaps for CAF files as large as 8GB, while still being able to find free
-space by only reading the 'index' bitmap and one block of the 'main' bitmap.
-(Previous versions of the CAF code had just a 'main' bitmap and scaled the
-blocksize up when CAF files got large; this became rather, um, non-optimal
-when control.cancel started to hit hundreds of thousands of articles and 8K
-blocksizes.) In practice, CAF files over 2GB or 4GB may be a problem because
-of unsigned/signed long problems, and ones over 4G are probably impossible
-on anything besides an Alpha unless you track down all the places in innd
-where they assume off_t is a long and fix it to work with long longs.
-
- At some point I'd also like to try some other, more efficient
-directory layout for the CAF files, as opposed to the old
-/var/spool/news/newsgroup/name/component/ scheme. At the time I
-started implementing this, it seemed like it'd be too much of a hassle
-to change this in INN as it stands. I'm hoping that changing this
-assumption (that newsgroup a.b.c is always in directory a/b/c) will be
-easier once INN acquires a nice interface for specifying alternate
-storage managers. [It is and it isn't; as I said, we've currently abandoned
-all relationship between newsgroup names and CAF file names, which
-provided a sizable jump in performance. Before that, I had changed the code
-so that the CAF file for, e.g.,
-alt.tv.babylon-5 will now be /var/spool/news/alt/tv/babylon-5.CF -- note the
-final . instead of a /. This pretty much bypasses the need for the 'terminal'
-layer of directories to be read, and means that these directory blocks will not
-be fighting with other blocks for the limited space available in the buffer
-cache. This provides more of an improvement than you might think; thruput on
-news.ecn.uoknor.edu went from 160,000 articles/day to >200,000 articles/day
-with this patch, and this is on an aging 32M 486/66.]
+++ /dev/null
-/* $Id: caf.c 6723 2004-05-16 21:12:53Z rra $
-**
-** Library routines needed for handling CAF (Crunched Article Files)
-** Written by Richard Todd (rmtodd@mailhost.ecn.uoknor.edu) 3/24/96,
-** modified extensively since then. Altered to work with storage manager
-** in INN1.8 by rmtodd 3/27/98.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "libinn.h"
-
-#define CAF_INNARDS
-#include "caf.h"
-
-/* following code lifted from inndf.c */
-
-#ifdef HAVE_STATVFS
-#include <sys/statvfs.h> /* specific includes */
-/* XXX is there a 'fstatvfs'? I don't have such a system to check--rmtodd*/
-#define STATFUNCT fstatvfs /* function call */
-#define STATSTRUC statvfs /* structure name */
-#define STATAVAIL f_bavail /* blocks available */
-#define STATMULTI f_frsize /* fragment size/block size */
-#define STATINODE f_favail /* inodes available */
-#define STATTYPES u_long /* type of f_bavail etc */
-#define STATFORMT "%lu" /* format string to match */
-#define STATFORMTPAD "%*lu" /* format string to match */
-#endif /* HAVE_STATVFS */
-
-#ifdef HAVE_STATFS
-#ifdef HAVE_SYS_VFS_H
-#include <sys/vfs.h>
-#endif /* HAVE_SYS_VFS_H */
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif /* HAVE_SYS_PARAM_H */
-#ifdef HAVE_SYS_MOUNT_H
-#include <sys/mount.h>
-#endif /* HAVE_SYS_MOUNT_H */
-#define STATFUNCT fstatfs
-#define STATSTRUC statfs
-#define STATAVAIL f_bavail
-#define STATMULTI f_bsize
-#define STATINODE f_ffree;
-#define STATTYPES long
-#define STATFORMT "%ld"
-#define STATFORMTPAD "%*ld"
-#endif /* HAVE_STATFS */
-
-int CAFClean(char *path, int verbose, double PercentFreeThreshold);
-
-int caf_error = 0;
-int caf_errno = 0;
-
-/* check assertions in code (lifted from lib/malloc.c) */
-#define ASSERT(p) do { if (!(p)) botch(__FILE__, __LINE__, #p); } while (0)
-
-static void
-botch(const char *f, int l, const char *s)
-{
-
- fprintf(stderr, "assertion botched: %s:%d:%s\n", f,l,s);
- fflush(stderr); /* if stderr writing to file--needed? */
- abort();
-}
-
-
-/* set error code appropriately. */
-static void
-CAFError(int code)
-{
- caf_error = code;
- if (caf_error == CAF_ERR_IO) {
- caf_errno = errno;
- }
-}
-
-/*
-** Wrapper around read that calls CAFError if needed. 0 for success, -1 for failure.
-*/
-
-static int
-OurRead(int fd, void *buf, size_t n)
-{
- ssize_t rval;
-
- rval = read(fd, buf, n);
- if (rval < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- if ((size_t) rval < n) {
- /* not enough data! */
- CAFError(CAF_ERR_BADFILE);
- return -1;
- }
- return 0;
-}
-
-/* Same as OurRead except for writes. */
-static int
-OurWrite(int fd, const void *buf, size_t n)
-{
- ssize_t rval;
-
- rval = write(fd, buf, n);
- if (rval < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- if ((size_t) rval < n) {
- /* not enough data written */
- CAFError(CAF_ERR_IO);
- return -1;
- }
- return 0;
-}
-
-/*
-** Given an fd, read in a CAF_HEADER from a file. Ret. 0 on success.
-*/
-
-int
-CAFReadHeader(int fd, CAFHEADER *h)
-{
- /* probably already at start anyway, but paranoia is good. */
- if (lseek(fd, 0L, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- if (OurRead(fd, h, sizeof(CAFHEADER)) < 0) return -1;
-
- if (strncmp(h->Magic, CAF_MAGIC, CAF_MAGIC_LEN) != 0) {
- CAFError(CAF_ERR_BADFILE);
- return -1;
- }
- return 0;
-}
-
-/*
-** Seek to the TOC entry for a given article. As usual, -1 for error, 0 succ.
-*/
-
-static int
-CAFSeekTOCEnt(int fd, CAFHEADER *head, ARTNUM art)
-{
- off_t offset;
-
- offset = sizeof(CAFHEADER) + head->FreeZoneTabSize;
- offset += (art - head->Low) * sizeof(CAFTOCENT);
- if (lseek(fd, offset, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- return 0;
-}
-
-/*
-** Fetch the TOC entry for a given article. As usual -1 for error, 0 success */
-
-static int
-CAFGetTOCEnt(int fd, CAFHEADER *head, ARTNUM art, CAFTOCENT *tocp)
-{
- if (CAFSeekTOCEnt(fd, head, art) < 0) {
- return -1;
- }
-
- if (OurRead(fd, tocp, sizeof(CAFTOCENT)) < 0) return -1;
-
- return 0;
-}
-
-/*
-** Round an offset up to the next highest block boundary. Needs the CAFHEADER
-** to find out what the blocksize is.
-*/
-off_t
-CAFRoundOffsetUp(off_t off, unsigned int blocksize)
-{
- off_t off2;
-
- /* Zero means default blocksize, though we shouldn't need this for long,
- as all new CAF files will have BlockSize set. */
- if (blocksize == 0) {
- blocksize = CAF_DEFAULT_BLOCKSIZE;
- }
-
- off2 = ((off + blocksize - 1) / blocksize) * blocksize;
- return off2;
-}
-
-/*
-** Dispose of an already-allocated CAFBITMAP.
-*/
-void
-CAFDisposeBitmap(CAFBITMAP *bm)
-{
- unsigned int i;
- CAFBMB *bmb;
-
- for (i = 0 ; i < bm->NumBMB ; ++i) {
- if (bm->Blocks[i]) {
- bmb = bm->Blocks[i];
- if (bmb->BMBBits) free(bmb->BMBBits);
- free(bmb);
- }
- }
- free(bm->Blocks);
- free(bm->Bits);
- free(bm);
-}
-
-/*
-** Read the index bitmap from a CAF file, return a CAFBITMAP structure.
-*/
-
-/* define this instead of littering all our formulas with semi-mysterious 8s. */
-#define BYTEWIDTH 8
-
-CAFBITMAP *
-CAFReadFreeBM(int fd, CAFHEADER *h)
-{
- size_t i;
- struct stat statbuf;
- CAFBITMAP *bm;
-
- if (lseek(fd, sizeof(CAFHEADER), SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return NULL;
- }
- bm = xmalloc(sizeof(CAFBITMAP));
-
- bm->FreeZoneTabSize = h->FreeZoneTabSize;
- bm->FreeZoneIndexSize = h->FreeZoneIndexSize;
- bm->NumBMB = BYTEWIDTH * bm->FreeZoneIndexSize;
- bm->BytesPerBMB = (h->BlockSize) * (h->BlockSize * BYTEWIDTH);
- bm->BlockSize = h->BlockSize;
-
- bm->Blocks = xmalloc(bm->NumBMB * sizeof(CAFBMB *));
- bm->Bits = xmalloc(bm->FreeZoneIndexSize);
- for (i = 0 ; i < bm->NumBMB ; ++i) {
- bm->Blocks[i] = NULL;
- }
-
- if (OurRead(fd, bm->Bits, bm->FreeZoneIndexSize) < 0) {
- CAFDisposeBitmap(bm);
- return NULL;
- }
-
- bm->StartDataBlock = h->StartDataBlock;
-
- if (fstat(fd, &statbuf) < 0) {
- /* it'd odd for this to fail, but paranoia is good for the soul. */
- CAFError(CAF_ERR_IO);
- CAFDisposeBitmap(bm);
- return NULL;
- }
- /* round st_size down to a mult. of BlockSize */
- bm->MaxDataBlock = (statbuf.st_size / bm->BlockSize) * bm->BlockSize + bm->BlockSize;
- /* (note: MaxDataBlock points to the block *after* the last block of the file. */
- return bm;
-}
-
-/*
-** Fetch a given bitmap block into memory, and make the CAFBITMAP point to
-** the new BMB appropriately. Return NULL on failure, and the BMB * on success.
-*/
-static CAFBMB *
-CAFFetchBMB(unsigned int blkno, int fd, CAFBITMAP *bm)
-{
- CAFBMB *newbmb;
-
- ASSERT(blkno < bm->NumBMB);
- /* if already in memory, don't need to do anything. */
- if (bm->Blocks[blkno]) return bm->Blocks[blkno];
-
- newbmb = xmalloc(sizeof(CAFBMB));
-
- newbmb->Dirty = 0;
- newbmb->StartDataBlock = bm->StartDataBlock + blkno*(bm->BytesPerBMB);
-
- newbmb->MaxDataBlock = newbmb->StartDataBlock + bm->BytesPerBMB;
- if (newbmb->MaxDataBlock > bm->MaxDataBlock) {
- /* limit the per-BMB MaxDataBlock to that for the bitmap as a whole */
- newbmb->MaxDataBlock = bm->MaxDataBlock;
- }
-
- newbmb->BMBBits = xmalloc(bm->BlockSize);
-
- if (lseek(fd, (blkno + 1) * bm->BlockSize, SEEK_SET) < 0) {
- free(newbmb->BMBBits);
- free(newbmb);
- CAFError(CAF_ERR_IO);
- return NULL;
- }
-
- if (OurRead(fd, newbmb->BMBBits, bm->BlockSize) < 0) {
- free(newbmb->BMBBits);
- free(newbmb);
- return NULL;
- }
-
- bm->Blocks[blkno] = newbmb;
- return newbmb;
-}
-
-/*
-** Flush out (if needed) a BMB to disk. Return 0 on success, -1 on failure.
-*/
-
-static int
-CAFFlushBMB(unsigned int blkno, int fd, CAFBITMAP *bm)
-{
- CAFBMB *bmb;
-
- ASSERT(blkno < bm->NumBMB);
-
- if (bm->Blocks[blkno] == NULL) return 0; /* nothing to do. */
-
- bmb = bm->Blocks[blkno];
- if (!bmb->Dirty) return 0;
-
- if (lseek(fd, (blkno + 1) * bm->BlockSize, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- if (OurWrite(fd, bmb->BMBBits, bm->BlockSize) < 0) return -1;
-
- bmb->Dirty = 0;
- return 0;
-}
-
-
-/*
-** Write the free bit map to the CAF file. Return 0 on success, -1 on failure.
-*/
-static int
-CAFWriteFreeBM(int fd, CAFBITMAP *bm)
-{
- size_t blkno;
-
- for (blkno = 0 ; blkno < bm->NumBMB ; ++blkno) {
- if (CAFFlushBMB(blkno, fd, bm) < 0) {
- return -1;
- }
- }
-
- if (lseek(fd, sizeof(CAFHEADER), SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- if(OurWrite(fd, bm->Bits, bm->FreeZoneIndexSize) < 0) return -1;
-
- return 0;
-}
-
-/*
-** Determine if a block at a given offset is free. Return 1 if it is, 0
-** otherwise.
-*/
-
-int
-CAFIsBlockFree(CAFBITMAP *bm, int fd, off_t block)
-{
- unsigned int ind;
- char mask;
- int blkno;
- CAFBMB *bmb;
-
- /* round block down to BlockSize boundary. */
- block = block - (block % bm->BlockSize);
-
- /* if < Start, always return 0 (should never happen in real usage) */
- if (block < bm->StartDataBlock) return 0;
-
- /* if off the end, also return 0. */
- if (block >= bm->MaxDataBlock) return 0;
-
- /* find blk # of appropriate BMB */
- blkno = (block - bm->StartDataBlock) / bm->BytesPerBMB;
-
- bmb = CAFFetchBMB(blkno, fd, bm);
- /* ick. not a lot we can do here if this fails. */
- if (bmb == NULL) return 0;
-
- /* Sanity checking that we have the right BMB. */
- ASSERT(block >= bmb->StartDataBlock);
- ASSERT(block < bmb->MaxDataBlock);
-
- ind = ((block - bmb->StartDataBlock) / bm->BlockSize) / BYTEWIDTH;
- mask = 1 << (((block - bmb->StartDataBlock) / bm->BlockSize) % BYTEWIDTH);
-
- ASSERT(ind < bm->BlockSize);
-
- return ((bmb->BMBBits[ind]) & mask) != 0;
-}
-
-/*
-** Check if a bitmap chunk is all zeros or not.
-*/
-static int
-IsMapAllZero(char *data, int len)
-{
- int i;
- for (i = 0 ; i < len ; ++i) {
- if (data[i] != 0) return 0;
- }
- return 1;
-}
-
-/* Set the free bitmap entry for a given block to be a given value (1 or 0). */
-static void
-CAFSetBlockFree(CAFBITMAP *bm, int fd, off_t block, int isfree)
-{
- unsigned int ind;
- char mask;
- int blkno;
- CAFBMB *bmb;
- int allzeros;
-
- /* round block down to BlockSize boundary. */
- block = block - (block % bm->BlockSize);
-
- /* if < Start, always return (should never happen in real usage) */
- if (block < bm->StartDataBlock) return;
-
- /* if off the end, also return. */
- if (block >= bm->MaxDataBlock) return;
- /* find blk # of appropriate BMB */
- blkno = (block - bm->StartDataBlock) / bm->BytesPerBMB;
-
- bmb = CAFFetchBMB(blkno, fd, bm);
- /* ick. not a lot we can do here if this fails. */
- if (bmb == NULL) return;
-
- /* Sanity checking that we have the right BMB. */
- ASSERT(block >= bmb->StartDataBlock);
- ASSERT(block < bmb->MaxDataBlock);
-
- ind = ((block - bmb->StartDataBlock) / bm->BlockSize) / BYTEWIDTH;
- mask = 1 << (((block - bmb->StartDataBlock) / bm->BlockSize) % BYTEWIDTH);
-
- ASSERT(ind < bm->BlockSize);
-
- if (isfree) {
- bmb->BMBBits[ind] |= mask; /* set bit */
- } else {
- bmb->BMBBits[ind] &= ~mask; /* clear bit. */
- }
-
- bmb->Dirty = 1;
-
- /* now have to set top level (index) bitmap appropriately */
- allzeros = IsMapAllZero(bmb->BMBBits, bm->BlockSize);
-
- ind = blkno/BYTEWIDTH;
- mask = 1 << (blkno % BYTEWIDTH);
-
- if (allzeros) {
- bm->Bits[ind] &= ~mask; /* clear bit */
- } else {
- bm->Bits[ind] |= mask;
- }
-
- return;
-}
-
-/*
-** Search a freebitmap to find n contiguous free blocks. Returns 0 for
-** failure, offset of starting block if successful.
-** XXX does not attempt to find chunks that span BMB boundaries. This is
-** messy to fix.
-** (Actually I think this case works, as does the case when it tries to find
-** a block bigger than BytesPerBMB. Testing reveals that it does seem to work,
-** though not optimally (some BMBs will get scanned several times).
-*/
-static off_t
-CAFFindFreeBlocks(CAFBITMAP *bm, int fd, unsigned int n)
-{
- off_t startblk, curblk;
- unsigned int i, ind, blkno, j;
- unsigned int bmblkno, k, l;
- CAFBMB *bmb;
-
- /* Iterate over all bytes and all bits in the toplevel bitmap. */
- for (k = 0 ; k < bm->FreeZoneIndexSize ; ++k) {
- if (bm->Bits[k] == 0) continue;
- for (l = 0; l < BYTEWIDTH ; ++l) {
- if ((bm->Bits[k] & (1 << l)) != 0) {
- /* found a bit set! fetch the BMB. */
- bmblkno = k*BYTEWIDTH + l;
- bmb = CAFFetchBMB(bmblkno, fd, bm);
- if (bmb == NULL) return 0;
-
- curblk = bmb->StartDataBlock;
- while (curblk < bmb->MaxDataBlock) {
- blkno = (curblk - bmb->StartDataBlock)/(bm->BlockSize);
- ind = blkno/BYTEWIDTH;
- if (bmb->BMBBits[ind] == 0) {
- /* nothing set in this byte, skip this byte and move on. */
- blkno = (ind+1)*BYTEWIDTH;
- curblk = blkno*bm->BlockSize + bmb->StartDataBlock;
- continue;
- }
-
- /* scan rest of current byte for 1 bits */
- for (j = blkno % BYTEWIDTH ; j < BYTEWIDTH ; j++, curblk += bm->BlockSize) {
- if ((bmb->BMBBits[ind] & (1 << j)) != 0) break;
- }
- if (j == BYTEWIDTH) continue;
-
- /* found a 1 bit, set startblk to be locn of corresponding free blk. */
- startblk = curblk;
- curblk += bm->BlockSize;
-
- /* scan for n blocks in a row. */
- for (i = 1 ; i < n ; ++i, curblk += bm->BlockSize) {
- if (!CAFIsBlockFree(bm, fd, curblk)) break;
- }
-
- if (i == n) return startblk;
-
- /* otherwise curblk points to a non-free blk, continue searching from there. */
- continue;
- }
- }
- }
- }
- return 0;
-}
-
-/*
-** Open a CAF file for reading and seek to the start of a given article.
-** Take as args the CAF file pathname, article #, and a pointer to where
-** the art. length can be returned.
-*/
-
-int
-CAFOpenArtRead(const char *path, ARTNUM art, size_t *len)
-{
- CAFHEADER head;
- int fd;
- CAFTOCENT tocent;
- struct stat st;
-
- if ( (fd = open(path, O_RDONLY)) < 0) {
- /*
- ** if ENOENT (not there), just call this "article not found",
- ** otherwise it's a more serious error and stash the errno.
- */
- if (errno == ENOENT) {
- CAFError(CAF_ERR_ARTNOTHERE);
- } else {
- CAFError(CAF_ERR_IO);
- }
- return -1;
- }
-
- /* Fetch the header */
- if (CAFReadHeader(fd, &head) < 0) {
- close(fd);
- return -1;
- }
-
- /* Is the requested article even in the file? */
- if (art < head.Low || art > head.High) {
- CAFError(CAF_ERR_ARTNOTHERE);
- close(fd);
- return -1;
- }
-
- if (CAFGetTOCEnt(fd, &head, art, &tocent) < 0) {
- close(fd);
- return -1;
- }
-
- if (tocent.Size == 0) {
- /* empty/otherwise not present article */
- CAFError(CAF_ERR_ARTNOTHERE);
- close(fd);
- return -1;
- }
-
- if (lseek(fd, tocent.Offset, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- close(fd);
- return -1;
- }
-
- /* I'm not sure if this fstat is worth the speed hit, but unless we check
- here, we may simply segfault when we try to access mmap'd space beyond
- the end of the file. I think robustness wins. */
- if (fstat(fd, &st) == 0)
- if (tocent.Size > st.st_size - tocent.Offset) {
- CAFError(CAF_ERR_IO);
- close(fd);
- return -1;
- }
-
- *len = tocent.Size;
- return fd;
-}
-
-/*
-** variables for keeping track of currently pending write.
-** FIXME: assumes only one article open for writing at a time.
-*/
-
-static int CAF_fd_write;
-static ARTNUM CAF_artnum_write;
-static off_t CAF_startoffset_write;
-static CAFHEADER CAF_header_write;
-static CAFBITMAP *CAF_free_bitmap_write;
-static unsigned int CAF_numblks_write;
-
-/*
-** Given estimated size of CAF file (i.e., the size of the old CAF file found
-** by cafclean), find an "optimal" blocksize (one big enough so that the
-** default FreeZoneTabSize can cover the entire
-** file so that we don't "lose" free space and not be able to reuse it.
-** (Currently only returns CAF_DEFAULT_BLOCKSIZE, as with the new 2-level
-** bitmaps, the FreeZoneTabSize that results from a 512-byte blocksize can
-** handle any newsgroup with <7.3G of data. Yow!)
-*/
-
-static unsigned int
-CAFFindOptimalBlocksize(ARTNUM tocsize UNUSED, size_t cfsize)
-{
-
- if (cfsize == 0) return CAF_DEFAULT_BLOCKSIZE; /* no size given, use default. */
-
- return CAF_DEFAULT_BLOCKSIZE;
-}
-
-/*
-** Create an empty CAF file. Used by CAFOpenArtWrite.
-** Must be careful here and create the new CAF file under a temp name and then
-** link it into place, to avoid possible race conditions.
-** Note: CAFCreateCAFFile returns fd locked, also to avoid race conds.
-** New args added for benefit of the cleaner program: "nolink", a flag that
-** tells it not to bother with the link business, and "temppath", a pointer
-** to a buffer that (if non-null) gets the pathname of the temp file copied
-** to it. "estcfsize", if nonzero, is an estimate of what the CF filesize will
-** be, used to automatically select a good blocksize.
-*/
-int
-CAFCreateCAFFile(char *cfpath, ARTNUM artnum, ARTNUM tocsize,
- size_t estcfsize, int nolink, char *temppath)
-{
- CAFHEADER head;
- int fd;
- char path[SPOOLNAMEBUFF];
- char finalpath[SPOOLNAMEBUFF];
- off_t offset;
- char nulls[1];
-
- strlcpy(finalpath, cfpath, sizeof(finalpath));
- snprintf(path, sizeof(path), "%s.%d", cfpath, getpid());/* create path with PID attached */
- /*
- ** Shouldn't be anyone else with our pid trying to write to the temp.
- ** file, but there might be an old one lying around. Nuke it.
- ** (yeah, I'm probably being overly paranoid.)
- */
- if (unlink(path) < 0 && errno != ENOENT) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- if ((fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0666)) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- /* Initialize the header. */
- strncpy(head.Magic, CAF_MAGIC, CAF_MAGIC_LEN);
- head.Low = artnum;
- head.High = artnum;
- head.NumSlots = tocsize;
- head.Free = 0;
- head.BlockSize = CAFFindOptimalBlocksize(tocsize, estcfsize);
- head.FreeZoneIndexSize = head.BlockSize - sizeof(CAFHEADER);
- head.FreeZoneTabSize = head.FreeZoneIndexSize
- + head.BlockSize*head.FreeZoneIndexSize*BYTEWIDTH;
- head.StartDataBlock = CAFRoundOffsetUp(sizeof(CAFHEADER)
- + head.FreeZoneTabSize + tocsize*sizeof(CAFTOCENT), head.BlockSize);
-
- head.spare[0] = head.spare[1] = head.spare[2] = 0;
-
- if (OurWrite(fd, &head, sizeof(head)) < 0) {
- close(fd);
- return -1;
- }
-
- offset = sizeof(CAFHEADER) + head.FreeZoneTabSize +
- sizeof(CAFTOCENT) * tocsize;
-
- if (lseek(fd, offset, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- /*
- ** put a null after the TOC as a 'placeholder', so that we'll have a sparse
- ** file and that EOF will be at where the articles should start going.
- */
- nulls[0] = 0;
- if (OurWrite(fd, nulls, 1) < 0) {
- close(fd);
- return -1;
- }
- /* shouldn't be anyone else locking our file, since temp file has unique
- PID-based name ... */
- if (!inn_lock_file(fd, INN_LOCK_WRITE, false)) {
- CAFError(CAF_ERR_IO);
- close(fd);
- return -1;
- }
-
- if (nolink) {
- if (temppath != NULL) {
- strcpy(temppath, path);
- }
- return fd;
- }
-
- /*
- ** Try to link to the real one. NOTE: we may get EEXIST here, which we
- ** will handle specially in OpenArtWrite.
- */
- if (link(path, finalpath) < 0) {
- CAFError(CAF_ERR_IO);
- /* bounced on the link attempt, go ahead and unlink the temp file and return. */
- unlink(path);
- close(fd);
- return -1;
- }
- /*
- ** Unlink the temp. link. Do we really care if this fails? XXX
- ** Not sure what we can do anyway.
- */
- unlink(path);
- return fd;
-}
-
-/*
-** Try to open a CAF file for writing a given article. Return an fd to
-** write to (already positioned to the right place to write at) if successful,
-** else -1 on error. if LockFlag is true, we wait for a lock on the file,
-** otherwise we fail if we can't lock it. If size is != 0, we try to allocate
-** a chunk from free space in the CAF instead of writing at the end of the
-** file. Artp is a pointer to the article number to use; if the article number
-** is zero, the next free article # ("High"+1) will be used, and *artp will
-** be set accordingly. Once the CAF file is open/created, CAFStartWriteFd()
-** does the remaining dirty work.
-*/
-
-int
-CAFOpenArtWrite(char *path, ARTNUM *artp, int waitlock, size_t size)
-{
- int fd;
-
- while (true) {
- /* try to open the file and lock it. */
- if ((fd = open(path, O_RDWR)) < 0) {
- /* if ENOENT, try creating CAF file, otherwise punt. */
- if (errno != ENOENT) {
- CAFError(CAF_ERR_IO);
- return -1;
- } else {
- /*
- ** the *artp? business is so that if *artp==0, we set initial
- ** article # to 1.
- */
- fd = CAFCreateCAFFile(path, (*artp ? *artp : 1),
- CAF_DEFAULT_TOC_SIZE, 0, 0, NULL);
- /*
- ** XXX possible race condition here, so we check to see if
- ** create failed because of EEXIST. If so, we go back to top
- ** of loop, because someone else was trying to create at the
- ** same time.
- ** Is this the best way to solve this?
- ** (Hmm. this condition should be quite rare, occuring only
- ** when two different programs are simultaneously doing
- ** CAFOpenArtWrite()s, and no CF file exists previously.)
- */
- if (fd < 0) {
- if (caf_errno == EEXIST) {
- /* ignore the error and try again */
- continue;
- }
- return -1; /* other error, assume caf_errno set properly. */
- }
- /*
- ** break here, because CreateCAFFile does
- ** lock fd, so we don't need to flock it ourselves.
- */
- break;
- }
- }
-
- /* try a nonblocking lock attempt first. */
- if (inn_lock_file(fd, INN_LOCK_WRITE, false)) break;
-
- if (!waitlock) {
- CAFError(CAF_ERR_FILEBUSY);
- close(fd); /* keep from leaking fds. */
- return -1;
- }
- /* wait around to try and get a lock. */
- inn_lock_file(fd, INN_LOCK_WRITE, true);
- /*
- ** and then close and reopen the file, in case someone changed the
- ** file out from under us.
- */
- close(fd);
- }
- return CAFStartWriteFd(fd, artp, size);
-}
-
-/*
-** Like CAFOpenArtWrite(), except we assume the CAF file is already
-** open/locked, and we have an open fd to it.
-*/
-int
-CAFStartWriteFd(int fd, ARTNUM *artp, size_t size)
-{
- CAFHEADER head;
- CAFTOCENT tocent;
- off_t offset, startoffset;
- unsigned int numblks = 0;
- CAFBITMAP *freebm;
- ARTNUM art;
-
- /* fd is open to the CAF file, open for write and locked. */
- /* Fetch the header */
- if (CAFReadHeader(fd, &head) < 0) {
- close(fd);
- return -1;
- }
-
- /* check for zero article number and handle accordingly. */
- art = *artp;
- if (art == 0) {
- /* assign next highest article number. */
- art = head.High + 1;
- /* and pass to caller. */
- *artp = art;
- }
-
- /* Is the requested article even in the file? */
- if (art < head.Low || art >= head.Low + head.NumSlots) {
- CAFError(CAF_ERR_ARTWONTFIT);
- close(fd);
- return -1;
- }
-
- /*
- ** Get the CAFTOCENT for that article, but only if article# is in the range
- ** Low <= art# <= High. If art# > High, use a zero CAFTOCENT. This means
- ** that in cases where the CAF file is inconsistent due to a crash ---
- ** the CAFTOCENT shows an article as being existent, but the header
- ** doesn't show that article as being in the currently valid range ---
- ** the header value "wins" and we assume the article does not exist.
- ** This avoids problems with "half-existent" articles that showed up
- ** in the CAF TOC, but were never picked up by ctlinnd renumber '' .
- */
- /* (Note: We already checked above that art >= head.Low.) */
-
- if (art > head.High) {
- /* clear the tocent */
- memset(&tocent, 0, sizeof(tocent));
- } else {
- if (CAFGetTOCEnt(fd, &head, art, &tocent) < 0) {
- close(fd);
- return -1;
- }
- }
-
- if (tocent.Size != 0) {
- /* article is already here */
- CAFError(CAF_ERR_ARTALREADYHERE);
- close(fd);
- return -1;
- }
-
- startoffset = 0;
- freebm = NULL;
-
- if (size != 0 && (freebm = CAFReadFreeBM(fd, &head)) != NULL) {
- numblks = (size + head.BlockSize - 1) / head.BlockSize;
- startoffset = CAFFindFreeBlocks(freebm, fd, numblks);
- if (startoffset == 0) {
- CAFDisposeBitmap(freebm);
- freebm = NULL;
- }
- }
-
- if (startoffset == 0) {
- /*
- ** No size given or free space not available, so
- ** seek to EOF to prepare to start writing article.
- */
-
- if ((offset = lseek(fd, 0, SEEK_END)) < 0) {
- CAFError(CAF_ERR_IO);
- close(fd);
- return -1;
- }
- /* and round up offset to a block boundary. */
- startoffset = CAFRoundOffsetUp(offset, head.BlockSize);
- }
-
- /* Seek to starting offset for the new artiicle. */
- if (lseek(fd, startoffset, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- close(fd);
- return -1;
- }
-
- /* stash data for FinishArtWrite's use. */
- CAF_fd_write = fd;
- CAF_artnum_write = art;
- CAF_startoffset_write = startoffset;
- CAF_header_write = head;
- CAF_free_bitmap_write = freebm;
- CAF_numblks_write = numblks;
-
- return fd;
-}
-
-/*
-** write out TOC entries for the previous article. Note that we do *not*
-** (as was previously done) close the fd; this allows reuse of the fd to write
-** another article to this CAF file w/o an (soemwhat expensive) open().
-*/
-
-int
-CAFFinishArtWrite(int fd)
-{
- off_t curpos;
- CAFTOCENT tocentry;
- off_t curblk;
- CAFHEADER *headp;
- unsigned int i;
-
- /* blah, really should handle multiple pending OpenArtWrites. */
- if (fd != CAF_fd_write) {
- fprintf(stderr, "CAF: fd mismatch in CloseArtWrite.\n");
- abort();
- }
-
- headp = &CAF_header_write;
-
- /* Find out where we left off writing in the file. */
- if ((curpos = lseek(fd, 0, SEEK_CUR)) < 0) {
- CAFError(CAF_ERR_IO);
- CAF_fd_write = 0;
- return -1;
- }
-
- /* Write the new TOC entry. */
- if (CAFSeekTOCEnt(fd, headp, CAF_artnum_write) < 0) {
- CAF_fd_write = 0;
- return -1;
- }
- tocentry.Offset = CAF_startoffset_write;
- tocentry.Size = curpos - CAF_startoffset_write;
- tocentry.ModTime = time((time_t *)NULL);
- if (OurWrite(fd, &tocentry, sizeof(CAFTOCENT)) < 0) {
- CAF_fd_write = 0;
- return -1;
- }
-
- /* if needed, update free bitmap. */
- if (CAF_free_bitmap_write != NULL) {
- /* Paranoia: check to make sure we didn't write more than we said we would. */
- if (tocentry.Size > CAF_numblks_write * headp->BlockSize) {
- /*
- ** for now core dump (might as well, if we've done this the CAF
- ** file is probably thoroughly hosed anyway.)
- */
- fprintf(stderr, "CAF: article written overran declared size.\n");
- abort();
- }
-
- curblk = CAF_startoffset_write;
-
- for (i = 0 ; i < CAF_numblks_write ; ++i, curblk += headp->BlockSize) {
- CAFSetBlockFree(CAF_free_bitmap_write, fd, curblk, 0);
- }
- if (CAFWriteFreeBM(fd, CAF_free_bitmap_write) < 0){
- CAFError(CAF_ERR_IO);
- CAF_fd_write = 0;
- return -1;
- }
- CAFDisposeBitmap(CAF_free_bitmap_write);
- /* and update the Free value in the header. */
- headp->Free -= CAF_numblks_write * headp->BlockSize;
- }
-
- if (CAF_artnum_write > headp->High || CAF_free_bitmap_write) {
- /* need to update header. */
- if (CAF_artnum_write > headp->High) {
- headp->High = CAF_artnum_write;
- }
- if (lseek(fd, 0, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- CAF_fd_write = 0;
- return -1;
- }
- if (OurWrite(fd, headp, sizeof(CAFHEADER)) < 0) {
- CAF_fd_write = 0;
- return -1;
- }
- }
-#if 0
- if (close(fd) < 0) {
- CAFError(CAF_ERR_IO);
- CAF_fd_write =0;
- return -1;
- }
-#endif
- CAF_fd_write = 0;
- return 0;
-}
-
-/*
-** return a string containing a description of the error.
-** Warning: uses a static buffer, or possibly a static string.
-*/
-
-static char errbuf[512];
-
-const char *
-CAFErrorStr(void)
-{
- if (caf_error == CAF_ERR_IO || caf_error == CAF_ERR_CANTCREATECAF) {
- snprintf(errbuf, sizeof(errbuf), "%s errno=%s\n",
- (caf_error == CAF_ERR_IO) ? "CAF_ERR_IO" : "CAF_ERR_CANTCREATECAF",
- strerror(errno));
- return errbuf;
- } else {
- switch(caf_error) {
- case CAF_ERR_BADFILE:
- return "CAF_ERR_BADFILE";
- case CAF_ERR_ARTNOTHERE:
- return "CAF_ERR_ARTNOTHERE";
- case CAF_ERR_FILEBUSY:
- return "CAF_ERR_FILEBUSY";
- case CAF_ERR_ARTWONTFIT:
- return "CAF_ERR_ARTWONTFIT";
- case CAF_ERR_ARTALREADYHERE:
- return "CAF_ERR_ARTALREADYHERE";
- case CAF_ERR_BOGUSPATH:
- return "CAF_ERR_BOGUSPATH";
- default:
- snprintf(errbuf, sizeof(errbuf), "CAF error %d", caf_error);
- return errbuf;
- }
- }
-}
-
-/*
-** Open a CAF file, snarf the TOC entries for all the articles inside,
-** and close the file. NOTE: returns the header for the CAF file in
-** the storage pointed to by *ch. Dynamically allocates storage for
-** the TOC entries, which should be freed by the caller when the
-** caller's done with it. Return NULL on failure.
-**
-** This function calls CAFOpenReadTOC(dir, ch, &tocp), which does most
-** (practically all) of the dirty work. CAFOpenReadTOC leaves the fd open
-** (and returns it); this is needed by cafls. CAFReadTOC() closes the fd
-** after CAFOpenReadTOC() is done with it.
-*/
-
-CAFTOCENT *
-CAFReadTOC(char *path, CAFHEADER *ch)
-{
- CAFTOCENT *tocp;
- int fd;
-
- if ((fd = CAFOpenReadTOC(path, ch, &tocp)) < 0) {
- return NULL; /* some sort of error happened */
- }
-
- close(fd);
- return tocp;
-}
-
-int
-CAFOpenReadTOC(char *path, CAFHEADER *ch, CAFTOCENT **tocpp)
-{
- int fd;
- int nb;
- CAFTOCENT *tocp;
- off_t offset;
-
- if ( (fd = open(path, O_RDONLY)) < 0) {
- /*
- ** if ENOENT (not there), just call this "article not found",
- ** otherwise it's a more serious error and stash the errno.
- */
- if (errno == ENOENT) {
- CAFError(CAF_ERR_ARTNOTHERE);
- } else {
- CAFError(CAF_ERR_IO);
- }
- return -1;
- }
-
- /* Fetch the header */
- if (CAFReadHeader(fd, ch) < 0) {
- close(fd);
- return -1;
- }
-
- /* Allocate memory for TOC. */
- tocp = xmalloc((ch->High - ch->Low + 1) * sizeof(CAFTOCENT));
- nb = (sizeof(CAFTOCENT))*(ch->High - ch->Low + 1); /* # bytes to read for toc. */
-
- /* seek to beginning of TOC */
- offset = sizeof(CAFHEADER) + ch->FreeZoneTabSize;
-
- if (lseek(fd, offset, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- if (OurRead(fd, tocp, nb) < 0) {
- return -1;
- }
-
- /* read TOC successfully, return fd and stash tocp where we were told to */
- *tocpp = tocp;
- return fd;
-}
-
-
-/*
-** Cancel/expire articles from a CAF file. This involves zeroing the Size
-** field of the TOC entry, and updating the Free field of the CAF header.
-** note that no disk space is actually freed by this process; space will only
-** be returned to the OS when the cleaner daemon runs on the CAF file.
-*/
-
-int
-CAFRemoveMultArts(char *path, unsigned int narts, ARTNUM *artnums)
-{
- int fd;
- CAFHEADER head;
- CAFTOCENT tocent;
- CAFBITMAP *freebitmap;
- ARTNUM art;
- unsigned int numblksfreed, i, j;
- off_t curblk;
- int errorfound = false;
-
- while (true) {
- /* try to open the file and lock it */
- if ((fd = open(path, O_RDWR)) < 0) {
- /* if ENOENT, CAF file isn't there, so return ARTNOTHERE, otherwise it's an I/O error. */
- if (errno != ENOENT) {
- CAFError(CAF_ERR_IO);
- return -1;
- } else {
- CAFError(CAF_ERR_ARTNOTHERE);
- return -1;
- }
- }
- /* try a nonblocking lock attempt first. */
- if (inn_lock_file(fd, INN_LOCK_WRITE, false)) break;
-
- /* wait around to try and get a lock. */
- inn_lock_file(fd, INN_LOCK_WRITE, true);
- /*
- ** and then close and reopen the file, in case someone changed the
- ** file out from under us.
- */
- close(fd);
- }
- /* got the file, open for write and locked. */
- /* Fetch the header */
- if (CAFReadHeader(fd, &head) < 0) {
- close(fd);
- return -1;
- }
-
- if ((freebitmap = CAFReadFreeBM(fd, &head)) == NULL) {
- close(fd);
- return -1;
- }
-
- for (j = 0 ; j < narts ; ++j) {
- art = artnums[j];
-
- /* Is the requested article even in the file? */
- if (art < head.Low || art > head.High) {
- CAFError(CAF_ERR_ARTNOTHERE);
- errorfound = true;
- continue; /* don't abandon the whole remove if just one art is missing */
- }
-
- if (CAFGetTOCEnt(fd, &head, art, &tocent) < 0) {
- close(fd);
- CAFDisposeBitmap(freebitmap);
- return -1;
- }
-
- if (tocent.Size == 0) {
- CAFError(CAF_ERR_ARTNOTHERE);
- errorfound = true;
- continue; /* don't abandon the whole remove if just one art is missing */
- }
-
- numblksfreed = (tocent.Size + head.BlockSize - 1) / head.BlockSize;
-
- /* Mark all the blocks as free. */
- for (curblk = tocent.Offset, i = 0 ; i < numblksfreed; ++i, curblk += head.BlockSize) {
- CAFSetBlockFree(freebitmap, fd, curblk, 1);
- }
- /* Note the amount of free space added. */
- head.Free += numblksfreed * head.BlockSize;
- /* and mark the tocent as a deleted entry. */
- tocent.Size = 0;
-
- if (CAFSeekTOCEnt(fd, &head, art) < 0) {
- close(fd);
- CAFDisposeBitmap(freebitmap);
- return -1;
- }
-
- if (OurWrite(fd, &tocent, sizeof(CAFTOCENT)) < 0) {
- close(fd);
- CAFDisposeBitmap(freebitmap);
- return -1;
- }
- }
-
- if (CAFWriteFreeBM(fd, freebitmap) < 0) {
- close(fd);
- CAFDisposeBitmap(freebitmap);
- return -1;
- }
- /* dispose of bitmap storage. */
- CAFDisposeBitmap(freebitmap);
-
- /* need to update header. */
- if (lseek(fd, 0, SEEK_SET) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
- if (OurWrite(fd, &head, sizeof(CAFHEADER)) < 0) {
- return -1;
- }
-
- if (close(fd) < 0) {
- CAFError(CAF_ERR_IO);
- return -1;
- }
-
- if (CAFClean(path, 0, 10.0) < 0) errorfound=true;
-
- return errorfound ? -1 : 0;
-}
-
-/*
-** Do a fake stat() of a CAF-stored article. Both 'inpaths' and 'innfeed'
-** find this functionality useful, so we've added a function to do this.
-** Caveats: not all of the stat structure is filled in, only these items:
-** st_mode, st_size, st_atime, st_ctime, st_mtime. (Note:
-** atime==ctime==mtime always, as we don't track times of CAF reads.)
-*/
-
-int
-CAFStatArticle(char *path, ARTNUM art, struct stat *stbuf)
-{
- CAFHEADER head;
- int fd;
- CAFTOCENT tocent;
-
- if ( (fd = open(path, O_RDONLY)) < 0) {
- /*
- ** if ENOENT (not there), just call this "article not found",
- ** otherwise it's a more serious error and stash the errno.
- */
- if (errno == ENOENT) {
- CAFError(CAF_ERR_ARTNOTHERE);
- } else {
- CAFError(CAF_ERR_IO);
- }
- return -1;
- }
-
- /* Fetch the header */
- if (CAFReadHeader(fd, &head) < 0) {
- close(fd);
- return -1;
- }
-
- /* Is the requested article even in the file? */
- if (art < head.Low || art > head.High) {
- CAFError(CAF_ERR_ARTNOTHERE);
- close(fd);
- return -1;
- }
-
- if (CAFGetTOCEnt(fd, &head, art, &tocent) < 0) {
- close(fd);
- return -1;
- }
-
- if (tocent.Size == 0) {
- /* empty/otherwise not present article */
- CAFError(CAF_ERR_ARTNOTHERE);
- close(fd);
- return -1;
- }
-
- /* done with file, can close it. */
- close(fd);
-
- memset(stbuf, 0, sizeof(struct stat));
- stbuf->st_mode = S_IFREG | 0444;
- stbuf->st_size = tocent.Size;
- stbuf->st_atime = stbuf->st_ctime = stbuf->st_mtime = tocent.ModTime;
- return 0;
-}
-
-/*
-** Taken from the old 'cafclean' program.
-** Function to clean a single CAF file.
-** Possibly the ugliest function I've ever written in my life.
-*/
-/*
-** We try to keep the total TOC size this many times larger than the actual
-** amount of TOC data in use so as not to have to reclean or compact the TOC
-** so often.
-*/
-#define TOC_CLEAN_RATIO 10
-/*
-** ditto, but for compacting, we want to force a compacting if the High art#
-** wanders into the top nth of the TOC slots.
-*/
-#define TOC_COMPACT_RATIO 5
-
-int
-CAFClean(char *path, int verbose, double PercentFreeThreshold)
-{
- char *newpath;
- CAFHEADER head, newhead;
- int fdin, fdout;
- ARTNUM newlow;
- ARTNUM i;
- CAFTOCENT *tocarray, *tocp;
- CAFTOCENT *newtocarray, *newtocp;
- size_t newtocsize;
- FILE *infile, *outfile;
- off_t startoffset, newstartoffset;
- char buf[BUFSIZ];
- int nbytes, ncur;
- int n;
- unsigned int blocksize;
- char *zerobuff;
- struct stat statbuf;
- size_t datasize;
- double percentfree;
- int toc_needs_expansion;
- int toc_needs_compacting;
-
-#ifdef STATFUNCT
- struct STATSTRUC fsinfo;
- long num_diskblocks_needed;
-#endif
-
- /* allocate buffer for newpath */
- newpath = xmalloc(strlen(path) + 10);
- while (true) {
- /* try to open the file and lock it. */
- if ((fdin = open(path, O_RDWR)) < 0) {
- /*
- ** if ENOENT, obviously no CAF file is here, so just return,
- ** otherwise report an error.
- */
- if (errno != ENOENT) {
- CAFError(CAF_ERR_IO);
- return -1;
- } else {
- return 0;
- }
- }
-
- /* try a nonblocking lock attempt first. */
- if (inn_lock_file(fdin, INN_LOCK_WRITE, false)) break;
-
- /* wait around to try and get a lock. */
- inn_lock_file(fdin, INN_LOCK_WRITE, true);
- /*
- ** and then close and reopen the file, in case someone changed the
- ** file out from under us.
- */
- close(fdin);
- }
-
- /* got the file, open for write and locked. */
- /* Fetch the header */
- if (CAFReadHeader(fdin, &head) < 0) {
- close(fdin);
- return -1;
- }
-
- /* Stat the file to see how big it is */
- if (fstat(fdin, &statbuf) < 0) {
- close(fdin);
- CAFError(CAF_ERR_IO);
- perror(path);
- return -1;
- }
-
- /* compute amount of actual data in file. */
- datasize = statbuf.st_size - head.StartDataBlock;
- if (datasize <= 0) {
- /* nothing in the file, set percentfree==0 so won't bother cleaning */
- percentfree = 0;
- } else {
- percentfree = (100.0 * head.Free) / datasize;
- }
-
- /*
- ** Grumble, we need to read the TOC now even before we clean, just so
- ** we can decide if a clean or a compaction is needed.
- */
-
- lseek(fdin, 0L, SEEK_SET);
-
- /* make input file stdio-buffered. */
- if ((infile = fdopen(fdin, "r+")) == NULL) {
- CAFError(CAF_ERR_IO);
- close(fdin);
- return -1;
- }
-
- /* Allocate memory for TOC. */
- tocarray = xmalloc((head.High - head.Low + 1) * sizeof(CAFTOCENT));
-
- fseeko(infile, (off_t) (sizeof(CAFHEADER) + head.FreeZoneTabSize),
- SEEK_SET);
-
- n = fread(tocarray, sizeof(CAFTOCENT), (head.High - head.Low + 1), infile);
- if (n < 0) {
- CAFError(CAF_ERR_IO);
- fclose(infile);
- free(tocarray);
- free(newpath);
- return -1;
- }
-
- if ((unsigned long) n < (head.High - head.Low +1)) {
- CAFError(CAF_ERR_BADFILE);
- fclose(infile);
- free(tocarray);
- free(newpath);
- return -1;
- }
-
- /* Scan to see what the new lower bound for CAF file should be. */
- newlow = head.High + 1;
-
- for (tocp = tocarray, i = head.Low; i <= head.High; ++tocp, ++i) {
- if (tocp->Size != 0) {
- newlow = i;
- break;
- }
- }
-
- /*
- ** if newlow is head.High+1, the TOC is completely empty and we can
- ** just remove the entire file.
- */
- if (newlow == head.High + 1) {
- unlink(path);
- fclose(infile);
- free(tocarray);
- free(newpath);
- return 0;
- }
-
- /*
- ** Ah. NOW we get to decide if we need a clean!
- ** Clean if either
- ** 1) the absolute freespace threshold is crossed
- ** 2) the percent free threshold is crossed.
- ** 3) The CAF TOC is over 10% full (assume it needs to be expanded,
- ** so we force a clean)
- ** Note that even if we do not need a clean, we may need a compaction
- ** if the high article number is in the top nth of the TOC.
- */
-
- toc_needs_expansion = 0;
- if ( (head.High - newlow) >= head.NumSlots/TOC_CLEAN_RATIO) {
- toc_needs_expansion = 1;
- }
-
- toc_needs_compacting = 0;
- if ( (head.Low + head.NumSlots - head.NumSlots/TOC_COMPACT_RATIO) <= head.High) {
- toc_needs_compacting = 1;
- }
-
- if ( (percentfree < PercentFreeThreshold)
- && (!toc_needs_expansion) ) {
- /* no cleaning, but do we need a TOC compaction ? */
- if (toc_needs_compacting) {
- int delta;
- CAFTOCENT *tocp2;
-
- if (verbose) {
- printf("Compacting %s: Free=%lu (%f%%)\n", path,
- (unsigned long) head.Free, percentfree);
- }
-
- delta = newlow - head.Low;
-
- /* slide TOC array down delta units. */
- for (i = newlow, tocp = tocarray, tocp2 = tocarray+delta;
- i <= head.High ; ++i) {
- *tocp++ = *tocp2++;
- }
-
- head.Low = newlow;
- /* note we don't set LastCleaned, this doesn't count a a clean. */
- /* (XXX: do we need a LastCompacted as well? might be nice.) */
-
- /* write new header on top of old */
- fseeko(infile, 0, SEEK_SET);
- if (fwrite(&head, sizeof(CAFHEADER), 1, infile) < 1) {
- CAFError(CAF_ERR_IO);
- free(tocarray);
- free(newpath);
- fclose(infile);
- return -1;
- }
- /*
- ** this next fseeko might actually fail, because we have buffered
- ** stuff that might fail on write.
- */
- if (fseeko(infile, sizeof(CAFHEADER) + head.FreeZoneTabSize,
- SEEK_SET) < 0) {
- perror(path);
- free(tocarray);
- free(newpath);
- fclose(infile);
- unlink(newpath);
- return -1;
- }
- if (fwrite(tocarray, sizeof(CAFTOCENT), head.High - newlow + 1, infile) < head.High - newlow + 1
- || fflush(infile) < 0) {
- CAFError(CAF_ERR_IO);
- free(tocarray);
- free(newpath);
- fclose(infile);
- return -1;
- }
- /* all done, return. */
- fclose(infile);
- free(tocarray);
- free(newpath);
- return 0;
- } else {
- /* need neither full cleaning nor compaction, so return. */
- if (verbose) {
- printf("Not cleaning %s: Free=%lu (%f%%)\n", path,
- (unsigned long) head.Free, percentfree);
- }
- fclose(infile);
- free(tocarray);
- free(newpath);
- return 0;
- }
- }
-
- /*
- ** If OS supports it, try to check for free space and skip this file if
- ** not enough free space on this filesystem.
- */
-#ifdef STATFUNCT
- if (STATFUNCT(fdin, &fsinfo) >= 0) {
- /* compare avail # blocks to # blocks needed for current file.
- ** # blocks needed is approximately
- ** datasize/blocksize + (size of the TOC)/blocksize
- ** + Head.BlockSize/blocksize, but we need to take rounding
- ** into account.
- */
-#define RoundIt(n) (CAFRoundOffsetUp((n), fsinfo.STATMULTI) / fsinfo.STATMULTI)
-
- num_diskblocks_needed = RoundIt((head.High - head.Low + 1)*sizeof(CAFTOCENT))
- + RoundIt(datasize - head.Free) + RoundIt(head.BlockSize);
- if (num_diskblocks_needed > fsinfo.STATAVAIL) {
- if (verbose) {
- printf("CANNOT clean %s: needs %ld blocks, only %ld avail.\n",
- path, num_diskblocks_needed,
- (unsigned long) fsinfo.f_bavail);
- }
- fclose(infile);
- free(tocarray);
- free(newpath);
- return 0;
- }
- }
-#endif
-
- if (verbose) {
- printf("Am cleaning %s: Free=%d (%f%%) %s\n", path, head.Free,
- percentfree, toc_needs_expansion ? "(Expanding TOC)" : "");
- }
-
- /* decide on proper size for new TOC */
- newtocsize = CAF_DEFAULT_TOC_SIZE;
- if (head.High - newlow > newtocsize/TOC_CLEAN_RATIO) {
- newtocsize = TOC_CLEAN_RATIO*(head.High - newlow);
- }
-
- /* try to create new CAF file with some temp. pathname */
- /* note: new CAF file is created in flocked state. */
- if ((fdout = CAFCreateCAFFile(path, newlow, newtocsize,
- statbuf.st_size, 1, newpath)) < 0) {
- fclose(infile);
- free(tocarray);
- free(newpath);
- return -1;
- }
-
- if ((outfile = fdopen(fdout, "w+")) == NULL) {
- CAFError(CAF_ERR_IO);
- fclose(infile);
- free(tocarray);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- newtocarray = xcalloc((head.High - newlow + 1), sizeof(CAFTOCENT));
-
- if (fseeko(outfile, 0, SEEK_SET) < 0) {
- perror(newpath);
- free(tocarray);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- /* read in the CAFheader from the new file. */
- if (fread(&newhead, sizeof(CAFHEADER), 1, outfile) < 1) {
- perror(newpath);
- free(tocarray);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- /* initialize blocksize, zeroes buffer. */
- blocksize = newhead.BlockSize;
- if (blocksize == 0) blocksize=CAF_DEFAULT_BLOCKSIZE;
-
- zerobuff = xcalloc(blocksize, 1);
-
- /* seek to end of output file/place to start writing new articles */
- fseeko(outfile, 0, SEEK_END);
- startoffset = ftello(outfile);
- startoffset = CAFRoundOffsetUp(startoffset, blocksize);
- fseeko(outfile, (off_t) startoffset, SEEK_SET);
-
- /*
- ** Note: startoffset will always give the start offset of the next
- ** art to be written to the outfile.
- */
-
- /*
- ** Loop over all arts in old TOC, copy arts that are still here to new
- ** file and new TOC.
- */
-
- for (tocp = tocarray, i = head.Low; i <= head.High; ++tocp, ++i) {
- if (tocp->Size != 0) {
- newtocp = &newtocarray[i - newlow];
- newtocp->Offset = startoffset;
- newtocp->Size = tocp->Size;
- newtocp->ModTime = tocp->ModTime;
-
- /* seek to right place in input. */
- fseeko(infile, (off_t) tocp->Offset, SEEK_SET);
-
- nbytes = tocp->Size;
- while (nbytes > 0) {
- ncur = (nbytes > BUFSIZ) ? BUFSIZ : nbytes;
- if (fread(buf, sizeof(char), ncur, infile) < ncur
- || fwrite(buf, sizeof(char), ncur, outfile) < ncur) {
- if (feof(infile)) {
- CAFError(CAF_ERR_BADFILE);
- } else {
- CAFError(CAF_ERR_IO);
- }
-
- errorexit:
- fclose(infile);
- fclose(outfile);
- free(tocarray);
- free(newtocarray);
- free(zerobuff);
- unlink(newpath);
- free(newpath);
- return -1;
- }
- nbytes -= ncur;
- }
- /* startoffset = ftello(outfile); */
- startoffset += tocp->Size;
- newstartoffset = CAFRoundOffsetUp(startoffset, blocksize);
- /* fseeko(outfile, (off_t) startoffset, SEEK_SET); */
- /* but we don't want to call fseeko, since that seems to always
- force a write(2) syscall, even when the new location would
- still be inside stdio's buffer. */
- if (newstartoffset - startoffset > 0) {
- ncur = newstartoffset - startoffset;
- if (fwrite(zerobuff, sizeof(char), ncur, outfile) < ncur) {
- /* write failed, must be disk error of some sort. */
- perror(newpath);
- goto errorexit; /* yeah, it's a goto. eurggh. */
- }
- }
- startoffset = newstartoffset;
- }
- }
-
- free(tocarray); /* don't need this guy anymore. */
- free(zerobuff);
-
- /*
- ** set up new file header, TOC.
- ** this next fseeko might actually fail, because we have buffered stuff
- ** that might fail on write.
- */
- if (fseeko(outfile, 0, SEEK_SET) < 0) {
- perror(newpath);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- /* Change what we need in new file's header. */
- newhead.Low = newlow;
- newhead.High = head.High;
- newhead.LastCleaned = time((time_t *) NULL);
-/* newhead.NumSlots = newtocsize; */
-/* newhead.Free = 0; */
-
- if (fwrite(&newhead, sizeof(CAFHEADER), 1, outfile) < 1) {
- CAFError(CAF_ERR_IO);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- /*
- ** this next fseeko might actually fail, because we have buffered stuff
- ** that might fail on write.
- */
- if (fseeko(outfile, sizeof(CAFHEADER) + newhead.FreeZoneTabSize,
- SEEK_SET) < 0) {
- perror(newpath);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- if (fwrite(newtocarray, sizeof(CAFTOCENT), head.High - newlow + 1, outfile) < head.High - newlow + 1
- || fflush(outfile) < 0) {
- CAFError(CAF_ERR_IO);
- free(newtocarray);
- fclose(infile);
- fclose(outfile);
- unlink(newpath);
- free(newpath);
- return -1;
- }
-
- if (rename(newpath, path) < 0) {
- CAFError(CAF_ERR_IO);
- free(newtocarray);
- free(newpath);
- fclose(infile);
- fclose(outfile);
- /* if can't rename, probably no point in trying to unlink newpath, is there? */
- return -1;
- }
- /* written and flushed newtocarray, can safely fclose and get out of
- here! */
- free(newtocarray);
- free(newpath);
- fclose(outfile);
- fclose(infile);
- return 0;
-}
+++ /dev/null
-/* $Revision: 5558 $
-** Declarations needed for handling CAF (Crunched Article Files)
-** Written by Richard Todd (rmtodd@mailhost.ecn.uoknor.edu) 3/24/96
-*/
-
-
-/*
-** Format of a crunched article file:
-** Header:
-*/
-
-typedef struct _CAFHEADER {
- char Magic[4]; /* Magic Number "CRMT" */
- ARTNUM Low; /* lowest article in the file */
- ARTNUM NumSlots; /* number of articles there are room for in the TOC */
- ARTNUM High; /* last article actually present in the file */
- size_t Free; /* amount of space currently unused (freed by cancels/expires) */
- off_t StartDataBlock; /* offset of first article data block. */
- unsigned int BlockSize; /* unit of allocation for CAF files. */
- size_t FreeZoneTabSize; /* amount of space taken up by the free zone table. */
- size_t FreeZoneIndexSize; /* size taken up by the "index" part of the free zone table. */
- time_t LastCleaned; /* note time of last cleaning. */
- int spare[3];
-} CAFHEADER;
-
-#define CAF_MAGIC "CRMT"
-#define CAF_MAGIC_LEN 4
-#define CAF_DEFAULT_BLOCKSIZE 512
-
-/*
-** then the table of free blocks. The table is FreeZoneTabSize bytes
-** long. First comes a "first-level" or "index" bitmap, taking up the
-** space from the end of the CAFHEADER to the end of the first
-** block, i.e. FreeZoneIndexBytes. The rest of the table is a big bitmap
-** listing free blocks in the 'data' portion of the CAF file.
-**
-** In the "index" bitmap: LSB of bitmap byte 0 is 1 if there are any 1s
-** (free blocks) listed in the first block of the big bitmap, and 0 if there
-** are no 1s in that block. The remaining bits of the index bitmap
-** correspond to the remaining blocks of the big bitmap accordingly.
-** The idea is that from the index bitmap one can tell which part of the
-** main bitmap is likely to have free blocks w/o having to read the entire
-** main bitmap.
-**
-** As for the main bitmap, each bit is 1 if the corresponding data
-** block (BlockSize bytes) is free. LSB of bitmap byte 0 corresponds
-** to the block @ offset StartDataBlock, and all the rest follow on
-** accordingly.
-**
-** Note that the main part of the bitmap is *always* FreeZoneIndexByte*8
-** blocks long, no matter how big the CAF file is. The table of free blocks
-** is almost always sparse. Also note that blocks past EOF in the CAF file
-** are *not* considered free. If the CAF article write routines fail to
-** find free space in the fre block bitmaps, they will always attempt to
-** extend the CAF file instead.
-*/
-
-#define CAF_DEFAULT_FZSIZE (512-sizeof(CAFHEADER))
-
-/*
-** (Note: the CAFBITMAP structure isn't what's actually stored on disk
-** in the free bitmap region, this is just a convenient structure to
-** keep the bitmap size and StartBlockOffset together with the bitmap
-** w/o having keep passing the original CAFHEADER to every routine
-** that wants it. The bitmap structure contains the first (index) bitmap,
-** as well as pointers to structures for each block of the main bitmap that
-** has been read into memory.
-*/
-
-typedef struct _CAFBITMAP {
- off_t StartDataBlock;
- off_t MaxDataBlock; /* can only handle offsets < this with this bitmap. */
- size_t FreeZoneTabSize;
- size_t FreeZoneIndexSize;
- size_t BytesPerBMB; /* size of chunk, in bytes, that any given BMBLK can map. */
- unsigned int BlockSize;
- unsigned int NumBMB; /* size of Blocks array. */
- struct _CAFBMB **Blocks;
- char *Bits;
-} CAFBITMAP;
-
-typedef struct _CAFBMB {
- off_t StartDataBlock;
- off_t MaxDataBlock;
- int Dirty; /* 1 if this BMB has had any bits changed. */
- char *BMBBits;
-} CAFBMB;
-
-/*
-** Next in the file are the TOC (Table of Contents) entries. Each TOC
-** entry describes an article.
-*/
-
-typedef struct _CAFTOCENT {
- off_t Offset;
- size_t Size;
- time_t ModTime;
-} CAFTOCENT;
-
-/*
-** and then after the NumSlots TOC Entries, the actual articles, one after
-** another, always starting at offsets == 0 mod BlockSize
-*/
-
-/*
-** Number of slots to put in TOC by default. Can be raised if we ever get
-** more than 256K articles in a newsgroup (frightening thought).
-*/
-
-#define CAF_DEFAULT_TOC_SIZE (256 * 1024)
-
-/*
-** Default name for CAF file in the news spool dir for a given newsgroup.
-*/
-#define CAF_NAME "CF"
-
-extern int CAFOpenArtRead(const char *cfpath, ARTNUM art, size_t *len);
-extern int CAFOpenArtWrite(char *cfpath, ARTNUM *art, int WaitLock, size_t size);
-extern int CAFStartWriteFd(int fd, ARTNUM *art, size_t size);
-extern int CAFFinishWriteFd(int fd);
-extern int CAFFinishArtWrite(int fd);
-extern int CAFCreateCAFFile(char *cfpath, ARTNUM lowart, ARTNUM tocsize, size_t cfsize, int nolink, char *temppath);
-extern const char *CAFErrorStr(void);
-extern CAFTOCENT *CAFReadTOC(char *cfpath, CAFHEADER *ch);
-extern int CAFRemoveMultArts(char *cfpath, unsigned int narts, ARTNUM *arts);
-extern int CAFStatArticle(char *path, ARTNUM art, struct stat *st);
-
-#ifdef CAF_INNARDS
-/* functions used internally by caf.c, and by the cleaner program, and cafls
- but probably aren't useful/desirable to be used by others. */
-extern int CAFOpenReadTOC(char *cfpath, CAFHEADER *ch, CAFTOCENT **tocpp);
-extern int CAFReadHeader(int fd, CAFHEADER *h);
-extern off_t CAFRoundOffsetUp(off_t offt, unsigned int bsize);
-extern CAFBITMAP * CAFReadFreeBM(int fd, CAFHEADER *h);
-extern void CAFDisposeBitmap(CAFBITMAP *cbm);
-/*
-** note! CAFIsBlockFree needs the fd, since blocks of the free bitmap may
-** need to be fetched from disk.
-*/
-extern int CAFIsBlockFree(CAFBITMAP *bm, int fd, off_t block);
-#endif
-
-extern int caf_error; /* last error encountered by library. */
-extern int caf_errno; /* saved value of errno here if I/O error hit by lib. */
-
-#define CAF_ERR_IO 1 /* generic I/O error, check caf_errno for details */
-#define CAF_ERR_BADFILE 2 /* corrupt file */
-#define CAF_ERR_ARTNOTHERE 3 /* article not in the database */
-#define CAF_ERR_CANTCREATECAF 4 /* can't create the CAF file, see errno. */
-#define CAF_ERR_FILEBUSY 5 /* file locked by someone else. */
-#define CAF_ERR_ARTWONTFIT 6 /* outside the range in the TOC */
-#define CAF_ERR_ARTALREADYHERE 7 /* tried to create an article that was already here. */
-#define CAF_ERR_BOGUSPATH 8 /* pathname not parseable. */
+++ /dev/null
-name = timecaf
-number = 4
-sources = caf.c timecaf.c
+++ /dev/null
-/* $Id: timecaf.c 7412 2005-10-09 03:44:35Z eagle $
-**
-** Like the timehash storage method (and heavily inspired by it), but uses
-** the CAF library to store multiple articles in a single file.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "caf.h"
-#include "inn/innconf.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "methods.h"
-#include "timecaf.h"
-#include "paths.h"
-
-/* Needed for htonl() and friends on AIX 4.1. */
-#include <netinet/in.h>
-
-typedef struct {
- char *artdata; /* start of the article data -- may be mmaped */
- char *mmapbase; /* actual start of mmaped region (on pagesize bndry, not necessarily == artdaya */
- unsigned int artlen; /* art length. */
- size_t mmaplen; /* length of mmap region. */
- DIR *top; /* open handle on top level dir. */
- DIR *sec; /* open handle on the 2nd level directory */
- DIR *ter; /* open handle on 3rd level dir. */
- struct dirent *topde; /* last entry we got from top */
- struct dirent *secde; /* last entry we got from sec */
- struct dirent *terde; /* last entry we got from sec */
- CAFTOCENT *curtoc;
- ARTNUM curartnum;
- CAFHEADER curheader;
-} PRIV_TIMECAF;
-
-/* current path/fd for an open CAF file */
-typedef struct {
- char *path; /* path to file. */
- int fd; /* open fd -- -1 if no file currently open. */
-} CAFOPENFILE;
-
-static CAFOPENFILE ReadingFile, WritingFile;
-static char *DeletePath;
-static ARTNUM *DeleteArtnums;
-static unsigned int NumDeleteArtnums, MaxDeleteArtnums;
-
-typedef enum {FIND_DIR, FIND_CAF, FIND_TOPDIR} FINDTYPE;
-
-/*
-** Structures for the cache for stat information (to make expireover etc.
-** faster.
-**
-** The first structure contains the TOC info for a single CAF file. The 2nd
-** one has pointers to the info for up to 256 CAF files, indexed
-** by the 2nd least significant byte of the arrival time.
-*/
-
-struct caftoccacheent {
- CAFTOCENT *toc;
- CAFHEADER header;
-};
-typedef struct caftoccacheent CAFTOCCACHEENT;
-
-struct caftocl1cache {
- CAFTOCCACHEENT *entries[256];
-};
-typedef struct caftocl1cache CAFTOCL1CACHE;
-
-/*
-** and similar structures indexed by the 3rd and 4th bytes of the arrival time.
-** pointing to the lower level structures. Note that the top level structure
-** (the one indexed by the MSByte of the timestamp) is likely to have only
-** one active pointer, unless your spool keeps more than 194 days of articles,
-** but it doesn't cost much to keep that one structure around and keep the
-** code general.
-*/
-
-struct caftocl2cache {
- CAFTOCL1CACHE *l1ptr[256];
-};
-typedef struct caftocl2cache CAFTOCL2CACHE;
-
-struct caftocl3cache {
- CAFTOCL2CACHE *l2ptr[256];
-};
-typedef struct caftocl3cache CAFTOCL3CACHE;
-
-static CAFTOCL3CACHE *TOCCache[256]; /* indexed by storage class! */
-static int TOCCacheHits, TOCCacheMisses;
-
-
-static TOKEN MakeToken(time_t now, int seqnum, STORAGECLASS class, TOKEN *oldtoken) {
- TOKEN token;
- unsigned int i;
- unsigned short s;
-
- if (oldtoken == (TOKEN *)NULL)
- memset(&token, '\0', sizeof(token));
- else
- memcpy(&token, oldtoken, sizeof(token));
- token.type = TOKEN_TIMECAF;
- token.class = class;
- i = htonl(now);
- memcpy(token.token, &i, sizeof(i));
- if (sizeof(i) > 4)
- memmove(token.token, &token.token[sizeof(i) - 4], 4);
- s = htons(seqnum);
- memcpy(&token.token[4], &s + (sizeof(s) - 2), 2);
- return token;
-}
-
-
-static void BreakToken(TOKEN token, int *now, int *seqnum) {
- unsigned int i;
- unsigned short s = 0;
-
- memcpy(&i, token.token, sizeof(i));
- memcpy(&s, &token.token[4], sizeof(s));
- *now = ntohl(i);
- *seqnum = (int)ntohs(s);
-}
-
-/*
-** Note: the time here is really "time>>8", i.e. a timestamp that's been
-** shifted right by 8 bits.
-*/
-static char *MakePath(int now, const STORAGECLASS class) {
- char *path;
- size_t length;
-
- /* innconf->patharticles + '/timecaf-zz/xx/xxxx.CF' */
- length = strlen(innconf->patharticles) + 32;
- path = xmalloc(length);
- snprintf(path, length, "%s/timecaf-%02x/%02x/%02x%02x.CF",
- innconf->patharticles, class,
- (now >> 8) & 0xff, (now >> 16) & 0xff, now & 0xff);
-
- return path;
-}
-
-static TOKEN *PathNumToToken(char *path, ARTNUM artnum) {
- int n;
- unsigned int t1, t2, class;
- unsigned int timestamp;
- static TOKEN token;
-
- n = sscanf(path, "timecaf-%02x/%02x/%04x.CF", &class, &t1, &t2);
- if (n != 3)
- return (TOKEN *)NULL;
- timestamp = ((t1 << 8) & 0xff00) | ((t2 << 8) & 0xff0000) | ((t2 << 0) & 0xff);
- token = MakeToken(timestamp, artnum, class, (TOKEN *)NULL);
- return &token;
-}
-
-
-bool timecaf_init(SMATTRIBUTE *attr) {
- if (attr == NULL) {
- syslog(L_ERROR, "timecaf: attr is NULL");
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- attr->selfexpire = false;
- attr->expensivestat = false;
- if (STORAGE_TOKEN_LENGTH < 6) {
- syslog(L_FATAL, "timecaf: token length is less than 6 bytes");
- SMseterror(SMERR_TOKENSHORT, NULL);
- return false;
- }
- ReadingFile.fd = WritingFile.fd = -1;
- ReadingFile.path = WritingFile.path = (char *)NULL;
- return true;
-}
-
-/*
-** Routines for managing the 'TOC cache' (cache of TOCs of various CAF files)
-**
-** Attempt to look up a given TOC entry in the cache. Takes the timestamp
-** as arguments.
-*/
-
-static CAFTOCCACHEENT *
-CheckTOCCache(int timestamp, int tokenclass)
-{
- CAFTOCL2CACHE *l2;
- CAFTOCL1CACHE *l1;
- CAFTOCCACHEENT *cent;
- unsigned char tmp;
-
- if (TOCCache[tokenclass] == NULL) return NULL; /* cache is empty */
-
- tmp = (timestamp>>16) & 0xff;
- l2 = TOCCache[tokenclass]->l2ptr[tmp];
- if (l2 == NULL) return NULL;
-
- tmp = (timestamp>>8) & 0xff;
- l1 = l2->l1ptr[tmp];
- if (l1 == NULL) return NULL;
-
- tmp = (timestamp) & 0xff;
- cent = l1->entries[tmp];
-
- ++TOCCacheHits;
- return cent;
-}
-
-/*
-** Add given TOC and header to the cache. Assume entry is not already in
-** cache.
-*/
-static CAFTOCCACHEENT *
-AddTOCCache(int timestamp, CAFTOCENT *toc, CAFHEADER head, int tokenclass)
-{
- CAFTOCL2CACHE *l2;
- CAFTOCL1CACHE *l1;
- CAFTOCCACHEENT *cent;
- unsigned char tmp;
- int i;
-
- if (TOCCache[tokenclass] == NULL) {
- TOCCache[tokenclass] = xmalloc(sizeof(CAFTOCL3CACHE));
- for (i = 0 ; i < 256 ; ++i) TOCCache[tokenclass]->l2ptr[i] = NULL;
- }
-
- tmp = (timestamp>>16) & 0xff;
- l2 = TOCCache[tokenclass]->l2ptr[tmp];
- if (l2 == NULL) {
- TOCCache[tokenclass]->l2ptr[tmp] = l2 = xmalloc(sizeof(CAFTOCL2CACHE));
- for (i = 0 ; i < 256 ; ++i) l2->l1ptr[i] = NULL;
- }
-
- tmp = (timestamp>>8) & 0xff;
- l1 = l2->l1ptr[tmp];
- if (l1 == NULL) {
- l2->l1ptr[tmp] = l1 = xmalloc(sizeof(CAFTOCL1CACHE));
- for (i = 0 ; i < 256 ; ++i) l1->entries[i] = NULL;
- }
-
- tmp = (timestamp) & 0xff;
- cent = xmalloc(sizeof(CAFTOCCACHEENT));
- l1->entries[tmp] = cent;
-
- cent->header = head;
- cent->toc = toc;
- ++TOCCacheMisses;
- return cent;
-}
-
-/*
-** Do stating of an article, going thru the TOC cache if possible.
-*/
-
-static ARTHANDLE *
-StatArticle(int timestamp, ARTNUM artnum, int tokenclass)
-{
- CAFTOCCACHEENT *cent;
- CAFTOCENT *toc;
- CAFHEADER head;
- char *path;
- CAFTOCENT *tocentry;
- ARTHANDLE *art;
-
- cent = CheckTOCCache(timestamp,tokenclass);
- if (cent == NULL) {
- path = MakePath(timestamp, tokenclass);
- toc = CAFReadTOC(path, &head);
- if (toc == NULL) {
- if (caf_error == CAF_ERR_ARTNOTHERE) {
- SMseterror(SMERR_NOENT, NULL);
- } else {
- SMseterror(SMERR_UNDEFINED, NULL);
- }
- free(path);
- return NULL;
- }
- cent = AddTOCCache(timestamp, toc, head, tokenclass);
- free(path);
- }
-
- /* check current TOC for the given artnum. */
- if (artnum < cent->header.Low || artnum > cent->header.High) {
- SMseterror(SMERR_NOENT, NULL);
- return NULL;
- }
-
- tocentry = &(cent->toc[artnum - cent->header.Low]);
- if (tocentry->Size == 0) {
- /* no article with that article number present */
- SMseterror(SMERR_NOENT, NULL);
- return NULL;
- }
-
- /* stat is a success, so build a null art struct to represent that. */
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMECAF;
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- return art;
-}
-
-
-static void
-CloseOpenFile(CAFOPENFILE *foo) {
- if (foo->fd >= 0) {
- close(foo->fd);
- foo->fd = -1;
- free(foo->path);
- foo->path = NULL;
- }
-}
-
-TOKEN timecaf_store(const ARTHANDLE article, const STORAGECLASS class) {
- char *path;
- char *p;
- time_t now;
- int timestamp;
- TOKEN token;
- int fd;
- ssize_t result;
- ARTNUM art;
-
- if (article.arrived == (time_t)0)
- now = time(NULL);
- else
- now = article.arrived;
-
- timestamp = now>>8;
- art = 0; /* magic: 0=="next available article number. */
-
- path = MakePath(timestamp, class);
- /* check to see if we have this CAF file already open. */
- if (WritingFile.fd < 0 || strcmp(WritingFile.path, path) != 0) {
- /* we're writing to a different file, close old one and start new one. */
- CloseOpenFile(&WritingFile);
- fd = CAFOpenArtWrite(path, &art, true, article.len);
- if (fd < 0) {
- if (caf_error == CAF_ERR_IO && caf_errno == ENOENT) {
- /* directories in the path don't exist, try creating them. */
- p = strrchr(path, '/');
- *p = '\0';
- if (!MakeDirectory(path, true)) {
- syslog(L_ERROR, "timecaf: could not make directory %s %m", path);
- token.type = TOKEN_EMPTY;
- free(path);
- SMseterror(SMERR_UNDEFINED, NULL);
- return token;
- } else {
- *p = '/';
- fd = CAFOpenArtWrite(path, &art, true, article.len);
- if (fd < 0) {
- syslog(L_ERROR, "timecaf: could not OpenArtWrite %s/%ld, %s", path, art, CAFErrorStr());
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- token.type = TOKEN_EMPTY;
- return token;
- }
- }
- } else {
- syslog(L_ERROR, "timecaf: could not OpenArtWrite %s/%ld, %s", path, art, CAFErrorStr());
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- token.type = TOKEN_EMPTY;
- return token;
- }
- }
- } else {
- /* can reuse existing fd, assuming all goes well. */
- fd = WritingFile.fd;
-
- /* nuke extraneous copy of path to avoid mem leaks. */
- free(path);
- path = WritingFile.path;
-
- if (CAFStartWriteFd(fd, &art, article.len) < 0) {
- syslog(L_ERROR, "timecaf: could not OpenArtWrite %s/%ld, %s", path, art, CAFErrorStr());
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- token.type = TOKEN_EMPTY;
- return token;
- }
- }
- WritingFile.fd = fd;
- WritingFile.path = path;
- close_on_exec(fd, true);
- result = xwritev(fd, article.iov, article.iovcnt);
- if (result != (ssize_t) article.len) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timecaf error writing %s %m", path);
- token.type = TOKEN_EMPTY;
- CloseOpenFile(&WritingFile);
- return token;
- }
- if (CAFFinishArtWrite(fd) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timecaf error writing %s %s", path, CAFErrorStr());
- token.type = TOKEN_EMPTY;
- CloseOpenFile(&WritingFile);
- return token;
- }
-
- return MakeToken(timestamp, art, class, article.token);
-}
-
-/* Get a handle to article artnum in CAF-file path. */
-static ARTHANDLE *OpenArticle(const char *path, ARTNUM artnum, const RETRTYPE amount) {
- int fd;
- PRIV_TIMECAF *private;
- char *p;
- size_t len;
- ARTHANDLE *art;
- static long pagesize = 0;
-
- if (pagesize == 0) {
- pagesize = getpagesize();
- if (pagesize < 0) {
- syslog(L_ERROR, "timecaf getpagesize failed: %m");
- pagesize = 0;
- return NULL;
- }
- }
-
-/* XXX need to figure some way to cache open fds or something? */
- if ((fd = CAFOpenArtRead((char *)path, artnum, &len)) < 0) {
- if (caf_error == CAF_ERR_ARTNOTHERE) {
- SMseterror(SMERR_NOENT, NULL);
- } else {
- SMseterror(SMERR_UNDEFINED, NULL);
- }
- return NULL;
- }
-
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMECAF;
-
- if (amount == RETR_STAT) {
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- close(fd);
- return art;
- }
-
- private = xmalloc(sizeof(PRIV_TIMECAF));
- art->private = (void *)private;
- private->artlen = len;
- if (innconf->articlemmap) {
- off_t curoff, tmpoff;
- size_t delta;
-
- curoff = lseek(fd, (off_t) 0, SEEK_CUR);
- delta = curoff % pagesize;
- tmpoff = curoff - delta;
- private->mmaplen = len + delta;
- if ((private->mmapbase = mmap(NULL, private->mmaplen, PROT_READ, MAP_SHARED, fd, tmpoff)) == MAP_FAILED) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timecaf: could not mmap article: %m");
- free(art->private);
- free(art);
- return NULL;
- }
- mmap_invalidate(private->mmapbase, private->mmaplen);
- if (amount == RETR_ALL)
- madvise(private->mmapbase, private->mmaplen, MADV_WILLNEED);
- else
- madvise(private->mmapbase, private->mmaplen, MADV_SEQUENTIAL);
- private->artdata = private->mmapbase + delta;
- } else {
- private->artdata = xmalloc(private->artlen);
- if (read(fd, private->artdata, private->artlen) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timecaf: could not read article: %m");
- free(private->artdata);
- free(art->private);
- free(art);
- return NULL;
- }
- }
- close(fd);
-
- private->top = NULL;
- private->sec = NULL;
- private->ter = NULL;
- private->curtoc = NULL;
- private->curartnum = 0;
- private->topde = NULL;
- private->secde = NULL;
- private->terde = NULL;
-
- if (amount == RETR_ALL) {
- art->data = private->artdata;
- art->len = private->artlen;
- return art;
- }
-
- if ((p = wire_findbody(private->artdata, private->artlen)) == NULL) {
- SMseterror(SMERR_NOBODY, NULL);
- if (innconf->articlemmap)
- munmap(private->mmapbase, private->mmaplen);
- else
- free(private->artdata);
- free(art->private);
- free(art);
- return NULL;
- }
-
- if (amount == RETR_HEAD) {
- art->data = private->artdata;
- art->len = p - private->artdata;
- return art;
- }
-
- if (amount == RETR_BODY) {
- art->data = p + 4;
- art->len = art->len - (private->artdata - p - 4);
- return art;
- }
- SMseterror(SMERR_UNDEFINED, "Invalid retrieve request");
- if (innconf->articlemmap)
- munmap(private->mmapbase, private->mmaplen);
- else
- free(private->artdata);
- free(art->private);
- free(art);
- return NULL;
-}
-
-ARTHANDLE *timecaf_retrieve(const TOKEN token, const RETRTYPE amount) {
- int timestamp;
- int artnum;
- char *path;
- ARTHANDLE *art;
- static TOKEN ret_token;
- time_t now;
-
- if (token.type != TOKEN_TIMECAF) {
- SMseterror(SMERR_INTERNAL, NULL);
- return NULL;
- }
-
- BreakToken(token, ×tamp, &artnum);
-
- /*
- ** Do a possible shortcut on RETR_STAT requests, going thru the "TOC cache"
- ** we mentioned above. We only try to go thru the TOC Cache under these
- ** conditions:
- ** 1) SMpreopen is true (so we're "preopening" the TOCs.)
- ** 2) the timestamp is older than the timestamp corresponding to current
- ** time. Any timestamp that matches current time (to within 256 secondsf
- ** would be in a CAF file that innd is actively
- ** writing, in which case we would not want to cache the TOC for that
- ** CAF file.
- */
-
- if (SMpreopen && amount == RETR_STAT) {
- now = time(NULL);
- if (timestamp < ((now >> 8) & 0xffffff)) {
- return StatArticle(timestamp, artnum, token.class);
- }
- }
-
- path = MakePath(timestamp, token.class);
- if ((art = OpenArticle(path, artnum, amount)) != (ARTHANDLE *)NULL) {
- art->arrived = timestamp<<8; /* XXX not quite accurate arrival time,
- ** but getting a more accurate one would
- ** require more fiddling with CAF innards.
- */
- ret_token = token;
- art->token = &ret_token;
- }
- free(path);
- return art;
-}
-
-void timecaf_freearticle(ARTHANDLE *article) {
- PRIV_TIMECAF *private;
-
- if (!article)
- return;
-
- if (article->private) {
- private = (PRIV_TIMECAF *)article->private;
- if (innconf->articlemmap)
- munmap(private->mmapbase, private->mmaplen);
- else
- free(private->artdata);
- if (private->top)
- closedir(private->top);
- if (private->sec)
- closedir(private->sec);
- if (private->ter)
- closedir(private->ter);
- if (private->curtoc)
- free(private->curtoc);
- free(private);
- }
- free(article);
-}
-
-/* Do cancels of all the article ids collected for a given pathname. */
-
-static void
-DoCancels(void) {
- if (DeletePath != NULL) {
- if (NumDeleteArtnums != 0) {
- /*
- ** Murgle. If we are trying to cancel something out of the
- ** currently open-for-writing file, we need to close it before
- ** doing CAFRemove...
- */
- if (WritingFile.path != NULL && strcmp(WritingFile.path, DeletePath) == 0) {
- CloseOpenFile(&WritingFile);
- }
- /* XXX should really check err. code here, but not much we can really do. */
- CAFRemoveMultArts(DeletePath, NumDeleteArtnums, DeleteArtnums);
- free(DeleteArtnums);
- DeleteArtnums = NULL;
- NumDeleteArtnums = MaxDeleteArtnums = 0;
- }
- free(DeletePath);
- DeletePath = NULL;
- }
-}
-
-bool timecaf_cancel(TOKEN token) {
- int now;
- int seqnum;
- char *path;
-
- BreakToken(token, &now, &seqnum);
- path = MakePath(now, token.class);
- if (DeletePath == NULL) {
- DeletePath = path;
- } else if (strcmp(DeletePath, path) != 0) {
- /* different path, so flush all pending cancels. */
- DoCancels();
- DeletePath = path;
- } else {
- free(path); /* free redundant copy of path */
- }
- if (NumDeleteArtnums >= MaxDeleteArtnums) {
- /* allocate/expand storage for artnums. */
- if (MaxDeleteArtnums == 0) {
- MaxDeleteArtnums = 100;
- } else {
- MaxDeleteArtnums *= 2;
- }
- DeleteArtnums = xrealloc(DeleteArtnums, MaxDeleteArtnums * sizeof(ARTNUM));
- }
- DeleteArtnums[NumDeleteArtnums++] = seqnum;
-
- return true;
-}
-
-static struct dirent *FindDir(DIR *dir, FINDTYPE type) {
- struct dirent *de;
-
- while ((de = readdir(dir)) != NULL) {
- if (type == FIND_TOPDIR)
- if ((strlen(de->d_name) == 10) &&
- (strncmp(de->d_name, "timecaf-", 8) == 0) &&
- CTYPE(isxdigit, de->d_name[8]) &&
- CTYPE(isxdigit, de->d_name[9]))
- return de;
-
- if (type == FIND_DIR)
- if ((strlen(de->d_name) == 2)
- && CTYPE(isxdigit, de->d_name[0])
- && CTYPE(isxdigit, de->d_name[1]))
- return de;
-
- if (type == FIND_CAF)
- if ((strlen(de->d_name) == 7) &&
- CTYPE(isxdigit, de->d_name[0]) &&
- CTYPE(isxdigit, de->d_name[1]) &&
- CTYPE(isxdigit, de->d_name[2]) &&
- CTYPE(isxdigit, de->d_name[3]) &&
- (de->d_name[4] == '.') &&
- (de->d_name[5] == 'C') &&
- (de->d_name[6] == 'F'))
- return de;
- }
-
- return NULL;
-}
-
-/* Grovel thru a CAF table-of-contents finding the next still-existing article */
-static int
-FindNextArt(const CAFHEADER *head, CAFTOCENT *toc, ARTNUM *artp)
-{
- ARTNUM art;
- CAFTOCENT *tocp;
- art = *artp;
- if (art == 0) {
- art = head->Low - 1; /* we never use art # 0, so 0 is a flag to start
- searching at the beginning */
- }
- while (true) {
- art++;
- if (art > head->High) return false; /* ran off the end of the TOC */
- tocp = &toc[art - head->Low];
- if (tocp->Size != 0) {
- /* got a valid article */
- *artp = art;
- return true;
- }
- }
-}
-
-
-
-ARTHANDLE *timecaf_next(const ARTHANDLE *article, const RETRTYPE amount) {
- PRIV_TIMECAF priv, *newpriv;
- char *path;
- ARTHANDLE *art;
- size_t length;
-
- length = strlen(innconf->patharticles) + 32;
- path = xmalloc(length);
- if (article == NULL) {
- priv.top = NULL;
- priv.sec = NULL;
- priv.ter = NULL;
- priv.curtoc = NULL;
- priv.topde = NULL;
- priv.secde = NULL;
- priv.terde = NULL;
- } else {
- priv = *(PRIV_TIMECAF *)article->private;
- free(article->private);
- free((void *)article);
- if (innconf->articlemmap)
- munmap(priv.mmapbase, priv.mmaplen);
- else
- free(priv.artdata);
- }
-
- while (priv.curtoc == NULL || !FindNextArt(&priv.curheader, priv.curtoc, &priv.curartnum)) {
- if (priv.curtoc) {
- free(priv.curtoc);
- priv.curtoc = NULL;
- }
- while (!priv.ter || ((priv.terde = FindDir(priv.ter, FIND_CAF)) == NULL)) {
- if (priv.ter) {
- closedir(priv.ter);
- priv.ter = NULL;
- }
- while (!priv.sec || ((priv.secde = FindDir(priv.sec, FIND_DIR)) == NULL)) {
- if (priv.sec) {
- closedir(priv.sec);
- priv.sec = NULL;
- }
- if (!priv.top || ((priv.topde = FindDir(priv.top, FIND_TOPDIR)) == NULL)) {
- if (priv.top) {
- /* end of search */
- closedir(priv.top);
- priv.top = NULL;
- free(path);
- return NULL;
- }
- snprintf(path, length, "%s", innconf->patharticles);
- if ((priv.top = opendir(path)) == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- return NULL;
- }
- if ((priv.topde = FindDir(priv.top, FIND_TOPDIR)) == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- closedir(priv.top);
- free(path);
- return NULL;
- }
- }
- snprintf(path, length, "%s/%s", innconf->patharticles, priv.topde->d_name);
- if ((priv.sec = opendir(path)) == NULL)
- continue;
- }
- snprintf(path, length, "%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name);
- if ((priv.ter = opendir(path)) == NULL)
- continue;
- }
- snprintf(path, length, "%s/%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name, priv.terde->d_name);
- if ((priv.curtoc = CAFReadTOC(path, &priv.curheader)) == NULL)
- continue;
- priv.curartnum = 0;
- }
- snprintf(path, length, "%s/%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name, priv.terde->d_name);
- art = OpenArticle(path, priv.curartnum, amount);
- if (art == (ARTHANDLE *)NULL) {
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMECAF;
- art->data = NULL;
- art->len = 0;
- art->private = xmalloc(sizeof(PRIV_TIMECAF));
- }
- newpriv = (PRIV_TIMECAF *)art->private;
- newpriv->top = priv.top;
- newpriv->sec = priv.sec;
- newpriv->ter = priv.ter;
- newpriv->topde = priv.topde;
- newpriv->secde = priv.secde;
- newpriv->terde = priv.terde;
- newpriv->curheader = priv.curheader;
- newpriv->curtoc = priv.curtoc;
- newpriv->curartnum = priv.curartnum;
-
- snprintf(path, length, "%s/%s/%s", priv.topde->d_name, priv.secde->d_name, priv.terde->d_name);
- art->token = PathNumToToken(path, priv.curartnum);
- art->arrived = priv.curtoc[priv.curartnum - priv.curheader.Low].ModTime;
- free(path);
- return art;
-}
-
-bool timecaf_ctl(PROBETYPE type, TOKEN *token UNUSED, void *value) {
- struct artngnum *ann;
-
- switch (type) {
- case SMARTNGNUM:
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- /* make SMprobe() call timecaf_retrieve() */
- ann->artnum = 0;
- return true;
- default:
- return false;
- }
-}
-
-bool timecaf_flushcacheddata(FLUSHTYPE type) {
- if (type == SM_ALL || type == SM_CANCELEDART)
- DoCancels();
- return true;
-}
-
-void
-timecaf_printfiles(FILE *file, TOKEN token, char **xref UNUSED,
- int ngroups UNUSED)
-{
- fprintf(file, "%s\n", TokenToText(token));
-}
-
-void timecaf_shutdown(void) {
- CloseOpenFile(&WritingFile);
- DoCancels();
-}
+++ /dev/null
-/* $Id: timecaf.h 4266 2001-01-04 06:01:36Z rra $
-**
-** timecaf -- like the timehash storage method (and heavily inspired
-** by it), but uses the CAF library to store multiple articles in a
-** single file.
-*/
-
-#ifndef __TIMECAF_H__
-#define __TIMECAF_H__
-
-#include "config.h"
-#include "interface.h"
-
-bool timecaf_init(SMATTRIBUTE *attr);
-TOKEN timecaf_store(const ARTHANDLE article, const STORAGECLASS class);
-ARTHANDLE *timecaf_retrieve(const TOKEN token, const RETRTYPE amount);
-ARTHANDLE *timecaf_next(const ARTHANDLE *article, const RETRTYPE amount);
-void timecaf_freearticle(ARTHANDLE *article);
-bool timecaf_cancel(TOKEN token);
-bool timecaf_ctl(PROBETYPE type, TOKEN *token, void *value);
-bool timecaf_flushcacheddata(FLUSHTYPE type);
-void timecaf_printfiles(FILE *file, TOKEN token, char **xref, int ngroups);
-void timecaf_shutdown(void);
-
-#endif
+++ /dev/null
-name = timehash
-number = 2
-sources = timehash.c
+++ /dev/null
-/* $Id: timehash.c 7412 2005-10-09 03:44:35Z eagle $
-**
-** Timehash based storage method.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "inn/innconf.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "methods.h"
-#include "paths.h"
-#include "timehash.h"
-
-typedef struct {
- char *base; /* Base of the mmaped file */
- int len; /* Length of the file */
- DIR *top; /* Open handle on the top level directory */
- DIR *sec; /* Open handle on the 2nd level directory */
- DIR *ter; /* Open handle on the third level directory */
- DIR *artdir; /* Open handle on the article directory */
- struct dirent *topde; /* dirent entry for the last entry retrieved in top */
- struct dirent *secde; /* dirent entry for the last entry retrieved in sec */
- struct dirent *terde; /* dirent entry for the last entry retrieved in ter */
-} PRIV_TIMEHASH;
-
-typedef enum {FIND_DIR, FIND_ART, FIND_TOPDIR} FINDTYPE;
-
-static int SeqNum = 0;
-
-static TOKEN MakeToken(time_t now, int seqnum, STORAGECLASS class, TOKEN *oldtoken) {
- TOKEN token;
- unsigned int i;
- unsigned short s;
-
- if (oldtoken == (TOKEN *)NULL)
- memset(&token, '\0', sizeof(token));
- else
- memcpy(&token, oldtoken, sizeof(token));
- token.type = TOKEN_TIMEHASH;
- token.class = class;
- i = htonl(now);
- memcpy(token.token, &i, sizeof(i));
- if (sizeof(i) > 4)
- memmove(token.token, &token.token[sizeof(i) - 4], 4);
- s = htons(seqnum);
- memcpy(&token.token[4], &s + (sizeof(s) - 2), 2);
- return token;
-}
-
-static void BreakToken(TOKEN token, int *now, int *seqnum) {
- unsigned int i;
- unsigned short s = 0;
-
- memcpy(&i, token.token, sizeof(i));
- memcpy(&s, &token.token[4], sizeof(s));
- *now = ntohl(i);
- *seqnum = (int)ntohs(s);
-}
-
-static char *MakePath(int now, int seqnum, const STORAGECLASS class) {
- char *path;
- size_t length;
-
- /* innconf->patharticles + '/time-zz/xx/xx/yyyy-xxxx' */
- length = strlen(innconf->patharticles) + 32;
- path = xmalloc(length);
- snprintf(path, length, "%s/time-%02x/%02x/%02x/%04x-%04x",
- innconf->patharticles, class,
- (now >> 16) & 0xff, (now >> 8) & 0xff, seqnum,
- (now & 0xff) | ((now >> 16 & 0xff00)));
- return path;
-}
-
-static TOKEN *PathToToken(char *path) {
- int n;
- unsigned int t1, t2, t3, seqnum, class;
- time_t now;
- static TOKEN token;
-
- n = sscanf(path, "time-%02x/%02x/%02x/%04x-%04x", &class, &t1, &t2, &seqnum, &t3);
- if (n != 5)
- return (TOKEN *)NULL;
- now = ((t1 << 16) & 0xff0000) | ((t2 << 8) & 0xff00) | ((t3 << 16) & 0xff000000) | (t3 & 0xff);
- token = MakeToken(now, seqnum, class, (TOKEN *)NULL);
- return &token;
-}
-
-bool timehash_init(SMATTRIBUTE *attr) {
- if (attr == NULL) {
- syslog(L_ERROR, "timehash: attr is NULL");
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- attr->selfexpire = false;
- attr->expensivestat = true;
- if (STORAGE_TOKEN_LENGTH < 6) {
- syslog(L_FATAL, "timehash: token length is less than 6 bytes");
- SMseterror(SMERR_TOKENSHORT, NULL);
- return false;
- }
- return true;
-}
-
-TOKEN timehash_store(const ARTHANDLE article, const STORAGECLASS class) {
- char *path;
- char *p;
- time_t now;
- TOKEN token;
- int fd;
- ssize_t result;
- int seq;
- int i;
-
- if (article.arrived == (time_t)0)
- now = time(NULL);
- else
- now = article.arrived;
-
- for (i = 0; i < 0x10000; i++) {
- seq = SeqNum;
- SeqNum = (SeqNum + 1) & 0xffff;
- path = MakePath(now, seq, class);
-
- if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, ARTFILE_MODE)) < 0) {
- if (errno == EEXIST)
- continue;
- p = strrchr(path, '/');
- *p = '\0';
- if (!MakeDirectory(path, true)) {
- syslog(L_ERROR, "timehash: could not make directory %s %m", path);
- token.type = TOKEN_EMPTY;
- free(path);
- SMseterror(SMERR_UNDEFINED, NULL);
- return token;
- } else {
- *p = '/';
- if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, ARTFILE_MODE)) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash: could not open %s %m", path);
- token.type = TOKEN_EMPTY;
- free(path);
- return token;
- }
- }
- }
- break;
- }
- if (i == 0x10000) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash: all sequence numbers for the time and class are reserved %lu %d", (unsigned long)now, class);
- token.type = TOKEN_EMPTY;
- free(path);
- return token;
- }
-
- result = xwritev(fd, article.iov, article.iovcnt);
- if (result != (ssize_t) article.len) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash error writing %s %m", path);
- close(fd);
- token.type = TOKEN_EMPTY;
- unlink(path);
- free(path);
- return token;
- }
- close(fd);
- free(path);
- return MakeToken(now, seq, class, article.token);
-}
-
-static ARTHANDLE *OpenArticle(const char *path, RETRTYPE amount) {
- int fd;
- PRIV_TIMEHASH *private;
- char *p;
- struct stat sb;
- ARTHANDLE *art;
-
- if (amount == RETR_STAT) {
- if (access(path, R_OK) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- return NULL;
- }
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMEHASH;
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- return art;
- }
-
- if ((fd = open(path, O_RDONLY)) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- return NULL;
- }
-
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMEHASH;
-
- if (fstat(fd, &sb) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash: could not fstat article: %m");
- free(art);
- return NULL;
- }
-
- private = xmalloc(sizeof(PRIV_TIMEHASH));
- art->private = (void *)private;
- private->len = sb.st_size;
- if (innconf->articlemmap) {
- if ((private->base = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash: could not mmap article: %m");
- free(art->private);
- free(art);
- return NULL;
- }
- if (amount == RETR_ALL)
- madvise(private->base, sb.st_size, MADV_WILLNEED);
- else
- madvise(private->base, sb.st_size, MADV_SEQUENTIAL);
- } else {
- private->base = xmalloc(private->len);
- if (read(fd, private->base, private->len) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "timehash: could not read article: %m");
- free(private->base);
- free(art->private);
- free(art);
- return NULL;
- }
- }
- close(fd);
-
- private->top = NULL;
- private->sec = NULL;
- private->ter = NULL;
- private->artdir = NULL;
- private->topde = NULL;
- private->secde = NULL;
- private->terde = NULL;
-
- if (amount == RETR_ALL) {
- art->data = private->base;
- art->len = private->len;
- return art;
- }
-
- if ((p = wire_findbody(private->base, private->len)) == NULL) {
- SMseterror(SMERR_NOBODY, NULL);
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- return NULL;
- }
-
- if (amount == RETR_HEAD) {
- art->data = private->base;
- art->len = p - private->base;
- return art;
- }
-
- if (amount == RETR_BODY) {
- art->data = p;
- art->len = private->len - (p - private->base);
- return art;
- }
- SMseterror(SMERR_UNDEFINED, "Invalid retrieve request");
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- free(art->private);
- free(art);
- return NULL;
-}
-
-ARTHANDLE *timehash_retrieve(const TOKEN token, const RETRTYPE amount) {
- int now;
- int seqnum;
- char *path;
- ARTHANDLE *art;
- static TOKEN ret_token;
-
- if (token.type != TOKEN_TIMEHASH) {
- SMseterror(SMERR_INTERNAL, NULL);
- return NULL;
- }
-
- BreakToken(token, &now, &seqnum);
- path = MakePath(now, seqnum, token.class);
- if ((art = OpenArticle(path, amount)) != (ARTHANDLE *)NULL) {
- art->arrived = now;
- ret_token = token;
- art->token = &ret_token;
- }
- free(path);
- return art;
-}
-
-void timehash_freearticle(ARTHANDLE *article) {
- PRIV_TIMEHASH *private;
-
- if (!article)
- return;
-
- if (article->private) {
- private = (PRIV_TIMEHASH *)article->private;
- if (innconf->articlemmap)
- munmap(private->base, private->len);
- else
- free(private->base);
- if (private->top)
- closedir(private->top);
- if (private->sec)
- closedir(private->sec);
- if (private->ter)
- closedir(private->ter);
- if (private->artdir)
- closedir(private->artdir);
- free(private);
- }
- free(article);
-}
-
-bool timehash_cancel(TOKEN token) {
- int now;
- int seqnum;
- char *path;
- int result;
-
- BreakToken(token, &now, &seqnum);
- path = MakePath(now, seqnum, token.class);
- result = unlink(path);
- free(path);
- if (result < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- return false;
- }
- return true;
-}
-
-static struct dirent *FindDir(DIR *dir, FINDTYPE type) {
- struct dirent *de;
-
- while ((de = readdir(dir)) != NULL) {
- if (type == FIND_TOPDIR)
- if ((strlen(de->d_name) == 7) &&
- (strncmp(de->d_name, "time-", 5) == 0) &&
- isxdigit((int)de->d_name[5]) &&
- isxdigit((int)de->d_name[6]))
- return de;
-
- if (type == FIND_DIR)
- if ((strlen(de->d_name) == 2) && isxdigit((int)de->d_name[0]) && isxdigit((int)de->d_name[1]))
- return de;
-
- if (type == FIND_ART)
- if ((strlen(de->d_name) == 9) &&
- isxdigit((int)de->d_name[0]) &&
- isxdigit((int)de->d_name[1]) &&
- isxdigit((int)de->d_name[2]) &&
- isxdigit((int)de->d_name[3]) &&
- isxdigit((int)de->d_name[5]) &&
- isxdigit((int)de->d_name[6]) &&
- isxdigit((int)de->d_name[7]) &&
- isxdigit((int)de->d_name[8]) &&
- (de->d_name[4] == '-'))
- return de;
- }
-
- return NULL;
-}
-
-ARTHANDLE *timehash_next(const ARTHANDLE *article, const RETRTYPE amount) {
- PRIV_TIMEHASH priv;
- PRIV_TIMEHASH *newpriv;
- char *path;
- struct dirent *de;
- ARTHANDLE *art;
- int seqnum;
- size_t length;
-
- length = strlen(innconf->patharticles) + 32;
- path = xmalloc(length);
- if (article == NULL) {
- priv.top = NULL;
- priv.sec = NULL;
- priv.ter = NULL;
- priv.artdir = NULL;
- priv.topde = NULL;
- priv.secde = NULL;
- priv.terde = NULL;
- } else {
- priv = *(PRIV_TIMEHASH *)article->private;
- free(article->private);
- free((void *)article);
- if (priv.base != NULL) {
- if (innconf->articlemmap)
- munmap(priv.base, priv.len);
- else
- free(priv.base);
- }
- }
-
- while (!priv.artdir || ((de = FindDir(priv.artdir, FIND_ART)) == NULL)) {
- if (priv.artdir) {
- closedir(priv.artdir);
- priv.artdir = NULL;
- }
- while (!priv.ter || ((priv.terde = FindDir(priv.ter, FIND_DIR)) == NULL)) {
- if (priv.ter) {
- closedir(priv.ter);
- priv.ter = NULL;
- }
- while (!priv.sec || ((priv.secde = FindDir(priv.sec, FIND_DIR)) == NULL)) {
- if (priv.sec) {
- closedir(priv.sec);
- priv.sec = NULL;
- }
- if (!priv.top || ((priv.topde = FindDir(priv.top, FIND_TOPDIR)) == NULL)) {
- if (priv.top) {
- /* end of search */
- closedir(priv.top);
- priv.top = NULL;
- free(path);
- return NULL;
- }
- snprintf(path, length, "%s", innconf->patharticles);
- if ((priv.top = opendir(path)) == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- return NULL;
- }
- if ((priv.topde = FindDir(priv.top, FIND_TOPDIR)) == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- closedir(priv.top);
- free(path);
- return NULL;
- }
- }
- snprintf(path, length, "%s/%s", innconf->patharticles, priv.topde->d_name);
- if ((priv.sec = opendir(path)) == NULL)
- continue;
- }
- snprintf(path, length, "%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name);
- if ((priv.ter = opendir(path)) == NULL)
- continue;
- }
- snprintf(path, length, "%s/%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name, priv.terde->d_name);
- if ((priv.artdir = opendir(path)) == NULL)
- continue;
- }
- if (de == NULL)
- return NULL;
- snprintf(path, length, "%s/%s/%s/%s/%s", innconf->patharticles, priv.topde->d_name, priv.secde->d_name, priv.terde->d_name, de->d_name);
-
- art = OpenArticle(path, amount);
- if (art == (ARTHANDLE *)NULL) {
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TIMEHASH;
- art->data = NULL;
- art->len = 0;
- art->private = xmalloc(sizeof(PRIV_TIMEHASH));
- newpriv = (PRIV_TIMEHASH *)art->private;
- newpriv->base = NULL;
- }
- newpriv = (PRIV_TIMEHASH *)art->private;
- newpriv->top = priv.top;
- newpriv->sec = priv.sec;
- newpriv->ter = priv.ter;
- newpriv->artdir = priv.artdir;
- newpriv->topde = priv.topde;
- newpriv->secde = priv.secde;
- newpriv->terde = priv.terde;
- snprintf(path, length, "%s/%s/%s/%s", priv.topde->d_name, priv.secde->d_name, priv.terde->d_name, de->d_name);
- art->token = PathToToken(path);
- BreakToken(*art->token, (int *)&(art->arrived), &seqnum);
- free(path);
- return art;
-}
-
-bool timehash_ctl(PROBETYPE type, TOKEN *token UNUSED, void *value) {
- struct artngnum *ann;
-
- switch (type) {
- case SMARTNGNUM:
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- /* make SMprobe() call timehash_retrieve() */
- ann->artnum = 0;
- return true;
- default:
- return false;
- }
-}
-
-bool
-timehash_flushcacheddata(FLUSHTYPE type UNUSED)
-{
- return true;
-}
-
-void
-timehash_printfiles(FILE *file, TOKEN token, char **xref UNUSED,
- int ngroups UNUSED)
-{
- int now, seqnum;
- char *path;
-
- BreakToken(token, &now, &seqnum);
- path = MakePath(now, seqnum, token.class);
- fprintf(file, "%s\n", path);
-}
-
-void timehash_shutdown(void) {
-}
+++ /dev/null
-/* $Id: timehash.h 4268 2001-01-04 06:02:50Z rra $
-**
-** timehash based storing method header
-*/
-
-#ifndef __TIMEHASH_H__
-#define __TIMEHASH_H__
-
-#include "config.h"
-#include "interface.h"
-
-bool timehash_init(SMATTRIBUTE *attr);
-TOKEN timehash_store(const ARTHANDLE article, const STORAGECLASS class);
-ARTHANDLE *timehash_retrieve(const TOKEN token, const RETRTYPE amount);
-ARTHANDLE *timehash_next(const ARTHANDLE *article, const RETRTYPE amount);
-void timehash_freearticle(ARTHANDLE *article);
-bool timehash_cancel(TOKEN token);
-bool timehash_ctl(PROBETYPE type, TOKEN *token, void *value);
-bool timehash_flushcacheddata(FLUSHTYPE type);
-void timehash_printfiles(FILE *file, TOKEN token, char **xref, int ngroups);
-void timehash_shutdown(void);
-
-#endif
+++ /dev/null
-name = tradindexed
-number = 2
-sources = tdx-cache.c tdx-group.c tdx-data.c tradindexed.c
-extra-sources = tdx-util.c
-programs = tdx-util
+++ /dev/null
-tradindexed/tdx-util.o: tradindexed/tdx-util.c
- $(CC) $(CFLAGS) -c -o $@ tradindexed/tdx-util.c
-
-tradindexed/tdx-util: tradindexed/tdx-util.o libstorage.$(EXTLIB) $(LIBHIST)
- $(LIBLD) $(LDFLAGS) -o $@ tradindexed/tdx-util.o \
- $(LIBSTORAGE) $(LIBHIST) $(LIBINN) $(EXTSTORAGELIBS) $(LIBS)
+++ /dev/null
-/* $Id: tdx-cache.c 5394 2002-04-04 22:55:24Z rra $
-**
-** Cache functions for open overview data files.
-**
-** This code maintains a cache of open overview data files to avoid some of
-** the overhead involved in closing and reopening files. All opens and
-** closes should go through this code, and the hit ratio is tracked to check
-** cache effectiveness.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <time.h>
-
-#include "inn/hashtab.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "storage.h"
-#include "tdx-private.h"
-
-/* Returned to callers as an opaque data type, this struct holds all of the
- information about the cache. */
-struct cache {
- struct hash *hashtable;
- unsigned int count;
- unsigned int max;
- unsigned long queries;
- unsigned long hits;
-};
-
-/* A cache entry, holding a group_data struct and some additional information
- used to do cache lookups and to choose what to drop from the cache. */
-struct cache_entry {
- struct group_data *data;
- HASH hash;
- time_t lastused;
-};
-
-
-/*
-** The hash function for a cache_entry. Just return as much of the group
-** hash as can fit in an unsigned long.
-*/
-static unsigned long
-entry_hash(const void *key)
-{
- const HASH *hash = key;
- unsigned long bucket;
-
- memcpy(&bucket, hash, sizeof(bucket));
- return bucket;
-}
-
-
-/*
-** Given a cache_entry, return its key.
-*/
-static const void *
-entry_key(const void *data)
-{
- const struct cache_entry *entry = (const struct cache_entry *) data;
-
- return &entry->hash;
-}
-
-
-/*
-** Check to see if two entries are equal.
-*/
-static bool
-entry_equal(const void *key, const void *data)
-{
- const HASH *hash = (const HASH *) key;
- const struct cache_entry *entry = (const struct cache_entry *) data;
-
- return (memcmp(hash, &entry->hash, sizeof(HASH)) == 0);
-}
-
-
-/*
-** Free a cache entry.
-*/
-static void
-entry_delete(void *data)
-{
- struct cache_entry *entry = (struct cache_entry *) data;
-
- entry->data->refcount--;
- if (entry->data->refcount == 0)
- tdx_data_close(entry->data);
- free(entry);
-}
-
-
-/*
-** Called by hash_traverse, this function finds the oldest entry with the
-** smallest refcount and stores it in the provided pointer so that it can be
-** freed. This is used when the cache is full to drop the least useful
-** entry.
-*/
-static void
-entry_find_oldest(void *data, void *cookie)
-{
- struct cache_entry *entry = (struct cache_entry *) data;
- struct cache_entry **oldest = (struct cache_entry **) cookie;
-
- if (*oldest == NULL) {
- *oldest = entry;
- return;
- }
- if (entry->data->refcount > (*oldest)->data->refcount)
- return;
- if (entry->lastused > (*oldest)->lastused)
- return;
- *oldest = data;
-}
-
-
-/*
-** Create a new cache with the given size.
-*/
-struct cache *
-tdx_cache_create(unsigned int size)
-{
- struct cache *cache;
-
- cache = xmalloc(sizeof(struct cache));
- cache->count = 0;
- cache->max = size;
- cache->queries = 0;
- cache->hits = 0;
- cache->hashtable = hash_create(size * 4 / 3, entry_hash, entry_key,
- entry_equal, entry_delete);
- return cache;
-}
-
-
-/*
-** Look up a particular entry and return it.
-*/
-struct group_data *
-tdx_cache_lookup(struct cache *cache, HASH hash)
-{
- struct cache_entry *entry;
-
- cache->queries++;
- entry = hash_lookup(cache->hashtable, &hash);
- if (entry != NULL) {
- cache->hits++;
- entry->lastused = time(NULL);
- }
- return (entry == NULL) ? NULL : entry->data;
-}
-
-
-/*
-** Insert a new entry, clearing out the oldest entry if the cache is
-** currently full.
-*/
-void
-tdx_cache_insert(struct cache *cache, HASH hash, struct group_data *data)
-{
- struct cache_entry *entry;
-
- if (cache->count == cache->max) {
- struct cache_entry *oldest = NULL;
-
- hash_traverse(cache->hashtable, entry_find_oldest, &oldest);
- if (oldest == NULL) {
- warn("tradindexed: unable to find oldest cache entry");
- return;
- } else {
- if (!hash_delete(cache->hashtable, &oldest->hash)) {
- warn("tradindexed: cannot delete oldest cache entry");
- return;
- }
- }
- cache->count--;
- }
- entry = xmalloc(sizeof(struct cache_entry));
- entry->data = data;
- entry->hash = hash;
- entry->lastused = time(NULL);
- if (!hash_insert(cache->hashtable, &entry->hash, entry)) {
- warn("tradindexed: duplicate cache entry for %s", HashToText(hash));
- free(entry);
- } else {
- entry->data->refcount++;
- cache->count++;
- }
-}
-
-
-/*
-** Delete an entry from the cache.
-*/
-void
-tdx_cache_delete(struct cache *cache, HASH hash)
-{
- if (!hash_delete(cache->hashtable, &hash))
- warn("tradindexed: unable to remove cache entry for %s",
- HashToText(hash));
-}
-
-
-/*
-** Delete the cache and all of the resources that it's holding open.
-*/
-void
-tdx_cache_free(struct cache *cache)
-{
- hash_free(cache->hashtable);
- free(cache);
-}
+++ /dev/null
-/* $Id: tdx-data.c 7598 2007-02-09 02:40:51Z eagle $
-**
-** Overview data file handling for the tradindexed overview method.
-**
-** Implements the handling of the .IDX and .DAT files for the tradindexed
-** overview method. The .IDX files are flat arrays of binary structs
-** specifying the offset in the data file of the overview data for a given
-** article as well as the length of that data and some additional meta-data
-** about that article. The .DAT files contain all of the overview data for
-** that group in wire format.
-**
-** Externally visible functions have a tdx_ prefix; internal functions do
-** not. (Externally visible unfortunately means everything that needs to be
-** visible outside of this object file, not just interfaces exported to
-** consumers of the overview API.)
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/mmap.h"
-#include "libinn.h"
-#include "ov.h"
-#include "ovinterface.h"
-#include "storage.h"
-#include "tdx-private.h"
-#include "tdx-structure.h"
-
-/* Returned to callers as an opaque data type, this holds the information
- needed to manage a search in progress. */
-struct search {
- ARTNUM limit;
- ARTNUM current;
- struct group_data *data;
-};
-
-/* Internal prototypes. */
-static char *group_path(const char *group);
-static int file_open(const char *base, const char *suffix, bool writable,
- bool append);
-static bool file_open_index(struct group_data *, const char *suffix);
-static bool file_open_data(struct group_data *, const char *suffix);
-static void *map_file(int fd, size_t length, const char *base,
- const char *suffix);
-static bool map_index(struct group_data *data);
-static bool map_data(struct group_data *data);
-static void unmap_index(struct group_data *data);
-static void unmap_data(struct group_data *data);
-static ARTNUM index_base(ARTNUM artnum);
-
-
-/*
-** Determine the path to the data files for a particular group and return
-** it. Allocates memory which the caller is responsible for freeing.
-*/
-static char *
-group_path(const char *group)
-{
- char *path, *p;
- size_t length;
- const char *gp;
-
- /* The path of the data files for news.groups is dir/n/g/news.groups. In
- other words, the first letter of each component becomes a directory.
- The length of the path is therefore the length of the base overview
- directory path, one character for the slash, two characters for the
- first letter and initial slash, two characters for each hierarchical
- level of the group, and then the length of the group name.
-
- For robustness, we want to handle leading or multiple consecutive
- periods. We only recognize a new hierarchical level after a string of
- periods (which doesn't end the group name). */
- length = strlen(innconf->pathoverview);
- for (gp = group; *gp != '\0'; gp++)
- if (*gp == '.') {
- if (gp[1] == '.' || gp[0] == '\0')
- continue;
- length += 2;
- }
- length += 1 + 2 + strlen(group) + 1;
- path = xmalloc(length);
- strlcpy(path, innconf->pathoverview, length);
- p = path + strlen(innconf->pathoverview);
-
- /* Generate the hierarchical directories. */
- if (*group != '.' && *group != '\0') {
- *p++ = '/';
- *p++ = *group;
- }
- for (gp = strchr(group, '.'); gp != NULL; gp = strchr(gp, '.')) {
- gp++;
- if (gp == group + 1)
- continue;
- if (*gp != '\0' && *gp != '.' && *gp != '/') {
- *p++ = '/';
- *p++ = *gp;
- }
- }
- *p++ = '/';
-
- /* Finally, append the group name to the generated path and then replace
- all slashes with commas. Commas have the advantage of being clearly
- illegal in newsgroup names because of the syntax of the Newsgroups
- header, but aren't shell metacharacters. */
- strlcpy(p, group, length - (p - path));
- for (; *p != '\0'; p++)
- if (*p == '/')
- *p = ',';
- return path;
-}
-
-
-/*
-** Open a data file for a group. Takes the base portion of the file, the
-** suffix, a bool saying whether or not the file is being opened for write,
-** and a bool saying whether to open it for append. Returns the file
-** descriptor.
-*/
-static int
-file_open(const char *base, const char *suffix, bool writable, bool append)
-{
- char *file;
- int flags, fd;
-
- file = concat(base, ".", suffix, (char *) 0);
- flags = writable ? (O_RDWR | O_CREAT) : O_RDONLY;
- if (append)
- flags |= O_APPEND;
- fd = open(file, flags, ARTFILE_MODE);
- if (fd < 0 && writable && errno == ENOENT) {
- char *p = strrchr(file, '/');
-
- *p = '\0';
- if (!MakeDirectory(file, true)) {
- syswarn("tradindexed: cannot create directory %s", file);
- free(file);
- return -1;
- }
- *p = '/';
- fd = open(file, flags, ARTFILE_MODE);
- }
- if (fd < 0) {
- if (errno != ENOENT)
- syswarn("tradindexed: cannot open %s", file);
- free(file);
- return -1;
- }
- free(file);
- return fd;
-}
-
-
-/*
-** Open the index file for a group. Takes an optional suffix to use instead
-** of IDX (used primarily for expiring).
-*/
-static bool
-file_open_index(struct group_data *data, const char *suffix)
-{
- struct stat st;
-
- if (suffix == NULL)
- suffix = "IDX";
- if (data->indexfd >= 0)
- close(data->indexfd);
- data->indexfd = file_open(data->path, suffix, data->writable, false);
- if (data->indexfd < 0)
- return false;
- if (fstat(data->indexfd, &st) < 0) {
- syswarn("tradindexed: cannot stat %s.%s", data->path, suffix);
- close(data->indexfd);
- return false;
- }
- data->indexinode = st.st_ino;
- close_on_exec(data->indexfd, true);
- return true;
-}
-
-
-/*
-** Open the data file for a group. Takes an optional suffix to use instead
-** of DAT (used primarily for expiring).
-*/
-static bool
-file_open_data(struct group_data *data, const char *suffix)
-{
- if (suffix == NULL)
- suffix = "DAT";
- if (data->datafd >= 0)
- close(data->datafd);
- data->datafd = file_open(data->path, suffix, data->writable, true);
- if (data->datafd < 0)
- return false;
- close_on_exec(data->datafd, true);
- return true;
-}
-
-
-/*
-** Open a particular group. Allocates a new struct group_data that should be
-** passed to tdx_data_close() when the caller is done with it.
-*/
-struct group_data *
-tdx_data_new(const char *group, bool writable)
-{
- struct group_data *data;
-
- data = xmalloc(sizeof(struct group_data));
- data->path = group_path(group);
- data->writable = writable;
- data->high = 0;
- data->base = 0;
- data->indexfd = -1;
- data->datafd = -1;
- data->index = NULL;
- data->data = NULL;
- data->indexlen = 0;
- data->datalen = 0;
- data->indexinode = 0;
- data->refcount = 0;
-
- return data;
-}
-
-
-/*
-** Open the index and data files for a group.
-*/
-bool
-tdx_data_open_files(struct group_data *data)
-{
- unmap_index(data);
- unmap_data(data);
- data->index = NULL;
- data->data = NULL;
- if (!file_open_index(data, NULL))
- goto fail;
- if (!file_open_data(data, NULL))
- goto fail;
- return true;
-
- fail:
- if (data->indexfd >= 0)
- close(data->indexfd);
- if (data->datafd >= 0)
- close(data->datafd);
- return false;
-}
-
-
-/*
-** Map a data file (either index or data), or read in all of the data in the
-** file if we're avoiding mmap. Takes the base and suffix of the file for
-** error reporting.
-*/
-static void *
-map_file(int fd, size_t length, const char *base, const char *suffix)
-{
- char *data;
-
- if (length == 0)
- return NULL;
-
- if (!innconf->tradindexedmmap) {
- ssize_t status;
-
- data = xmalloc(length);
- status = read(fd, data, length);
- if ((size_t) status != length) {
- syswarn("tradindexed: cannot read data file %s.%s", base, suffix);
- free(data);
- return NULL;
- }
- } else {
- data = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- syswarn("tradindexed: cannot mmap %s.%s", base, suffix);
- return NULL;
- }
- }
- return data;
-}
-
-
-/*
-** Memory map the index file.
-*/
-static bool
-map_index(struct group_data *data)
-{
- struct stat st;
- int r;
-
- r = fstat(data->indexfd, &st);
- if (r == -1) {
- if (errno == ESTALE) {
- r = file_open_index(data, NULL);
- } else {
- syswarn("tradindexed: cannot stat %s.IDX", data->path);
- }
- }
- if (r == -1)
- return false;
- data->indexlen = st.st_size;
- data->index = map_file(data->indexfd, data->indexlen, data->path, "IDX");
- return (data->index == NULL && data->indexlen > 0) ? false : true;
-}
-
-
-/*
-** Memory map the data file.
-*/
-static bool
-map_data(struct group_data *data)
-{
- struct stat st;
- int r;
-
- r = fstat(data->datafd, &st);
- if (r == -1) {
- if (errno == ESTALE) {
- r = file_open_data(data, NULL);
- } else {
- syswarn("tradindexed: cannot stat %s.DAT", data->path);
- }
- }
- if (r == -1)
- return false;
- data->datalen = st.st_size;
- data->data = map_file(data->datafd, data->datalen, data->path, "DAT");
- return (data->data == NULL && data->indexlen > 0) ? false : true;
-}
-
-
-/*
-** Unmap a data file or free the memory copy if we're not using mmap. Takes
-** the memory to free or unmap, the length for munmap, and the name base and
-** suffix for error reporting.
-*/
-static void
-unmap_file(void *data, off_t length, const char *base, const char *suffix)
-{
- if (data == NULL)
- return;
- if (!innconf->tradindexedmmap)
- free(data);
- else {
- if (munmap(data, length) < 0)
- syswarn("tradindexed: cannot munmap %s.%s", base, suffix);
- }
- return;
-}
-
-/*
-** Unmap the index file.
-*/
-static void
-unmap_index(struct group_data *data)
-{
- unmap_file(data->index, data->indexlen, data->path, "IDX");
- data->index = NULL;
-}
-
-
-/*
-** Unmap the data file.
-*/
-static void
-unmap_data(struct group_data *data)
-{
- unmap_file(data->data, data->datalen, data->path, "DAT");
- data->data = NULL;
-}
-
-/*
-** Determine if the file handle associated with the index table is stale
-*/
-static bool
-stale_index(struct group_data *data)
-{
- struct stat st;
- int r;
-
- r = fstat(data->indexfd, &st);
- return r == -1 && errno == ESTALE;
-}
-
-
-/*
-** Determine if the file handle associated with the data table is stale
-*/
-static bool
-stale_data(struct group_data *data)
-{
- struct stat st;
- int r;
-
- r = fstat(data->datafd, &st);
- return r == -1 && errno == ESTALE;
-}
-
-
-/*
-** Retrieves the article metainformation stored in the index table (all the
-** stuff we can return without opening the data file). Takes the article
-** number and returns a pointer to the index entry. Also takes the high
-** water mark from the group index; this is used to decide whether to attempt
-** remapping of the index file if the current high water mark is too low.
-*/
-const struct index_entry *
-tdx_article_entry(struct group_data *data, ARTNUM article, ARTNUM high)
-{
- struct index_entry *entry;
- ARTNUM offset;
-
- if (article > data->high && high > data->high) {
- unmap_index(data);
- map_index(data);
- data->high = high;
- } else if (innconf->nfsreader && stale_index(data))
- unmap_index(data);
- if (data->index == NULL)
- if (!map_index(data))
- return NULL;
-
- if (article < data->base)
- return NULL;
- offset = article - data->base;
- if (offset >= data->indexlen / sizeof(struct index_entry))
- return NULL;
- entry = data->index + offset;
- if (entry->length == 0)
- return NULL;
- return entry;
-}
-
-
-/*
-** Begin an overview search. In addition to the bounds of the search, we
-** also take the high water mark from the group index; this is used to decide
-** whether or not to attempt remapping of the index file if the current high
-** water mark is too low.
-*/
-struct search *
-tdx_search_open(struct group_data *data, ARTNUM start, ARTNUM end, ARTNUM high)
-{
- struct search *search;
-
- if (end < data->base)
- return NULL;
- if (end < start)
- return NULL;
-
- if (end > data->high && high > data->high) {
- unmap_index(data);
- map_index(data);
- data->high = high;
- }
- if (start > data->high)
- return NULL;
-
- if (innconf->nfsreader && stale_index(data))
- unmap_index(data);
- if (data->index == NULL)
- if (!map_index(data))
- return NULL;
- if (innconf->nfsreader && stale_data(data))
- unmap_data(data);
- if (data->data == NULL)
- if (!map_data(data))
- return NULL;
-
- search = xmalloc(sizeof(struct search));
- search->limit = end - data->base;
- search->current = (start < data->base) ? 0 : start - data->base;
- search->data = data;
- search->data->refcount++;
-
- return search;
-}
-
-
-/*
-** Return the next record in a search.
-*/
-bool
-tdx_search(struct search *search, struct article *artdata)
-{
- struct index_entry *entry;
- size_t max;
-
- if (search == NULL || search->data == NULL)
- return false;
- if (search->data->index == NULL || search->data->data == NULL)
- return false;
-
- max = (search->data->indexlen / sizeof(struct index_entry)) - 1;
- entry = search->data->index + search->current;
- while (search->current <= search->limit && search->current <= max) {
- if (entry->length != 0)
- break;
- search->current++;
- entry++;
- }
- if (search->current > search->limit || search->current > max)
- return false;
-
- /* Make sure that the offset into the data file is sensible, and try
- remapping the data file if the portion the offset is pointing to isn't
- currently mapped. Otherwise, warn about possible corruption and return
- a miss. */
- if (entry->offset + entry->length > search->data->datalen) {
- unmap_data(search->data);
- if (!map_data(search->data))
- return false;
- }
- if (entry->offset + entry->length > search->data->datalen) {
- warn("Invalid entry for article %lu in %s.IDX: offset %lu length %lu",
- search->current + search->data->base, search->data->path,
- (unsigned long) entry->offset, (unsigned long) entry->length);
- return false;
- }
-
- artdata->number = search->current + search->data->base;
- artdata->overview = search->data->data + entry->offset;
- artdata->overlen = entry->length;
- artdata->token = entry->token;
- artdata->arrived = entry->arrived;
- artdata->expires = entry->expires;
-
- search->current++;
- return true;
-}
-
-
-/*
-** End an overview search.
-*/
-void
-tdx_search_close(struct search *search)
-{
- if (search->data != NULL) {
- search->data->refcount--;
- if (search->data->refcount == 0)
- tdx_data_close(search->data);
- }
- free(search);
-}
-
-
-/*
-** Given an article number, return an index base appropriate for that article
-** number. This includes a degree of slop so that we don't have to
-** constantly repack if the article numbers are clustered around a particular
-** value but don't come in order.
-*/
-ARTNUM
-index_base(ARTNUM artnum)
-{
- return (artnum > 128) ? (artnum - 128) : 1;
-}
-
-
-/*
-** Store the data for a single article into the overview files for a group.
-** Assumes any necessary repacking has already been done. If the base value
-** in the group_data structure is 0, assumes this is the first time we've
-** written overview information to this group and sets it appropriately.
-*/
-bool
-tdx_data_store(struct group_data *data, const struct article *article)
-{
- struct index_entry entry;
- off_t offset;
-
- if (!data->writable)
- return false;
- if (data->base == 0)
- data->base = index_base(article->number);
- if (data->base > article->number) {
- warn("tradindexed: cannot add %lu to %s.IDX, base == %lu",
- article->number, data->path, data->base);
- return false;
- }
-
- /* Write out the data and fill in the index entry. */
- memset(&entry, 0, sizeof(entry));
- if (xwrite(data->datafd, article->overview, article->overlen) < 0) {
- syswarn("tradindexed: cannot append %lu of data for %lu to %s.DAT",
- (unsigned long) article->overlen, article->number,
- data->path);
- return false;
- }
- entry.offset = lseek(data->datafd, 0, SEEK_CUR);
- if (entry.offset < 0) {
- syswarn("tradindexed: cannot get offset for article %lu in %s.DAT",
- article->number, data->path);
- return false;
- }
- entry.length = article->overlen;
- entry.offset -= entry.length;
- entry.arrived = article->arrived;
- entry.expires = article->expires;
- entry.token = article->token;
-
- /* Write out the index entry. */
- offset = (article->number - data->base) * sizeof(struct index_entry);
- if (xpwrite(data->indexfd, &entry, sizeof(entry), offset) < 0) {
- syswarn("tradindexed: cannot write index record for %lu in %s.IDX",
- article->number, data->path);
- return false;
- }
- return true;
-}
-
-
-/*
-** Start the process of packing a group (rewriting its index file so that it
-** uses a different article base). Takes the article number of an article
-** that needs to be written to the index file and is below the current base.
-** Returns the true success and false on failure, and sets data->base to the
-** new article base and data->indexinode to the new inode number. At the
-** conclusion of this routine, the new index file has been created, but it
-** has not yet been moved into place; that is done by tdx_data_pack_finish.
-*/
-bool
-tdx_data_pack_start(struct group_data *data, ARTNUM artnum)
-{
- ARTNUM base;
- unsigned long delta;
- int fd;
- char *idxfile;
- struct stat st;
-
- if (!data->writable)
- return false;
- if (data->base <= artnum) {
- warn("tradindexed: tdx_data_pack_start called unnecessarily");
- return false;
- }
-
- /* Open the new index file. */
- base = index_base(artnum);
- delta = data->base - base;
- fd = file_open(data->path, "IDX-NEW", true, false);
- if (fd < 0)
- return false;
- if (fstat(fd, &st) < 0) {
- warn("tradindexed: cannot stat %s.IDX-NEW", data->path);
- goto fail;
- }
-
- /* For convenience, memory map the old index file. */
- unmap_index(data);
- if (!map_index(data))
- goto fail;
-
- /* Write the contents of the old index file to the new index file. */
- if (lseek(fd, delta * sizeof(struct index_entry), SEEK_SET) < 0) {
- syswarn("tradindexed: cannot seek in %s.IDX-NEW", data->path);
- goto fail;
- }
- if (xwrite(fd, data->index, data->indexlen) < 0) {
- syswarn("tradindexed: cannot write to %s.IDX-NEW", data->path);
- goto fail;
- }
- if (close(fd) < 0) {
- syswarn("tradindexed: cannot close %s.IDX-NEW", data->path);
- goto fail;
- }
- data->base = base;
- data->indexinode = st.st_ino;
- return true;
-
- fail:
- if (fd >= 0) {
- close(fd);
- idxfile = concat(data->path, ".IDX-NEW", (char *) 0);
- if (unlink(idxfile) < 0)
- syswarn("tradindexed: cannot unlink %s", idxfile);
- free(idxfile);
- }
- return false;
-}
-
-
-/*
-** Finish the process of packing a group by replacing the new index with the
-** old index. Also reopen the index file and update indexinode to keep our
-** caller from having to close and reopen the index file themselves.
-*/
-bool
-tdx_data_pack_finish(struct group_data *data)
-{
- char *newidx, *idx;
-
- if (!data->writable)
- return false;
- newidx = concat(data->path, ".IDX-NEW", (char *) 0);
- idx = concat(data->path, ".IDX", (char *) 0);
- if (rename(newidx, idx) < 0) {
- syswarn("tradindexed: cannot rename %s to %s", newidx, idx);
- unlink(newidx);
- free(newidx);
- free(idx);
- return false;
- } else {
- free(newidx);
- free(idx);
- if (!file_open_index(data, NULL))
- return false;
- return true;
- }
-}
-
-
-/*
-** Open the data files for a group data rebuild, and return a struct
-** group_data for the new files. Calling this function doesn't interfere
-** with the existing data for the group. Either tdx_data_rebuild_abort or
-** tdx_data_rebuild_finish should be called on the returned struct group_data
-** when the caller is done.
-*/
-struct group_data *
-tdx_data_rebuild_start(const char *group)
-{
- struct group_data *data;
-
- data = tdx_data_new(group, true);
- tdx_data_delete(group, "-NEW");
- if (!file_open_index(data, "IDX-NEW"))
- goto fail;
- if (!file_open_data(data, "DAT-NEW"))
- goto fail;
- return data;
-
- fail:
- tdx_data_delete(group, "-NEW");
- tdx_data_close(data);
- return NULL;
-}
-
-
-/*
-** Finish a rebuild by renaming the new index and data files to their
-** permanent names.
-*/
-bool
-tdx_data_rebuild_finish(const char *group)
-{
- char *base, *newidx, *bakidx, *idx, *newdat, *dat;
- bool saved = false;
-
- base = group_path(group);
- idx = concat(base, ".IDX", (char *) 0);
- newidx = concat(base, ".IDX-NEW", (char *) 0);
- bakidx = concat(base, ".IDX-BAK", (char *) 0);
- dat = concat(base, ".DAT", (char *) 0);
- newdat = concat(base, ".DAT-NEW", (char *) 0);
- free(base);
- if (rename(idx, bakidx) < 0) {
- syswarn("tradindexed: cannot rename %s to %s", idx, bakidx);
- goto fail;
- } else {
- saved = true;
- }
- if (rename(newidx, idx) < 0) {
- syswarn("tradindexed: cannot rename %s to %s", newidx, idx);
- goto fail;
- }
- if (rename(newdat, dat) < 0) {
- syswarn("tradindexed: cannot rename %s to %s", newdat, dat);
- goto fail;
- }
- if (unlink(bakidx) < 0)
- syswarn("tradindexed: cannot remove backup %s", bakidx);
- free(idx);
- free(newidx);
- free(bakidx);
- free(dat);
- free(newdat);
- return true;
-
- fail:
- if (saved && rename(bakidx, idx) < 0)
- syswarn("tradindexed: cannot restore old index %s", bakidx);
- free(idx);
- free(newidx);
- free(bakidx);
- free(dat);
- free(newdat);
- return false;
-}
-
-
-/*
-** Do the main work of expiring a group. Step through each article in the
-** group, only writing the unexpired entries out to the new group. There's
-** probably some room for optimization here for newsgroups that don't expire
-** so that the files don't have to be rewritten, or newsgroups where all the
-** data at the end of the file is still good and just needs to be moved
-** as-is.
-*/
-bool
-tdx_data_expire_start(const char *group, struct group_data *data,
- struct group_entry *index, struct history *history)
-{
- struct group_data *new_data;
- struct search *search;
- struct article article;
- ARTNUM high;
-
- new_data = tdx_data_rebuild_start(group);
- if (new_data == NULL)
- return false;
- index->indexinode = new_data->indexinode;
-
- /* Try to make sure that the search range is okay for even an empty group
- so that we can treat all errors on opening a search as errors. */
- high = index->high > 0 ? index->high : data->base;
- new_data->high = high;
- search = tdx_search_open(data, data->base, high, high);
- if (search == NULL)
- goto fail;
-
- /* Loop through all of the articles in the group, adding the ones that are
- still valid to the new index. */
- while (tdx_search(search, &article)) {
- ARTHANDLE *ah;
-
- if (!SMprobe(EXPENSIVESTAT, &article.token, NULL) || OVstatall) {
- ah = SMretrieve(article.token, RETR_STAT);
- if (ah == NULL)
- continue;
- SMfreearticle(ah);
- } else {
- if (!OVhisthasmsgid(history, article.overview))
- continue;
- }
- if (innconf->groupbaseexpiry)
- if (OVgroupbasedexpire(article.token, group, article.overview,
- article.overlen, article.arrived,
- article.expires))
- continue;
- if (!tdx_data_store(new_data, &article))
- goto fail;
- if (index->base == 0) {
- index->base = new_data->base;
- index->low = article.number;
- }
- if (article.number > index->high)
- index->high = article.number;
- index->count++;
- }
-
- /* Done; the rest happens in tdx_data_rebuild_finish. */
- tdx_data_close(new_data);
- return true;
-
- fail:
- tdx_data_delete(group, "-NEW");
- tdx_data_close(new_data);
- return false;
-}
-
-
-/*
-** Close the data files for a group and free the data structure.
-*/
-void
-tdx_data_close(struct group_data *data)
-{
- unmap_index(data);
- unmap_data(data);
- if (data->indexfd >= 0)
- close(data->indexfd);
- if (data->datafd >= 0)
- close(data->datafd);
- free(data->path);
- free(data);
-}
-
-
-/*
-** Delete the data files for a particular group, called when that group is
-** deleted from the server. Takes an optional suffix, which if present is
-** appended to the ends of the file names (used by expire to delete the -NEW
-** versions of the files).
-*/
-void
-tdx_data_delete(const char *group, const char *suffix)
-{
- char *path, *idx, *dat;
-
- path = group_path(group);
- idx = concat(path, ".IDX", suffix, (char *) 0);
- dat = concat(path, ".DAT", suffix, (char *) 0);
- if (unlink(idx) < 0 && errno != ENOENT)
- syswarn("tradindexed: cannot unlink %s", idx);
- if (unlink(dat) < 0 && errno != ENOENT)
- syswarn("tradindexed: cannot unlink %s", dat);
- free(dat);
- free(idx);
- free(path);
-}
-
-
-/*
-** RECOVERY AND AUDITING
-**
-** All code below this point is not used in the normal operations of the
-** overview method. Instead, it's code to dump various data structures or
-** audit them for consistency, used by recovery tools and inspection tools.
-*/
-
-/*
-** Dump the index file for a given group in human-readable format.
-*/
-void
-tdx_data_index_dump(struct group_data *data, FILE *output)
-{
- ARTNUM current;
- struct index_entry *entry, *end;
-
- if (data->index == NULL)
- if (!map_index(data))
- return;
-
- current = data->base;
- end = data->index + (data->indexlen / sizeof(struct index_entry));
- for (entry = data->index; entry < end; entry++) {
- fprintf(output, "%lu %lu %lu %lu %lu %s\n", current,
- (unsigned long) entry->offset, (unsigned long) entry->length,
- (unsigned long) entry->arrived,
- (unsigned long) entry->expires, TokenToText(entry->token));
- current++;
- }
-}
-
-
-/*
-** Audit a specific index entry for a particular article. If there's
-** anything wrong with it, we delete it; to repair a particular group, it's
-** best to just regenerate it from scratch.
-*/
-static void
-entry_audit(struct group_data *data, struct index_entry *entry,
- const char *group, ARTNUM article, bool fix)
-{
- struct index_entry new_entry;
- off_t offset;
-
- if (entry->length < 0) {
- warn("tradindexed: negative length %d in %s:%lu", entry->length,
- group, article);
- if (fix)
- goto clear;
- return;
- }
- if (entry->offset > data->datalen || entry->length > data->datalen) {
- warn("tradindexed: offset %lu or length %lu out of bounds for %s:%lu",
- (unsigned long) entry->offset, (unsigned long) entry->length,
- group, article);
- if (fix)
- goto clear;
- return;
- }
- if (entry->offset + entry->length > data->datalen) {
- warn("tradindexed: offset %lu plus length %lu out of bounds for"
- " %s:%lu", (unsigned long) entry->offset,
- (unsigned long) entry->length, group, article);
- if (fix)
- goto clear;
- return;
- }
- if (!overview_check(data->data + entry->offset, entry->length, article)) {
- warn("tradindexed: malformed overview data for %s:%lu", group,
- article);
- if (fix)
- goto clear;
- }
- return;
-
- clear:
- new_entry = *entry;
- new_entry.offset = 0;
- new_entry.length = 0;
- offset = (entry - data->index) * sizeof(struct index_entry);
- if (xpwrite(data->indexfd, &new_entry, sizeof(new_entry), offset) != 0)
- warn("tradindexed: unable to repair %s:%lu", group, article);
-}
-
-
-/*
-** Audit the data for a particular group. Takes the index entry from the
-** group.index file and optionally corrects any problems with the data or the
-** index entry based on the contents of the data.
-*/
-void
-tdx_data_audit(const char *group, struct group_entry *index, bool fix)
-{
- struct group_data *data;
- struct index_entry *entry;
- long count;
- off_t expected;
- unsigned long entries, current;
- ARTNUM low = 0;
- bool changed = false;
-
- data = tdx_data_new(group, true);
- if (!tdx_data_open_files(data))
- return;
- if (!map_index(data))
- goto end;
- if (!map_data(data))
- goto end;
-
- /* Check the inode of the index. */
- if (data->indexinode != index->indexinode) {
- warn("tradindexed: index inode mismatch for %s: %lu != %lu", group,
- (unsigned long) data->indexinode,
- (unsigned long) index->indexinode);
- if (fix) {
- index->indexinode = data->indexinode;
- changed = true;
- }
- }
-
- /* Check the index size. */
- entries = data->indexlen / sizeof(struct index_entry);
- expected = entries * sizeof(struct index_entry);
- if (data->indexlen != expected) {
- warn("tradindexed: %lu bytes of trailing trash in %s.IDX",
- (unsigned long)(data->indexlen - expected), data->path);
- if (fix) {
- unmap_index(data);
- if (ftruncate(data->indexfd, expected) < 0)
- syswarn("tradindexed: cannot truncate %s.IDX", data->path);
- if (!map_index(data))
- goto end;
- }
- }
-
- /* Now iterate through all of the index entries. In addition to checking
- each one individually, also count the number of valid entries to check
- the count in the index and verify that the low water mark is
- correct. */
- for (current = 0, count = 0; current < entries; current++) {
- entry = &data->index[current];
- if (entry->length == 0)
- continue;
- entry_audit(data, entry, group, index->base + current, fix);
- if (entry->length != 0) {
- if (low == 0)
- low = index->base + current;
- count++;
- }
- }
- if (index->low != low && entries != 0) {
- warn("tradindexed: low water mark incorrect for %s: %lu != %lu",
- group, low, index->low);
- if (fix) {
- index->low = low;
- changed = true;
- }
- }
- if (index->count != count) {
- warn("tradindexed: count incorrect for %s: %lu != %lu", group,
- (unsigned long) count, (unsigned long) index->count);
- if (fix) {
- index->count = count;
- changed = true;
- }
- }
-
- /* All done. Close things down and flush the data we changed, if
- necessary. */
- if (changed)
- inn_mapcntl(index, sizeof(*index), MS_ASYNC);
-
- end:
- tdx_data_close(data);
-}
+++ /dev/null
-/* $Id: tdx-group.c 7598 2007-02-09 02:40:51Z eagle $
-**
-** Group index handling for the tradindexed overview method.
-**
-** Implements the handling of the group.index file for the tradindexed
-** overview method. This file contains an entry for every group and stores
-** the high and low article marks and the base article numbers for each
-** individual group index file.
-**
-** Externally visible functions have a tdx_ prefix; internal functions do
-** not. (Externally visible unfortunately means everything that needs to be
-** visible outside of this object file, not just interfaces exported to
-** consumers of the overview API.)
-**
-** This code has to support readers and writers sharing the same files, and
-** we want to avoid locking where possible since locking may be very slow
-** (such as over NFS). Each group has two data files (and one has to get the
-** right index file for a given data file or get mangled results) and one
-** piece of data in the main index file required to interpret the individual
-** index file, namely the article base of that index.
-**
-** We can make the following assumptions:
-**
-** - The high water mark for a group is monotonically increasing; in other
-** words, the highest numbered article in a group won't ever decrease.
-**
-** - While the article base may either increase or decrease, it will never
-** change unless the inode of the index file on disk also changes, since
-** changing the base requires rewriting the index file.
-**
-** - No two files will have the same inode (this requirement should be safe
-** even in strange Unix file formats, since the files are all in the same
-** directory).
-**
-** We therefore use the following procedure to update the data: The high
-** water mark may be changed at any time but surrounded in a write lock. The
-** base may only be changed as part of an index rebuild. To do an index
-** rebuild, we follow the following procedure:
-**
-** 1) Obtain a write lock on the group entry in the main index.
-** 2) Write out new index and data files to new temporary file names.
-** 3) Store the new index inode into the main index.
-** 4) Update the high, low, and base article numbers in the main index.
-** 5) Rename the data file to its correct name.
-** 6) Rename the index file to its correct name.
-** 7) Release the write lock.
-**
-** We use the following procedure to read the data:
-**
-** 1) Open the group data files (both index and data).
-** 2) Store copies of the current high water mark and base in variables.
-** 3) Check to be sure the index inode matches the master index file.
-**
-** If it does match, then we have a consistent set of data, since the high
-** water mark and base values have to match the index we have (the inode
-** value is updated first). It may not be the most current set of data, but
-** since we have those index and data files open, even if they're later
-** rebuilt we'll continue looking at the same files. They may have further
-** data appended to them, but that's safe.
-**
-** If the index inode doesn't match, someone's rebuilt the file while we were
-** trying to open it. Continue with the following procedure:
-**
-** 4) Close the data files that we opened.
-** 5) Obtain a read lock on the group entry in the main index.
-** 6) Reopen the data files.
-** 7) Grab the current high water mark and base.
-** 8) Release the read lock.
-**
-** In other words, if there appears to be contention, we fall back to using
-** locking so that we don't try to loop (which also avoids an infinite loop
-** in the event of corruption of the main index).
-**
-** Note that once we have a consistent set of data files open, we don't need
-** to aggressively check for new data files until someone asks for an article
-** outside the range of articles that we know about. We may be working from
-** outdated data files, but the most we'll miss is a cancel or an expiration
-** run. Overview data doesn't change; new data is appended and old data is
-** expired. We can afford to check only every once in a while, just to be
-** sure that we're not going to hand out overview data for a bunch of expired
-** articles.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <time.h>
-
-#include "inn/hashtab.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/mmap.h"
-#include "inn/qio.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "paths.h"
-#include "tdx-private.h"
-#include "tdx-structure.h"
-
-/* Returned to callers as an opaque data type, this stashes all of the
- information about an open group.index file. */
-struct group_index {
- char *path;
- int fd;
- bool writable;
- struct group_header *header;
- struct group_entry *entries;
- int count;
-};
-
-/* Forward declaration. */
-struct hashmap;
-
-/* Internal prototypes. */
-static int index_entry_count(size_t size);
-static size_t index_file_size(int count);
-static bool index_lock(int fd, enum inn_locktype type);
-static bool index_lock_group(int fd, ptrdiff_t offset, enum inn_locktype);
-static bool index_map(struct group_index *);
-static bool index_maybe_remap(struct group_index *, long loc);
-static void index_unmap(struct group_index *);
-static bool index_expand(struct group_index *);
-static long index_find(struct group_index *, const char *group);
-
-
-/*
-** Given a file size, return the number of group entries that it contains.
-*/
-static int
-index_entry_count(size_t size)
-{
- return (size - sizeof(struct group_header)) / sizeof(struct group_entry);
-}
-
-
-/*
-** Given a number of group entries, return the required file size.
-*/
-static size_t
-index_file_size(int count)
-{
- return sizeof(struct group_header) + count * sizeof(struct group_entry);
-}
-
-
-/*
-** Lock the hash table for the group index, used to acquire global locks on
-** the group index when updating it.
-*/
-static bool
-index_lock(int fd, enum inn_locktype type)
-{
- bool status;
-
- status = inn_lock_range(fd, type, true, 0, sizeof(struct group_header));
- if (!status)
- syswarn("tradindexed: cannot %s index hash table",
- (type == INN_LOCK_UNLOCK) ? "unlock" : "lock");
- return status;
-}
-
-
-/*
-** Lock the group entry for a particular group. Takes the offset of that
-** group entry from the start of the group entries (not the start of the
-** file; we have to add the size of the group header). Used for coordinating
-** updates of the data for a group.
-*/
-static bool
-index_lock_group(int fd, ptrdiff_t offset, enum inn_locktype type)
-{
- bool status;
- size_t size;
-
- size = sizeof(struct group_entry);
- offset = offset * size + sizeof(struct group_header);
- status = inn_lock_range(fd, type, true, offset, size);
- if (!status)
- syswarn("tradindexed: cannot %s group entry at %lu",
- (type == INN_LOCK_UNLOCK) ? "unlock" : "lock",
- (unsigned long) offset);
- return status;
-}
-
-
-/*
-** Memory map (or read into memory) the key portions of the group.index
-** file. Takes a struct group_index to fill in and returns true on success
-** and false on failure.
-*/
-static bool
-index_map(struct group_index *index)
-{
- if (!innconf->tradindexedmmap && index->writable) {
- warn("tradindexed: cannot open for writing without mmap");
- return false;
- }
-
- if (!innconf->tradindexedmmap) {
- ssize_t header_size;
- ssize_t entry_size;
-
- header_size = sizeof(struct group_header);
- entry_size = index->count * sizeof(struct group_entry);
- index->header = xmalloc(header_size);
- index->entries = xmalloc(entry_size);
- if (read(index->fd, index->header, header_size) != header_size) {
- syswarn("tradindexed: cannot read header from %s", index->path);
- goto fail;
- }
- if (read(index->fd, index->entries, entry_size) != entry_size) {
- syswarn("tradindexed: cannot read entries from %s", index->path);
- goto fail;
- }
- return true;
-
- fail:
- free(index->header);
- free(index->entries);
- index->header = NULL;
- index->entries = NULL;
- return false;
-
- } else {
- char *data;
- size_t size;
- int flag = PROT_READ;
-
- if (index->writable)
- flag = PROT_READ | PROT_WRITE;
- size = index_file_size(index->count);
- data = mmap(NULL, size, flag, MAP_SHARED, index->fd, 0);
- if (data == MAP_FAILED) {
- syswarn("tradindexed: cannot mmap %s", index->path);
- return false;
- }
- index->header = (struct group_header *)(void *) data;
- index->entries = (struct group_entry *)
- (void *)(data + sizeof(struct group_header));
- return true;
- }
-}
-
-
-static bool
-file_open_group_index(struct group_index *index, struct stat *st)
-{
- int open_mode;
-
- index->header = NULL;
- open_mode = index->writable ? O_RDWR | O_CREAT : O_RDONLY;
- index->fd = open(index->path, open_mode, ARTFILE_MODE);
- if (index->fd < 0) {
- syswarn("tradindexed: cannot open %s", index->path);
- goto fail;
- }
-
- if (fstat(index->fd, st) < 0) {
- syswarn("tradindexed: cannot fstat %s", index->path);
- goto fail;
- }
- close_on_exec(index->fd, true);
- return true;
-
- fail:
- if (index->fd >= 0) {
- close(index->fd);
- index->fd = -1;
- }
- return false;
-}
-
-
-/*
-** Given a group location, remap the index file if our existing mapping isn't
-** large enough to include that group. (This can be the case when another
-** writer is appending entries to the group index.)
-*/
-static bool
-index_maybe_remap(struct group_index *index, long loc)
-{
- struct stat st;
- int count;
- int r;
-
- if (loc < index->count)
- return true;
-
- /* Don't remap if remapping wouldn't actually help. */
- r = fstat(index->fd, &st);
- if (r == -1) {
- if (errno == ESTALE) {
- index_unmap(index);
- if (!file_open_group_index(index, &st))
- return false;
- } else {
- syswarn("tradindexed: cannot stat %s", index->path);
- return false;
- }
- }
- count = index_entry_count(st.st_size);
- if (count < loc && index->header != NULL)
- return true;
-
- /* Okay, remapping will actually help. */
- index_unmap(index);
- index->count = count;
- return index_map(index);
-}
-
-
-/*
-** Unmap the index file, either in preparation for closing the overview
-** method or to get ready to remap it. We warn about failures to munmap but
-** don't do anything about them; there isn't much that we can do.
-*/
-static void
-index_unmap(struct group_index *index)
-{
- if (index->header == NULL)
- return;
- if (!innconf->tradindexedmmap) {
- free(index->header);
- free(index->entries);
- } else {
- if (munmap(index->header, index_file_size(index->count)) < 0)
- syswarn("tradindexed: cannot munmap %s", index->path);
- }
- index->header = NULL;
- index->entries = NULL;
-}
-
-
-/*
-** Expand the group.index file to hold more entries; also used to build the
-** initial file. The caller is expected to lock the group index.
-*/
-static bool
-index_expand(struct group_index *index)
-{
- int i;
-
- index_unmap(index);
- index->count += 1024;
- if (ftruncate(index->fd, index_file_size(index->count)) < 0) {
- syswarn("tradindexed: cannot expand %s", index->path);
- return false;
- }
-
- /* If mapping the index fails, we've already extended it but we haven't
- done anything with the new portion of the file. That means that it's
- all zeroes, which means that it contains index entries who all think
- their next entry is entry 0. We don't want to leave things in this
- state (particularly if this was the first expansion of the index file,
- in which case entry 0 points to entry 0 and our walking functions may
- go into infinite loops. Undo the file expansion. */
- if (!index_map(index)) {
- index->count -= 1024;
- if (ftruncate(index->fd, index_file_size(index->count)) < 0) {
- syswarn("tradindexed: cannot shrink %s", index->path);
- }
- return false;
- }
-
- /* If the magic isn't right, assume this is a new index file. */
- if (index->header->magic != TDX_MAGIC) {
- index->header->magic = TDX_MAGIC;
- index->header->freelist.recno = -1;
- for (i = 0; i < TDX_HASH_SIZE; i++)
- index->header->hash[i].recno = -1;
- }
-
- /* Walk the new entries back to front, adding them to the free list. */
- for (i = index->count - 1; i >= index->count - 1024; i--) {
- index->entries[i].next = index->header->freelist;
- index->header->freelist.recno = i;
- }
-
- inn_mapcntl(index->header, index_file_size(index->count), MS_ASYNC);
- return true;
-}
-
-
-/*
-** Open the group.index file and allocate a new struct for it, returning a
-** pointer to that struct. Takes a bool saying whether or not the overview
-** should be opened for write.
-*/
-struct group_index *
-tdx_index_open(bool writable)
-{
- struct group_index *index;
- struct stat st;
-
- index = xmalloc(sizeof(struct group_index));
- index->path = concatpath(innconf->pathoverview, "group.index");
- index->writable = writable;
- if (!file_open_group_index(index, &st)) {
- goto fail;
- }
- if ((size_t) st.st_size > sizeof(struct group_header)) {
- index->count = index_entry_count(st.st_size);
- if (!index_map(index))
- goto fail;
- } else {
- index->count = 0;
- if (index->writable) {
- if (st.st_size > 0)
- warn("tradindexed: recreating truncated %s", index->path);
- if (!index_expand(index))
- goto fail;
- } else {
- index->header = NULL;
- index->entries = NULL;
- }
- }
- return index;
-
- fail:
- tdx_index_close(index);
- return NULL;
-}
-
-
-/*
-** Given a group name hash, return an index into the hash table in the
-** group.index header.
-*/
-static long
-index_bucket(HASH hash)
-{
- unsigned int bucket;
-
- memcpy(&bucket, &hash, sizeof(bucket));
- return bucket % TDX_HASH_SIZE;
-}
-
-
-/*
-** Given a pointer to a group entry, return its location number.
-*/
-static long
-entry_loc(const struct group_index *index, const struct group_entry *entry)
-{
- return entry - index->entries;
-}
-
-
-/*
-** Splice out a particular group entry. Takes the entry and a pointer to the
-** location where a pointer to it is stored.
-*/
-static void
-entry_splice(struct group_entry *entry, int *parent)
-{
- *parent = entry->next.recno;
- entry->next.recno = -1;
- inn_mapcntl(parent, sizeof(*parent), MS_ASYNC);
-}
-
-
-/*
-** Add a new entry to the appropriate hash chain.
-*/
-static void
-index_add(struct group_index *index, struct group_entry *entry)
-{
- long bucket, loc;
-
- bucket = index_bucket(entry->hash);
- loc = entry_loc(index, entry);
- if (loc == index->header->hash[bucket].recno) {
- warn("tradindexed: refusing to add a loop for %ld in bucket %ld",
- loc, bucket);
- return;
- }
- entry->next.recno = index->header->hash[bucket].recno;
- index->header->hash[bucket].recno = entry_loc(index, entry);
- inn_mapcntl(&index->header->hash[bucket], sizeof(struct loc), MS_ASYNC);
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
-}
-
-
-/*
-** Find a group in the index file, returning the group number for that group
-** or -1 if the group can't be found.
-*/
-static long
-index_find(struct group_index *index, const char *group)
-{
- HASH hash;
- long loc;
-
- if (index->header == NULL || index->entries == NULL)
- return -1;
- hash = Hash(group, strlen(group));
- if (innconf->nfsreader && !index_maybe_remap(index, LONG_MAX))
- return -1;
- loc = index->header->hash[index_bucket(hash)].recno;
-
- while (loc >= 0 && loc < index->count) {
- struct group_entry *entry;
-
- if (loc > index->count && !index_maybe_remap(index, loc))
- return -1;
- entry = index->entries + loc;
- if (entry->deleted == 0)
- if (memcmp(&hash, &entry->hash, sizeof(hash)) == 0)
- return loc;
- if (loc == entry->next.recno) {
- syswarn("tradindexed: index loop for entry %ld", loc);
- return -1;
- }
- loc = entry->next.recno;
- }
- return -1;
-}
-
-
-/*
-** Add a given entry to the free list.
-*/
-static void
-freelist_add(struct group_index *index, struct group_entry *entry)
-{
- entry->next.recno = index->header->freelist.recno;
- index->header->freelist.recno = entry_loc(index, entry);
- inn_mapcntl(&index->header->freelist, sizeof(struct loc), MS_ASYNC);
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
-}
-
-
-/*
-** Find an entry by hash value (rather than group name) and splice it out of
-** whatever chain it might belong to. This function is called by both
-** index_unlink and index_audit_group. Locking must be done by the caller.
-** Returns the group location of the spliced group.
-*/
-static long
-index_unlink_hash(struct group_index *index, HASH hash)
-{
- int *parent;
- long current;
-
- parent = &index->header->hash[index_bucket(hash)].recno;
- current = *parent;
-
- while (current >= 0 && current < index->count) {
- struct group_entry *entry;
-
- if (current > index->count && !index_maybe_remap(index, current))
- return -1;
- entry = &index->entries[current];
- if (entry->deleted == 0)
- if (memcmp(&hash, &entry->hash, sizeof(hash)) == 0) {
- entry_splice(entry, parent);
- return current;
- }
- if (current == entry->next.recno) {
- syswarn("tradindexed: index loop for entry %ld", current);
- return -1;
- }
- parent = &entry->next.recno;
- current = *parent;
- }
- return -1;
-}
-
-
-/*
-** Like index_find, but also removes that entry out of whatever chain it
-** might belong to. This function is called by tdx_index_delete. Locking
-** must be done by the caller.
-*/
-static long
-index_unlink(struct group_index *index, const char *group)
-{
- HASH hash;
-
- hash = Hash(group, strlen(group));
- return index_unlink_hash(index, hash);
-}
-
-
-/*
-** Return the information stored about a given group in the group index.
-*/
-struct group_entry *
-tdx_index_entry(struct group_index *index, const char *group)
-{
- long loc;
- struct group_entry *entry;
-
- loc = index_find(index, group);
- if (loc == -1)
- return NULL;
- entry = index->entries + loc;
- if (innconf->tradindexedmmap && innconf->nfsreader)
- inn_mapcntl(entry, sizeof *entry, MS_INVALIDATE);
- return entry;
-}
-
-
-/*
-** Add a new newsgroup to the group.index file. Takes the newsgroup name,
-** its high and low water marks, and the newsgroup flag. Note that aliased
-** newsgroups are not currently handled. If the group already exists, just
-** update the flag (not the high and low water marks).
-*/
-bool
-tdx_index_add(struct group_index *index, const char *group, ARTNUM low,
- ARTNUM high, const char *flag)
-{
- HASH hash;
- long loc;
- struct group_entry *entry;
- struct group_data *data;
-
- if (!index->writable)
- return false;
-
- /* If the group already exists, update the flag as necessary and then
- we're all done. */
- loc = index_find(index, group);
- if (loc != -1) {
- entry = &index->entries[loc];
- if (entry->flag != *flag) {
- entry->flag = *flag;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- }
- return true;
- }
-
- index_lock(index->fd, INN_LOCK_WRITE);
-
- /* Find a free entry. If we don't have any free space, make some. */
- if (index->header->freelist.recno == -1)
- if (!index_expand(index)) {
- index_lock(index->fd, INN_LOCK_UNLOCK);
- return false;
- }
- loc = index->header->freelist.recno;
- index->header->freelist.recno = index->entries[loc].next.recno;
- inn_mapcntl(&index->header->freelist, sizeof(struct loc), MS_ASYNC);
-
- /* Initialize the entry. */
- entry = &index->entries[loc];
- hash = Hash(group, strlen(group));
- entry->hash = hash;
- entry->low = (low == 0 && high != 0) ? high + 1 : low;
- entry->high = high;
- entry->deleted = 0;
- entry->base = 0;
- entry->count = 0;
- entry->flag = *flag;
- data = tdx_data_new(group, index->writable);
- if (!tdx_data_open_files(data))
- warn("tradindexed: unable to create data files for %s", group);
- entry->indexinode = data->indexinode;
- tdx_data_close(data);
- index_add(index, entry);
-
- index_lock(index->fd, INN_LOCK_UNLOCK);
- return true;
-}
-
-
-/*
-** Delete a group index entry.
-*/
-bool
-tdx_index_delete(struct group_index *index, const char *group)
-{
- long loc;
- struct group_entry *entry;
-
- if (!index->writable)
- return false;
-
- /* Lock the header for the entire operation, mostly as prevention against
- interfering with ongoing audits (which lock while they're running). */
- index_lock(index->fd, INN_LOCK_WRITE);
-
- /* Splice out the entry and mark it as deleted. */
- loc = index_unlink(index, group);
- if (loc == -1) {
- index_lock(index->fd, INN_LOCK_UNLOCK);
- return false;
- }
- entry = &index->entries[loc];
- entry->deleted = time(NULL);
- HashClear(&entry->hash);
-
- /* Add the entry to the free list. */
- freelist_add(index, entry);
- index_lock(index->fd, INN_LOCK_UNLOCK);
-
- /* Delete the group data files for this group. */
- tdx_data_delete(group, NULL);
-
- return true;
-}
-
-
-/*
-** Close an open handle to the group index file, freeing the group_index
-** structure at the same time. The argument to this function becomes invalid
-** after this call.
-*/
-void
-tdx_index_close(struct group_index *index)
-{
- index_unmap(index);
- if (index->fd >= 0) {
- close(index->fd);
- index->fd = -1;
- }
- free(index->path);
- free(index);
-}
-
-
-/*
-** Open the data files for a particular group. The interface to this has to
-** be in this file because we have to lock the group and retry if the inode
-** of the opened index file doesn't match the one recorded in the group index
-** file. Optionally take a pointer to the group index entry if the caller
-** has already gone to the work of finding it.
-*/
-struct group_data *
-tdx_data_open(struct group_index *index, const char *group,
- struct group_entry *entry)
-{
- struct group_data *data;
- ARTNUM high, base;
- ptrdiff_t offset;
-
- if (entry == NULL) {
- entry = tdx_index_entry(index, group);
- if (entry == NULL)
- return NULL;
- }
- offset = entry - index->entries;
- data = tdx_data_new(group, index->writable);
-
- /* Check to see if the inode of the index file matches. If it doesn't,
- this probably means that as we were opening the index file, someone
- else rewrote it (either expire or repack). Obtain a lock and try
- again. If there's still a mismatch, go with what we get; there's some
- sort of corruption.
-
- This code is very sensitive to order and parallelism. See the comment
- at the beginning of this file for methodology. */
- if (!tdx_data_open_files(data))
- goto fail;
- high = entry->high;
- base = entry->base;
- if (entry->indexinode != data->indexinode) {
- index_lock_group(index->fd, offset, INN_LOCK_READ);
- if (!tdx_data_open_files(data)) {
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- goto fail;
- }
- if (entry->indexinode != data->indexinode)
- warn("tradindexed: index inode mismatch for %s", group);
- high = entry->high;
- base = entry->base;
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- }
- data->high = high;
- data->base = base;
- return data;
-
- fail:
- tdx_data_close(data);
- return NULL;
-}
-
-
-/*
-** Add an overview record for a particular article. Takes the group entry,
-** the open overview data structure, and the information about the article
-** and returns true on success, false on failure. This function calls
-** tdx_data_store to do most of the real work and then updates the index
-** information.
-*/
-bool
-tdx_data_add(struct group_index *index, struct group_entry *entry,
- struct group_data *data, const struct article *article)
-{
- ARTNUM old_base;
- ino_t old_inode;
- ptrdiff_t offset = entry - index->entries;
-
- if (!index->writable)
- return false;
- index_lock_group(index->fd, offset, INN_LOCK_WRITE);
-
- /* Make sure we have the most current data files and that we have the
- right base article number. */
- if (entry->indexinode != data->indexinode) {
- if (!tdx_data_open_files(data))
- goto fail;
- if (entry->indexinode != data->indexinode)
- warn("tradindexed: index inode mismatch for %s",
- HashToText(entry->hash));
- data->base = entry->base;
- }
-
- /* If the article number is too low to store in the group index, repack
- the group with a lower base index. */
- if (entry->base > article->number) {
- if (!tdx_data_pack_start(data, article->number))
- goto fail;
- old_inode = entry->indexinode;
- old_base = entry->base;
- entry->indexinode = data->indexinode;
- entry->base = data->base;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- if (!tdx_data_pack_finish(data)) {
- entry->base = old_base;
- entry->indexinode = old_inode;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- goto fail;
- }
- }
-
- /* Store the data. */
- if (!tdx_data_store(data, article))
- goto fail;
- if (entry->base == 0)
- entry->base = data->base;
- if (entry->low == 0 || entry->low > article->number)
- entry->low = article->number;
- if (entry->high < article->number)
- entry->high = article->number;
- entry->count++;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- return true;
-
- fail:
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- return false;
-}
-
-
-/*
-** Start a rebuild of the group data for a newsgroup. Right now, all this
-** does is lock the group index entry.
-*/
-bool
-tdx_index_rebuild_start(struct group_index *index, struct group_entry *entry)
-{
- ptrdiff_t offset;
-
- offset = entry - index->entries;
- return index_lock_group(index->fd, offset, INN_LOCK_WRITE);
-}
-
-
-/*
-** Finish a rebuild of the group data for a newsgroup. Takes the old and new
-** entry and writes the data from the new entry into the group index, and
-** then unlocks it.
-*/
-bool
-tdx_index_rebuild_finish(struct group_index *index, struct group_entry *entry,
- struct group_entry *new)
-{
- ptrdiff_t offset;
- ino_t new_inode;
-
- new_inode = new->indexinode;
- new->indexinode = entry->indexinode;
- *entry = *new;
- entry->indexinode = new_inode;
- new->indexinode = new_inode;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- offset = entry - index->entries;
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- return true;
-}
-
-
-/*
-** Expire a single newsgroup. Most of the work is done by tdx_data_expire*,
-** but this routine has the responsibility to do locking (the same as would
-** be done for repacking, since the group base may change) and updating the
-** group entry.
-*/
-bool
-tdx_expire(const char *group, ARTNUM *low, struct history *history)
-{
- struct group_index *index;
- struct group_entry *entry;
- struct group_entry new_entry;
- struct group_data *data = NULL;
- ptrdiff_t offset;
- ARTNUM old_base;
- ino_t old_inode;
-
- index = tdx_index_open(true);
- if (index == NULL)
- return false;
- entry = tdx_index_entry(index, group);
- if (entry == NULL) {
- tdx_index_close(index);
- return false;
- }
- tdx_index_rebuild_start(index, entry);
-
- /* tdx_data_expire_start builds the new IDX and DAT files and fills in the
- struct group_entry that was passed to it. tdx_data_rebuild_finish does
- the renaming of the new files to the final file names. */
- new_entry = *entry;
- new_entry.low = 0;
- new_entry.count = 0;
- new_entry.base = 0;
- data = tdx_data_open(index, group, entry);
- if (data == NULL)
- goto fail;
- if (!tdx_data_expire_start(group, data, &new_entry, history))
- goto fail;
- old_inode = entry->indexinode;
- old_base = entry->base;
- entry->indexinode = new_entry.indexinode;
- entry->base = new_entry.base;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- tdx_data_close(data);
- if (!tdx_data_rebuild_finish(group)) {
- entry->base = old_base;
- entry->indexinode = old_inode;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- goto fail;
- }
-
- /* Almost done. Update the group index. If there are no articles in the
- group, the low water mark should be one more than the high water
- mark. */
- if (new_entry.low == 0)
- new_entry.low = new_entry.high + 1;
- tdx_index_rebuild_finish(index, entry, &new_entry);
- if (low != NULL)
- *low = entry->low;
- tdx_index_close(index);
- return true;
-
- fail:
- offset = entry - index->entries;
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
- if (data != NULL)
- tdx_data_close(data);
- tdx_index_close(index);
- return false;
-}
-
-
-/*
-** RECOVERY AND AUDITING
-**
-** All code below this point is not used in the normal operations of the
-** overview method. Instead, it's code to dump various data structures or
-** audit them for consistency, used by recovery tools and inspection tools.
-*/
-
-/* Holds a newsgroup name and its hash, used to form a hash table mapping
- newsgroup hash values to the actual names. */
-struct hashmap {
- HASH hash;
- char *name;
- char flag;
-};
-
-/* Holds information needed by hash traversal functions. Right now, this is
- just the pointer to the group index and a flag saying whether to fix
- problems or not. */
-struct audit_data {
- struct group_index *index;
- bool fix;
-};
-
-
-/*
-** Hash table functions for the mapping from group hashes to names.
-*/
-static unsigned long
-hashmap_hash(const void *entry)
-{
- unsigned long hash;
- const struct hashmap *group = entry;
-
- memcpy(&hash, &group->hash, sizeof(hash));
- return hash;
-}
-
-
-static const void *
-hashmap_key(const void *entry)
-{
- return &((const struct hashmap *) entry)->hash;
-}
-
-
-static bool
-hashmap_equal(const void *key, const void *entry)
-{
- const HASH *first = key;
- const HASH *second;
-
- second = &((const struct hashmap *) entry)->hash;
- return memcmp(first, second, sizeof(HASH)) == 0;
-}
-
-
-static void
-hashmap_delete(void *entry)
-{
- struct hashmap *group = entry;
-
- free(group->name);
- free(group);
-}
-
-
-/*
-** Construct a hash table of group hashes to group names by scanning the
-** active file. Returns the constructed hash table.
-*/
-static struct hash *
-hashmap_load(void)
-{
- struct hash *hash;
- QIOSTATE *active;
- char *activepath, *line;
- struct cvector *data = NULL;
- struct stat st;
- size_t hash_size;
- struct hashmap *group;
- HASH grouphash;
-
- activepath = concatpath(innconf->pathdb, _PATH_ACTIVE);
- active = QIOopen(activepath);
- free(activepath);
- if (active == NULL)
- return NULL;
- if (fstat(QIOfileno(active), &st) < 0)
- hash_size = 32 * 1024;
- else
- hash_size = st.st_size / 30;
- hash = hash_create(hash_size, hashmap_hash, hashmap_key, hashmap_equal,
- hashmap_delete);
-
- line = QIOread(active);
- while (line != NULL) {
- data = cvector_split_space(line, data);
- if (data->count != 4) {
- warn("tradindexed: malformed active file line %s", line);
- continue;
- }
- group = xmalloc(sizeof(struct hashmap));
- group->name = xstrdup(data->strings[0]);
- group->flag = data->strings[3][0];
- grouphash = Hash(group->name, strlen(group->name));
- memcpy(&group->hash, &grouphash, sizeof(HASH));
- hash_insert(hash, &group->hash, group);
- line = QIOread(active);
- }
- cvector_free(data);
- QIOclose(active);
- return hash;
-}
-
-
-/*
-** Print the stored information about a single group in human-readable form
-** to stdout. The format is:
-**
-** name high low base count flag deleted inode
-**
-** all on one line. Name is passed into this function.
-*/
-void
-tdx_index_print(const char *name, const struct group_entry *entry,
- FILE *output)
-{
- fprintf(output, "%s %lu %lu %lu %lu %c %lu %lu\n", name, entry->high,
- entry->low, entry->base, (unsigned long) entry->count,
- entry->flag, (unsigned long) entry->deleted,
- (unsigned long) entry->indexinode);
-}
-
-
-/*
-** Dump the complete contents of the group.index file in human-readable form
-** to the specified file, one line per group.
-*/
-void
-tdx_index_dump(struct group_index *index, FILE *output)
-{
- int bucket;
- long current;
- struct group_entry *entry;
- struct hash *hashmap;
- struct hashmap *group;
- char *name;
-
- if (index->header == NULL || index->entries == NULL)
- return;
- hashmap = hashmap_load();
- for (bucket = 0; bucket < TDX_HASH_SIZE; bucket++) {
- current = index->header->hash[bucket].recno;
- while (current != -1) {
- if (!index_maybe_remap(index, current))
- return;
- entry = index->entries + current;
- name = NULL;
- if (hashmap != NULL) {
- group = hash_lookup(hashmap, &entry->hash);
- if (group != NULL)
- name = group->name;
- }
- if (name == NULL)
- name = HashToText(entry->hash);
- tdx_index_print(name, entry, output);
- if (current == entry->next.recno) {
- warn("tradindexed: index loop for entry %ld", current);
- return;
- }
- current = entry->next.recno;
- }
- }
- if (hashmap != NULL)
- hash_free(hashmap);
-}
-
-
-/*
-** Audit a particular group entry location to ensure that it points to a
-** valid entry within the group index file. Takes a pointer to the location,
-** the number of the location, a pointer to the group entry if any (if not,
-** the location is assumed to be part of the header hash table), and a flag
-** saying whether to fix problems that are found.
-*/
-static void
-index_audit_loc(struct group_index *index, int *loc, long number,
- struct group_entry *entry, bool fix)
-{
- bool error = false;
-
- if (*loc >= index->count) {
- warn("tradindexed: out of range index %d in %s %ld",
- *loc, (entry == NULL ? "bucket" : "entry"), number);
- error = true;
- }
- if (*loc < 0 && *loc != -1) {
- warn("tradindexed: invalid negative index %d in %s %ld",
- *loc, (entry == NULL ? "bucket" : "entry"), number);
- error = true;
- }
- if (entry != NULL && *loc == number) {
- warn("tradindexed: index loop for entry %ld", number);
- error = true;
- }
-
- if (fix && error) {
- *loc = -1;
- inn_mapcntl(loc, sizeof(*loc), MS_ASYNC);
- }
-}
-
-
-/*
-** Check an entry to see if it was actually deleted. Make sure that all the
-** information is consistent with a deleted group if it's not and the fix
-** flag is set.
-*/
-static void
-index_audit_deleted(struct group_entry *entry, long number, bool fix)
-{
- if (entry->deleted != 0 && !HashEmpty(entry->hash)) {
- warn("tradindexed: entry %ld has a delete time but a non-zero hash",
- number);
- if (fix) {
- HashClear(&entry->hash);
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- }
- }
-}
-
-
-/*
-** Audit the group header for any inconsistencies. This checks the
-** reachability of all of the group entries, makes sure that deleted entries
-** are on the free list, and otherwise checks the linked structure of the
-** whole file. The data in individual entries is not examined. If the
-** second argument is true, also attempt to fix inconsistencies.
-*/
-static void
-index_audit_header(struct group_index *index, bool fix)
-{
- long bucket, current;
- struct group_entry *entry;
- int *parent, *next;
- bool *reachable;
-
- /* First, walk all of the regular hash buckets, making sure that all of
- the group location pointers are valid and sane, that all groups that
- have been deleted are correctly marked as such, and that all groups are
- in their correct hash chain. Build reachability information as we go,
- used later to ensure that all group entries are reachable. */
- reachable = xcalloc(index->count, sizeof(bool));
- for (bucket = 0; bucket < TDX_HASH_SIZE; bucket++) {
- parent = &index->header->hash[bucket].recno;
- index_audit_loc(index, parent, bucket, NULL, fix);
- current = *parent;
- while (current >= 0 && current < index->count) {
- entry = &index->entries[current];
- next = &entry->next.recno;
- if (entry->deleted == 0 && bucket != index_bucket(entry->hash)) {
- warn("tradindexed: entry %ld is in bucket %ld instead of its"
- " correct bucket %ld", current, bucket,
- index_bucket(entry->hash));
- if (fix) {
- entry_splice(entry, parent);
- next = parent;
- }
- } else {
- if (reachable[current])
- warn("tradindexed: entry %ld is reachable from multiple"
- " paths", current);
- reachable[current] = true;
- }
- index_audit_deleted(entry, current, fix);
- index_audit_loc(index, &entry->next.recno, current, entry, fix);
- if (entry->deleted != 0) {
- warn("tradindexed: entry %ld is deleted but not in the free"
- " list", current);
- if (fix) {
- entry_splice(entry, parent);
- next = parent;
- reachable[current] = false;
- }
- }
- if (*next == current)
- break;
- parent = next;
- current = *parent;
- }
- }
-
- /* Now, walk the free list. Make sure that each group in the free list is
- actually deleted, and update the reachability information. */
- index_audit_loc(index, &index->header->freelist.recno, 0, NULL, fix);
- parent = &index->header->freelist.recno;
- current = *parent;
- while (current >= 0 && current < index->count) {
- entry = &index->entries[current];
- index_audit_deleted(entry, current, fix);
- reachable[current] = true;
- if (!HashEmpty(entry->hash) && entry->deleted == 0) {
- warn("tradindexed: undeleted entry %ld in free list", current);
- if (fix) {
- entry_splice(entry, parent);
- reachable[current] = false;
- }
- }
- index_audit_loc(index, &entry->next.recno, current, entry, fix);
- if (entry->next.recno == current)
- break;
- parent = &entry->next.recno;
- current = *parent;
- }
-
- /* Finally, check all of the unreachable entries and if fix is true, try
- to reattach them in the appropriate location. */
- for (current = 0; current < index->count; current++)
- if (!reachable[current]) {
- warn("tradindexed: unreachable entry %ld", current);
- if (fix) {
- entry = &index->entries[current];
- if (!HashEmpty(entry->hash) && entry->deleted == 0)
- index_add(index, entry);
- else {
- HashClear(&entry->hash);
- entry->deleted = 0;
- freelist_add(index, entry);
- }
- }
- }
-
- /* All done. */
- free(reachable);
-}
-
-
-/*
-** Audit a particular group entry for any inconsistencies. This doesn't
-** check any of the structure, or whether the group is deleted, just the data
-** as stored in the group data files (mostly by calling tdx_data_audit to do
-** the real work). Note that while the low water mark may be updated, the
-** high water mark is left unchanged.
-*/
-static void
-index_audit_group(struct group_index *index, struct group_entry *entry,
- struct hash *hashmap, bool fix)
-{
- struct hashmap *group;
- ptrdiff_t offset;
-
- offset = entry - index->entries;
- index_lock_group(index->fd, offset, INN_LOCK_WRITE);
- group = hash_lookup(hashmap, &entry->hash);
- if (group == NULL) {
- warn("tradindexed: group %ld not found in active file",
- entry_loc(index, entry));
- if (fix) {
- index_unlink_hash(index, entry->hash);
- HashClear(&entry->hash);
- entry->deleted = time(NULL);
- freelist_add(index, entry);
- }
- } else {
- if (entry->flag != group->flag) {
- entry->flag = group->flag;
- inn_mapcntl(entry, sizeof(*entry), MS_ASYNC);
- }
- tdx_data_audit(group->name, entry, fix);
- }
- index_lock_group(index->fd, offset, INN_LOCK_UNLOCK);
-}
-
-
-/*
-** Check to be sure that a given group exists in the overview index, and if
-** missing, adds it. Assumes that the index isn't locked, since it calls the
-** normal functions for adding new groups (this should only be called after
-** the index has already been repaired, for the same reason). Called as a
-** hash traversal function, walking the hash table of groups from the active
-** file.
-*/
-static void
-index_audit_active(void *value, void *cookie)
-{
- struct hashmap *group = value;
- struct audit_data *data = cookie;
- struct group_entry *entry;
-
- entry = tdx_index_entry(data->index, group->name);
- if (entry == NULL) {
- warn("tradindexed: group %s missing from overview", group->name);
- if (data->fix)
- tdx_index_add(data->index, group->name, 0, 0, &group->flag);
- }
-}
-
-
-/*
-** Audit the group index for any inconsistencies. If the argument is true,
-** also attempt to fix those inconsistencies.
-*/
-void
-tdx_index_audit(bool fix)
-{
- struct group_index *index;
- struct stat st;
- off_t expected;
- int count;
- struct hash *hashmap;
- long bucket;
- struct group_entry *entry;
- struct audit_data data;
-
- index = tdx_index_open(true);
- if (index == NULL)
- return;
-
- /* Keep a lock on the header through the whole audit process. This will
- stall any newgroups or rmgroups, but not normal article reception. We
- don't want the structure of the group entries changing out from under
- us, although we don't mind if the data does until we're validating that
- particular group. */
- index_lock(index->fd, INN_LOCK_WRITE);
-
- /* Make sure the size looks sensible. */
- if (fstat(index->fd, &st) < 0) {
- syswarn("tradindexed: cannot fstat %s", index->path);
- return;
- }
- count = index_entry_count(st.st_size);
- expected = index_file_size(count);
- if (expected != st.st_size) {
- syswarn("tradindexed: %ld bytes of trailing trash in %s",
- (unsigned long) (st.st_size - expected), index->path);
- if (fix)
- if (ftruncate(index->fd, expected) < 0)
- syswarn("tradindexed: cannot truncate %s", index->path);
- }
- index_maybe_remap(index, count);
-
- /* Okay everything is now mapped and happy. Validate the header. */
- index_audit_header(index, fix);
- index_lock(index->fd, INN_LOCK_UNLOCK);
-
- /* Walk all the group entries and check them individually. To do this, we
- need to map hashes to group names, so load a hash of the active file to
- do that resolution. */
- hashmap = hashmap_load();
- data.index = index;
- data.fix = fix;
- hash_traverse(hashmap, index_audit_active, &data);
- for (bucket = 0; bucket < index->count; bucket++) {
- entry = &index->entries[bucket];
- if (HashEmpty(entry->hash) || entry->deleted != 0)
- continue;
- index_audit_group(index, entry, hashmap, fix);
- }
- if (hashmap != NULL)
- hash_free(hashmap);
-}
+++ /dev/null
-/* $Id: tdx-private.h 5465 2002-05-06 05:46:15Z rra $
-**
-** Private APIs for the tradindexed overview method.
-*/
-
-#ifndef INN_TDX_PRIVATE_H
-#define INN_TDX_PRIVATE_H 1
-
-#include "config.h"
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "libinn.h"
-#include "storage.h"
-
-/* Forward declarations to avoid unnecessary includes. */
-struct history;
-
-/* Opaque data structure used by the cache. */
-struct cache;
-
-/* Opaque data structure returned by group index functions. */
-struct group_index;
-
-/* Opaque data structure returned by search functions. */
-struct search;
-
-/* All of the information about an open set of group data files. */
-struct group_data {
- char *path;
- bool writable;
- ARTNUM high;
- ARTNUM base;
- int indexfd;
- int datafd;
- struct index_entry *index;
- char *data;
- off_t indexlen;
- off_t datalen;
- ino_t indexinode;
- int refcount;
-};
-
-/* All of the data about an article, used as the return of the search
- functions. This is just cleaner than passing back all of the information
- that's used by the regular interface. */
-struct article {
- ARTNUM number;
- const char *overview;
- size_t overlen;
- TOKEN token;
- time_t arrived;
- time_t expires;
-};
-
-BEGIN_DECLS
-
-/* tdx-cache.c */
-
-/* Create a new cache with the given number of entries. */
-struct cache *tdx_cache_create(unsigned int size);
-
-/* Look up a given newsgroup hash in the cache, returning the group_data
- struct for its open data files if present. */
-struct group_data *tdx_cache_lookup(struct cache *, HASH);
-
-/* Insert a new group_data struct into the cache. */
-void tdx_cache_insert(struct cache *, HASH, struct group_data *);
-
-/* Delete a group entry from the cache. */
-void tdx_cache_delete(struct cache *, HASH);
-
-/* Free the cache and its resources. */
-void tdx_cache_free(struct cache *);
-
-
-/* tdx-group.c */
-
-/* Open the group index and return an opaque data structure to use for further
- queries. */
-struct group_index *tdx_index_open(bool writable);
-
-/* Return the stored information about a single newsgroup. */
-struct group_entry *tdx_index_entry(struct group_index *, const char *group);
-
-/* Print the contents of a single group entry in human-readable form. */
-void tdx_index_print(const char *name, const struct group_entry *, FILE *);
-
-/* Add a new newsgroup to the index file. */
-bool tdx_index_add(struct group_index *, const char *group, ARTNUM low,
- ARTNUM high, const char *flag);
-
-/* Delete a newsgroup from the index file. */
-bool tdx_index_delete(struct group_index *, const char *group);
-
-/* Dump the contents of the index file to stdout in human-readable form. */
-void tdx_index_dump(struct group_index *, FILE *);
-
-/* Audit all of the overview data, optionally trying to fix it. */
-void tdx_index_audit(bool fix);
-
-/* Close the open index file and dispose of the opaque data structure. */
-void tdx_index_close(struct group_index *);
-
-/* Open the overview information for a particular group. */
-struct group_data *tdx_data_open(struct group_index *, const char *group,
- struct group_entry *);
-
-/* Add a new overview entry. */
-bool tdx_data_add(struct group_index *, struct group_entry *,
- struct group_data *, const struct article *);
-
-/* Handle rebuilds of the data for a particular group. Call _start first and
- then _finish when done, with the new group_entry information. */
-bool tdx_index_rebuild_start(struct group_index *, struct group_entry *);
-bool tdx_index_rebuild_finish(struct group_index *, struct group_entry *,
- struct group_entry *new);
-
-/* Expire a single group. */
-bool tdx_expire(const char *group, ARTNUM *low, struct history *);
-
-
-/* tdx-data.c */
-
-/* Create a new group data structure. */
-struct group_data *tdx_data_new(const char *group, bool writable);
-
-/* Open the data files for a group. */
-bool tdx_data_open_files(struct group_data *);
-
-/* Return the metadata about a particular article in a group. */
-const struct index_entry *tdx_article_entry(struct group_data *,
- ARTNUM article, ARTNUM high);
-
-/* Create, perform, and close a search. */
-struct search *tdx_search_open(struct group_data *, ARTNUM start, ARTNUM end,
- ARTNUM high);
-bool tdx_search(struct search *, struct article *);
-void tdx_search_close(struct search *);
-
-/* Store article data. */
-bool tdx_data_store(struct group_data *, const struct article *);
-
-/* Start a repack of the files for a newsgroup. */
-bool tdx_data_pack_start(struct group_data *, ARTNUM);
-
-/* Complete a repack of the files for a newsgroup. */
-bool tdx_data_pack_finish(struct group_data *);
-
-/* Manage a rebuild of the data files for a particular group. Until
- tdx_data_rebuild_finish is called, anything stored into the returned struct
- group_data will have no effect on the data for that group. Does not handle
- updating the index entries; that must be done separately. */
-struct group_data *tdx_data_rebuild_start(const char *group);
-bool tdx_data_rebuild_finish(const char *group);
-
-/* Start the expiration of a newsgroup and do most of the work, filling out
- the provided group_entry struct. Complete with tdx_data_rebuild_finish. */
-bool tdx_data_expire_start(const char *group, struct group_data *,
- struct group_entry *, struct history *);
-
-/* Dump the contents of the index file for a group. */
-void tdx_data_index_dump(struct group_data *, FILE *);
-
-/* Audit the data for a particular group, optionally trying to fix it. */
-void tdx_data_audit(const char *group, struct group_entry *, bool fix);
-
-/* Close the open data files for a group and free the structure. */
-void tdx_data_close(struct group_data *);
-
-/* Delete the data files for a group. */
-void tdx_data_delete(const char *group, const char *suffix);
-
-END_DECLS
-
-#endif /* INN_TDX_PRIVATE_H */
+++ /dev/null
-/* $Id: tdx-structure.h 5327 2002-03-16 00:33:55Z rra $
-**
-** Data structures for the tradindexed overview method.
-**
-** This header defines the data structures used by the tradindexed overview
-** method. Currently, these data structures are read and written directly to
-** disk (and the disk files are therefore endian-dependent and possibly
-** architecture-dependent due to structure padding). This will eventually be
-** fixed.
-**
-** The structure of a tradindexed overview spool is as follows: At the root
-** of the spool is a group.index file composed of a struct group_header
-** followed by some number of struct group_entry's, one for each group plus
-** possibly some number of free entries linked to a free list that's headed
-** in the struct index_header. Each entry corresponds to a particular
-** newsgroup carried by the server and stores the high and low article
-** numbers for that group, its status flag, and the base of the index file
-** for each group.
-**
-** The storage of the group.index file implements a hash table with chaining;
-** in other words, there is a table indexed by hash value stored in the
-** header that points to the starts of the chains, new entries are appended
-** to the end of the file and added to the hash table, and if they collide
-** with an existing entry are instead linked to the appropriate hash chain.
-**
-** The overview information for each group is stored in a pair of files named
-** <group>.IDX and <group>.DAT. These files are found in a subdirectory
-** formed by taking the first letter of component of the newsgroup name as
-** a directory name; in other words, news.announce.newgroups overview data is
-** stored in <pathoverview>/n/a/n/news.announce.newgroups.{IDX,DAT}. The
-** .DAT file contains the individual overview entries, one per line, stored
-** in wire format (in other words, suitable for dumping directly across the
-** network to a client in response to an XOVER command). The overview data
-** stored in that file may be out of order.
-**
-** The .IDX file consists of a series of struct index_entry's, one for each
-** overview entry stored in the .DAT file. Each index entry stores the
-** offset of the data for one article in the .DAT file and its length, along
-** with some additional metainformation about the article used to drive
-** article expiration. The .IDX file is addressed like an array; the first
-** entry corresponds to the article with the number stored in the base field
-** of the group_entry for that newsgroup in the group.index file and each
-** entry stores the data for the next consecutive article. Index entries may
-** be tagged as deleted if that article has been deleted or expired.
-*/
-
-#ifndef INN_TDX_STRUCTURE_H
-#define INN_TDX_STRUCTURE_H 1
-
-#include "config.h"
-#include <sys/types.h>
-
-#include "libinn.h"
-#include "storage.h"
-
-/* A location in group.index (this many records past the end of the header of
- the file). There's no reason for this to be a struct, but that can't be
- changed until the format of the group.index file is changed to be
- architecture-independent since putting it into a struct may have changed
- the alignment or padding on some architectures. */
-struct loc {
- int recno;
-};
-
-/* The hard-coded constant size of the hash table for group.index. This need
- not be a power of two and has no special constraints. Changing this at
- present will break backward compatibility with group.index files written by
- previous versions of the code. */
-#define TDX_HASH_SIZE (16 * 1024)
-
-/* A magic number for the group.index file so that we can later change the
- format in a backward-compatible fashion. */
-#define TDX_MAGIC (~(0xf1f0f33d))
-
-/* The header at the top of group.index. magic contains GROUPHEADERMAGIC
- always; hash contains pointers to the heads of the entry chains, and
- freelist points to a linked list of free entries (entries that were used
- for groups that have since been deleted). */
-struct group_header {
- int magic;
- struct loc hash[TDX_HASH_SIZE];
- struct loc freelist;
-};
-
-/* An entry for a particular group. Note that a good bit of active file
- information is duplicated here, and depending on the portion of INN asking
- questions, sometimes the main active file is canonical and sometimes the
- overview data is canonical. This needs to be rethought at some point.
-
- Groups are matched based on the MD5 hash of their name. This may prove
- inadequate in the future. Ideally, INN really needs to assign unique
- numbers to each group, which could then be used here as well as in
- tradspool rather than having to do hacks like using a hash of the group
- name or constructing one's own number to name mapping like tradspool does.
- Unfortunately, this ideally requires a non-backward-compatible change to
- the active file format.
-
- Several of these elements aren't used. This structure, like the others,
- cannot be changed until the whole format of the group.index file is changed
- since it's currently read as binary structs directly from disk. */
-struct group_entry {
- HASH hash; /* MD5 hash of the group name. */
- HASH alias; /* Intended to point to the group this group
- is an alias for. Not currently used. */
- ARTNUM high; /* High article number in the group. */
- ARTNUM low; /* Low article number in the group. */
- ARTNUM base; /* Article number of the first entry in the
- .IDX index file for the group. */
- int count; /* Number of articles in group. */
- int flag; /* Posting/moderation status. */
- time_t deleted; /* When this group was deleted, or 0 if the
- group is still valid. */
- ino_t indexinode; /* The inode of the index file for the group,
- used to detect when the file has been
- recreated and swapped out. */
- struct loc next; /* Next block in this chain. */
-};
-
-/* An entry in the per-group .IDX index file. */
-struct index_entry {
- off_t offset;
- int length;
- time_t arrived;
- time_t expires; /* Expiration time from Expires: header. */
- TOKEN token;
-};
-
-#endif /* INN_TDX_STRUCTURE_H */
+++ /dev/null
-/* $Id: tdx-util.c 6289 2003-04-09 04:16:16Z rra $
-**
-** Utility for managing a tradindexed overview spool.
-**
-** This utility can manipulate a tradindexed overview spool in various ways,
-** including some ways that are useful for recovery from crashes. It allows
-** the user to view the contents of the various data structures that
-** tradindexed stores on disk.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <sys/stat.h>
-
-#include "inn/buffer.h"
-#include "inn/history.h"
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "ov.h"
-#include "ovinterface.h"
-#include "paths.h"
-#include "tdx-private.h"
-#include "tdx-structure.h"
-
-/*
-** Dump the main index data, either all of it or that for a particular group
-** if the group argument is non-NULL.
-*/
-static void
-dump_index(const char *group)
-{
- struct group_index *index;
-
- index = tdx_index_open(OV_READ);
- if (index == NULL)
- return;
- if (group == NULL)
- tdx_index_dump(index, stdout);
- else {
- const struct group_entry *entry;
-
- entry = tdx_index_entry(index, group);
- if (entry == NULL) {
- warn("cannot find group %s", group);
- return;
- }
- tdx_index_print(group, entry, stdout);
- }
- tdx_index_close(index);
-}
-
-
-/*
-** Dump the data index file for a particular group.
-*/
-static void
-dump_group_index(const char *group)
-{
- struct group_index *index;
- struct group_entry *entry;
- struct group_data *data;
-
- index = tdx_index_open(OV_READ);
- if (index == NULL)
- return;
- entry = tdx_index_entry(index, group);
- if (entry == NULL) {
- warn("cannot find group %s in the index", group);
- return;
- }
- data = tdx_data_open(index, group, entry);
- if (data == NULL) {
- warn("cannot open group %s", group);
- return;
- }
- tdx_data_index_dump(data, stdout);
- tdx_data_close(data);
- tdx_index_close(index);
-}
-
-
-/*
-** Dump the overview data for a particular group. If number is 0, dump the
-** overview data for all current articles; otherwise, only dump the data for
-** that particular article. Include the article number, token, arrived time,
-** and expires time (if any) in the overview data as additional fields.
-*/
-static void
-dump_overview(const char *group, ARTNUM number)
-{
- struct group_index *index;
- struct group_data *data;
- struct group_entry *entry;
- struct article article;
- struct search *search;
- char datestring[256];
-
- index = tdx_index_open(OV_READ);
- if (index == NULL)
- return;
- entry = tdx_index_entry(index, group);
- if (entry == NULL) {
- warn("cannot find group %s", group);
- return;
- }
- data = tdx_data_open(index, group, entry);
- if (data == NULL) {
- warn("cannot open group %s", group);
- return;
- }
- data->refcount++;
-
- if (number != 0)
- search = tdx_search_open(data, number, number, entry->high);
- else
- search = tdx_search_open(data, entry->low, entry->high, entry->high);
- if (search == NULL) {
- if (number != 0)
- puts("Article not found");
- else
- warn("cannot open search in %s: %lu - %lu", group, entry->low,
- entry->high);
- return;
- }
- while (tdx_search(search, &article)) {
- fwrite(article.overview, article.overlen - 2, 1, stdout);
- printf("\tArticle: %lu\tToken: %s", article.number,
- TokenToText(article.token));
- makedate(article.arrived, true, datestring, sizeof(datestring));
- printf("\tArrived: %s", datestring);
- if (article.expires != 0) {
- makedate(article.expires, true, datestring, sizeof(datestring));
- printf("\tExpires: %s", datestring);
- }
- printf("\n");
- }
- tdx_search_close(search);
- tdx_data_close(data);
- tdx_index_close(index);
-}
-
-
-/*
-** Check a string to see if its a valid number.
-*/
-static bool
-check_number(const char *string)
-{
- const char *p;
-
- for (p = string; *p != '\0'; p++)
- if (!CTYPE(isdigit, *p))
- return false;
- return true;
-}
-
-
-/*
-** Find the message ID in the group overview data and return a copy of it.
-** Caller is responsible for freeing.
-*/
-static char *
-extract_messageid(const char *overview)
-{
- const char *p, *end;
- int count;
-
- for (p = overview, count = 0; count < 4; count++) {
- p = strchr(p + 1, '\t');
- if (p == NULL)
- return NULL;
- }
- p++;
- end = strchr(p, '\t');
- if (end == NULL)
- return NULL;
- return xstrndup(p, end - p);
-}
-
-
-/*
-** Compare two file names assuming they're numbers, used to sort the list of
-** articles numerically. Suitable for use as a comparison function for
-** qsort.
-*/
-static int
-file_compare(const void *p1, const void *p2)
-{
- const char *file1 = *((const char * const *) p1);
- const char *file2 = *((const char * const *) p2);
- ARTNUM n1, n2;
-
- n1 = strtoul(file1, NULL, 10);
- n2 = strtoul(file2, NULL, 10);
- if (n1 > n2)
- return 1;
- else if (n1 < n2)
- return -1;
- else
- return 0;
-}
-
-
-/*
-** Get a list of articles in a directory, sorted by article number.
-*/
-static struct vector *
-article_list(const char *directory)
-{
- DIR *articles;
- struct dirent *file;
- struct vector *list;
-
- list = vector_new();
- articles = opendir(directory);
- if (articles == NULL)
- sysdie("cannot open directory %s", directory);
- while ((file = readdir(articles)) != NULL) {
- if (!check_number(file->d_name))
- continue;
- vector_add(list, file->d_name);
- }
- closedir(articles);
-
- qsort(list->strings, list->count, sizeof(list->strings[0]), file_compare);
- return list;
-}
-
-
-/*
-** Rebuild the overview data for a particular group. Takes a path to a
-** directory containing all the articles, as individual files, that should be
-** in that group. The names of the files should be the article numbers in
-** the group.
-*/
-static void
-group_rebuild(const char *group, const char *path)
-{
- char *filename, *histpath, *article, *wireformat, *p;
- size_t size, file;
- int flags, length;
- struct buffer *overview = NULL;
- struct vector *extra, *files;
- struct history *history;
- struct group_index *index;
- struct group_data *data;
- struct group_entry *entry, info;
- struct article artdata;
- struct stat st;
-
- index = tdx_index_open(OV_READ);
- if (index == NULL)
- die("cannot open group index");
- entry = tdx_index_entry(index, group);
- if (entry == NULL) {
- if (!tdx_index_add(index, group, 1, 0, "y"))
- die("cannot create group %s", group);
- entry = tdx_index_entry(index, group);
- if (entry == NULL)
- die("cannot find group %s", group);
- }
- info = *entry;
- data = tdx_data_rebuild_start(group);
- if (data == NULL)
- die("cannot start data rebuild for %s", group);
- if (!tdx_index_rebuild_start(index, entry))
- die("cannot start index rebuild for %s", group);
-
- histpath = concatpath(innconf->pathdb, _PATH_HISTORY);
- flags = HIS_RDONLY | HIS_ONDISK;
- history = HISopen(histpath, innconf->hismethod, flags);
- if (history == NULL)
- sysdie("cannot open history %s", histpath);
- free(histpath);
-
- extra = overview_extra_fields();
- files = article_list(path);
-
- info.count = 0;
- info.high = 0;
- info.low = 0;
- for (file = 0; file < files->count; file++) {
- filename = concatpath(path, files->strings[file]);
- article = ReadInFile(filename, &st);
- size = st.st_size;
- if (article == NULL) {
- syswarn("cannot read in %s", filename);
- free(filename);
- continue;
- }
-
- /* Check to see if the article is not in wire format. If it isn't,
- convert it. We only check the first line ending. */
- p = strchr(article, '\n');
- if (p != NULL && (p == article || p[-1] != '\r')) {
- wireformat = ToWireFmt(article, size, (size_t *)&length);
- free(article);
- article = wireformat;
- size = length;
- }
-
- artdata.number = strtoul(files->strings[file], NULL, 10);
- if (artdata.number > info.high)
- info.high = artdata.number;
- if (artdata.number < info.low || info.low == 0)
- info.low = artdata.number;
- info.count++;
- overview = overview_build(artdata.number, article, size, extra,
- overview);
- artdata.overview = overview->data;
- artdata.overlen = overview->left;
- p = extract_messageid(overview->data);
- if (p == NULL) {
- warn("cannot find message ID in %s", filename);
- free(filename);
- free(article);
- continue;
- }
- if (HISlookup(history, p, &artdata.arrived, NULL, &artdata.expires,
- &artdata.token)) {
- if (!tdx_data_store(data, &artdata))
- warn("cannot store data for %s", filename);
- } else {
- warn("cannot find article %s in history", p);
- }
- free(p);
- free(filename);
- free(article);
- }
- vector_free(files);
- vector_free(extra);
-
- info.indexinode = data->indexinode;
- info.base = data->base;
- if (!tdx_index_rebuild_finish(index, entry, &info))
- die("cannot update group index for %s", group);
- if (!tdx_data_rebuild_finish(group))
- die("cannot finish rebuilding data for group %s", group);
- tdx_data_close(data);
- HISclose(history);
-}
-
-
-/*
-** Change to the news user if possible, and if not, die. Used for operations
-** that may change the overview files so as not to mess up the ownership.
-*/
-static void
-setuid_news(void)
-{
- struct passwd *pwd;
-
- pwd = getpwnam(NEWSUSER);
- if (pwd == NULL)
- die("can't resolve %s to a UID (account doesn't exist?)", NEWSUSER);
- if (getuid() == 0)
- setuid(pwd->pw_uid);
- if (getuid() != pwd->pw_uid)
- die("must be run as %s", NEWSUSER);
-}
-
-
-/*
-** Main routine. Load inn.conf, parse the arguments, and dispatch to the
-** appropriate function.
-*/
-int
-main(int argc, char *argv[])
-{
- int option;
- char mode = '\0';
- const char *newsgroup = NULL;
- const char *path = NULL;
- ARTNUM article = 0;
-
- message_program_name = "tdx-util";
-
- if (!innconf_read(NULL))
- exit(1);
-
- /* Parse options. */
- opterr = 0;
- while ((option = getopt(argc, argv, "a:n:p:AFR:gio")) != EOF) {
- switch (option) {
- case 'a':
- article = strtoul(optarg, NULL, 10);
- if (article == 0)
- die("invalid article number %s", optarg);
- break;
- case 'n':
- newsgroup = optarg;
- break;
- case 'p':
- innconf->pathoverview = xstrdup(optarg);
- break;
- case 'A':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'A';
- break;
- case 'F':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'F';
- break;
- case 'R':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'R';
- path = optarg;
- break;
- case 'g':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'g';
- break;
- case 'i':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'i';
- break;
- case 'o':
- if (mode != '\0')
- die("only one mode option allowed");
- mode = 'o';
- break;
- default:
- die("invalid option %c", optopt);
- break;
- }
- }
-
- /* Modes g and o require a group be specified. */
- if ((mode == 'g' || mode == 'o' || mode == 'R') && newsgroup == NULL)
- die("group must be specified for -%c", mode);
-
- /* Run the specified function. */
- switch (mode) {
- case 'A':
- tdx_index_audit(false);
- break;
- case 'F':
- setuid_news();
- tdx_index_audit(true);
- break;
- case 'R':
- setuid_news();
- group_rebuild(newsgroup, path);
- break;
- case 'i':
- dump_index(newsgroup);
- break;
- case 'g':
- dump_group_index(newsgroup);
- break;
- case 'o':
- dump_overview(newsgroup, article);
- break;
- default:
- die("a mode option must be specified");
- break;
- }
- exit(0);
-}
+++ /dev/null
-/* $Id: tradindexed.c 7138 2005-03-16 18:15:51Z hkehoe $
-**
-** Interface implementation for the tradindexed overview method.
-**
-** This code converts between the internal interface used by the tradindexed
-** implementation and the interface expected by the INN overview API. The
-** internal interface is in some cases better suited to the data structures
-** that the tradindexed overview method uses, and this way the internal
-** interface can be kept isolated from the external interface. (There are
-** also some operations that can be performed entirely in the interface
-** layer.)
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "ov.h"
-#include "storage.h"
-#include "tdx-private.h"
-#include "tdx-structure.h"
-#include "tradindexed.h"
-
-/* This structure holds all of the data about the open overview files. We can
- eventually pass one of these structures back to the caller of open when the
- overview API is more object-oriented. */
-struct tradindexed {
- struct group_index *index;
- struct cache *cache;
- bool cutoff;
-};
-
-/* Global data about the open tradindexed method. */
-static struct tradindexed *tradindexed;
-
-
-/*
-** Helper function to open a group_data structure via the cache, inserting it
-** into the cache if it wasn't found in the cache.
-*/
-static struct group_data *
-data_cache_open(struct tradindexed *global, const char *group,
- struct group_entry *entry)
-{
- struct group_data *data;
-
- data = tdx_cache_lookup(global->cache, entry->hash);
- if (data == NULL) {
- data = tdx_data_open(global->index, group, entry);
- if (data == NULL)
- return NULL;
- tdx_cache_insert(global->cache, entry->hash, data);
- }
- return data;
-}
-
-
-/*
-** Helper function to reopen the data files and remove the old entry from the
-** cache if we think that might help better fulfill a search.
-*/
-static struct group_data *
-data_cache_reopen(struct tradindexed *global, const char *group,
- struct group_entry *entry)
-{
- struct group_data *data;
-
- tdx_cache_delete(global->cache, entry->hash);
- data = tdx_data_open(global->index, group, entry);
- if (data == NULL)
- return NULL;
- tdx_cache_insert(global->cache, entry->hash, data);
- return data;
-}
-
-
-/*
-** Open the overview method.
-*/
-bool
-tradindexed_open(int mode)
-{
- unsigned int cache_size, fdlimit;
-
- if (tradindexed != NULL) {
- warn("tradindexed: overview method already open");
- return false;
- }
- tradindexed = xmalloc(sizeof(struct tradindexed));
- tradindexed->index = tdx_index_open((mode & OV_WRITE) ? true : false);
- tradindexed->cutoff = false;
-
- /* Use a cache size of two for read-only connections. We may want to
- rethink the limitation of the cache for reading later based on
- real-world experience. */
- cache_size = (mode & OV_WRITE) ? innconf->overcachesize : 1;
- fdlimit = getfdlimit();
- if (fdlimit > 0 && fdlimit < cache_size * 2) {
- warn("tradindexed: not enough file descriptors for an overview cache"
- " size of %u; increase rlimitnofile or decrease overcachesize"
- " to at most %u", cache_size, fdlimit / 2);
- cache_size = (fdlimit > 2) ? fdlimit / 2 : 1;
- }
- tradindexed->cache = tdx_cache_create(cache_size);
-
- return (tradindexed->index == NULL) ? false : true;
-}
-
-
-/*
-** Get statistics about a group. Convert between the multiple pointer API
-** and the structure API used internally.
-*/
-bool
-tradindexed_groupstats(char *group, int *low, int *high, int *count,
- int *flag)
-{
- const struct group_entry *entry;
-
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
- entry = tdx_index_entry(tradindexed->index, group);
- if (entry == NULL)
- return false;
- if (low != NULL)
- *low = entry->low;
- if (high != NULL)
- *high = entry->high;
- if (count != NULL)
- *count = entry->count;
- if (flag != NULL)
- *flag = entry->flag;
- return true;
-}
-
-
-/*
-** Add a new newsgroup to the index.
-*/
-bool
-tradindexed_groupadd(char *group, ARTNUM low, ARTNUM high, char *flag)
-{
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
- return tdx_index_add(tradindexed->index, group, low, high, flag);
-}
-
-
-/*
-** Delete a newsgroup from the index.
-*/
-bool
-tradindexed_groupdel(char *group)
-{
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
- return tdx_index_delete(tradindexed->index, group);
-}
-
-
-/*
-** Add data about a single article. Convert between the multiple argument
-** API and the structure API used internally, and also implement low article
-** cutoff if that was requested.
-*/
-bool
-tradindexed_add(char *group, ARTNUM artnum, TOKEN token, char *data,
- int length, time_t arrived, time_t expires)
-{
- struct article article;
- struct group_data *group_data;
- struct group_entry *entry;
-
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
-
- /* Get the group index entry and don't do any work if cutoff is set and
- the article number is lower than the low water mark for the group. */
- entry = tdx_index_entry(tradindexed->index, group);
- if (entry == NULL)
- return true;
- if (tradindexed->cutoff && entry->low > artnum)
- return true;
-
- /* Fill out the article data structure. */
- article.number = artnum;
- article.overview = data;
- article.overlen = length;
- article.token = token;
- article.arrived = arrived;
- article.expires = expires;
-
- /* Open the appropriate data structures, using the cache. */
- group_data = data_cache_open(tradindexed, group, entry);
- if (group_data == NULL)
- return false;
- return tdx_data_add(tradindexed->index, entry, group_data, &article);
-}
-
-
-/*
-** Cancel an article. At present, tradindexed can't do anything with this
-** information because we lack a mapping from the token to newsgroup names
-** and article numbers, so we just silently return true and let expiration
-** take care of this.
-*/
-bool
-tradindexed_cancel(TOKEN token UNUSED)
-{
- return true;
-}
-
-
-/*
-** Open an overview search. Open the appropriate group and then start a
-** search in it.
-*/
-void *
-tradindexed_opensearch(char *group, int low, int high)
-{
- struct group_entry *entry;
- struct group_data *data;
-
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return NULL;
- }
- entry = tdx_index_entry(tradindexed->index, group);
- if (entry == NULL)
- return NULL;
- data = data_cache_open(tradindexed, group, entry);
- if (data == NULL)
- return NULL;
- if (entry->base != data->base)
- if (data->base > (ARTNUM) low && entry->base < data->base) {
- data = data_cache_reopen(tradindexed, group, entry);
- if (data == NULL)
- return NULL;
- }
- return tdx_search_open(data, low, high, entry->high);
-}
-
-
-/*
-** Get the next article returned by a search. Convert between the multiple
-** pointer API and the structure API we use internally.
-*/
-bool
-tradindexed_search(void *handle, ARTNUM *artnum, char **data, int *length,
- TOKEN *token, time_t *arrived)
-{
- struct article article;
-
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
- if (!tdx_search(handle, &article))
- return false;
- if (artnum != NULL)
- *artnum = article.number;
- if (data != NULL)
- *data = (char *) article.overview;
- if (length != NULL)
- *length = article.overlen;
- if (token != NULL)
- *token = article.token;
- if (arrived != NULL)
- *arrived = article.arrived;
- return true;
-}
-
-
-/*
-** Close an overview search.
-*/
-void
-tradindexed_closesearch(void *handle)
-{
- tdx_search_close(handle);
-}
-
-
-/*
-** Get information for a single article. Open the appropriate group and then
-** convert from the pointer API to the struct API used internally.
-*/
-bool
-tradindexed_getartinfo(char *group, ARTNUM artnum, TOKEN *token)
-{
- struct group_entry *entry;
- struct group_data *data;
- const struct index_entry *index_entry;
-
- if (tradindexed == NULL || tradindexed->index == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
- entry = tdx_index_entry(tradindexed->index, group);
- if (entry == NULL)
- return false;
- data = data_cache_open(tradindexed, group, entry);
- if (data == NULL)
- return false;
- if (entry->base != data->base)
- if (data->base > artnum && entry->base <= artnum) {
- data = data_cache_reopen(tradindexed, group, entry);
- if (data == NULL)
- return false;
- }
- index_entry = tdx_article_entry(data, artnum, entry->high);
- if (index_entry == NULL)
- return false;
- if (token != NULL)
- *token = index_entry->token;
- return true;
-}
-
-
-/*
-** Expire a single newsgroup.
-*/
-bool
-tradindexed_expiregroup(char *group, int *low, struct history *history)
-{
- ARTNUM new_low;
- bool status;
-
- /* tradindexed doesn't have any periodic cleanup. */
- if (group == NULL)
- return true;
-
- status = tdx_expire(group, &new_low, history);
- if (status && low != NULL)
- *low = (int) new_low;
- return status;
-}
-
-
-/*
-** Set various options or query various paramaters for the overview method.
-** The interface is, at present, not particularly sane.
-*/
-bool
-tradindexed_ctl(OVCTLTYPE type, void *val)
-{
- int *i;
- bool *b;
- OVSORTTYPE *sort;
-
- if (tradindexed == NULL) {
- warn("tradindexed: overview method not initialized");
- return false;
- }
-
- switch (type) {
- case OVSPACE:
- i = (int *) val;
- *i = -1;
- return true;
- case OVSORT:
- sort = (OVSORTTYPE *) val;
- *sort = OVNEWSGROUP;
- return true;
- case OVCUTOFFLOW:
- b = (bool *) val;
- tradindexed->cutoff = *b;
- return true;
- case OVSTATICSEARCH:
- i = (int *) val;
- *i = false;
- return true;
- case OVCACHEKEEP:
- case OVCACHEFREE:
- b = (bool *) val;
- *b = false;
- return true;
- default:
- return false;
- }
-}
-
-
-/*
-** Close the overview method.
-*/
-void
-tradindexed_close(void)
-{
- if (tradindexed != NULL) {
- if (tradindexed->index != NULL)
- tdx_index_close(tradindexed->index);
- if (tradindexed->cache != NULL)
- tdx_cache_free(tradindexed->cache);
- free(tradindexed);
- tradindexed = NULL;
- }
-}
+++ /dev/null
-/* $Id: tradindexed.h 5324 2002-03-15 21:09:33Z rra $
-**
-** Public interface for the tradindexed overview method.
-**
-** The exact API specified here must match the expectations of the overview
-** API. Any changes here have to be made to all the overview methods at the
-** same time.
-*/
-
-#ifndef TRADINDEXED_H
-#define TRADINDEXED_H 1
-
-#include "config.h"
-#include <sys/types.h>
-
-#include "ov.h"
-#include "storage.h"
-
-BEGIN_DECLS
-
-bool tradindexed_open(int mode);
-bool tradindexed_groupstats(char *group, int *low, int *high, int *count,
- int *flag);
-bool tradindexed_groupadd(char *group, ARTNUM low, ARTNUM high, char *flag);
-bool tradindexed_groupdel(char *group);
-bool tradindexed_add(char *group, ARTNUM artnum, TOKEN token, char *data,
- int length, time_t arrived, time_t expires);
-bool tradindexed_cancel(TOKEN token);
-void *tradindexed_opensearch(char *group, int low, int high);
-bool tradindexed_search(void *handle, ARTNUM *artnum, char **data,
- int *length, TOKEN *token, time_t *arrived);
-void tradindexed_closesearch(void *handle);
-bool tradindexed_getartinfo(char *group, ARTNUM artnum, TOKEN *token);
-bool tradindexed_expiregroup(char *group, int *low, struct history *);
-bool tradindexed_ctl(OVCTLTYPE type, void *val);
-void tradindexed_close(void);
-
-END_DECLS
-
-#endif /* TRADINDEXED_H */
+++ /dev/null
-This storage manager attempts to implement the 'traditional' INN storage
-layout, i.e a message crossposted to alt.fan.james-brister and rec.pets.wombats
-will be written as a file in
- <patharticles>/alt/fan/james-brister/nnnnn
-and a symlink pointing to the above file in
- <patharticles>/rec/pets/wombats/mmmmmm
-where nnnnn and mmmmmm are the article numbers that article has in each of
-those two newsgroups. (Actually in the traditional spool form the link
-could be either a symlink or a regular link).
-
-The storage token data for a tradspool stored article is a 16-byte block.
-The storage token contains two ints; the first one is a number
-telling what the name of the "primary" newsgroup is for this article, the
-second one telling what article number the article has in that newsgroup.
-The mapping between newsgroup name and number is given by a database in
-the file
- <pathspool>/ts.ng.db
-; this file is a straight ASCII file listing newsgroup names and
-numbers, and will be automatically generated by innd if one does not
-exist already. This database is read in automatically by any program
-that uses this storage manager module, and is updated by innd whenever
-a new newsgroup is encountered. Other programs (like innfeed) check
-the mod time of that database every 5 minutes to see if they need to
-recheck it for any new newsgroups that might have been added. Should
-the database become corrupted, simply shutting down news, removing the
-database, and doing a makehistory will recreate the database. It
-should, in principle, be possible to write a perl script to recreate
-just the database from just the spool files and history files without
-doing a full makehistory.
-
-Currently the storage manager code works, although not perhaps as fast
-as it could. The expiration code is somewhat unwieldy; since the storage
-token does not have enough space to hold all the newsgroups an article
-is posted to, when expiration is done SMCancel() has to open the article
-to find out what other newsgroups the article is posted to. Eurggh.
-Suggestions for a better scheme are welcome.
-
-Other problems of note: the storage manager code has no way to get to the
-'DoLinks' (-L) flag setting of innd, so currently you can't use the
-"crosspost" program with tradspool. I guess the proper thing to do would be
-to make DoLinks a config option in storage.conf instead, but I haven't
-done that yet.
-
+++ /dev/null
-name = tradspool
-number = 5
-sources = tradspool.c
+++ /dev/null
-/* $Id: tradspool.c 7412 2005-10-09 03:44:35Z eagle $
-**
-** Storage manager module for traditional spool format.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/mmap.h"
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <time.h>
-
-/* Needed for htonl() and friends on AIX 4.1. */
-#include <netinet/in.h>
-
-#include "inn/innconf.h"
-#include "inn/qio.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "paths.h"
-
-#include "methods.h"
-#include "tradspool.h"
-
-typedef struct {
- char *artbase; /* start of the article data -- may be mmaped */
- unsigned int artlen; /* art length. */
- int nextindex;
- char *curdirname;
- DIR *curdir;
- struct _ngtent *ngtp;
- bool mmapped;
-} PRIV_TRADSPOOL;
-
-/*
-** The 64-bit hashed representation of a ng name that gets stashed in each token.
-*/
-
-#define HASHEDNGLEN 8
-typedef struct {
- char hash[HASHEDNGLEN];
-} HASHEDNG;
-
-/*
-** We have two structures here for facilitating newsgroup name->number mapping
-** and number->name mapping. NGTable is a hash table based on hashing the
-** newsgroup name, and is used to give the name->number mapping. NGTree is
-** a binary tree, indexed by newsgroup number, used for the number->name
-** mapping.
-*/
-
-#define NGT_SIZE 2048
-
-typedef struct _ngtent {
- char *ngname;
-/* HASHEDNG hash; XXX */
- unsigned long ngnumber;
- struct _ngtent *next;
- struct _ngtreenode *node;
-} NGTENT;
-
-typedef struct _ngtreenode {
- unsigned long ngnumber;
- struct _ngtreenode *left, *right;
- NGTENT *ngtp;
-} NGTREENODE;
-
-NGTENT *NGTable[NGT_SIZE];
-unsigned long MaxNgNumber = 0;
-NGTREENODE *NGTree;
-
-bool NGTableUpdated; /* set to true if we've added any entries since reading
- in the database file */
-
-/*
-** Convert all .s to /s in a newsgroup name. Modifies the passed string
-** inplace.
-*/
-static void
-DeDotify(char *ngname) {
- char *p = ngname;
-
- for ( ; *p ; ++p) {
- if (*p == '.') *p = '/';
- }
- return;
-}
-
-/*
-** Hash a newsgroup name to an 8-byte. Basically, we convert all .s to
-** /s (so it doesn't matter if we're passed the spooldir name or newsgroup
-** name) and then call Hash to MD5 the mess, then take 4 bytes worth of
-** data from the front of the hash. This should be good enough for our
-** purposes.
-*/
-
-static HASHEDNG
-HashNGName(char *ng) {
- HASH hash;
- HASHEDNG return_hash;
- char *p;
-
- p = xstrdup(ng);
- DeDotify(p);
- hash = Hash(p, strlen(p));
- free(p);
-
- memcpy(return_hash.hash, hash.hash, HASHEDNGLEN);
-
- return return_hash;
-}
-
-#if 0 /* XXX */
-/* compare two hashes */
-static int
-CompareHash(HASHEDNG *h1, HASHEDNG *h2) {
- int i;
- for (i = 0 ; i < HASHEDNGLEN ; ++i) {
- if (h1->hash[i] != h2->hash[i]) {
- return h1->hash[i] - h2->hash[i];
- }
- }
- return 0;
-}
-#endif
-
-/* Add a new newsgroup name to the NG table. */
-static void
-AddNG(char *ng, unsigned long number) {
- char *p;
- unsigned int h;
- HASHEDNG hash;
- NGTENT *ngtp, **ngtpp;
- NGTREENODE *newnode, *curnode, **nextnode;
-
- p = xstrdup(ng);
- DeDotify(p); /* canonicalize p to standard (/) form. */
- hash = HashNGName(p);
-
- h = (unsigned char)hash.hash[0];
- h = h + (((unsigned char)hash.hash[1])<<8);
-
- h = h % NGT_SIZE;
-
- ngtp = NGTable[h];
- ngtpp = &NGTable[h];
- while (true) {
- if (ngtp == NULL) {
- /* ng wasn't in table, add new entry. */
- NGTableUpdated = true;
-
- ngtp = xmalloc(sizeof(NGTENT));
- ngtp->ngname = p; /* note: we store canonicalized name */
- /* ngtp->hash = hash XXX */
- ngtp->next = NULL;
-
- /* assign a new NG number if needed (not given) */
- if (number == 0) {
- number = ++MaxNgNumber;
- }
- ngtp->ngnumber = number;
-
- /* link new table entry into the hash table chain. */
- *ngtpp = ngtp;
-
- /* Now insert an appropriate record into the binary tree */
- newnode = xmalloc(sizeof(NGTREENODE));
- newnode->left = newnode->right = (NGTREENODE *) NULL;
- newnode->ngnumber = number;
- newnode->ngtp = ngtp;
- ngtp->node = newnode;
-
- if (NGTree == NULL) {
- /* tree was empty, so put our one element in and return */
- NGTree = newnode;
- return;
- } else {
- nextnode = &NGTree;
- while (*nextnode) {
- curnode = *nextnode;
- if (curnode->ngnumber < number) {
- nextnode = &curnode->right;
- } else if (curnode->ngnumber > number) {
- nextnode = &curnode->left;
- } else {
- /* Error, same number is already in NGtree (shouldn't happen!) */
- syslog(L_ERROR, "tradspool: AddNG: duplicate newsgroup number in NGtree: %ld(%s)", number, p);
- return;
- }
- }
- *nextnode = newnode;
- return;
- }
- } else if (strcmp(ngtp->ngname, p) == 0) {
- /* entry in table already, so return */
- free(p);
- return;
-#if 0 /* XXX */
- } else if (CompareHash(&ngtp->hash, &hash) == 0) {
- /* eep! we hit a hash collision. */
- syslog(L_ERROR, "tradspool: AddNG: Hash collison %s/%s", ngtp->ngname, p);
- free(p);
- return;
-#endif
- } else {
- /* not found yet, so advance to next entry in chain */
- ngtpp = &(ngtp->next);
- ngtp = ngtp->next;
- }
- }
-}
-
-/* find a newsgroup table entry, given only the name. */
-static NGTENT *
-FindNGByName(char *ngname) {
- NGTENT *ngtp;
- unsigned int h;
- HASHEDNG hash;
- char *p;
-
- p = xstrdup(ngname);
- DeDotify(p); /* canonicalize p to standard (/) form. */
- hash = HashNGName(p);
-
- h = (unsigned char)hash.hash[0];
- h = h + (((unsigned char)hash.hash[1])<<8);
-
- h = h % NGT_SIZE;
-
- ngtp = NGTable[h];
-
- while (ngtp) {
- if (strcmp(p, ngtp->ngname) == 0) {
- free(p);
- return ngtp;
- }
- ngtp = ngtp->next;
- }
- free(p);
- return NULL;
-}
-
-/* find a newsgroup/spooldir name, given only the newsgroup number */
-static char *
-FindNGByNum(unsigned long ngnumber) {
- NGTENT *ngtp;
- NGTREENODE *curnode;
-
- curnode = NGTree;
-
- while (curnode) {
- if (curnode->ngnumber == ngnumber) {
- ngtp = curnode->ngtp;
- return ngtp->ngname;
- }
- if (curnode->ngnumber < ngnumber) {
- curnode = curnode->right;
- } else {
- curnode = curnode->left;
- }
- }
- /* not in tree, return NULL */
- return NULL;
-}
-
-#define _PATH_TRADSPOOLNGDB "tradspool.map"
-#define _PATH_NEWTSNGDB "tradspool.map.new"
-
-
-/* dump DB to file. */
-static void
-DumpDB(void)
-{
- char *fname, *fnamenew;
- NGTENT *ngtp;
- unsigned int i;
- FILE *out;
-
- if (!SMopenmode) return; /* don't write if we're not in read/write mode. */
- if (!NGTableUpdated) return; /* no need to dump new DB */
-
- fname = concatpath(innconf->pathspool, _PATH_TRADSPOOLNGDB);
- fnamenew = concatpath(innconf->pathspool, _PATH_NEWTSNGDB);
-
- if ((out = fopen(fnamenew, "w")) == NULL) {
- syslog(L_ERROR, "tradspool: DumpDB: can't write %s: %m", fnamenew);
- free(fname);
- free(fnamenew);
- return;
- }
- for (i = 0 ; i < NGT_SIZE ; ++i) {
- ngtp = NGTable[i];
- for ( ; ngtp ; ngtp = ngtp->next) {
- fprintf(out, "%s %lu\n", ngtp->ngname, ngtp->ngnumber);
- }
- }
- if (fclose(out) < 0) {
- syslog(L_ERROR, "tradspool: DumpDB: can't close %s: %m", fnamenew);
- free(fname);
- free(fnamenew);
- return;
- }
- if (rename(fnamenew, fname) < 0) {
- syslog(L_ERROR, "tradspool: can't rename %s", fnamenew);
- free(fname);
- free(fnamenew);
- return;
- }
- free(fname);
- free(fnamenew);
- NGTableUpdated = false; /* reset modification flag. */
- return;
-}
-
-/*
-** init NGTable from saved database file and from active. Note that
-** entries in the database file get added first, and get their specifications
-** of newsgroup number from there.
-*/
-
-static bool
-ReadDBFile(void)
-{
- char *fname;
- QIOSTATE *qp;
- char *line;
- char *p;
- unsigned long number;
-
- fname = concatpath(innconf->pathspool, _PATH_TRADSPOOLNGDB);
- if ((qp = QIOopen(fname)) == NULL) {
- /* only warn if db not found. */
- syslog(L_NOTICE, "tradspool: %s not found", fname);
- } else {
- while ((line = QIOread(qp)) != NULL) {
- p = strchr(line, ' ');
- if (p == NULL) {
- syslog(L_FATAL, "tradspool: corrupt line in active %s", line);
- QIOclose(qp);
- free(fname);
- return false;
- }
- *p++ = 0;
- number = atol(p);
- AddNG(line, number);
- if (MaxNgNumber < number) MaxNgNumber = number;
- }
- QIOclose(qp);
- }
- free(fname);
- return true;
-}
-
-static bool
-ReadActiveFile(void)
-{
- char *fname;
- QIOSTATE *qp;
- char *line;
- char *p;
-
- fname = concatpath(innconf->pathdb, _PATH_ACTIVE);
- if ((qp = QIOopen(fname)) == NULL) {
- syslog(L_FATAL, "tradspool: can't open %s", fname);
- free(fname);
- return false;
- }
-
- while ((line = QIOread(qp)) != NULL) {
- p = strchr(line, ' ');
- if (p == NULL) {
- syslog(L_FATAL, "tradspool: corrupt line in active %s", line);
- QIOclose(qp);
- free(fname);
- return false;
- }
- *p = 0;
- AddNG(line, 0);
- }
- QIOclose(qp);
- free(fname);
- /* dump any newly added changes to database */
- DumpDB();
- return true;
-}
-
-static bool
-InitNGTable(void)
-{
- if (!ReadDBFile()) return false;
-
- /*
- ** set NGTableUpdated to false; that way we know if the load of active or
- ** any AddNGs later on did in fact add new entries to the db.
- */
- NGTableUpdated = false;
- if (!SMopenmode)
- /* don't read active unless write mode. */
- return true;
- return ReadActiveFile();
-}
-
-/*
-** Routine called to check every so often to see if we need to reload the
-** database and add in any new groups that have been added. This is primarily
-** for the benefit of innfeed in funnel mode, which otherwise would never
-** get word that any new newsgroups had been added.
-*/
-
-#define RELOAD_TIME_CHECK 600
-
-static void
-CheckNeedReloadDB(bool force)
-{
- static TIMEINFO lastcheck, oldlastcheck, now;
- struct stat sb;
- char *fname;
-
- if (GetTimeInfo(&now) < 0) return; /* anyone ever seen gettimeofday fail? :-) */
- if (!force && lastcheck.time + RELOAD_TIME_CHECK > now.time) return;
-
- oldlastcheck = lastcheck;
- lastcheck = now;
-
- fname = concatpath(innconf->pathspool, _PATH_TRADSPOOLNGDB);
- if (stat(fname, &sb) < 0) {
- free(fname);
- return;
- }
- free(fname);
- if (sb.st_mtime > oldlastcheck.time) {
- /* add any newly added ngs to our in-memory copy of the db. */
- ReadDBFile();
- }
-}
-
-/* Init routine, called by SMinit */
-
-bool
-tradspool_init(SMATTRIBUTE *attr) {
- if (attr == NULL) {
- syslog(L_ERROR, "tradspool: attr is NULL");
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- if (!innconf->storeonxref) {
- syslog(L_ERROR, "tradspool: storeonxref needs to be true");
- SMseterror(SMERR_INTERNAL, "storeonxref needs to be true");
- return false;
- }
- attr->selfexpire = false;
- attr->expensivestat = true;
- return InitNGTable();
-}
-
-/* Make a token for an article given the primary newsgroup name and article # */
-static TOKEN
-MakeToken(char *ng, unsigned long artnum, STORAGECLASS class) {
- TOKEN token;
- NGTENT *ngtp;
- unsigned long num;
-
- memset(&token, '\0', sizeof(token));
-
- token.type = TOKEN_TRADSPOOL;
- token.class = class;
-
- /*
- ** if not already in the NG Table, be sure to add this ng! This way we
- ** catch things like newsgroups added since startup.
- */
- if ((ngtp = FindNGByName(ng)) == NULL) {
- AddNG(ng, 0);
- DumpDB(); /* flush to disk so other programs can see the change */
- ngtp = FindNGByName(ng);
- }
-
- num = ngtp->ngnumber;
- num = htonl(num);
-
- memcpy(token.token, &num, sizeof(num));
- artnum = htonl(artnum);
- memcpy(&token.token[sizeof(num)], &artnum, sizeof(artnum));
- return token;
-}
-
-/*
-** Convert a token back to a pathname.
-*/
-static char *
-TokenToPath(TOKEN token) {
- unsigned long ngnum;
- unsigned long artnum;
- char *ng, *path;
- size_t length;
-
- CheckNeedReloadDB(false);
-
- memcpy(&ngnum, &token.token[0], sizeof(ngnum));
- memcpy(&artnum, &token.token[sizeof(ngnum)], sizeof(artnum));
- artnum = ntohl(artnum);
- ngnum = ntohl(ngnum);
-
- ng = FindNGByNum(ngnum);
- if (ng == NULL) {
- CheckNeedReloadDB(true);
- ng = FindNGByNum(ngnum);
- if (ng == NULL)
- return NULL;
- }
-
- length = strlen(ng) + 20 + strlen(innconf->patharticles);
- path = xmalloc(length);
- snprintf(path, length, "%s/%s/%lu", innconf->patharticles, ng, artnum);
- return path;
-}
-
-/*
-** Crack an Xref line apart into separate strings, each of the form "ng:artnum".
-** Return in "num" the number of newsgroups found.
-*/
-static char **
-CrackXref(char *xref, unsigned int *lenp) {
- char *p;
- char **xrefs;
- char *q;
- unsigned int len, xrefsize;
-
- len = 0;
- xrefsize = 5;
- xrefs = xmalloc(xrefsize * sizeof(char *));
-
- /* no path element should exist, nor heading white spaces exist */
- p = xref;
- while (true) {
- /* check for EOL */
- /* shouldn't ever hit null w/o hitting a \r\n first, but best to be paranoid */
- if (*p == '\n' || *p == '\r' || *p == 0) {
- /* hit EOL, return. */
- *lenp = len;
- return xrefs;
- }
- /* skip to next space or EOL */
- for (q=p; *q && *q != ' ' && *q != '\n' && *q != '\r' ; ++q) ;
-
- xrefs[len] = xstrndup(p, q - p);
-
- if (++len == xrefsize) {
- /* grow xrefs if needed. */
- xrefsize *= 2;
- xrefs = xrealloc(xrefs, xrefsize * sizeof(char *));
- }
-
- p = q;
- /* skip spaces */
- for ( ; *p == ' ' ; p++) ;
- }
-}
-
-TOKEN
-tradspool_store(const ARTHANDLE article, const STORAGECLASS class) {
- char **xrefs;
- char *xrefhdr;
- TOKEN token;
- unsigned int numxrefs;
- char *ng, *p, *onebuffer;
- unsigned long artnum;
- char *path, *linkpath, *dirname;
- int fd;
- size_t used;
- char *nonwfarticle; /* copy of article converted to non-wire format */
- unsigned int i;
- size_t length, nonwflen;
-
- xrefhdr = article.groups;
- if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
- token.type = TOKEN_EMPTY;
- SMseterror(SMERR_UNDEFINED, "bogus Xref: header");
- if (xrefs != NULL)
- free(xrefs);
- return token;
- }
-
- if ((p = strchr(xrefs[0], ':')) == NULL) {
- token.type = TOKEN_EMPTY;
- SMseterror(SMERR_UNDEFINED, "bogus Xref: header");
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- }
- *p++ = '\0';
- ng = xrefs[0];
- DeDotify(ng);
- artnum = atol(p);
-
- token = MakeToken(ng, artnum, class);
-
- length = strlen(innconf->patharticles) + strlen(ng) + 32;
- path = xmalloc(length);
- snprintf(path, length, "%s/%s/%lu", innconf->patharticles, ng, artnum);
-
- /* following chunk of code boldly stolen from timehash.c :-) */
- if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, ARTFILE_MODE)) < 0) {
- p = strrchr(path, '/');
- *p = '\0';
- if (!MakeDirectory(path, true)) {
- syslog(L_ERROR, "tradspool: could not make directory %s %m", path);
- token.type = TOKEN_EMPTY;
- free(path);
- SMseterror(SMERR_UNDEFINED, NULL);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- } else {
- *p = '/';
- if ((fd = open(path, O_CREAT|O_EXCL|O_WRONLY, ARTFILE_MODE)) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not open %s %m", path);
- token.type = TOKEN_EMPTY;
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- }
- }
- }
- if (innconf->wireformat) {
- if (xwritev(fd, article.iov, article.iovcnt) != (ssize_t) article.len) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool error writing %s %m", path);
- close(fd);
- token.type = TOKEN_EMPTY;
- unlink(path);
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- }
- } else {
- onebuffer = xmalloc(article.len);
- for (used = i = 0 ; i < article.iovcnt ; i++) {
- memcpy(&onebuffer[used], article.iov[i].iov_base, article.iov[i].iov_len);
- used += article.iov[i].iov_len;
- }
- nonwfarticle = FromWireFmt(onebuffer, used, &nonwflen);
- free(onebuffer);
- if (write(fd, nonwfarticle, nonwflen) != (ssize_t) nonwflen) {
- free(nonwfarticle);
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool error writing %s %m", path);
- close(fd);
- token.type = TOKEN_EMPTY;
- unlink(path);
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- }
- free(nonwfarticle);
- }
- close(fd);
-
- /*
- ** blah, this is ugly. Have to make symlinks under other pathnames for
- ** backwards compatiblility purposes.
- */
-
- if (numxrefs > 1) {
- for (i = 1; i < numxrefs ; ++i) {
- if ((p = strchr(xrefs[i], ':')) == NULL) continue;
- *p++ = '\0';
- ng = xrefs[i];
- DeDotify(ng);
- artnum = atol(p);
-
- length = strlen(innconf->patharticles) + strlen(ng) + 32;
- linkpath = xmalloc(length);
- snprintf(linkpath, length, "%s/%s/%lu", innconf->patharticles,
- ng, artnum);
- if (link(path, linkpath) < 0) {
- p = strrchr(linkpath, '/');
- *p = '\0';
- dirname = xstrdup(linkpath);
- *p = '/';
- if (!MakeDirectory(dirname, true) || link(path, linkpath) < 0) {
-#if !defined(HAVE_SYMLINK)
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not link %s to %s %m", path, linkpath);
- token.type = TOKEN_EMPTY;
- free(dirname);
- free(linkpath);
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
-#else
- if (symlink(path, linkpath) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not symlink %s to %s %m", path, linkpath);
- token.type = TOKEN_EMPTY;
- free(dirname);
- free(linkpath);
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
- }
-#endif /* !defined(HAVE_SYMLINK) */
- }
- free(dirname);
- }
- free(linkpath);
- }
- }
- free(path);
- for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
- free(xrefs);
- return token;
-}
-
-static ARTHANDLE *
-OpenArticle(const char *path, RETRTYPE amount) {
- int fd;
- PRIV_TRADSPOOL *private;
- char *p;
- struct stat sb;
- ARTHANDLE *art;
- char *wfarticle;
- size_t wflen;
-
- if (amount == RETR_STAT) {
- if (access(path, R_OK) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- return NULL;
- }
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TRADSPOOL;
- art->data = NULL;
- art->len = 0;
- art->private = NULL;
- return art;
- }
-
- if ((fd = open(path, O_RDONLY)) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- return NULL;
- }
-
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TRADSPOOL;
-
- if (fstat(fd, &sb) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not fstat article: %m");
- free(art);
- close(fd);
- return NULL;
- }
-
- art->arrived = sb.st_mtime;
-
- private = xmalloc(sizeof(PRIV_TRADSPOOL));
- art->private = (void *)private;
- private->artlen = sb.st_size;
- if (innconf->articlemmap) {
- if ((private->artbase = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not mmap article: %m");
- free(art->private);
- free(art);
- close(fd);
- return NULL;
- }
- if (amount == RETR_ALL)
- madvise(private->artbase, sb.st_size, MADV_WILLNEED);
- else
- madvise(private->artbase, sb.st_size, MADV_SEQUENTIAL);
-
- /* consider coexisting both wireformatted and nonwireformatted */
- p = memchr(private->artbase, '\n', private->artlen);
- if (p == NULL || p == private->artbase) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not mmap article: %m");
- munmap(private->artbase, private->artlen);
- free(art->private);
- free(art);
- close(fd);
- return NULL;
- }
- if (p[-1] == '\r') {
- private->mmapped = true;
- } else {
- wfarticle = ToWireFmt(private->artbase, private->artlen, &wflen);
- munmap(private->artbase, private->artlen);
- private->artbase = wfarticle;
- private->artlen = wflen;
- private->mmapped = false;
- }
- } else {
- private->mmapped = false;
- private->artbase = xmalloc(private->artlen);
- if (read(fd, private->artbase, private->artlen) < 0) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not read article: %m");
- free(private->artbase);
- free(art->private);
- free(art);
- close(fd);
- return NULL;
- }
- p = memchr(private->artbase, '\n', private->artlen);
- if (p == NULL || p == private->artbase) {
- SMseterror(SMERR_UNDEFINED, NULL);
- syslog(L_ERROR, "tradspool: could not mmap article: %m");
- free(art->private);
- free(art);
- close(fd);
- return NULL;
- }
- if (p[-1] != '\r') {
- /* need to make a wireformat copy of the article */
- wfarticle = ToWireFmt(private->artbase, private->artlen, &wflen);
- free(private->artbase);
- private->artbase = wfarticle;
- private->artlen = wflen;
- }
- }
- close(fd);
-
- private->ngtp = NULL;
- private->curdir = NULL;
- private->curdirname = NULL;
- private->nextindex = -1;
-
- if (amount == RETR_ALL) {
- art->data = private->artbase;
- art->len = private->artlen;
- return art;
- }
-
- if (((p = wire_findbody(private->artbase, private->artlen)) == NULL)) {
- if (private->mmapped)
- munmap(private->artbase, private->artlen);
- else
- free(private->artbase);
- SMseterror(SMERR_NOBODY, NULL);
- free(art->private);
- free(art);
- return NULL;
- }
-
- if (amount == RETR_HEAD) {
- art->data = private->artbase;
- art->len = p - private->artbase;
- return art;
- }
-
- if (amount == RETR_BODY) {
- art->data = p;
- art->len = private->artlen - (p - private->artbase);
- return art;
- }
- SMseterror(SMERR_UNDEFINED, "Invalid retrieve request");
- if (private->mmapped)
- munmap(private->artbase, private->artlen);
- else
- free(private->artbase);
- free(art->private);
- free(art);
- return NULL;
-}
-
-
-ARTHANDLE *
-tradspool_retrieve(const TOKEN token, const RETRTYPE amount) {
- char *path;
- ARTHANDLE *art;
- static TOKEN ret_token;
-
- if (token.type != TOKEN_TRADSPOOL) {
- SMseterror(SMERR_INTERNAL, NULL);
- return NULL;
- }
-
- if ((path = TokenToPath(token)) == NULL) {
- SMseterror(SMERR_NOENT, NULL);
- return NULL;
- }
- if ((art = OpenArticle(path, amount)) != (ARTHANDLE *)NULL) {
- ret_token = token;
- art->token = &ret_token;
- }
- free(path);
- return art;
-}
-
-void
-tradspool_freearticle(ARTHANDLE *article)
-{
- PRIV_TRADSPOOL *private;
-
- if (article == NULL)
- return;
-
- if (article->private) {
- private = (PRIV_TRADSPOOL *) article->private;
- if (private->mmapped)
- munmap(private->artbase, private->artlen);
- else
- free(private->artbase);
- if (private->curdir)
- closedir(private->curdir);
- free(private->curdirname);
- free(private);
- }
- free(article);
-}
-
-bool
-tradspool_cancel(TOKEN token) {
- char **xrefs;
- char *xrefhdr;
- ARTHANDLE *article;
- unsigned int numxrefs;
- char *ng, *p;
- char *path, *linkpath;
- unsigned int i;
- bool result = true;
- unsigned long artnum;
- size_t length;
-
- if ((path = TokenToPath(token)) == NULL) {
- SMseterror(SMERR_UNDEFINED, NULL);
- free(path);
- return false;
- }
- /*
- ** Ooooh, this is gross. To find the symlinks pointing to this article,
- ** we open the article and grab its Xref line (since the token isn't long
- ** enough to store this info on its own). This is *not* going to do
- ** good things for performance of fastrm... -- rmtodd
- */
- if ((article = OpenArticle(path, RETR_HEAD)) == NULL) {
- free(path);
- SMseterror(SMERR_UNDEFINED, NULL);
- return false;
- }
-
- xrefhdr = wire_findheader(article->data, article->len, "Xref");
- if (xrefhdr == NULL) {
- /* for backwards compatibility; there is no Xref unless crossposted
- for 1.4 and 1.5 */
- if (unlink(path) < 0) result = false;
- free(path);
- tradspool_freearticle(article);
- return result;
- }
-
- if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
- if (xrefs != NULL)
- free(xrefs);
- free(path);
- tradspool_freearticle(article);
- SMseterror(SMERR_UNDEFINED, NULL);
- return false;
- }
-
- tradspool_freearticle(article);
- for (i = 1 ; i < numxrefs ; ++i) {
- if ((p = strchr(xrefs[i], ':')) == NULL) continue;
- *p++ = '\0';
- ng = xrefs[i];
- DeDotify(ng);
- artnum = atol(p);
-
- length = strlen(innconf->patharticles) + strlen(ng) + 32;
- linkpath = xmalloc(length);
- snprintf(linkpath, length, "%s/%s/%lu", innconf->patharticles, ng,
- artnum);
- /* repeated unlinkings of a crossposted article may fail on account
- of the file no longer existing without it truly being an error */
- if (unlink(linkpath) < 0)
- if (errno != ENOENT || i == 1)
- result = false;
- free(linkpath);
- }
- if (unlink(path) < 0)
- if (errno != ENOENT || numxrefs == 1)
- result = false;
- free(path);
- for (i = 0 ; i < numxrefs ; ++i) free(xrefs[i]);
- free(xrefs);
- return result;
-}
-
-
-/*
-** Find entries for possible articles in dir. "dir" (directory name "dirname").
-** The dirname is needed so we can do stats in the directory to disambiguate
-** files from symlinks and directories.
-*/
-
-static struct dirent *
-FindDir(DIR *dir, char *dirname) {
- struct dirent *de;
- int i;
- bool flag;
- char *path;
- struct stat sb;
- size_t length;
- unsigned char namelen;
-
- while ((de = readdir(dir)) != NULL) {
- namelen = strlen(de->d_name);
- for (i = 0, flag = true ; i < namelen ; ++i) {
- if (!CTYPE(isdigit, de->d_name[i])) {
- flag = false;
- break;
- }
- }
- if (!flag) continue; /* if not all digits, skip this entry. */
-
- length = strlen(dirname) + namelen + 2;
- path = xmalloc(length);
- strlcpy(path, dirname, length);
- strlcat(path, "/", length);
- strlcat(path, de->d_name, length);
-
- if (lstat(path, &sb) < 0) {
- free(path);
- continue;
- }
- free(path);
- if (!S_ISREG(sb.st_mode)) continue;
- return de;
- }
- return NULL;
-}
-
-ARTHANDLE *tradspool_next(const ARTHANDLE *article, const RETRTYPE amount) {
- PRIV_TRADSPOOL priv;
- PRIV_TRADSPOOL *newpriv;
- char *path, *linkpath;
- struct dirent *de;
- ARTHANDLE *art;
- unsigned long artnum;
- unsigned int i;
- static TOKEN token;
- char **xrefs;
- char *xrefhdr, *ng, *p, *expires, *x;
- unsigned int numxrefs;
- STORAGE_SUB *sub;
- size_t length;
-
- if (article == NULL) {
- priv.ngtp = NULL;
- priv.curdir = NULL;
- priv.curdirname = NULL;
- priv.nextindex = -1;
- } else {
- priv = *(PRIV_TRADSPOOL *) article->private;
- free(article->private);
- free((void*)article);
- if (priv.artbase != NULL) {
- if (priv.mmapped)
- munmap(priv.artbase, priv.artlen);
- else
- free(priv.artbase);
- }
- }
-
- while (!priv.curdir || ((de = FindDir(priv.curdir, priv.curdirname)) == NULL)) {
- if (priv.curdir) {
- closedir(priv.curdir);
- priv.curdir = NULL;
- free(priv.curdirname);
- priv.curdirname = NULL;
- }
-
- /*
- ** advance ngtp to the next entry, if it exists, otherwise start
- ** searching down another ngtable hashchain.
- */
- while (priv.ngtp == NULL || (priv.ngtp = priv.ngtp->next) == NULL) {
- /*
- ** note that at the start of a search nextindex is -1, so the inc.
- ** makes nextindex 0, as it should be.
- */
- priv.nextindex++;
- if (priv.nextindex >= NGT_SIZE) {
- /* ran off the end of the table, so return. */
- return NULL;
- }
- priv.ngtp = NGTable[priv.nextindex];
- if (priv.ngtp != NULL)
- break;
- }
-
- priv.curdirname = concatpath(innconf->patharticles, priv.ngtp->ngname);
- priv.curdir = opendir(priv.curdirname);
- }
-
- path = concatpath(priv.curdirname, de->d_name);
- i = strlen(priv.curdirname);
- /* get the article number while we're here, we'll need it later. */
- artnum = atol(&path[i+1]);
-
- art = OpenArticle(path, amount);
- if (art == (ARTHANDLE *)NULL) {
- art = xmalloc(sizeof(ARTHANDLE));
- art->type = TOKEN_TRADSPOOL;
- art->data = NULL;
- art->len = 0;
- art->private = xmalloc(sizeof(PRIV_TRADSPOOL));
- art->expires = 0;
- art->groups = NULL;
- art->groupslen = 0;
- newpriv = (PRIV_TRADSPOOL *) art->private;
- newpriv->artbase = NULL;
- } else {
- /* Skip linked (not symlinked) crossposted articles.
-
- This algorithm is rather questionable; it only works if the first
- group/number combination listed in the Xref header is the
- canonical path. This will always be true for spools created by
- this implementation, but for traditional INN 1.x servers,
- articles are expired indepedently from each group and may expire
- out of the first listed newsgroup before other groups. This
- algorithm will orphan such articles, not adding them to history.
-
- The bit of skipping articles by setting the length of the article
- to zero is also rather suspect, and I'm not sure what
- implications that might have for the callers of SMnext.
-
- Basically, this whole area really needs to be rethought. */
- xrefhdr = wire_findheader(art->data, art->len, "Xref");
- if (xrefhdr != NULL) {
- if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
- art->len = 0;
- } else {
- /* assumes first one is the original */
- if ((p = strchr(xrefs[1], ':')) != NULL) {
- *p++ = '\0';
- ng = xrefs[1];
- DeDotify(ng);
- artnum = atol(p);
-
- length = strlen(innconf->patharticles) + strlen(ng) + 32;
- linkpath = xmalloc(length);
- snprintf(linkpath, length, "%s/%s/%lu",
- innconf->patharticles, ng, artnum);
- if (strcmp(path, linkpath) != 0) {
- /* this is linked article, skip it */
- art->len = 0;
- }
- free(linkpath);
- }
- }
- for (i = 0 ; i < numxrefs ; ++i) free(xrefs[i]);
- free(xrefs);
- if (innconf->storeonxref) {
- /* skip path element */
- if ((xrefhdr = strchr(xrefhdr, ' ')) == NULL) {
- art->groups = NULL;
- art->groupslen = 0;
- } else {
- for (xrefhdr++; *xrefhdr == ' '; xrefhdr++);
- art->groups = xrefhdr;
- for (p = xrefhdr ; (*p != '\n') && (*p != '\r') ; p++);
- art->groupslen = p - xrefhdr;
- }
- }
- }
- if (xrefhdr == NULL || !innconf->storeonxref) {
- ng = wire_findheader(art->data, art->len, "Newsgroups");
- if (ng == NULL) {
- art->groups = NULL;
- art->groupslen = 0;
- } else {
- art->groups = ng;
- for (p = ng ; (*p != '\n') && (*p != '\r') ; p++);
- art->groupslen = p - ng;
- }
- }
- expires = wire_findheader(art->data, art->len, "Expires");
- if (expires == NULL) {
- art->expires = 0;
- } else {
- /* optionally parse expire header */
- for (p = expires + 1; (*p != '\n') && (*(p - 1) != '\r'); p++);
- x = xmalloc(p - expires);
- memcpy(x, expires, p - expires - 1);
- x[p - expires - 1] = '\0';
-
- art->expires = parsedate(x, NULL);
- if (art->expires == -1)
- art->expires = 0;
- else
- art->expires -= time(0);
- free(x);
- }
- /* for backwards compatibility; assumes no Xref unless crossposted
- for 1.4 and 1.5: just fall through */
- }
- newpriv = (PRIV_TRADSPOOL *) art->private;
- newpriv->nextindex = priv.nextindex;
- newpriv->curdir = priv.curdir;
- newpriv->curdirname = priv.curdirname;
- newpriv->ngtp = priv.ngtp;
-
- if ((sub = SMgetsub(*art)) == NULL || sub->type != TOKEN_TRADSPOOL) {
- /* maybe storage.conf is modified, after receiving article */
- token = MakeToken(priv.ngtp->ngname, artnum, 0);
-
- /* Only log an error if art->len is non-zero, since otherwise we get
- all the ones skipped via the hard-link skipping algorithm
- commented above. */
- if (art->len > 0)
- syslog(L_ERROR, "tradspool: can't determine class: %s: %s",
- TokenToText(token), SMerrorstr);
- } else {
- token = MakeToken(priv.ngtp->ngname, artnum, sub->class);
- }
- art->token = &token;
- free(path);
- return art;
-}
-
-static void
-FreeNGTree(void)
-{
- unsigned int i;
- NGTENT *ngtp, *nextngtp;
-
- for (i = 0 ; i < NGT_SIZE ; i++) {
- ngtp = NGTable[i];
- for ( ; ngtp != NULL ; ngtp = nextngtp) {
- nextngtp = ngtp->next;
- free(ngtp->ngname);
- free(ngtp->node);
- free(ngtp);
- }
- NGTable[i] = NULL;
- }
- MaxNgNumber = 0;
- NGTree = NULL;
-}
-
-bool tradspool_ctl(PROBETYPE type, TOKEN *token, void *value) {
- struct artngnum *ann;
- unsigned long ngnum;
- unsigned long artnum;
- char *ng, *p;
-
- switch (type) {
- case SMARTNGNUM:
- if ((ann = (struct artngnum *)value) == NULL)
- return false;
- CheckNeedReloadDB(false);
- memcpy(&ngnum, &token->token[0], sizeof(ngnum));
- memcpy(&artnum, &token->token[sizeof(ngnum)], sizeof(artnum));
- artnum = ntohl(artnum);
- ngnum = ntohl(ngnum);
- ng = FindNGByNum(ngnum);
- if (ng == NULL) {
- CheckNeedReloadDB(true);
- ng = FindNGByNum(ngnum);
- if (ng == NULL)
- return false;
- }
- ann->groupname = xstrdup(ng);
- for (p = ann->groupname; *p != 0; p++)
- if (*p == '/')
- *p = '.';
- ann->artnum = (ARTNUM)artnum;
- return true;
- default:
- return false;
- }
-}
-
-bool
-tradspool_flushcacheddata(FLUSHTYPE type UNUSED)
-{
- return true;
-}
-
-void
-tradspool_printfiles(FILE *file, TOKEN token UNUSED, char **xref, int ngroups)
-{
- int i;
- char *path, *p;
-
- for (i = 0; i < ngroups; i++) {
- path = xstrdup(xref[i]);
- for (p = path; *p != '\0'; p++)
- if (*p == '.' || *p == ':')
- *p = '/';
- fprintf(file, "%s\n", path);
- free(path);
- }
-}
-
-void
-tradspool_shutdown(void) {
- DumpDB();
- FreeNGTree();
-}
+++ /dev/null
-/*
-** $Id: tradspool.h 4269 2001-01-04 06:04:10Z rra $
-** tradspool -- storage manager for traditional spool format.
-*/
-
-#ifndef __TRADSPOOL_H__
-#define __TRADSPOOL_H__
-
-#include "config.h"
-#include "interface.h"
-
-bool tradspool_init(SMATTRIBUTE *attr);
-TOKEN tradspool_store(const ARTHANDLE article, const STORAGECLASS class);
-ARTHANDLE *tradspool_retrieve(const TOKEN token, const RETRTYPE amount);
-ARTHANDLE *tradspool_next(const ARTHANDLE *article, const RETRTYPE amount);
-void tradspool_freearticle(ARTHANDLE *article);
-bool tradspool_cancel(TOKEN token);
-bool tradspool_ctl(PROBETYPE type, TOKEN *token, void *value);
-bool tradspool_flushcacheddata(FLUSHTYPE type);
-void tradspool_printfiles(FILE *file, TOKEN token, char **xref, int ngroups);
-void tradspool_shutdown(void);
-
-#endif
+++ /dev/null
-name = trash
-number = 0
-sources = trash.c
+++ /dev/null
-/* $Id: trash.c 6124 2003-01-14 06:03:29Z rra $
-**
-** Trashing articles method
-*/
-#include "config.h"
-#include "clibrary.h"
-#include "libinn.h"
-#include "methods.h"
-
-#include "trash.h"
-
-bool
-trash_init(SMATTRIBUTE *attr)
-{
- if (attr == NULL) {
- SMseterror(SMERR_INTERNAL, "attr is NULL");
- return false;
- }
- attr->selfexpire = true;
- attr->expensivestat = false;
- return true;
-}
-
-TOKEN
-trash_store(const ARTHANDLE article, const STORAGECLASS class)
-{
- TOKEN token;
-
- if (article.token == (TOKEN *)NULL)
- memset(&token, '\0', sizeof(token));
- else {
- memcpy(&token, article.token, sizeof(token));
- memset(&token.token, '\0', STORAGE_TOKEN_LENGTH);
- }
- token.type = TOKEN_TRASH;
- token.class = class;
- return token;
-}
-
-ARTHANDLE *
-trash_retrieve(const TOKEN token, const RETRTYPE amount UNUSED)
-{
- if (token.type != TOKEN_TRASH) {
- SMseterror(SMERR_INTERNAL, NULL);
- return (ARTHANDLE *)NULL;
- }
- SMseterror(SMERR_NOENT, NULL);
- return (ARTHANDLE *)NULL;
-}
-
-void
-trash_freearticle(ARTHANDLE *article UNUSED)
-{
-}
-
-bool
-trash_cancel(TOKEN token UNUSED)
-{
- SMseterror(SMERR_NOENT, NULL);
- return false;
-}
-
-bool
-trash_ctl(PROBETYPE type, TOKEN *token UNUSED, void *value UNUSED)
-{
- switch (type) {
- case SMARTNGNUM:
- default:
- return false;
- }
-}
-
-bool
-trash_flushcacheddata(FLUSHTYPE type UNUSED)
-{
- return true;
-}
-
-void
-trash_printfiles(FILE *file UNUSED, TOKEN token UNUSED, char **xref UNUSED,
- int ngroups UNUSED)
-{
-}
-
-ARTHANDLE *
-trash_next(const ARTHANDLE *article UNUSED, const RETRTYPE amount UNUSED)
-{
- return NULL;
-}
-
-void
-trash_shutdown(void)
-{
-}
+++ /dev/null
-/* $Id: trash.h 4267 2001-01-04 06:02:02Z rra $
-**
-** trashing articles method header
-*/
-
-#ifndef __TRASH_H__
-#define __TRASH_H__
-
-#include "config.h"
-#include "interface.h"
-
-bool trash_init(SMATTRIBUTE *attr);
-TOKEN trash_store(const ARTHANDLE article, const STORAGECLASS class);
-ARTHANDLE *trash_retrieve(const TOKEN token, const RETRTYPE amount);
-ARTHANDLE *trash_next(const ARTHANDLE *article, const RETRTYPE amount);
-void trash_freearticle(ARTHANDLE *article);
-bool trash_cancel(TOKEN token);
-bool trash_ctl(PROBETYPE type, TOKEN *token, void *value);
-bool trash_flushcacheddata(FLUSHTYPE type);
-void trash_printfiles(FILE *file, TOKEN token, char **xref, int ngroups);
-void trash_shutdown(void);
-
-#endif
+++ /dev/null
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-# Free Software Foundation, Inc.
-
-timestamp='2008-04-14'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help" >&2
- exit 1 ;;
- * )
- break ;;
- esac
-done
-
-if test $# != 0; then
- echo "$me: too many arguments$help" >&2
- exit 1
-fi
-
-trap 'exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
-# compiler to aid in system detection is discouraged as it requires
-# temporary files to be created and, as you can see below, it is a
-# headache to deal with in a portable fashion.
-
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-# Portable tmp directory creation inspired by the Autoconf team.
-
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int x;" > $dummy.c ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- *:NetBSD:*:*)
- # NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
- # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
- # switched to ELF, *-*-netbsd* would select the old
- # object file format. This provides both forward
- # compatibility and a consistent mechanism for selecting the
- # object file format.
- #
- # Note: NetBSD doesn't particularly care about the vendor
- # portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
- case "${UNAME_MACHINE_ARCH}" in
- armeb) machine=armeb-unknown ;;
- arm*) machine=arm-unknown ;;
- sh3el) machine=shl-unknown ;;
- sh3eb) machine=sh-unknown ;;
- sh5el) machine=sh5le-unknown ;;
- *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
- esac
- # The Operating System including object format, if it has switched
- # to ELF recently, or will in the future.
- case "${UNAME_MACHINE_ARCH}" in
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval $set_cc_for_build
- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep __ELF__ >/dev/null
- then
- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
- # Return netbsd for either. FIX?
- os=netbsd
- else
- os=netbsdelf
- fi
- ;;
- *)
- os=netbsd
- ;;
- esac
- # The OS release
- # Debian GNU/NetBSD machines have a different userland, and
- # thus, need a distinct triplet. However, they do not need
- # kernel version information, so it can be replaced with a
- # suitable tag, in the style of linux-gnu.
- case "${UNAME_VERSION}" in
- Debian*)
- release='-gnu'
- ;;
- *)
- release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- ;;
- esac
- # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
- # contains redundant information, the shorter form:
- # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}"
- exit ;;
- *:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
- exit ;;
- *:ekkoBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
- exit ;;
- *:SolidBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
- exit ;;
- macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- *:MirBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- alpha:OSF1:*:*)
- case $UNAME_RELEASE in
- *4.0)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- ;;
- *5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
- ;;
- esac
- # According to Compaq, /usr/sbin/psrinfo has been available on
- # OSF/1 and Tru64 systems produced since 1995. I hope that
- # covers most systems running today. This code pipes the CPU
- # types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
- case "$ALPHA_CPU_TYPE" in
- "EV4 (21064)")
- UNAME_MACHINE="alpha" ;;
- "EV4.5 (21064)")
- UNAME_MACHINE="alpha" ;;
- "LCA4 (21066/21068)")
- UNAME_MACHINE="alpha" ;;
- "EV5 (21164)")
- UNAME_MACHINE="alphaev5" ;;
- "EV5.6 (21164A)")
- UNAME_MACHINE="alphaev56" ;;
- "EV5.6 (21164PC)")
- UNAME_MACHINE="alphapca56" ;;
- "EV5.7 (21164PC)")
- UNAME_MACHINE="alphapca57" ;;
- "EV6 (21264)")
- UNAME_MACHINE="alphaev6" ;;
- "EV6.7 (21264A)")
- UNAME_MACHINE="alphaev67" ;;
- "EV6.8CB (21264C)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.8AL (21264B)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.8CX (21264D)")
- UNAME_MACHINE="alphaev68" ;;
- "EV6.9A (21264/EV69A)")
- UNAME_MACHINE="alphaev69" ;;
- "EV7 (21364)")
- UNAME_MACHINE="alphaev7" ;;
- "EV7.9 (21364A)")
- UNAME_MACHINE="alphaev79" ;;
- esac
- # A Pn.n version is a patched version.
- # A Vn.n version is a released version.
- # A Tn.n version is a released field test version.
- # A Xn.n version is an unreleased experimental baselevel.
- # 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- exit ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit ;;
- Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
- *:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
- exit ;;
- *:[Mm]orph[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-morphos
- exit ;;
- *:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
- *:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
- *:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit ;;
- arm:riscos:*:*|arm:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
- SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
- # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
- NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
- DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
- DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
- sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit ;;
- sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
- case "`/bin/arch`" in
- sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
- ;;
- sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
- ;;
- esac
- exit ;;
- aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
- exit ;;
- # The situation for MiNT is a little confusing. The machine name
- # can be virtually everything (everything which is not
- # "atarist" or "atariste" at least should have a processor
- # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
- # to the lowercase version "mint" (or "freemint"). Finally
- # the system name "TOS" denotes a system which is actually not
- # MiNT. But MiNT is downward compatible to TOS, so this should
- # be no problem.
- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
- m68k:machten:*:*)
- echo m68k-apple-machten${UNAME_RELEASE}
- exit ;;
- powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
- exit ;;
- RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit ;;
- 2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
- exit ;;
- mips:*:*:UMIPS | mips:*:*:RISCos)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
- #if defined (host_mips) && defined (MIPSEB)
- #if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
- #endif
- #endif
- exit (-1);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c &&
- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`$dummy $dummyarg` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos${UNAME_RELEASE}
- exit ;;
- Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
- Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
- AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
- then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
- [ ${TARGET_BINARY_INTERFACE}x = x ]
- then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- else
- echo i586-dg-dgux${UNAME_RELEASE}
- fi
- exit ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
- ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
- then
- echo "$SYSTEM_NAME"
- else
- echo rs6000-ibm-aix3.2.5
- fi
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit ;;
- *:AIX:*:[456])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
- 9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
- 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH="hppa2.0n" ;;
- 64) HP_ARCH="hppa2.0w" ;;
- '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
- esac ;;
- esac
- fi
- if [ "${HP_ARCH}" = "" ]; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
-
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
-
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
-EOF
- (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
- test -z "$HP_ARCH" && HP_ARCH=hppa
- fi ;;
- esac
- if [ ${HP_ARCH} = "hppa2.0w" ]
- then
- eval $set_cc_for_build
-
- # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
- # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
- # generating 64-bit code. GNU and HP use different nomenclature:
- #
- # $ CC_FOR_BUILD=cc ./config.guess
- # => hppa2.0w-hp-hpux11.23
- # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
- # => hppa64-hp-hpux11.23
-
- if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
- grep __LP64__ >/dev/null
- then
- HP_ARCH="hppa2.0w"
- else
- HP_ARCH="hppa64"
- fi
- fi
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit ;;
- ia64:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux${HPUX_REV}
- exit ;;
- 3050*:HI-UX:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
- *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
- i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
- else
- echo ${UNAME_MACHINE}-unknown-osf1
- fi
- exit ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
- -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*SV1:*:*:*)
- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- *:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- 5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit ;;
- sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:FreeBSD:*:*)
- case ${UNAME_MACHINE} in
- pc98)
- echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- esac
- exit ;;
- i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
- exit ;;
- *:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
- exit ;;
- i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
- exit ;;
- i*:PW*:*)
- echo ${UNAME_MACHINE}-pc-pw32
- exit ;;
- *:Interix*:[3456]*)
- case ${UNAME_MACHINE} in
- x86)
- echo i586-pc-interix${UNAME_RELEASE}
- exit ;;
- EM64T | authenticamd)
- echo x86_64-unknown-interix${UNAME_RELEASE}
- exit ;;
- IA64)
- echo ia64-unknown-interix${UNAME_RELEASE}
- exit ;;
- esac ;;
- [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
- echo i${UNAME_MACHINE}-pc-mks
- exit ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i586-pc-interix
- exit ;;
- i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
- exit ;;
- amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
- exit ;;
- prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- *:GNU:*:*)
- # the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit ;;
- *:GNU/*:*:*)
- # other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
- exit ;;
- i*86:Minix:*:*)
- echo ${UNAME_MACHINE}-pc-minix
- exit ;;
- arm*:Linux:*:*)
- eval $set_cc_for_build
- if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep -q __ARM_EABI__
- then
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- else
- echo ${UNAME_MACHINE}-unknown-linux-gnueabi
- fi
- exit ;;
- avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- cris:Linux:*:*)
- echo cris-axis-linux-gnu
- exit ;;
- crisv32:Linux:*:*)
- echo crisv32-axis-linux-gnu
- exit ;;
- frv:Linux:*:*)
- echo frv-unknown-linux-gnu
- exit ;;
- ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- mips:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips
- #undef mipsel
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mipsel
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- mips64:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef mips64
- #undef mips64el
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=mips64el
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=mips64
- #else
- CPU=
- #endif
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^CPU/{
- s: ::g
- p
- }'`"
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
- ;;
- or32:Linux:*:*)
- echo or32-unknown-linux-gnu
- exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-gnu
- exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-gnu
- exit ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
- if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
- exit ;;
- parisc:Linux:*:* | hppa:Linux:*:*)
- # Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-gnu ;;
- PA8*) echo hppa2.0-unknown-linux-gnu ;;
- *) echo hppa-unknown-linux-gnu ;;
- esac
- exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-gnu
- exit ;;
- s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux
- exit ;;
- sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-gnu
- exit ;;
- x86_64:Linux:*:*)
- echo x86_64-unknown-linux-gnu
- exit ;;
- xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-gnu
- exit ;;
- i*86:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us. cd to the root directory to prevent
- # problems with other programs or directories called `ld' in the path.
- # Set LC_ALL=C to ensure ld outputs messages in English.
- ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
- | sed -ne '/supported targets:/!d
- s/[ ][ ]*/ /g
- s/.*supported targets: *//
- s/ .*//
- p'`
- case "$ld_supported_targets" in
- elf32-i386)
- TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
- ;;
- a.out-i386-linux)
- echo "${UNAME_MACHINE}-pc-linux-gnuaout"
- exit ;;
- "")
- # Either a pre-BFD a.out linker (linux-gnuoldld) or
- # one that does not give us useful --help.
- echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
- exit ;;
- esac
- # Determine whether the default compiler is a.out or elf
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <features.h>
- #ifdef __ELF__
- # ifdef __GLIBC__
- # if __GLIBC__ >= 2
- LIBC=gnu
- # else
- LIBC=gnulibc1
- # endif
- # else
- LIBC=gnulibc1
- # endif
- #else
- #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
- LIBC=gnu
- #else
- LIBC=gnuaout
- #endif
- #endif
- #ifdef __dietlibc__
- LIBC=dietlibc
- #endif
-EOF
- eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
- /^LIBC/{
- s: ::g
- p
- }'`"
- test x"${LIBC}" != x && {
- echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
- exit
- }
- test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
- ;;
- i*86:DYNIX/ptx:4*:*)
- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
- # earlier versions are messed up and put the nodename in both
- # sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
- i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
- # I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit ;;
- i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
- # is probably installed.
- echo ${UNAME_MACHINE}-pc-os2-emx
- exit ;;
- i*86:XTS-300:*:STOP)
- echo ${UNAME_MACHINE}-unknown-stop
- exit ;;
- i*86:atheos:*:*)
- echo ${UNAME_MACHINE}-unknown-atheos
- exit ;;
- i*86:syllable:*:*)
- echo ${UNAME_MACHINE}-pc-syllable
- exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- i*86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit ;;
- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
- fi
- exit ;;
- i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
- case `/bin/uname -X | grep "^Machine"` in
- *486*) UNAME_MACHINE=i486 ;;
- *Pentium) UNAME_MACHINE=i586 ;;
- *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
- esac
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit ;;
- i*86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
- (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
- && UNAME_MACHINE=i586
- (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
- && UNAME_MACHINE=i686
- (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
- && UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-pc-sysv32
- fi
- exit ;;
- pc:*:*:*)
- # Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i386.
- echo i386-pc-msdosdjgpp
- exit ;;
- Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit ;;
- mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
- M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
- M68*:*:R3V[5678]*:*)
- test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
- 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
- OS_REL=''
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
- m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
- TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
- echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
- exit ;;
- RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
- *:UNIX_System_V:4*:FTX*)
- # From Gerald Hewes <hewes@openmarket.com>.
- # How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
- *:*:*:FTX*)
- # From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit ;;
- i*86:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo ${UNAME_MACHINE}-stratus-vos
- exit ;;
- *:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit ;;
- mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
- exit ;;
- news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
- else
- echo mips-unknown-sysv${UNAME_RELEASE}
- fi
- exit ;;
- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
- BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
- BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
- echo i586-pc-haiku
- exit ;;
- SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux${UNAME_RELEASE}
- exit ;;
- Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- case $UNAME_PROCESSOR in
- unknown) UNAME_PROCESSOR=powerpc ;;
- esac
- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
- exit ;;
- *:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = "x86"; then
- UNAME_PROCESSOR=i386
- UNAME_MACHINE=pc
- fi
- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit ;;
- *:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
- NSE-?:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk${UNAME_RELEASE}
- exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk${UNAME_RELEASE}
- exit ;;
- *:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
- BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
- DS/*:UNIX_System_V:*:*)
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit ;;
- *:Plan9:*:*)
- # "uname -m" is not consistent, so use $cputype instead. 386
- # is converted to i386 for consistency with other x86
- # operating systems.
- if test "$cputype" = "386"; then
- UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
- fi
- echo ${UNAME_MACHINE}-unknown-plan9
- exit ;;
- *:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
- *:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
- KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
- XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
- *:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
- *:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
- SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
- exit ;;
- *:DragonFly:*:*)
- echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit ;;
- *:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "${UNAME_MACHINE}" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
- esac ;;
- *:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
- i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
- exit ;;
- i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
- exit ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
- I don't know.... */
- printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
- printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
- "4"
-#else
- ""
-#endif
- ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
- printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
- int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
- if (version < 4)
- printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
- else
- printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
- exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
- printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
- printf ("ns32k-encore-mach\n"); exit (0);
-#else
- printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
- printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
- printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
- printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
- struct utsname un;
-
- uname(&un);
-
- if (strncmp(un.version, "V2", 2) == 0) {
- printf ("i386-sequent-ptx2\n"); exit (0);
- }
- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
- printf ("i386-sequent-ptx1\n"); exit (0);
- }
- printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-# include <sys/param.h>
-# if defined (BSD)
-# if BSD == 43
- printf ("vax-dec-bsd4.3\n"); exit (0);
-# else
-# if BSD == 199006
- printf ("vax-dec-bsd4.3reno\n"); exit (0);
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# endif
-# else
- printf ("vax-dec-bsd\n"); exit (0);
-# endif
-# else
- printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
- printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
- exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
- case `getsysinfo -f cpu_type` in
- c1*)
- echo c1-convex-bsd
- exit ;;
- c2*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit ;;
- c34*)
- echo c34-convex-bsd
- exit ;;
- c38*)
- echo c38-convex-bsd
- exit ;;
- c4*)
- echo c4-convex-bsd
- exit ;;
- esac
-fi
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
-
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
-and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
-
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <config-patches@gnu.org> in order to provide the needed
-information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
+++ /dev/null
-#! /bin/sh
-# Configuration validation subroutine script.
-# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-# Free Software Foundation, Inc.
-
-timestamp='2008-04-14'
-
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Please send patches to <config-patches@gnu.org>. Submit a context
-# diff and a properly formatted ChangeLog entry.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support. The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
- $0 [OPTION] ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help"
- exit 1 ;;
-
- *local*)
- # First pass through any local machine types.
- echo $1
- exit ;;
-
- * )
- break ;;
- esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
- exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
- exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
- uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray)
- os=
- basic_machine=$1
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*)
- os=-lynxos
- ;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
- ;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
- ;;
- -psos*)
- os=-psos
- ;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
- | bfin \
- | c4x | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | fido | fr30 | frv \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | i370 | i860 | i960 | ia64 \
- | ip2k | iq2000 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | mcore | mep | metag \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | mt \
- | msp430 \
- | nios | nios2 \
- | ns16k | ns32k \
- | or32 \
- | pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
- | pyramid \
- | score \
- | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu | strongarm \
- | tahoe | thumb | tic4x | tic80 | tron \
- | v850 | v850e \
- | we32k \
- | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
- | z8k)
- basic_machine=$basic_machine-unknown
- ;;
- m6811 | m68hc11 | m6812 | m68hc12)
- # Motorola 68HC11/12.
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
- ;;
- ms1)
- basic_machine=mt-unknown
- ;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
- | clipper-* | craynv-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | i*86-* | i860-* | i960-* | ia64-* \
- | ip2k-* | iq2000-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64octeon-* | mips64octeonel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64r5900-* | mips64r5900el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nios-* | nios2-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
- | pyramid-* \
- | romp-* | rs6000-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
- | tahoe-* | thumb-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
- | tron-* \
- | v850-* | v850e-* | vax-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
- | xstormy16-* | xtensa*-* \
- | ymp-* \
- | z8k-*)
- ;;
- # Recognize the basic CPU types without company name, with glob match.
- xtensa*)
- basic_machine=$basic_machine-unknown
- ;;
- # Recognize the various machine names and aliases which stand
- # for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
- ;;
- 3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- blackfin)
- basic_machine=bfin-unknown
- os=-linux
- ;;
- blackfin-*)
- basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- craynv)
- basic_machine=craynv-cray
- os=-unicosmp
- ;;
- cr16)
- basic_machine=cr16-unknown
- os=-elf
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=-elf
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
- ;;
- decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
- ;;
- decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
- ;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dicos)
- basic_machine=i686-pc
- os=-dicos
- ;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
- ;;
- encore | umax | mmax)
- basic_machine=ns32k-encore
- ;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
- ;;
- fx2800)
- basic_machine=i860-alliant
- ;;
- genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
- ;;
- h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
- ;;
- hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
- ;;
- hp9k3[2-9][0-9])
- basic_machine=m68k-hp
- ;;
- hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
- ;;
- hp9k78[0-9] | hp78[0-9])
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
- ;;
-# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i*86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
- ;;
- i*86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
- ;;
- i*86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
- ;;
- i*86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
- ;;
- iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
- ;;
- *)
- os=-irix4
- ;;
- esac
- ;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- m68knommu)
- basic_machine=m68k-unknown
- os=-linux
- ;;
- m68knommu-*)
- basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- mingw32)
- basic_machine=i386-pc
- os=-mingw32
- ;;
- mingw32ce)
- basic_machine=arm-unknown
- os=-mingw32ce
- ;;
- miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
- ;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
- ;;
- news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
- ;;
- next | m*-next )
- basic_machine=m68k-next
- case $os in
- -nextstep* )
- ;;
- -ns2*)
- os=-nextstep2
- ;;
- *)
- os=-nextstep3
- ;;
- esac
- ;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
- np1)
- basic_machine=np1-gould
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
- ;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
- ;;
- os400)
- basic_machine=powerpc-ibm
- os=-os400
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
- ;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- parisc)
- basic_machine=hppa-unknown
- os=-linux
- ;;
- parisc-*)
- basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- pbd)
- basic_machine=sparc-tti
- ;;
- pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
- ;;
- pentium4)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium4-*)
- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc) basic_machine=powerpc-unknown
- ;;
- ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle | ppc-le | powerpc-little)
- basic_machine=powerpcle-unknown
- ;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64) basic_machine=powerpc64-unknown
- ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64le | powerpc64little | ppc64-le | powerpc64-little)
- basic_machine=powerpc64le-unknown
- ;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ps2)
- basic_machine=i386-ibm
- ;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
- ;;
- rdos)
- basic_machine=i386-pc
- os=-rdos
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- rm[46]00)
- basic_machine=mips-siemens
- ;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
- ;;
- s390 | s390-*)
- basic_machine=s390-ibm
- ;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
- ;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
- ;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
- ;;
- sde)
- basic_machine=mipsisa32-sde
- os=-elf
- ;;
- sei)
- basic_machine=mips-sei
- os=-seiux
- ;;
- sequent)
- basic_machine=i386-sequent
- ;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
- ;;
- sh5el)
- basic_machine=sh5le-unknown
- ;;
- sh64)
- basic_machine=sh64-unknown
- ;;
- sparclite-wrs | simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
- ;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
- ;;
- spur)
- basic_machine=spur-unknown
- ;;
- st2000)
- basic_machine=m68k-tandem
- ;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
- ;;
- sun2)
- basic_machine=m68000-sun
- ;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
- ;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
- ;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
- ;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
- ;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
- ;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
- ;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
- ;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
- ;;
- sun4)
- basic_machine=sparc-sun
- ;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
- ;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
- ;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
- ;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
- ;;
- t90)
- basic_machine=t90-cray
- os=-unicos
- ;;
- tic54x | c54x*)
- basic_machine=tic54x-unknown
- os=-coff
- ;;
- tic55x | c55x*)
- basic_machine=tic55x-unknown
- os=-coff
- ;;
- tic6x | c6x*)
- basic_machine=tic6x-unknown
- os=-coff
- ;;
- tile*)
- basic_machine=tile-unknown
- os=-linux-gnu
- ;;
- tx39)
- basic_machine=mipstx39-unknown
- ;;
- tx39el)
- basic_machine=mipstx39el-unknown
- ;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
- ;;
- tower | tower-32)
- basic_machine=m68k-ncr
- ;;
- tpf)
- basic_machine=s390x-ibm
- os=-tpf
- ;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
- ;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
- ;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
- ;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
- ;;
- vms)
- basic_machine=vax-dec
- os=-vms
- ;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
- ;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
- ;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
- ;;
- w65*)
- basic_machine=w65-wdc
- os=-none
- ;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
- ;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- xps | xps100)
- basic_machine=xps100-honeywell
- ;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
- ;;
- none)
- basic_machine=none-none
- os=-none
- ;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- mmix)
- basic_machine=mmix-knuth
- ;;
- rs6000)
- basic_machine=rs6000-ibm
- ;;
- vax)
- basic_machine=vax-dec
- ;;
- pdp10)
- # there are many clones, so DEC is not a safe bet
- basic_machine=pdp10-unknown
- ;;
- pdp11)
- basic_machine=pdp11-dec
- ;;
- we32k)
- basic_machine=we32k-att
- ;;
- sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
- ;;
- sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
- basic_machine=sparc-sun
- ;;
- cydra)
- basic_machine=cydra-cydrome
- ;;
- orion)
- basic_machine=orion-highlevel
- ;;
- orion105)
- basic_machine=clipper-highlevel
- ;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
- ;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
- ;;
- *)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
- ;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
- ;;
- *)
- ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
- ;;
- -solaris)
- os=-solaris2
- ;;
- -svr4*)
- os=-sysv4
- ;;
- -unixware*)
- os=-sysv4.2uw
- ;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
- # First accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -openbsd* | -solidbsd* \
- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* \
- | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* \
- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=-nto$os
- ;;
- esac
- ;;
- -nto-qnx*)
- ;;
- -nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
- ;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
- ;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
- ;;
- -linux-dietlibc)
- os=-linux-dietlibc
- ;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
- ;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
- ;;
- -opened*)
- os=-openedition
- ;;
- -os400*)
- os=-os400
- ;;
- -wince*)
- os=-wince
- ;;
- -osfrose*)
- os=-osfrose
- ;;
- -osf*)
- os=-osf
- ;;
- -utek*)
- os=-bsd
- ;;
- -dynix*)
- os=-bsd
- ;;
- -acis*)
- os=-aos
- ;;
- -atheos*)
- os=-atheos
- ;;
- -syllable*)
- os=-syllable
- ;;
- -386bsd)
- os=-bsd
- ;;
- -ctix* | -uts*)
- os=-sysv
- ;;
- -nova*)
- os=-rtmk-nova
- ;;
- -ns2 )
- os=-nextstep2
- ;;
- -nsk*)
- os=-nsk
- ;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
- ;;
- -sinix*)
- os=-sysv4
- ;;
- -tpf*)
- os=-tpf
- ;;
- -triton*)
- os=-sysv3
- ;;
- -oss*)
- os=-sysv3
- ;;
- -svr4)
- os=-sysv4
- ;;
- -svr3)
- os=-sysv3
- ;;
- -sysvr4)
- os=-sysv4
- ;;
- # This must come after -sysvr4.
- -sysv*)
- ;;
- -ose*)
- os=-ose
- ;;
- -es1800*)
- os=-ose
- ;;
- -xenix)
- os=-xenix
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
- ;;
- -aros*)
- os=-aros
- ;;
- -kaos*)
- os=-kaos
- ;;
- -zvmoe)
- os=-zvmoe
- ;;
- -dicos*)
- os=-dicos
- ;;
- -none)
- ;;
- *)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
- exit 1
- ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system. Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
- score-*)
- os=-elf
- ;;
- spu-*)
- os=-elf
- ;;
- *-acorn)
- os=-riscix1.2
- ;;
- arm*-rebel)
- os=-linux
- ;;
- arm*-semi)
- os=-aout
- ;;
- c4x-* | tic4x-*)
- os=-coff
- ;;
- # This must come before the *-dec entry.
- pdp10-*)
- os=-tops20
- ;;
- pdp11-*)
- os=-none
- ;;
- *-dec | vax-*)
- os=-ultrix4.2
- ;;
- m68*-apollo)
- os=-domain
- ;;
- i386-sun)
- os=-sunos4.0.2
- ;;
- m68000-sun)
- os=-sunos3
- # This also exists in the configure program, but was not the
- # default.
- # os=-sunos4
- ;;
- m68*-cisco)
- os=-aout
- ;;
- mep-*)
- os=-elf
- ;;
- mips*-cisco)
- os=-elf
- ;;
- mips*-*)
- os=-elf
- ;;
- or32-*)
- os=-coff
- ;;
- *-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
- ;;
- sparc-* | *-sun)
- os=-sunos4.1.1
- ;;
- *-be)
- os=-beos
- ;;
- *-haiku)
- os=-haiku
- ;;
- *-ibm)
- os=-aix
- ;;
- *-knuth)
- os=-mmixware
- ;;
- *-wec)
- os=-proelf
- ;;
- *-winbond)
- os=-proelf
- ;;
- *-oki)
- os=-proelf
- ;;
- *-hp)
- os=-hpux
- ;;
- *-hitachi)
- os=-hiux
- ;;
- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
- ;;
- *-cbm)
- os=-amigaos
- ;;
- *-dg)
- os=-dgux
- ;;
- *-dolphin)
- os=-sysv3
- ;;
- m68k-ccur)
- os=-rtu
- ;;
- m88k-omron*)
- os=-luna
- ;;
- *-next )
- os=-nextstep
- ;;
- *-sequent)
- os=-ptx
- ;;
- *-crds)
- os=-unos
- ;;
- *-ns)
- os=-genix
- ;;
- i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
- ;;
- *-gould)
- os=-sysv
- ;;
- *-highlevel)
- os=-bsd
- ;;
- *-encore)
- os=-bsd
- ;;
- *-sgi)
- os=-irix
- ;;
- *-siemens)
- os=-sysv4
- ;;
- *-masscomp)
- os=-rtu
- ;;
- f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
- ;;
- *-rom68k)
- os=-coff
- ;;
- *-*bug)
- os=-coff
- ;;
- *-apple)
- os=-macos
- ;;
- *-atari*)
- os=-mint
- ;;
- *)
- os=-none
- ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
- vendor=acorn
- ;;
- -sunos*)
- vendor=sun
- ;;
- -aix*)
- vendor=ibm
- ;;
- -beos*)
- vendor=be
- ;;
- -hpux*)
- vendor=hp
- ;;
- -mpeix*)
- vendor=hp
- ;;
- -hiux*)
- vendor=hitachi
- ;;
- -unos*)
- vendor=crds
- ;;
- -dgux*)
- vendor=dg
- ;;
- -luna*)
- vendor=omron
- ;;
- -genix*)
- vendor=ns
- ;;
- -mvs* | -opened*)
- vendor=ibm
- ;;
- -os400*)
- vendor=ibm
- ;;
- -ptx*)
- vendor=sequent
- ;;
- -tpf*)
- vendor=ibm
- ;;
- -vxsim* | -vxworks* | -windiss*)
- vendor=wrs
- ;;
- -aux*)
- vendor=apple
- ;;
- -hms*)
- vendor=hitachi
- ;;
- -mpw* | -macos*)
- vendor=apple
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- vendor=atari
- ;;
- -vos*)
- vendor=stratus
- ;;
- esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
- ;;
-esac
-
-echo $basic_machine$os
-exit
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
+++ /dev/null
-#! @_PATH_SH@
-
-## $Id: fixscript.in 2805 1999-11-27 07:23:49Z rra $
-##
-## Fix interpretor paths and INN variable load paths.
-##
-## Scripts shipped with INN always have the invocation path for the
-## interpretor on the first line and the command to load INN variable
-## settings into the script on the second line. For example, for a Bourne
-## shell script:
-##
-## #!/bin/sh
-## . /var/news/lib/innshellvars
-##
-## This script takes as input such a script and outputs the same script
-## with the first two lines replaced to have the correct path to the
-## interpretor and to the INN variable library, as determined by configure.
-##
-## If the script is invoked with the -i flag, only fix the interpretor
-## path and don't modify the second line of the file to include the
-## appropriate innshellvars.
-
-SED='@_PATH_SED@'
-
-PERLPATH='@_PATH_PERL@'
-SHPATH='@_PATH_SH@'
-LIBDIR='@LIBDIR@'
-
-options=true
-addlib=true
-while $options ; do
- case X"$1" in
- X-i) addlib=false ;;
- *) options=false ;;
- esac
- $options && shift
-done
-
-input="$1"
-if [ -z "$input" ] ; then
- echo "No input file specified" >&2
- exit 1
-fi
-
-output="$2"
-if [ -z "$output" ] ; then
- output=`echo "$input" | sed 's/\.in$//'`
-fi
-if [ x"$input" = x"$output" ] ; then
- echo "No output file specified and input file doesn't end in .in" >&2
- exit 1
-fi
-
-interpretor=`head -1 "$input"`
-case "$interpretor" in
-*/sh|*SH*)
- path="$SHPATH"
- lib=". $LIBDIR/innshellvars"
- ;;
-*/perl*|*PERL*)
- path=`echo "$interpretor" | sed 's%^#! *[^ ][^ ]*%'"$PERLPATH%"`
- lib="require '$LIBDIR/innshellvars.pl';"
- ;;
-*)
- echo "Unknown interpretor $interpretor" >&2
- exit 1
- ;;
-esac
-
-echo "#! $path" > "$output"
-if $addlib ; then
- echo "$lib" >> "$output"
- "$SED" 1,2d "$input" >> "$output"
-else
- "$SED" 1d "$input" >> "$output"
-fi
-chmod 755 "$output"
+++ /dev/null
-#! /bin/sh
-
-## $Id: indent 5165 2002-03-02 01:43:53Z rra $
-##
-## Run indent on source files with INN options.
-##
-## This is a simple wrapper around GNU indent to call it with all of the
-## options suitable for INN's coding style and typedefs. These options
-## are also documented in HACKING. Assumes indent is on the user's path.
-##
-## The order of options matches the order in which they're described in
-## the GNU indent info manual. In order, each line sets options for:
-## blank lines, comments, statements, declarations, indentation, breaking
-## long lines, and typedefs used by INN.
-##
-## Note that the resulting output should not be used without manual review,
-## nor should this script be run automatically. indent still has a few
-## bugs, tends to mangle case statements written compactly, and varies from
-## the prevailing INN style in a few ways that can't be changed.
-
-indent \
- -bad -bap -nsob \
- -fca -lc78 -cd32 -cp1 \
- -br -ce -cdw -cli0 -ss -npcs -cs \
- -di1 -nbc -psl -brs \
- -i4 -ci4 -lp -ts8 -nut -ip5 -lps \
- -l78 -bbo -hnl \
- -T off_t -T size_t -T uint32_t -T time_t -T FILE \
- $*
+++ /dev/null
-#!/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.
-
-# Modified for INN by adding the -B option to request saving of the original
-# file (if install is overwriting an existing file). -B takes an argument,
-# the suffix to use. INN invokes this script as install-sh -B .OLD. Also
-# modified to use cp -p instead of just cp to install programs when invoked
-# as install -c.
-
-
-# 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}"
-
-backupsuffix=""
-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
- -B) backupsuffix="$2"
- shift
- shift
- continue;;
-
- -c) instcmd="$cpprog -p"
- 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
-
-# For Cygwin compatibility.
-if [ -x "$src".exe ]; then
- src=${src}.exe
-fi
-
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- chmodcmd=""
- chowncmd=""
- 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. If $backupsuffix
-# is set, rename the existing file if it exists; otherwise, just
-# remove it.
-
- if [ x"$backupsuffix" != x ] && [ -f "$dstdir/$dstfile" ]; then
- $doit $mvcmd $dstdir/$dstfile $dstdir/$dstfile$backupsuffix
- else
- $doit $rmcmd -f $dstdir/$dstfile
- fi &&
-
- $doit $mvcmd $dsttmp $dstdir/$dstfile
-
-fi &&
-
-
-exit 0
+++ /dev/null
-# ltmain.sh - Provide generalized library-building support services.
-# NOTE: Changing this file will not affect anything until you rerun configure.
-#
-# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
-# Free Software Foundation, Inc.
-# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file has been modified from the standard libtool version to
-# recognize the additional -O, -G, and -b flags that INN's install program
-# recognizes; apart from that, it's identical to the stock libtool
-# distribution.
-
-# Check that we have a working $echo.
-if test "X$1" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
-elif test "X$1" = X--fallback-echo; then
- # Avoid inline document here, it may be left over
- :
-elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
- # Yippee, $echo works!
- :
-else
- # Restart under the correct shell, and then maybe $echo will work.
- exec $SHELL "$0" --no-reexec ${1+"$@"}
-fi
-
-if test "X$1" = X--fallback-echo; then
- # used as fallback echo
- shift
- cat <<EOF
-$*
-EOF
- exit 0
-fi
-
-# The name of this program.
-progname=`$echo "$0" | sed 's%^.*/%%'`
-modename="$progname"
-
-# Constants.
-PROGRAM=ltmain.sh
-PACKAGE=libtool
-VERSION=1.4.2
-TIMESTAMP=" (1.922.2.53 2001/09/11 03:18:52)"
-
-default_mode=
-help="Try \`$progname --help' for more information."
-magic="%%%MAGIC variable%%%"
-mkdir="mkdir"
-mv="mv -f"
-rm="rm -f"
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
-SP2NL='tr \040 \012'
-NL2SP='tr \015\012 \040\040'
-
-# NLS nuisances.
-# Only set LANG and LC_ALL to C if already set.
-# These must not be set unconditionally because not all systems understand
-# e.g. LANG=C (notably SCO).
-# We save the old values to restore during execute mode.
-if test "${LC_ALL+set}" = set; then
- save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
-fi
-if test "${LANG+set}" = set; then
- save_LANG="$LANG"; LANG=C; export LANG
-fi
-
-# Make sure IFS has a sensible default
-: ${IFS=" "}
-
-if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
- echo "$modename: not configured to build any kind of library" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
-fi
-
-# Global variables.
-mode=$default_mode
-nonopt=
-prev=
-prevopt=
-run=
-show="$echo"
-show_help=
-execute_dlfiles=
-lo2o="s/\\.lo\$/.${objext}/"
-o2lo="s/\\.${objext}\$/.lo/"
-
-# Parse our command line options once, thoroughly.
-while test $# -gt 0
-do
- arg="$1"
- shift
-
- case $arg in
- -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
- *) optarg= ;;
- esac
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- execute_dlfiles)
- execute_dlfiles="$execute_dlfiles $arg"
- ;;
- *)
- eval "$prev=\$arg"
- ;;
- esac
-
- prev=
- prevopt=
- continue
- fi
-
- # Have we seen a non-optional argument yet?
- case $arg in
- --help)
- show_help=yes
- ;;
-
- --version)
- echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
- exit 0
- ;;
-
- --config)
- sed -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0
- exit 0
- ;;
-
- --debug)
- echo "$progname: enabling shell trace mode"
- set -x
- ;;
-
- --dry-run | -n)
- run=:
- ;;
-
- --features)
- echo "host: $host"
- if test "$build_libtool_libs" = yes; then
- echo "enable shared libraries"
- else
- echo "disable shared libraries"
- fi
- if test "$build_old_libs" = yes; then
- echo "enable static libraries"
- else
- echo "disable static libraries"
- fi
- exit 0
- ;;
-
- --finish) mode="finish" ;;
-
- --mode) prevopt="--mode" prev=mode ;;
- --mode=*) mode="$optarg" ;;
-
- --quiet | --silent)
- show=:
- ;;
-
- -dlopen)
- prevopt="-dlopen"
- prev=execute_dlfiles
- ;;
-
- -*)
- $echo "$modename: unrecognized option \`$arg'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-
- *)
- nonopt="$arg"
- break
- ;;
- esac
-done
-
-if test -n "$prevopt"; then
- $echo "$modename: option \`$prevopt' requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
-fi
-
-# If this variable is set in any of the actions, the command in it
-# will be execed at the end. This prevents here-documents from being
-# left over by shells.
-exec_cmd=
-
-if test -z "$show_help"; then
-
- # Infer the operation mode.
- if test -z "$mode"; then
- case $nonopt in
- *cc | *++ | gcc* | *-gcc*)
- mode=link
- for arg
- do
- case $arg in
- -c)
- mode=compile
- break
- ;;
- esac
- done
- ;;
- *db | *dbx | *strace | *truss)
- mode=execute
- ;;
- *install*|cp|mv)
- mode=install
- ;;
- *rm)
- mode=uninstall
- ;;
- *)
- # If we have no mode, but dlfiles were specified, then do execute mode.
- test -n "$execute_dlfiles" && mode=execute
-
- # Just use the default operation mode.
- if test -z "$mode"; then
- if test -n "$nonopt"; then
- $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
- else
- $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
- fi
- fi
- ;;
- esac
- fi
-
- # Only execute mode is allowed to have -dlopen flags.
- if test -n "$execute_dlfiles" && test "$mode" != execute; then
- $echo "$modename: unrecognized option \`-dlopen'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Change the help message to a mode-specific one.
- generic_help="$help"
- help="Try \`$modename --help --mode=$mode' for more information."
-
- # These modes are in order of execution frequency so that they run quickly.
- case $mode in
- # libtool compile mode
- compile)
- modename="$modename: compile"
- # Get the compilation command and the source file.
- base_compile=
- prev=
- lastarg=
- srcfile="$nonopt"
- suppress_output=
-
- user_target=no
- for arg
- do
- case $prev in
- "") ;;
- xcompiler)
- # Aesthetically quote the previous argument.
- prev=
- lastarg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
-
- case $arg in
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
-
- # Add the previous argument to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- continue
- ;;
- esac
-
- # Accept any command-line options.
- case $arg in
- -o)
- if test "$user_target" != "no"; then
- $echo "$modename: you cannot specify \`-o' more than once" 1>&2
- exit 1
- fi
- user_target=next
- ;;
-
- -static)
- build_old_libs=yes
- continue
- ;;
-
- -prefer-pic)
- pic_mode=yes
- continue
- ;;
-
- -prefer-non-pic)
- pic_mode=no
- continue
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
- lastarg=
- save_ifs="$IFS"; IFS=','
- for arg in $args; do
- IFS="$save_ifs"
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- lastarg="$lastarg $arg"
- done
- IFS="$save_ifs"
- lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
-
- # Add the arguments to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- continue
- ;;
- esac
-
- case $user_target in
- next)
- # The next one is the -o target name
- user_target=yes
- continue
- ;;
- yes)
- # We got the output file
- user_target=set
- libobj="$arg"
- continue
- ;;
- esac
-
- # Accept the current argument as the source file.
- lastarg="$srcfile"
- srcfile="$arg"
-
- # Aesthetically quote the previous argument.
-
- # Backslashify any backslashes, double quotes, and dollar signs.
- # These are the only characters that are still specially
- # interpreted inside of double-quoted scrings.
- lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
-
- # Double-quote args containing other shell metacharacters.
- # Many Bourne shells cannot handle close brackets correctly
- # in scan sets, so we specify it separately.
- case $lastarg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- lastarg="\"$lastarg\""
- ;;
- esac
-
- # Add the previous argument to base_compile.
- if test -z "$base_compile"; then
- base_compile="$lastarg"
- else
- base_compile="$base_compile $lastarg"
- fi
- done
-
- case $user_target in
- set)
- ;;
- no)
- # Get the name of the library object.
- libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
- ;;
- *)
- $echo "$modename: you must specify a target with \`-o'" 1>&2
- exit 1
- ;;
- esac
-
- # Recognize several different file suffixes.
- # If the user specifies -o file.o, it is replaced with file.lo
- xform='[cCFSfmso]'
- case $libobj in
- *.ada) xform=ada ;;
- *.adb) xform=adb ;;
- *.ads) xform=ads ;;
- *.asm) xform=asm ;;
- *.c++) xform=c++ ;;
- *.cc) xform=cc ;;
- *.cpp) xform=cpp ;;
- *.cxx) xform=cxx ;;
- *.f90) xform=f90 ;;
- *.for) xform=for ;;
- esac
-
- libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
-
- case $libobj in
- *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
- *)
- $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
- exit 1
- ;;
- esac
-
- if test -z "$base_compile"; then
- $echo "$modename: you must specify a compilation command" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Delete any leftover library objects.
- if test "$build_old_libs" = yes; then
- removelist="$obj $libobj"
- else
- removelist="$libobj"
- fi
-
- $run $rm $removelist
- trap "$run $rm $removelist; exit 1" 1 2 15
-
- # On Cygwin there's no "real" PIC flag so we must build both object types
- case $host_os in
- cygwin* | mingw* | pw32* | os2*)
- pic_mode=default
- ;;
- esac
- if test $pic_mode = no && test "$deplibs_check_method" != pass_all; then
- # non-PIC code in shared libraries is not supported
- pic_mode=default
- fi
-
- # Calculate the filename of the output object if compiler does
- # not support -o with -c
- if test "$compiler_c_o" = no; then
- output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
- lockfile="$output_obj.lock"
- removelist="$removelist $output_obj $lockfile"
- trap "$run $rm $removelist; exit 1" 1 2 15
- else
- need_locks=no
- lockfile=
- fi
-
- # Lock this critical section if it is needed
- # We use this script file to make the link, it avoids creating a new file
- if test "$need_locks" = yes; then
- until $run ln "$0" "$lockfile" 2>/dev/null; do
- $show "Waiting for $lockfile to be removed"
- sleep 2
- done
- elif test "$need_locks" = warn; then
- if test -f "$lockfile"; then
- echo "\
-*** ERROR, $lockfile exists and contains:
-`cat $lockfile 2>/dev/null`
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
- echo $srcfile > "$lockfile"
- fi
-
- if test -n "$fix_srcfile_path"; then
- eval srcfile=\"$fix_srcfile_path\"
- fi
-
- # Only build a PIC object if we are building libtool libraries.
- if test "$build_libtool_libs" = yes; then
- # Without this assignment, base_compile gets emptied.
- fbsd_hideous_sh_bug=$base_compile
-
- if test "$pic_mode" != no; then
- # All platforms use -DPIC, to notify preprocessed assembler code.
- command="$base_compile $srcfile $pic_flag -DPIC"
- else
- # Don't build PIC code
- command="$base_compile $srcfile"
- fi
- if test "$build_old_libs" = yes; then
- lo_libobj="$libobj"
- dir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$libobj"; then
- dir="$objdir"
- else
- dir="$dir/$objdir"
- fi
- libobj="$dir/"`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
-
- if test -d "$dir"; then
- $show "$rm $libobj"
- $run $rm $libobj
- else
- $show "$mkdir $dir"
- $run $mkdir $dir
- status=$?
- if test $status -ne 0 && test ! -d $dir; then
- exit $status
- fi
- fi
- fi
- if test "$compiler_o_lo" = yes; then
- output_obj="$libobj"
- command="$command -o $output_obj"
- elif test "$compiler_c_o" = yes; then
- output_obj="$obj"
- command="$command -o $output_obj"
- fi
-
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- test -n "$output_obj" && $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed, then go on to compile the next one
- if test x"$output_obj" != x"$libobj"; then
- $show "$mv $output_obj $libobj"
- if $run $mv $output_obj $libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # If we have no pic_flag, then copy the object into place and finish.
- if (test -z "$pic_flag" || test "$pic_mode" != default) &&
- test "$build_old_libs" = yes; then
- # Rename the .lo from within objdir to obj
- if test -f $obj; then
- $show $rm $obj
- $run $rm $obj
- fi
-
- $show "$mv $libobj $obj"
- if $run $mv $libobj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
-
- xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$obj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$obj" | $Xsed -e "s%.*/%%"`
- libobj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
- # Now arrange that obj and lo_libobj become the same file
- $show "(cd $xdir && $LN_S $baseobj $libobj)"
- if $run eval '(cd $xdir && $LN_S $baseobj $libobj)'; then
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $run $rm "$lockfile"
- fi
- exit 0
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Allow error messages only from the first compilation.
- suppress_output=' >/dev/null 2>&1'
- fi
-
- # Only build a position-dependent object if we build old libraries.
- if test "$build_old_libs" = yes; then
- if test "$pic_mode" != yes; then
- # Don't build PIC code
- command="$base_compile $srcfile"
- else
- # All platforms use -DPIC, to notify preprocessed assembler code.
- command="$base_compile $srcfile $pic_flag -DPIC"
- fi
- if test "$compiler_c_o" = yes; then
- command="$command -o $obj"
- output_obj="$obj"
- fi
-
- # Suppress compiler output if we already did a PIC compilation.
- command="$command$suppress_output"
- $run $rm "$output_obj"
- $show "$command"
- if $run eval "$command"; then :
- else
- $run $rm $removelist
- exit 1
- fi
-
- if test "$need_locks" = warn &&
- test x"`cat $lockfile 2>/dev/null`" != x"$srcfile"; then
- echo "\
-*** ERROR, $lockfile contains:
-`cat $lockfile 2>/dev/null`
-
-but it should contain:
-$srcfile
-
-This indicates that another process is trying to use the same
-temporary object file, and libtool could not work around it because
-your compiler does not support \`-c' and \`-o' together. If you
-repeat this compilation, it may succeed, by chance, but you had better
-avoid parallel builds (make -j) in this platform, or get a better
-compiler."
-
- $run $rm $removelist
- exit 1
- fi
-
- # Just move the object if needed
- if test x"$output_obj" != x"$obj"; then
- $show "$mv $output_obj $obj"
- if $run $mv $output_obj $obj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
-
- # Create an invalid libtool object if no PIC, so that we do not
- # accidentally link it into a program.
- if test "$build_libtool_libs" != yes; then
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > \$libobj" || exit $?
- else
- # Move the .lo from within objdir
- $show "$mv $libobj $lo_libobj"
- if $run $mv $libobj $lo_libobj; then :
- else
- error=$?
- $run $rm $removelist
- exit $error
- fi
- fi
- fi
-
- # Unlock the critical section if it was locked
- if test "$need_locks" != no; then
- $run $rm "$lockfile"
- fi
-
- exit 0
- ;;
-
- # libtool link mode
- link | relink)
- modename="$modename: link"
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # It is impossible to link a dll without this setting, and
- # we shouldn't force the makefile maintainer to figure out
- # which system we are compiling for in order to pass an extra
- # flag for every libtool invokation.
- # allow_undefined=no
-
- # FIXME: Unfortunately, there are problems with the above when trying
- # to make a dll which has undefined symbols, in which case not
- # even a static library is built. For now, we need to specify
- # -no-undefined on the libtool link line when we can be certain
- # that all symbols are satisfied, otherwise we get a static library.
- allow_undefined=yes
- ;;
- *)
- allow_undefined=yes
- ;;
- esac
- libtool_args="$nonopt"
- compile_command="$nonopt"
- finalize_command="$nonopt"
-
- compile_rpath=
- finalize_rpath=
- compile_shlibpath=
- finalize_shlibpath=
- convenience=
- old_convenience=
- deplibs=
- old_deplibs=
- compiler_flags=
- linker_flags=
- dllsearchpath=
- lib_search_path=`pwd`
-
- avoid_version=no
- dlfiles=
- dlprefiles=
- dlself=no
- export_dynamic=no
- export_symbols=
- export_symbols_regex=
- generated=
- libobjs=
- ltlibs=
- module=no
- no_install=no
- objs=
- prefer_static_libs=no
- preload=no
- prev=
- prevarg=
- release=
- rpath=
- xrpath=
- perm_rpath=
- temp_rpath=
- thread_safe=no
- vinfo=
-
- # We need to know -static, to get the right output filenames.
- for arg
- do
- case $arg in
- -all-static | -static)
- if test "X$arg" = "X-all-static"; then
- if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
- $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
- fi
- if test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- else
- if test -z "$pic_flag" && test -n "$link_static_flag"; then
- dlopen_self=$dlopen_self_static
- fi
- fi
- build_libtool_libs=no
- build_old_libs=yes
- prefer_static_libs=yes
- break
- ;;
- esac
- done
-
- # See if our shared archives depend on static archives.
- test -n "$old_archive_from_new_cmds" && build_old_libs=yes
-
- # Go through the arguments, transforming them on the way.
- while test $# -gt 0; do
- arg="$1"
- shift
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
- ;;
- *) qarg=$arg ;;
- esac
- libtool_args="$libtool_args $qarg"
-
- # If the previous option needs an argument, assign it.
- if test -n "$prev"; then
- case $prev in
- output)
- compile_command="$compile_command @OUTPUT@"
- finalize_command="$finalize_command @OUTPUT@"
- ;;
- esac
-
- case $prev in
- dlfiles|dlprefiles)
- if test "$preload" = no; then
- # Add the symbol object into the linking commands.
- compile_command="$compile_command @SYMFILE@"
- finalize_command="$finalize_command @SYMFILE@"
- preload=yes
- fi
- case $arg in
- *.la | *.lo) ;; # We handle these cases below.
- force)
- if test "$dlself" = no; then
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- self)
- if test "$prev" = dlprefiles; then
- dlself=yes
- elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
- dlself=yes
- else
- dlself=needless
- export_dynamic=yes
- fi
- prev=
- continue
- ;;
- *)
- if test "$prev" = dlfiles; then
- dlfiles="$dlfiles $arg"
- else
- dlprefiles="$dlprefiles $arg"
- fi
- prev=
- continue
- ;;
- esac
- ;;
- expsyms)
- export_symbols="$arg"
- if test ! -f "$arg"; then
- $echo "$modename: symbol file \`$arg' does not exist"
- exit 1
- fi
- prev=
- continue
- ;;
- expsyms_regex)
- export_symbols_regex="$arg"
- prev=
- continue
- ;;
- release)
- release="-$arg"
- prev=
- continue
- ;;
- rpath | xrpath)
- # We need an absolute path.
- case $arg in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- if test "$prev" = rpath; then
- case "$rpath " in
- *" $arg "*) ;;
- *) rpath="$rpath $arg" ;;
- esac
- else
- case "$xrpath " in
- *" $arg "*) ;;
- *) xrpath="$xrpath $arg" ;;
- esac
- fi
- prev=
- continue
- ;;
- xcompiler)
- compiler_flags="$compiler_flags $qarg"
- prev=
- compile_command="$compile_command $qarg"
- finalize_command="$finalize_command $qarg"
- continue
- ;;
- xlinker)
- linker_flags="$linker_flags $qarg"
- compiler_flags="$compiler_flags $wl$qarg"
- prev=
- compile_command="$compile_command $wl$qarg"
- finalize_command="$finalize_command $wl$qarg"
- continue
- ;;
- *)
- eval "$prev=\"\$arg\""
- prev=
- continue
- ;;
- esac
- fi # test -n $prev
-
- prevarg="$arg"
-
- case $arg in
- -all-static)
- if test -n "$link_static_flag"; then
- compile_command="$compile_command $link_static_flag"
- finalize_command="$finalize_command $link_static_flag"
- fi
- continue
- ;;
-
- -allow-undefined)
- # FIXME: remove this flag sometime in the future.
- $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
- continue
- ;;
-
- -avoid-version)
- avoid_version=yes
- continue
- ;;
-
- -dlopen)
- prev=dlfiles
- continue
- ;;
-
- -dlpreopen)
- prev=dlprefiles
- continue
- ;;
-
- -export-dynamic)
- export_dynamic=yes
- continue
- ;;
-
- -export-symbols | -export-symbols-regex)
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: more than one -exported-symbols argument is not allowed"
- exit 1
- fi
- if test "X$arg" = "X-export-symbols"; then
- prev=expsyms
- else
- prev=expsyms_regex
- fi
- continue
- ;;
-
- # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
- # so, if we see these flags be careful not to treat them like -L
- -L[A-Z][A-Z]*:*)
- case $with_gcc/$host in
- no/*-*-irix*)
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- ;;
- esac
- continue
- ;;
-
- -L*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
- exit 1
- fi
- dir="$absdir"
- ;;
- esac
- case "$deplibs " in
- *" -L$dir "*) ;;
- *)
- deplibs="$deplibs -L$dir"
- lib_search_path="$lib_search_path $dir"
- ;;
- esac
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- case :$dllsearchpath: in
- *":$dir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$dir";;
- esac
- ;;
- esac
- continue
- ;;
-
- -l*)
- if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
- case $host in
- *-*-cygwin* | *-*-pw32* | *-*-beos*)
- # These systems don't actually have a C or math library (as such)
- continue
- ;;
- *-*-mingw* | *-*-os2*)
- # These systems don't actually have a C library (as such)
- test "X$arg" = "X-lc" && continue
- ;;
- *-*-openbsd*)
- # Do not include libc due to us having libc/libc_r.
- test "X$arg" = "X-lc" && continue
- ;;
- esac
- elif test "X$arg" = "X-lc_r"; then
- case $host in
- *-*-openbsd*)
- # Do not include libc_r directly, use -pthread flag.
- continue
- ;;
- esac
- fi
- deplibs="$deplibs $arg"
- continue
- ;;
-
- -module)
- module=yes
- continue
- ;;
-
- -no-fast-install)
- fast_install=no
- continue
- ;;
-
- -no-install)
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- # The PATH hackery in wrapper scripts is required on Windows
- # in order for the loader to find any dlls it needs.
- $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
- $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
- fast_install=no
- ;;
- *) no_install=yes ;;
- esac
- continue
- ;;
-
- -no-undefined)
- allow_undefined=no
- continue
- ;;
-
- -o) prev=output ;;
-
- -release)
- prev=release
- continue
- ;;
-
- -rpath)
- prev=rpath
- continue
- ;;
-
- -R)
- prev=xrpath
- continue
- ;;
-
- -R*)
- dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- $echo "$modename: only absolute run-paths are allowed" 1>&2
- exit 1
- ;;
- esac
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- continue
- ;;
-
- -static)
- # The effects of -static are defined in a previous loop.
- # We used to do the same as -all-static on platforms that
- # didn't have a PIC flag, but the assumption that the effects
- # would be equivalent was wrong. It would break on at least
- # Digital Unix and AIX.
- continue
- ;;
-
- -thread-safe)
- thread_safe=yes
- continue
- ;;
-
- -version-info)
- prev=vinfo
- continue
- ;;
-
- -Wc,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Wl,*)
- args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
- arg=
- save_ifs="$IFS"; IFS=','
- for flag in $args; do
- IFS="$save_ifs"
- case $flag in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- flag="\"$flag\""
- ;;
- esac
- arg="$arg $wl$flag"
- compiler_flags="$compiler_flags $wl$flag"
- linker_flags="$linker_flags $flag"
- done
- IFS="$save_ifs"
- arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
- ;;
-
- -Xcompiler)
- prev=xcompiler
- continue
- ;;
-
- -Xlinker)
- prev=xlinker
- continue
- ;;
-
- # Some other compiler flag.
- -* | +*)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
-
- *.lo | *.$objext)
- # A library or standard object.
- if test "$prev" = dlfiles; then
- # This file was specified with -dlopen.
- if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
- dlfiles="$dlfiles $arg"
- prev=
- continue
- else
- # If libtool objects are unsupported, then we need to preload.
- prev=dlprefiles
- fi
- fi
-
- if test "$prev" = dlprefiles; then
- # Preload the old-style object.
- dlprefiles="$dlprefiles "`$echo "X$arg" | $Xsed -e "$lo2o"`
- prev=
- else
- case $arg in
- *.lo) libobjs="$libobjs $arg" ;;
- *) objs="$objs $arg" ;;
- esac
- fi
- ;;
-
- *.$libext)
- # An archive.
- deplibs="$deplibs $arg"
- old_deplibs="$old_deplibs $arg"
- continue
- ;;
-
- *.la)
- # A libtool-controlled library.
-
- if test "$prev" = dlfiles; then
- # This library was specified with -dlopen.
- dlfiles="$dlfiles $arg"
- prev=
- elif test "$prev" = dlprefiles; then
- # The library was specified with -dlpreopen.
- dlprefiles="$dlprefiles $arg"
- prev=
- else
- deplibs="$deplibs $arg"
- fi
- continue
- ;;
-
- # Some other compiler argument.
- *)
- # Unknown arguments in both finalize_command and compile_command need
- # to be aesthetically quoted because they are evaled later.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
- arg="\"$arg\""
- ;;
- esac
- ;;
- esac # arg
-
- # Now actually substitute the argument into the commands.
- if test -n "$arg"; then
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
- done # argument parsing loop
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
- eval arg=\"$export_dynamic_flag_spec\"
- compile_command="$compile_command $arg"
- finalize_command="$finalize_command $arg"
- fi
-
- # calculate the name of the file, without its directory
- outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
- libobjs_save="$libobjs"
-
- if test -n "$shlibpath_var"; then
- # get the directories listed in $shlibpath_var
- eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
- else
- shlib_search_path=
- fi
- eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
- eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
-
- output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$output_objdir" = "X$output"; then
- output_objdir="$objdir"
- else
- output_objdir="$output_objdir/$objdir"
- fi
- # Create the object directory.
- if test ! -d $output_objdir; then
- $show "$mkdir $output_objdir"
- $run $mkdir $output_objdir
- status=$?
- if test $status -ne 0 && test ! -d $output_objdir; then
- exit $status
- fi
- fi
-
- # Determine the type of output
- case $output in
- "")
- $echo "$modename: you must specify an output file" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- *.$libext) linkmode=oldlib ;;
- *.lo | *.$objext) linkmode=obj ;;
- *.la) linkmode=lib ;;
- *) linkmode=prog ;; # Anything else should be a program.
- esac
-
- specialdeplibs=
- libs=
- # Find all interdependent deplibs by searching for libraries
- # that are linked more than once (e.g. -la -lb -la)
- for deplib in $deplibs; do
- case "$libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- libs="$libs $deplib"
- done
- deplibs=
- newdependency_libs=
- newlib_search_path=
- need_relink=no # whether we're linking any uninstalled libtool libraries
- notinst_deplibs= # not-installed libtool libraries
- notinst_path= # paths that contain not-installed libtool libraries
- case $linkmode in
- lib)
- passes="conv link"
- for file in $dlfiles $dlprefiles; do
- case $file in
- *.la) ;;
- *)
- $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
- exit 1
- ;;
- esac
- done
- ;;
- prog)
- compile_deplibs=
- finalize_deplibs=
- alldeplibs=no
- newdlfiles=
- newdlprefiles=
- passes="conv scan dlopen dlpreopen link"
- ;;
- *) passes="conv"
- ;;
- esac
- for pass in $passes; do
- if test $linkmode = prog; then
- # Determine which files to process
- case $pass in
- dlopen)
- libs="$dlfiles"
- save_deplibs="$deplibs" # Collect dlpreopened libraries
- deplibs=
- ;;
- dlpreopen) libs="$dlprefiles" ;;
- link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
- esac
- fi
- for deplib in $libs; do
- lib=
- found=no
- case $deplib in
- -l*)
- if test $linkmode = oldlib && test $linkmode = obj; then
- $echo "$modename: warning: \`-l' is ignored for archives/objects: $deplib" 1>&2
- continue
- fi
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
- for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
- # Search the libtool library
- lib="$searchdir/lib${name}.la"
- if test -f "$lib"; then
- found=yes
- break
- fi
- done
- if test "$found" != yes; then
- # deplib doesn't seem to be a libtool library
- if test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- deplibs="$deplib $deplibs"
- test $linkmode = lib && newdependency_libs="$deplib $newdependency_libs"
- fi
- continue
- fi
- ;; # -l
- -L*)
- case $linkmode in
- lib)
- deplibs="$deplib $deplibs"
- test $pass = conv && continue
- newdependency_libs="$deplib $newdependency_libs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- ;;
- prog)
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- if test $pass = scan; then
- deplibs="$deplib $deplibs"
- newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- ;;
- *)
- $echo "$modename: warning: \`-L' is ignored for archives/objects: $deplib" 1>&2
- ;;
- esac # linkmode
- continue
- ;; # -L
- -R*)
- if test $pass = link; then
- dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
- # Make sure the xrpath contains only unique directories.
- case "$xrpath " in
- *" $dir "*) ;;
- *) xrpath="$xrpath $dir" ;;
- esac
- fi
- deplibs="$deplib $deplibs"
- continue
- ;;
- *.la) lib="$deplib" ;;
- *.$libext)
- if test $pass = conv; then
- deplibs="$deplib $deplibs"
- continue
- fi
- case $linkmode in
- lib)
- if test "$deplibs_check_method" != pass_all; then
- echo
- echo "*** Warning: This library needs some functionality provided by $deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- else
- echo
- echo "*** Warning: Linking the shared library $output against the"
- echo "*** static library $deplib is not portable!"
- deplibs="$deplib $deplibs"
- fi
- continue
- ;;
- prog)
- if test $pass != link; then
- deplibs="$deplib $deplibs"
- else
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- fi
- continue
- ;;
- esac # linkmode
- ;; # *.$libext
- *.lo | *.$objext)
- if test $pass = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlopen support or we're linking statically,
- # we need to preload.
- newdlprefiles="$newdlprefiles $deplib"
- compile_deplibs="$deplib $compile_deplibs"
- finalize_deplibs="$deplib $finalize_deplibs"
- else
- newdlfiles="$newdlfiles $deplib"
- fi
- continue
- ;;
- %DEPLIBS%)
- alldeplibs=yes
- continue
- ;;
- esac # case $deplib
- if test $found = yes || test -f "$lib"; then :
- else
- $echo "$modename: cannot find the library \`$lib'" 1>&2
- exit 1
- fi
-
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $lib | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
-
- ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$ladir" = "X$lib" && ladir="."
-
- dlname=
- dlopen=
- dlpreopen=
- libdir=
- library_names=
- old_library=
- # If the library was installed with an old release of libtool,
- # it will not redefine variable installed.
- installed=yes
-
- # Read the .la file
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
-
- if test "$linkmode,$pass" = "lib,link" ||
- test "$linkmode,$pass" = "prog,scan" ||
- { test $linkmode = oldlib && test $linkmode = obj; }; then
- # Add dl[pre]opened files of deplib
- test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
- test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
- fi
-
- if test $pass = conv; then
- # Only check for convenience libraries
- deplibs="$lib $deplibs"
- if test -z "$libdir"; then
- if test -z "$old_library"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
- fi
- # It is a libtool convenience library, so add in its objects.
- convenience="$convenience $ladir/$objdir/$old_library"
- old_convenience="$old_convenience $ladir/$objdir/$old_library"
- tmp_libs=
- for deplib in $dependency_libs; do
- deplibs="$deplib $deplibs"
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done
- elif test $linkmode != prog && test $linkmode != lib; then
- $echo "$modename: \`$lib' is not a convenience library" 1>&2
- exit 1
- fi
- continue
- fi # $pass = conv
-
- # Get the name of the library we link against.
- linklib=
- for l in $old_library $library_names; do
- linklib="$l"
- done
- if test -z "$linklib"; then
- $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
- exit 1
- fi
-
- # This library was specified with -dlopen.
- if test $pass = dlopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
- exit 1
- fi
- if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
- # If there is no dlname, no dlopen support or we're linking
- # statically, we need to preload.
- dlprefiles="$dlprefiles $lib"
- else
- newdlfiles="$newdlfiles $lib"
- fi
- continue
- fi # $pass = dlopen
-
- # We need an absolute path.
- case $ladir in
- [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
- *)
- abs_ladir=`cd "$ladir" && pwd`
- if test -z "$abs_ladir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
- $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
- abs_ladir="$ladir"
- fi
- ;;
- esac
- laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
-
- # Find the relevant object directory and library name.
- if test "X$installed" = Xyes; then
- if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
- $echo "$modename: warning: library \`$lib' was moved." 1>&2
- dir="$ladir"
- absdir="$abs_ladir"
- libdir="$abs_ladir"
- else
- dir="$libdir"
- absdir="$libdir"
- fi
- else
- dir="$ladir/$objdir"
- absdir="$abs_ladir/$objdir"
- # Remove this search path later
- notinst_path="$notinst_path $abs_ladir"
- fi # $installed = yes
- name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
-
- # This library was specified with -dlpreopen.
- if test $pass = dlpreopen; then
- if test -z "$libdir"; then
- $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
- exit 1
- fi
- # Prefer using a static library (so that no silly _DYNAMIC symbols
- # are required to link).
- if test -n "$old_library"; then
- newdlprefiles="$newdlprefiles $dir/$old_library"
- # Otherwise, use the dlname, so that lt_dlopen finds it.
- elif test -n "$dlname"; then
- newdlprefiles="$newdlprefiles $dir/$dlname"
- else
- newdlprefiles="$newdlprefiles $dir/$linklib"
- fi
- fi # $pass = dlpreopen
-
- if test -z "$libdir"; then
- # Link the convenience library
- if test $linkmode = lib; then
- deplibs="$dir/$old_library $deplibs"
- elif test "$linkmode,$pass" = "prog,link"; then
- compile_deplibs="$dir/$old_library $compile_deplibs"
- finalize_deplibs="$dir/$old_library $finalize_deplibs"
- else
- deplibs="$lib $deplibs"
- fi
- continue
- fi
-
- if test $linkmode = prog && test $pass != link; then
- newlib_search_path="$newlib_search_path $ladir"
- deplibs="$lib $deplibs"
-
- linkalldeplibs=no
- if test "$link_all_deplibs" != no || test -z "$library_names" ||
- test "$build_libtool_libs" = no; then
- linkalldeplibs=yes
- fi
-
- tmp_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
- esac
- # Need to link against all dependency_libs?
- if test $linkalldeplibs = yes; then
- deplibs="$deplib $deplibs"
- else
- # Need to hardcode shared library paths
- # or/and link against static libraries
- newdependency_libs="$deplib $newdependency_libs"
- fi
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done # for deplib
- continue
- fi # $linkmode = prog...
-
- link_static=no # Whether the deplib will be linked statically
- if test -n "$library_names" &&
- { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
- # Link against this shared library
-
- if test "$linkmode,$pass" = "prog,link" ||
- { test $linkmode = lib && test $hardcode_into_libs = yes; }; then
- # Hardcode the library path.
- # Skip directories that are in the system default run-time
- # search path.
- case " $sys_lib_dlsearch_path " in
- *" $absdir "*) ;;
- *)
- case "$compile_rpath " in
- *" $absdir "*) ;;
- *) compile_rpath="$compile_rpath $absdir"
- esac
- ;;
- esac
- case " $sys_lib_dlsearch_path " in
- *" $libdir "*) ;;
- *)
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir"
- esac
- ;;
- esac
- if test $linkmode = prog; then
- # We need to hardcode the library path
- if test -n "$shlibpath_var"; then
- # Make sure the rpath contains only unique directories.
- case "$temp_rpath " in
- *" $dir "*) ;;
- *" $absdir "*) ;;
- *) temp_rpath="$temp_rpath $dir" ;;
- esac
- fi
- fi
- fi # $linkmode,$pass = prog,link...
-
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
- test -n "$library_names"; }; }; then
- # We only need to search for static libraries
- continue
- fi
-
- if test "$installed" = no; then
- notinst_deplibs="$notinst_deplibs $lib"
- need_relink=yes
- fi
-
- if test -n "$old_archive_from_expsyms_cmds"; then
- # figure out the soname
- set dummy $library_names
- realname="$2"
- shift; shift
- libname=`eval \\$echo \"$libname_spec\"`
- # use dlname if we got it. it's perfectly good, no?
- if test -n "$dlname"; then
- soname="$dlname"
- elif test -n "$soname_spec"; then
- # bleh windows
- case $host in
- *cygwin*)
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
- esac
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
-
- # Make a new name for the extract_expsyms_cmds to use
- soroot="$soname"
- soname=`echo $soroot | sed -e 's/^.*\///'`
- newlib="libimp-`echo $soname | sed 's/^lib//;s/\.dll$//'`.a"
-
- # If the library has no export list, then create one now
- if test -f "$output_objdir/$soname-def"; then :
- else
- $show "extracting exported symbol list from \`$soname'"
- save_ifs="$IFS"; IFS='~'
- eval cmds=\"$extract_expsyms_cmds\"
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Create $newlib
- if test -f "$output_objdir/$newlib"; then :; else
- $show "generating import library for \`$soname'"
- save_ifs="$IFS"; IFS='~'
- eval cmds=\"$old_archive_from_expsyms_cmds\"
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
- # make sure the library variables are pointing to the new library
- dir=$output_objdir
- linklib=$newlib
- fi # test -n $old_archive_from_expsyms_cmds
-
- if test $linkmode = prog || test "$mode" != relink; then
- add_shlibpath=
- add_dir=
- add=
- lib_linked=yes
- case $hardcode_action in
- immediate | unsupported)
- if test "$hardcode_direct" = no; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = no; then
- case $host in
- *-*-sunos*) add_shlibpath="$dir" ;;
- esac
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = no; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- relink)
- if test "$hardcode_direct" = yes; then
- add="$dir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$dir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- add_shlibpath="$dir"
- add="-l$name"
- else
- lib_linked=no
- fi
- ;;
- *) lib_linked=no ;;
- esac
-
- if test "$lib_linked" != yes; then
- $echo "$modename: configuration error: unsupported hardcode properties"
- exit 1
- fi
-
- if test -n "$add_shlibpath"; then
- case :$compile_shlibpath: in
- *":$add_shlibpath:"*) ;;
- *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
- esac
- fi
- if test $linkmode = prog; then
- test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
- test -n "$add" && compile_deplibs="$add $compile_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- if test "$hardcode_direct" != yes && \
- test "$hardcode_minus_L" != yes && \
- test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- fi
- fi
- fi
-
- if test $linkmode = prog || test "$mode" = relink; then
- add_shlibpath=
- add_dir=
- add=
- # Finalize command for both is simple: just hardcode it.
- if test "$hardcode_direct" = yes; then
- add="$libdir/$linklib"
- elif test "$hardcode_minus_L" = yes; then
- add_dir="-L$libdir"
- add="-l$name"
- elif test "$hardcode_shlibpath_var" = yes; then
- case :$finalize_shlibpath: in
- *":$libdir:"*) ;;
- *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
- esac
- add="-l$name"
- else
- # We cannot seem to hardcode it, guess we'll fake it.
- add_dir="-L$libdir"
- add="-l$name"
- fi
-
- if test $linkmode = prog; then
- test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
- test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
- else
- test -n "$add_dir" && deplibs="$add_dir $deplibs"
- test -n "$add" && deplibs="$add $deplibs"
- fi
- fi
- elif test $linkmode = prog; then
- if test "$alldeplibs" = yes &&
- { test "$deplibs_check_method" = pass_all ||
- { test "$build_libtool_libs" = yes &&
- test -n "$library_names"; }; }; then
- # We only need to search for static libraries
- continue
- fi
-
- # Try to link the static library
- # Here we assume that one of hardcode_direct or hardcode_minus_L
- # is not unsupported. This is valid on all known static and
- # shared platforms.
- if test "$hardcode_direct" != unsupported; then
- test -n "$old_library" && linklib="$old_library"
- compile_deplibs="$dir/$linklib $compile_deplibs"
- finalize_deplibs="$dir/$linklib $finalize_deplibs"
- else
- compile_deplibs="-l$name -L$dir $compile_deplibs"
- finalize_deplibs="-l$name -L$dir $finalize_deplibs"
- fi
- elif test "$build_libtool_libs" = yes; then
- # Not a shared library
- if test "$deplibs_check_method" != pass_all; then
- # We're trying link a shared library against a static one
- # but the system doesn't support it.
-
- # Just print a warning and add the library to dependency_libs so
- # that the program can be linked against the static library.
- echo
- echo "*** Warning: This library needs some functionality provided by $lib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- if test "$module" = yes; then
- echo "*** Therefore, libtool will create a static module, that should work "
- echo "*** as long as the dlopening application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- else
- convenience="$convenience $dir/$old_library"
- old_convenience="$old_convenience $dir/$old_library"
- deplibs="$dir/$old_library $deplibs"
- link_static=yes
- fi
- fi # link shared/static library?
-
- if test $linkmode = lib; then
- if test -n "$dependency_libs" &&
- { test $hardcode_into_libs != yes || test $build_old_libs = yes ||
- test $link_static = yes; }; then
- # Extract -R from dependency_libs
- temp_deplibs=
- for libdir in $dependency_libs; do
- case $libdir in
- -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
- case " $xrpath " in
- *" $temp_xrpath "*) ;;
- *) xrpath="$xrpath $temp_xrpath";;
- esac;;
- *) temp_deplibs="$temp_deplibs $libdir";;
- esac
- done
- dependency_libs="$temp_deplibs"
- fi
-
- newlib_search_path="$newlib_search_path $absdir"
- # Link against this library
- test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
- # ... and its dependency_libs
- tmp_libs=
- for deplib in $dependency_libs; do
- newdependency_libs="$deplib $newdependency_libs"
- case "$tmp_libs " in
- *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
- esac
- tmp_libs="$tmp_libs $deplib"
- done
-
- if test $link_all_deplibs != no; then
- # Add the search paths of all dependency libraries
- for deplib in $dependency_libs; do
- case $deplib in
- -L*) path="$deplib" ;;
- *.la)
- dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$deplib" && dir="."
- # We need an absolute path.
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
- *)
- absdir=`cd "$dir" && pwd`
- if test -z "$absdir"; then
- $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
- absdir="$dir"
- fi
- ;;
- esac
- if grep "^installed=no" $deplib > /dev/null; then
- path="-L$absdir/$objdir"
- else
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- if test "$absdir" != "$libdir"; then
- $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
- fi
- path="-L$absdir"
- fi
- ;;
- *) continue ;;
- esac
- case " $deplibs " in
- *" $path "*) ;;
- *) deplibs="$deplibs $path" ;;
- esac
- done
- fi # link_all_deplibs != no
- fi # linkmode = lib
- done # for deplib in $libs
- if test $pass = dlpreopen; then
- # Link the dlpreopened libraries before other libraries
- for deplib in $save_deplibs; do
- deplibs="$deplib $deplibs"
- done
- fi
- if test $pass != dlopen; then
- test $pass != scan && dependency_libs="$newdependency_libs"
- if test $pass != conv; then
- # Make sure lib_search_path contains only unique directories.
- lib_search_path=
- for dir in $newlib_search_path; do
- case "$lib_search_path " in
- *" $dir "*) ;;
- *) lib_search_path="$lib_search_path $dir" ;;
- esac
- done
- newlib_search_path=
- fi
-
- if test "$linkmode,$pass" != "prog,link"; then
- vars="deplibs"
- else
- vars="compile_deplibs finalize_deplibs"
- fi
- for var in $vars dependency_libs; do
- # Add libraries to $var in reverse order
- eval tmp_libs=\"\$$var\"
- new_libs=
- for deplib in $tmp_libs; do
- case $deplib in
- -L*) new_libs="$deplib $new_libs" ;;
- *)
- case " $specialdeplibs " in
- *" $deplib "*) new_libs="$deplib $new_libs" ;;
- *)
- case " $new_libs " in
- *" $deplib "*) ;;
- *) new_libs="$deplib $new_libs" ;;
- esac
- ;;
- esac
- ;;
- esac
- done
- tmp_libs=
- for deplib in $new_libs; do
- case $deplib in
- -L*)
- case " $tmp_libs " in
- *" $deplib "*) ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- ;;
- *) tmp_libs="$tmp_libs $deplib" ;;
- esac
- done
- eval $var=\"$tmp_libs\"
- done # for var
- fi
- if test "$pass" = "conv" &&
- { test "$linkmode" = "lib" || test "$linkmode" = "prog"; }; then
- libs="$deplibs" # reset libs
- deplibs=
- fi
- done # for pass
- if test $linkmode = prog; then
- dlfiles="$newdlfiles"
- dlprefiles="$newdlprefiles"
- fi
-
- case $linkmode in
- oldlib)
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for archives" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
- fi
-
- if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
- $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
- fi
-
- # Now set the variables for building old libraries.
- build_libtool_libs=no
- oldlibs="$output"
- objs="$objs$old_deplibs"
- ;;
-
- lib)
- # Make sure we only generate libraries of the form `libNAME.la'.
- case $outputname in
- lib*)
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
- eval libname=\"$libname_spec\"
- ;;
- *)
- if test "$module" = no; then
- $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- if test "$need_lib_prefix" != no; then
- # Add the "lib" prefix for modules if required
- name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- eval libname=\"$libname_spec\"
- else
- libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
- fi
- ;;
- esac
-
- if test -n "$objs"; then
- if test "$deplibs_check_method" != pass_all; then
- $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
- exit 1
- else
- echo
- echo "*** Warning: Linking the shared library $output against the non-libtool"
- echo "*** objects $objs is not portable!"
- libobjs="$libobjs $objs"
- fi
- fi
-
- if test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
- fi
-
- set dummy $rpath
- if test $# -gt 2; then
- $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
- fi
- install_libdir="$2"
-
- oldlibs=
- if test -z "$rpath"; then
- if test "$build_libtool_libs" = yes; then
- # Building a libtool convenience library.
- libext=al
- oldlibs="$output_objdir/$libname.$libext $oldlibs"
- build_libtool_libs=convenience
- build_old_libs=yes
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for convenience libraries" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
- fi
- else
-
- # Parse the version information argument.
- save_ifs="$IFS"; IFS=':'
- set dummy $vinfo 0 0 0
- IFS="$save_ifs"
-
- if test -n "$8"; then
- $echo "$modename: too many parameters to \`-version-info'" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- current="$2"
- revision="$3"
- age="$4"
-
- # Check that each of the things are valid numbers.
- case $current in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case $revision in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- case $age in
- 0 | [1-9] | [1-9][0-9] | [1-9][0-9][0-9]) ;;
- *)
- $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- ;;
- esac
-
- if test $age -gt $current; then
- $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
- $echo "$modename: \`$vinfo' is not valid version information" 1>&2
- exit 1
- fi
-
- # Calculate the version variables.
- major=
- versuffix=
- verstring=
- case $version_type in
- none) ;;
-
- darwin)
- # Like Linux, but with the current version available in
- # verstring for coding it into the library header
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- # Darwin ld doesn't like 0 for these options...
- minor_current=`expr $current + 1`
- verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
- ;;
-
- freebsd-aout)
- major=".$current"
- versuffix=".$current.$revision";
- ;;
-
- freebsd-elf)
- major=".$current"
- versuffix=".$current";
- ;;
-
- irix)
- major=`expr $current - $age + 1`
- verstring="sgi$major.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$revision
- while test $loop != 0; do
- iface=`expr $revision - $loop`
- loop=`expr $loop - 1`
- verstring="sgi$major.$iface:$verstring"
- done
-
- # Before this point, $major must not contain `.'.
- major=.$major
- versuffix="$major.$revision"
- ;;
-
- linux)
- major=.`expr $current - $age`
- versuffix="$major.$age.$revision"
- ;;
-
- osf)
- major=`expr $current - $age`
- versuffix=".$current.$age.$revision"
- verstring="$current.$age.$revision"
-
- # Add in all the interfaces that we are compatible with.
- loop=$age
- while test $loop != 0; do
- iface=`expr $current - $loop`
- loop=`expr $loop - 1`
- verstring="$verstring:${iface}.0"
- done
-
- # Make executables depend on our current version.
- verstring="$verstring:${current}.0"
- ;;
-
- sunos)
- major=".$current"
- versuffix=".$current.$revision"
- ;;
-
- windows)
- # Use '-' rather than '.', since we only want one
- # extension on DOS 8.3 filesystems.
- major=`expr $current - $age`
- versuffix="-$major"
- ;;
-
- *)
- $echo "$modename: unknown library version type \`$version_type'" 1>&2
- echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
- exit 1
- ;;
- esac
-
- # Clear the version info if we defaulted, and they specified a release.
- if test -z "$vinfo" && test -n "$release"; then
- major=
- verstring="0.0"
- case $version_type in
- darwin)
- # we can't check for "0.0" in archive_cmds due to quoting
- # problems, so we reset it completely
- verstring=""
- ;;
- *)
- verstring="0.0"
- ;;
- esac
- if test "$need_version" = no; then
- versuffix=
- else
- versuffix=".0.0"
- fi
- fi
-
- # Remove version info from name if versioning should be avoided
- if test "$avoid_version" = yes && test "$need_version" = no; then
- major=
- versuffix=
- verstring=""
- fi
-
- # Check to see if the archive will have undefined symbols.
- if test "$allow_undefined" = yes; then
- if test "$allow_undefined_flag" = unsupported; then
- $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
- build_libtool_libs=no
- build_old_libs=yes
- fi
- else
- # Don't allow undefined symbols.
- allow_undefined_flag="$no_undefined_flag"
- fi
- fi
-
- if test "$mode" != relink; then
- # Remove our outputs.
- $show "${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*"
- $run ${rm}r $output_objdir/$outputname $output_objdir/$libname.* $output_objdir/${libname}${release}.*
- fi
-
- # Now set the variables for building old libraries.
- if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
- oldlibs="$oldlibs $output_objdir/$libname.$libext"
-
- # Transform .lo files to .o files.
- oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
- fi
-
- # Eliminate all temporary directories.
- for path in $notinst_path; do
- lib_search_path=`echo "$lib_search_path " | sed -e 's% $path % %g'`
- deplibs=`echo "$deplibs " | sed -e 's% -L$path % %g'`
- dependency_libs=`echo "$dependency_libs " | sed -e 's% -L$path % %g'`
- done
-
- if test -n "$xrpath"; then
- # If the user specified any rpath flags, then add them.
- temp_xrpath=
- for libdir in $xrpath; do
- temp_xrpath="$temp_xrpath -R$libdir"
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- if test $hardcode_into_libs != yes || test $build_old_libs = yes; then
- dependency_libs="$temp_xrpath $dependency_libs"
- fi
- fi
-
- # Make sure dlfiles contains only unique files that won't be dlpreopened
- old_dlfiles="$dlfiles"
- dlfiles=
- for lib in $old_dlfiles; do
- case " $dlprefiles $dlfiles " in
- *" $lib "*) ;;
- *) dlfiles="$dlfiles $lib" ;;
- esac
- done
-
- # Make sure dlprefiles contains only unique files
- old_dlprefiles="$dlprefiles"
- dlprefiles=
- for lib in $old_dlprefiles; do
- case "$dlprefiles " in
- *" $lib "*) ;;
- *) dlprefiles="$dlprefiles $lib" ;;
- esac
- done
-
- if test "$build_libtool_libs" = yes; then
- if test -n "$rpath"; then
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
- # these systems don't actually have a c library (as such)!
- ;;
- *-*-rhapsody* | *-*-darwin1.[012])
- # Rhapsody C library is in the System framework
- deplibs="$deplibs -framework System"
- ;;
- *-*-netbsd*)
- # Don't link with libc until the a.out ld.so is fixed.
- ;;
- *-*-openbsd*)
- # Do not include libc due to us having libc/libc_r.
- ;;
- *)
- # Add libc to deplibs on all other systems if necessary.
- if test $build_libtool_need_lc = "yes"; then
- deplibs="$deplibs -lc"
- fi
- ;;
- esac
- fi
-
- # Transform deplibs into only deplibs that can be linked in shared.
- name_save=$name
- libname_save=$libname
- release_save=$release
- versuffix_save=$versuffix
- major_save=$major
- # I'm not sure if I'm treating the release correctly. I think
- # release should show up in the -l (ie -lgmp5) so we don't want to
- # add it in twice. Is that correct?
- release=""
- versuffix=""
- major=""
- newdeplibs=
- droppeddeps=no
- case $deplibs_check_method in
- pass_all)
- # Don't check for shared/static. Everything works.
- # This might be a little naive. We might want to check
- # whether the library exists or not. But this is on
- # osf3 & osf4 and I'm not really sure... Just
- # implementing what was already the behaviour.
- newdeplibs=$deplibs
- ;;
- test_compile)
- # This code stresses the "libraries are programs" paradigm to its
- # limits. Maybe even breaks it. We compile a program, linking it
- # against the deplibs as a proxy for the library. Then we can check
- # whether they linked in statically or dynamically with ldd.
- $rm conftest.c
- cat > conftest.c <<EOF
- int main() { return 0; }
-EOF
- $rm conftest
- $CC -o conftest conftest.c $deplibs
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- else
- # Error occured in the first compile. Let's try to salvage the situation:
- # Compile a seperate program for each library.
- for i in $deplibs; do
- name="`expr $i : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- $rm conftest
- $CC -o conftest conftest.c $i
- # Did it work?
- if test $? -eq 0 ; then
- ldd_output=`ldd conftest`
- libname=`eval \\$echo \"$libname_spec\"`
- deplib_matches=`eval \\$echo \"$library_names_spec\"`
- set dummy $deplib_matches
- deplib_match=$2
- if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
- newdeplibs="$newdeplibs $i"
- else
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $i."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- droppeddeps=yes
- echo
- echo "*** Warning! Library $i is needed by this library but I was not able to"
- echo "*** make it link in! You will probably need to install it or some"
- echo "*** library that it depends on before this library will be fully"
- echo "*** functional. Installing it before continuing would be even better."
- fi
- else
- newdeplibs="$newdeplibs $i"
- fi
- done
- fi
- ;;
- file_magic*)
- set dummy $deplibs_check_method
- file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- # Follow soft links.
- if ls -lLd "$potent_lib" 2>/dev/null \
- | grep " -> " >/dev/null; then
- continue
- fi
- # The statement above tries to avoid entering an
- # endless loop below, in case of cyclic links.
- # We might still enter an endless loop, since a link
- # loop can be closed while we follow links,
- # but so what?
- potlib="$potent_lib"
- while test -h "$potlib" 2>/dev/null; do
- potliblink=`ls -ld $potlib | sed 's/.* -> //'`
- case $potliblink in
- [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
- *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
- esac
- done
- if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
- | sed 10q \
- | egrep "$file_magic_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- match_pattern*)
- set dummy $deplibs_check_method
- match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
- for a_deplib in $deplibs; do
- name="`expr $a_deplib : '-l\(.*\)'`"
- # If $name is empty we are operating on a -L argument.
- if test -n "$name" && test "$name" != "0"; then
- libname=`eval \\$echo \"$libname_spec\"`
- for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
- potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
- for potent_lib in $potential_libs; do
- if eval echo \"$potent_lib\" 2>/dev/null \
- | sed 10q \
- | egrep "$match_pattern_regex" > /dev/null; then
- newdeplibs="$newdeplibs $a_deplib"
- a_deplib=""
- break 2
- fi
- done
- done
- if test -n "$a_deplib" ; then
- droppeddeps=yes
- echo
- echo "*** Warning: This library needs some functionality provided by $a_deplib."
- echo "*** I have the capability to make that library automatically link in when"
- echo "*** you link to this library. But I can only do this if you have a"
- echo "*** shared version of the library, which you do not appear to have."
- fi
- else
- # Add a -L argument.
- newdeplibs="$newdeplibs $a_deplib"
- fi
- done # Gone through all deplibs.
- ;;
- none | unknown | *)
- newdeplibs=""
- if $echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
- -e 's/ -[LR][^ ]*//g' -e 's/[ ]//g' |
- grep . >/dev/null; then
- echo
- if test "X$deplibs_check_method" = "Xnone"; then
- echo "*** Warning: inter-library dependencies are not supported in this platform."
- else
- echo "*** Warning: inter-library dependencies are not known to be supported."
- fi
- echo "*** All declared inter-library dependencies are being dropped."
- droppeddeps=yes
- fi
- ;;
- esac
- versuffix=$versuffix_save
- major=$major_save
- release=$release_save
- libname=$libname_save
- name=$name_save
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- if test "$droppeddeps" = yes; then
- if test "$module" = yes; then
- echo
- echo "*** Warning: libtool could not satisfy all declared inter-library"
- echo "*** dependencies of module $libname. Therefore, libtool will create"
- echo "*** a static module, that should work as long as the dlopening"
- echo "*** application is linked with the -dlopen flag."
- if test -z "$global_symbol_pipe"; then
- echo
- echo "*** However, this would only work if libtool was able to extract symbol"
- echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
- echo "*** not find such a program. So, this module is probably useless."
- echo "*** \`nm' from GNU binutils and a full rebuild may help."
- fi
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- else
- echo "*** The inter-library dependencies that have been dropped here will be"
- echo "*** automatically added whenever a program is linked with this library"
- echo "*** or is declared to -dlopen it."
-
- if test $allow_undefined = no; then
- echo
- echo "*** Since this library must not contain undefined symbols,"
- echo "*** because either the platform does not support them or"
- echo "*** it was explicitly requested with -no-undefined,"
- echo "*** libtool will only create a static version of it."
- if test "$build_old_libs" = no; then
- oldlibs="$output_objdir/$libname.$libext"
- build_libtool_libs=module
- build_old_libs=yes
- else
- build_libtool_libs=no
- fi
- fi
- fi
- fi
- # Done checking deplibs!
- deplibs=$newdeplibs
- fi
-
- # All the library-specific variables (install_libdir is set above).
- library_names=
- old_library=
- dlname=
-
- # Test again, we may have decided not to build it any more
- if test "$build_libtool_libs" = yes; then
- if test $hardcode_into_libs = yes; then
- # Hardcode the library paths
- hardcode_libdirs=
- dep_rpath=
- rpath="$finalize_rpath"
- test "$mode" != relink && rpath="$compile_rpath$rpath"
- for libdir in $rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- dep_rpath="$dep_rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval dep_rpath=\"$hardcode_libdir_flag_spec\"
- fi
- if test -n "$runpath_var" && test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
- fi
- test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
- fi
-
- shlibpath="$finalize_shlibpath"
- test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
- if test -n "$shlibpath"; then
- eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
- fi
-
- # Get the real and link names of the library.
- eval library_names=\"$library_names_spec\"
- set dummy $library_names
- realname="$2"
- shift; shift
-
- if test -n "$soname_spec"; then
- eval soname=\"$soname_spec\"
- else
- soname="$realname"
- fi
- test -z "$dlname" && dlname=$soname
-
- lib="$output_objdir/$realname"
- for link
- do
- linknames="$linknames $link"
- done
-
- # Ensure that we have .o objects for linkers which dislike .lo
- # (e.g. aix) in case we are running --disable-static
- for obj in $libobjs; do
- xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$obj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
- oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
- if test ! -f $xdir/$oldobj; then
- $show "(cd $xdir && ${LN_S} $baseobj $oldobj)"
- $run eval '(cd $xdir && ${LN_S} $baseobj $oldobj)' || exit $?
- fi
- done
-
- # Use standard objects if they are pic
- test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
- $show "generating symbol list for \`$libname.la'"
- export_symbols="$output_objdir/$libname.exp"
- $run $rm $export_symbols
- eval cmds=\"$export_symbols_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- if test -n "$export_symbols_regex"; then
- $show "egrep -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
- $run eval 'egrep -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
- $show "$mv \"${export_symbols}T\" \"$export_symbols\""
- $run eval '$mv "${export_symbols}T" "$export_symbols"'
- fi
- fi
- fi
-
- if test -n "$export_symbols" && test -n "$include_expsyms"; then
- $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
- fi
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- libobjs="$libobjs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
- eval flag=\"$thread_safe_flag_spec\"
- linker_flags="$linker_flags $flag"
- fi
-
- # Make a backup of the uninstalled library when relinking
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
- fi
-
- # Do each of the archive commands.
- if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
- eval cmds=\"$archive_expsym_cmds\"
- else
- eval cmds=\"$archive_cmds\"
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Restore the uninstalled library and exit
- if test "$mode" = relink; then
- $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
- exit 0
- fi
-
- # Create links to the real library.
- for linkname in $linknames; do
- if test "$realname" != "$linkname"; then
- $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
- fi
- done
-
- # If -module or -export-dynamic was specified, set the dlname.
- if test "$module" = yes || test "$export_dynamic" = yes; then
- # On all known operating systems, these are identical.
- dlname="$soname"
- fi
- fi
- ;;
-
- obj)
- if test -n "$deplibs"; then
- $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
- fi
-
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
- fi
-
- if test -n "$rpath"; then
- $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
- fi
-
- if test -n "$xrpath"; then
- $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
- fi
-
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
- fi
-
- case $output in
- *.lo)
- if test -n "$objs$old_deplibs"; then
- $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
- exit 1
- fi
- libobj="$output"
- obj=`$echo "X$output" | $Xsed -e "$lo2o"`
- ;;
- *)
- libobj=
- obj="$output"
- ;;
- esac
-
- # Delete the old objects.
- $run $rm $obj $libobj
-
- # Objects from convenience libraries. This assumes
- # single-version convenience libraries. Whenever we create
- # different ones for PIC/non-PIC, this we'll have to duplicate
- # the extraction.
- reload_conv_objs=
- gentop=
- # reload_cmds runs $LD directly, so let us get rid of
- # -Wl from whole_archive_flag_spec
- wl=
-
- if test -n "$convenience"; then
- if test -n "$whole_archive_flag_spec"; then
- eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
- else
- gentop="$output_objdir/${obj}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- for xlib in $convenience; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- reload_conv_objs="$reload_objs "`find $xdir -name \*.o -print -o -name \*.lo -print | $NL2SP`
- done
- fi
- fi
-
- # Create the old-style object.
- reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
-
- output="$obj"
- eval cmds=\"$reload_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
-
- # Exit if we aren't doing a library object file.
- if test -z "$libobj"; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- fi
-
- if test "$build_libtool_libs" != yes; then
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- # Create an invalid libtool object if no PIC, so that we don't
- # accidentally link it into a program.
- $show "echo timestamp > $libobj"
- $run eval "echo timestamp > $libobj" || exit $?
- exit 0
- fi
-
- if test -n "$pic_flag" || test "$pic_mode" != default; then
- # Only do commands if we really have different PIC objects.
- reload_objs="$libobjs $reload_conv_objs"
- output="$libobj"
- eval cmds=\"$reload_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- else
- # Just create a symlink.
- $show $rm $libobj
- $run $rm $libobj
- xdir=`$echo "X$libobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$libobj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$libobj" | $Xsed -e 's%^.*/%%'`
- oldobj=`$echo "X$baseobj" | $Xsed -e "$lo2o"`
- $show "(cd $xdir && $LN_S $oldobj $baseobj)"
- $run eval '(cd $xdir && $LN_S $oldobj $baseobj)' || exit $?
- fi
-
- if test -n "$gentop"; then
- $show "${rm}r $gentop"
- $run ${rm}r $gentop
- fi
-
- exit 0
- ;;
-
- prog)
- case $host in
- *cygwin*) output=`echo $output | sed -e 's,.exe$,,;s,$,.exe,'` ;;
- esac
- if test -n "$vinfo"; then
- $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
- fi
-
- if test -n "$release"; then
- $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
- fi
-
- if test "$preload" = yes; then
- if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
- test "$dlopen_self_static" = unknown; then
- $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
- fi
- fi
-
- case $host in
- *-*-rhapsody* | *-*-darwin1.[012])
- # On Rhapsody replace the C library is the System framework
- compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
- ;;
- esac
-
- compile_command="$compile_command $compile_deplibs"
- finalize_command="$finalize_command $finalize_deplibs"
-
- if test -n "$rpath$xrpath"; then
- # If the user specified any rpath flags, then add them.
- for libdir in $rpath $xrpath; do
- # This is the magic to use -rpath.
- case "$finalize_rpath " in
- *" $libdir "*) ;;
- *) finalize_rpath="$finalize_rpath $libdir" ;;
- esac
- done
- fi
-
- # Now hardcode the library paths
- rpath=
- hardcode_libdirs=
- for libdir in $compile_rpath $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$perm_rpath " in
- *" $libdir "*) ;;
- *) perm_rpath="$perm_rpath $libdir" ;;
- esac
- fi
- case $host in
- *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
- case :$dllsearchpath: in
- *":$libdir:"*) ;;
- *) dllsearchpath="$dllsearchpath:$libdir";;
- esac
- ;;
- esac
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- compile_rpath="$rpath"
-
- rpath=
- hardcode_libdirs=
- for libdir in $finalize_rpath; do
- if test -n "$hardcode_libdir_flag_spec"; then
- if test -n "$hardcode_libdir_separator"; then
- if test -z "$hardcode_libdirs"; then
- hardcode_libdirs="$libdir"
- else
- # Just accumulate the unique libdirs.
- case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
- *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
- ;;
- *)
- hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
- ;;
- esac
- fi
- else
- eval flag=\"$hardcode_libdir_flag_spec\"
- rpath="$rpath $flag"
- fi
- elif test -n "$runpath_var"; then
- case "$finalize_perm_rpath " in
- *" $libdir "*) ;;
- *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
- esac
- fi
- done
- # Substitute the hardcoded libdirs into the rpath.
- if test -n "$hardcode_libdir_separator" &&
- test -n "$hardcode_libdirs"; then
- libdir="$hardcode_libdirs"
- eval rpath=\" $hardcode_libdir_flag_spec\"
- fi
- finalize_rpath="$rpath"
-
- if test -n "$libobjs" && test "$build_old_libs" = yes; then
- # Transform all the library objects into standard objects.
- compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- fi
-
- dlsyms=
- if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
- if test -n "$NM" && test -n "$global_symbol_pipe"; then
- dlsyms="${outputname}S.c"
- else
- $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
- fi
- fi
-
- if test -n "$dlsyms"; then
- case $dlsyms in
- "") ;;
- *.c)
- # Discover the nlist of each of the dlfiles.
- nlist="$output_objdir/${outputname}.nm"
-
- $show "$rm $nlist ${nlist}S ${nlist}T"
- $run $rm "$nlist" "${nlist}S" "${nlist}T"
-
- # Parse the name list into a source file.
- $show "creating $output_objdir/$dlsyms"
-
- test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
-/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
-/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
-
-#ifdef __cplusplus
-extern \"C\" {
-#endif
-
-/* Prevent the only kind of declaration conflicts we can make. */
-#define lt_preloaded_symbols some_other_symbol
-
-/* External symbol declarations for the compiler. */\
-"
-
- if test "$dlself" = yes; then
- $show "generating symbol list for \`$output'"
-
- test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
-
- # Add our own program objects to the symbol list.
- progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
- for arg in $progfiles; do
- $show "extracting global C symbols from \`$arg'"
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -n "$exclude_expsyms"; then
- $run eval 'egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- if test -n "$export_symbols_regex"; then
- $run eval 'egrep -e "$export_symbols_regex" "$nlist" > "$nlist"T'
- $run eval '$mv "$nlist"T "$nlist"'
- fi
-
- # Prepare the list of exported symbols
- if test -z "$export_symbols"; then
- export_symbols="$output_objdir/$output.exp"
- $run $rm $export_symbols
- $run eval "sed -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
- else
- $run eval "sed -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
- $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
- $run eval 'mv "$nlist"T "$nlist"'
- fi
- fi
-
- for arg in $dlprefiles; do
- $show "extracting global C symbols from \`$arg'"
- name=`echo "$arg" | sed -e 's%^.*/%%'`
- $run eval 'echo ": $name " >> "$nlist"'
- $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
- done
-
- if test -z "$run"; then
- # Make sure we have at least an empty file.
- test -f "$nlist" || : > "$nlist"
-
- if test -n "$exclude_expsyms"; then
- egrep -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
- $mv "$nlist"T "$nlist"
- fi
-
- # Try sorting and uniquifying the output.
- if grep -v "^: " < "$nlist" | sort +2 | uniq > "$nlist"S; then
- :
- else
- grep -v "^: " < "$nlist" > "$nlist"S
- fi
-
- if test -f "$nlist"S; then
- eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
- else
- echo '/* NONE */' >> "$output_objdir/$dlsyms"
- fi
-
- $echo >> "$output_objdir/$dlsyms" "\
-
-#undef lt_preloaded_symbols
-
-#if defined (__STDC__) && __STDC__
-# define lt_ptr void *
-#else
-# define lt_ptr char *
-# define const
-#endif
-
-/* The mapping between symbol names and symbols. */
-const struct {
- const char *name;
- lt_ptr address;
-}
-lt_preloaded_symbols[] =
-{\
-"
-
- eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
-
- $echo >> "$output_objdir/$dlsyms" "\
- {0, (lt_ptr) 0}
-};
-
-/* This works around a problem in FreeBSD linker */
-#ifdef FREEBSD_WORKAROUND
-static const void *lt_preloaded_setup() {
- return lt_preloaded_symbols;
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif\
-"
- fi
-
- pic_flag_for_symtable=
- case $host in
- # compiling the symbol table file with pic_flag works around
- # a FreeBSD bug that causes programs to crash when -lm is
- # linked before any other PIC object. But we must not use
- # pic_flag when linking with -static. The problem exists in
- # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
- *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DPIC -DFREEBSD_WORKAROUND";;
- esac;;
- *-*-hpux*)
- case "$compile_command " in
- *" -static "*) ;;
- *) pic_flag_for_symtable=" $pic_flag -DPIC";;
- esac
- esac
-
- # Now compile the dynamic symbol file.
- $show "(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
- $run eval '(cd $output_objdir && $CC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
-
- # Clean up the generated files.
- $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
- $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
-
- # Transform the symbol file into the correct name.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
- ;;
- *)
- $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
- exit 1
- ;;
- esac
- else
- # We keep going just in case the user didn't refer to
- # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
- # really was required.
-
- # Nullify the symbol file.
- compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
- finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
- fi
-
- if test $need_relink = no || test "$build_libtool_libs" != yes; then
- # Replace the output file specification.
- compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- link_command="$compile_command$compile_rpath"
-
- # We have no uninstalled library dependencies, so finalize right now.
- $show "$link_command"
- $run eval "$link_command"
- status=$?
-
- # Delete the generated files.
- if test -n "$dlsyms"; then
- $show "$rm $output_objdir/${outputname}S.${objext}"
- $run $rm "$output_objdir/${outputname}S.${objext}"
- fi
-
- exit $status
- fi
-
- if test -n "$shlibpath_var"; then
- # We should set the shlibpath_var
- rpath=
- for dir in $temp_rpath; do
- case $dir in
- [\\/]* | [A-Za-z]:[\\/]*)
- # Absolute path.
- rpath="$rpath$dir:"
- ;;
- *)
- # Relative path: add a thisdir entry.
- rpath="$rpath\$thisdir/$dir:"
- ;;
- esac
- done
- temp_rpath="$rpath"
- fi
-
- if test -n "$compile_shlibpath$finalize_shlibpath"; then
- compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
- fi
- if test -n "$finalize_shlibpath"; then
- finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
- fi
-
- compile_var=
- finalize_var=
- if test -n "$runpath_var"; then
- if test -n "$perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $perm_rpath; do
- rpath="$rpath$dir:"
- done
- compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- if test -n "$finalize_perm_rpath"; then
- # We should set the runpath_var.
- rpath=
- for dir in $finalize_perm_rpath; do
- rpath="$rpath$dir:"
- done
- finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
- fi
- fi
-
- if test "$no_install" = yes; then
- # We don't need to create a wrapper script.
- link_command="$compile_var$compile_command$compile_rpath"
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
- # Delete the old output file.
- $run $rm $output
- # Link the executable and exit
- $show "$link_command"
- $run eval "$link_command" || exit $?
- exit 0
- fi
-
- if test "$hardcode_action" = relink; then
- # Fast installation is not supported
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
-
- $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
- $echo "$modename: \`$output' will be relinked during installation" 1>&2
- else
- if test "$fast_install" != no; then
- link_command="$finalize_var$compile_command$finalize_rpath"
- if test "$fast_install" = yes; then
- relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
- else
- # fast_install is set to needless
- relink_command=
- fi
- else
- link_command="$compile_var$compile_command$compile_rpath"
- relink_command="$finalize_var$finalize_command$finalize_rpath"
- fi
- fi
-
- # Replace the output file specification.
- link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
-
- # Delete the old output files.
- $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
-
- $show "$link_command"
- $run eval "$link_command" || exit $?
-
- # Now create the wrapper script.
- $show "creating $output"
-
- # Quote the relink command for shipping.
- if test -n "$relink_command"; then
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- relink_command="cd `pwd`; $relink_command"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Quote $echo for shipping.
- if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
- case $0 in
- [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
- *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
- esac
- qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
- else
- qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
- fi
-
- # Only actually do things if our run command is non-null.
- if test -z "$run"; then
- # win32 will think the script is a binary if it has
- # a .exe suffix, so we strip it off here.
- case $output in
- *.exe) output=`echo $output|sed 's,.exe$,,'` ;;
- esac
- # test for cygwin because mv fails w/o .exe extensions
- case $host in
- *cygwin*) exeext=.exe ;;
- *) exeext= ;;
- esac
- $rm $output
- trap "$rm $output; exit 1" 1 2 15
-
- $echo > $output "\
-#! $SHELL
-
-# $output - temporary wrapper script for $objdir/$outputname
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# The $output program cannot be directly executed until all the libtool
-# libraries that it depends on are installed.
-#
-# This wrapper script should never be moved out of the build directory.
-# If it is, it will not operate correctly.
-
-# Sed substitution that helps us do robust quoting. It backslashifies
-# metacharacters that are still active within double-quoted strings.
-Xsed='sed -e 1s/^X//'
-sed_quote_subst='$sed_quote_subst'
-
-# The HP-UX ksh and POSIX shell print the target directory to stdout
-# if CDPATH is set.
-if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
-
-relink_command=\"$relink_command\"
-
-# This environment variable determines our operation mode.
-if test \"\$libtool_install_magic\" = \"$magic\"; then
- # install mode needs the following variable:
- notinst_deplibs='$notinst_deplibs'
-else
- # When we are sourced in execute mode, \$file and \$echo are already set.
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- echo=\"$qecho\"
- file=\"\$0\"
- # Make sure echo works.
- if test \"X\$1\" = X--no-reexec; then
- # Discard the --no-reexec flag, and continue.
- shift
- elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
- # Yippee, \$echo works!
- :
- else
- # Restart under the correct shell, and then maybe \$echo will work.
- exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
- fi
- fi\
-"
- $echo >> $output "\
-
- # Find the directory that this script lives in.
- thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
- test \"x\$thisdir\" = \"x\$file\" && thisdir=.
-
- # Follow symbolic links until we get to the real thisdir.
- file=\`ls -ld \"\$file\" | sed -n 's/.*-> //p'\`
- while test -n \"\$file\"; do
- destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
-
- # If there was a directory component, then change thisdir.
- if test \"x\$destdir\" != \"x\$file\"; then
- case \"\$destdir\" in
- [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
- *) thisdir=\"\$thisdir/\$destdir\" ;;
- esac
- fi
-
- file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
- file=\`ls -ld \"\$thisdir/\$file\" | sed -n 's/.*-> //p'\`
- done
-
- # Try to get the absolute directory name.
- absdir=\`cd \"\$thisdir\" && pwd\`
- test -n \"\$absdir\" && thisdir=\"\$absdir\"
-"
-
- if test "$fast_install" = yes; then
- echo >> $output "\
- program=lt-'$outputname'$exeext
- progdir=\"\$thisdir/$objdir\"
-
- if test ! -f \"\$progdir/\$program\" || \\
- { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | sed 1q\`; \\
- test \"X\$file\" != \"X\$progdir/\$program\"; }; then
-
- file=\"\$\$-\$program\"
-
- if test ! -d \"\$progdir\"; then
- $mkdir \"\$progdir\"
- else
- $rm \"\$progdir/\$file\"
- fi"
-
- echo >> $output "\
-
- # relink executable if necessary
- if test -n \"\$relink_command\"; then
- if relink_command_output=\`eval \$relink_command 2>&1\`; then :
- else
- $echo \"\$relink_command_output\" >&2
- $rm \"\$progdir/\$file\"
- exit 1
- fi
- fi
-
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
- { $rm \"\$progdir/\$program\";
- $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
- $rm \"\$progdir/\$file\"
- fi"
- else
- echo >> $output "\
- program='$outputname'
- progdir=\"\$thisdir/$objdir\"
-"
- fi
-
- echo >> $output "\
-
- if test -f \"\$progdir/\$program\"; then"
-
- # Export our shlibpath_var if we have one.
- if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
- $echo >> $output "\
- # Add our own library path to $shlibpath_var
- $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
-
- # Some systems cannot cope with colon-terminated $shlibpath_var
- # The second colon is a workaround for a bug in BeOS R4 sed
- $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
-
- export $shlibpath_var
-"
- fi
-
- # fixup the dll searchpath if we need to.
- if test -n "$dllsearchpath"; then
- $echo >> $output "\
- # Add the dll search path components to the executable PATH
- PATH=$dllsearchpath:\$PATH
-"
- fi
-
- $echo >> $output "\
- if test \"\$libtool_execute_magic\" != \"$magic\"; then
- # Run the actual program with our arguments.
-"
- case $host in
- # win32 systems need to use the prog path for dll
- # lookup to work
- *-*-cygwin* | *-*-pw32*)
- $echo >> $output "\
- exec \$progdir/\$program \${1+\"\$@\"}
-"
- ;;
-
- # Backslashes separate directories on plain windows
- *-*-mingw | *-*-os2*)
- $echo >> $output "\
- exec \$progdir\\\\\$program \${1+\"\$@\"}
-"
- ;;
-
- *)
- $echo >> $output "\
- # Export the path to the program.
- PATH=\"\$progdir:\$PATH\"
- export PATH
-
- exec \$program \${1+\"\$@\"}
-"
- ;;
- esac
- $echo >> $output "\
- \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
- exit 1
- fi
- else
- # The program doesn't exist.
- \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
- \$echo \"This script is just a wrapper for \$program.\" 1>&2
- echo \"See the $PACKAGE documentation for more information.\" 1>&2
- exit 1
- fi
-fi\
-"
- chmod +x $output
- fi
- exit 0
- ;;
- esac
-
- # See if we need to build an old-fashioned archive.
- for oldlib in $oldlibs; do
-
- if test "$build_libtool_libs" = convenience; then
- oldobjs="$libobjs_save"
- addlibs="$convenience"
- build_libtool_libs=no
- else
- if test "$build_libtool_libs" = module; then
- oldobjs="$libobjs_save"
- build_libtool_libs=no
- else
- oldobjs="$objs$old_deplibs "`$echo "X$libobjs_save" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`
- fi
- addlibs="$old_convenience"
- fi
-
- if test -n "$addlibs"; then
- gentop="$output_objdir/${outputname}x"
- $show "${rm}r $gentop"
- $run ${rm}r "$gentop"
- $show "mkdir $gentop"
- $run mkdir "$gentop"
- status=$?
- if test $status -ne 0 && test ! -d "$gentop"; then
- exit $status
- fi
- generated="$generated $gentop"
-
- # Add in members from convenience archives.
- for xlib in $addlibs; do
- # Extract the objects.
- case $xlib in
- [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
- *) xabs=`pwd`"/$xlib" ;;
- esac
- xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
- xdir="$gentop/$xlib"
-
- $show "${rm}r $xdir"
- $run ${rm}r "$xdir"
- $show "mkdir $xdir"
- $run mkdir "$xdir"
- status=$?
- if test $status -ne 0 && test ! -d "$xdir"; then
- exit $status
- fi
- $show "(cd $xdir && $AR x $xabs)"
- $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
-
- oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
- done
- fi
-
- # Do each command in the archive commands.
- if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
- eval cmds=\"$old_archive_from_new_cmds\"
- else
- # Ensure that we have .o objects in place in case we decided
- # not to build a shared library, and have fallen back to building
- # static libs even though --disable-static was passed!
- for oldobj in $oldobjs; do
- if test ! -f $oldobj; then
- xdir=`$echo "X$oldobj" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$xdir" = "X$oldobj"; then
- xdir="."
- else
- xdir="$xdir"
- fi
- baseobj=`$echo "X$oldobj" | $Xsed -e 's%^.*/%%'`
- obj=`$echo "X$baseobj" | $Xsed -e "$o2lo"`
- $show "(cd $xdir && ${LN_S} $obj $baseobj)"
- $run eval '(cd $xdir && ${LN_S} $obj $baseobj)' || exit $?
- fi
- done
-
- eval cmds=\"$old_archive_cmds\"
- fi
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$generated"; then
- $show "${rm}r$generated"
- $run ${rm}r$generated
- fi
-
- # Now create the libtool archive.
- case $output in
- *.la)
- old_library=
- test "$build_old_libs" = yes && old_library="$libname.$libext"
- $show "creating $output"
-
- # Preserve any variables that may affect compiler behavior
- for var in $variables_saved_for_relink; do
- if eval test -z \"\${$var+set}\"; then
- relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
- elif eval var_value=\$$var; test -z "$var_value"; then
- relink_command="$var=; export $var; $relink_command"
- else
- var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
- relink_command="$var=\"$var_value\"; export $var; $relink_command"
- fi
- done
- # Quote the link command for shipping.
- relink_command="cd `pwd`; $SHELL $0 --mode=relink $libtool_args"
- relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
-
- # Only create the output if not a dry run.
- if test -z "$run"; then
- for installed in no yes; do
- if test "$installed" = yes; then
- if test -z "$install_libdir"; then
- break
- fi
- output="$output_objdir/$outputname"i
- # Replace all uninstalled libtool libraries with the installed ones
- newdependency_libs=
- for deplib in $dependency_libs; do
- case $deplib in
- *.la)
- name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
- if test -z "$libdir"; then
- $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdependency_libs="$newdependency_libs $libdir/$name"
- ;;
- *) newdependency_libs="$newdependency_libs $deplib" ;;
- esac
- done
- dependency_libs="$newdependency_libs"
- newdlfiles=
- for lib in $dlfiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdlfiles="$newdlfiles $libdir/$name"
- done
- dlfiles="$newdlfiles"
- newdlprefiles=
- for lib in $dlprefiles; do
- name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
- eval libdir=`sed -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
- if test -z "$libdir"; then
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- exit 1
- fi
- newdlprefiles="$newdlprefiles $libdir/$name"
- done
- dlprefiles="$newdlprefiles"
- fi
- $rm $output
- # place dlname in correct position for cygwin
- tdlname=$dlname
- case $host,$output,$installed,$module,$dlname in
- *cygwin*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
- esac
- $echo > $output "\
-# $outputname - a libtool library file
-# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
-#
-# Please DO NOT delete this file!
-# It is necessary for linking the library.
-
-# The name that we can dlopen(3).
-dlname='$tdlname'
-
-# Names of this library.
-library_names='$library_names'
-
-# The name of the static archive.
-old_library='$old_library'
-
-# Libraries that this one depends upon.
-dependency_libs='$dependency_libs'
-
-# Version information for $libname.
-current=$current
-age=$age
-revision=$revision
-
-# Is this an already installed library?
-installed=$installed
-
-# Files to dlopen/dlpreopen
-dlopen='$dlfiles'
-dlpreopen='$dlprefiles'
-
-# Directory that this library needs to be installed in:
-libdir='$install_libdir'"
- if test "$installed" = no && test $need_relink = yes; then
- $echo >> $output "\
-relink_command=\"$relink_command\""
- fi
- done
- fi
-
- # Do a symbolic link so that the libtool archive can be found in
- # LD_LIBRARY_PATH before the program is installed.
- $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
- $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
- ;;
- esac
- exit 0
- ;;
-
- # libtool install mode
- install)
- modename="$modename: install"
-
- # There may be an optional sh(1) argument at the beginning of
- # install_prog (especially on Windows NT).
- if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
- # Allow the use of GNU shtool's install command.
- $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
- # Aesthetically quote it.
- arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$arg "
- arg="$1"
- shift
- else
- install_prog=
- arg="$nonopt"
- fi
-
- # The real first argument should be the name of the installation program.
- # Aesthetically quote it.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog$arg"
-
- # We need to accept at least all the BSD install flags.
- dest=
- files=
- opts=
- prev=
- install_type=
- isdir=no
- stripme=
- for arg
- do
- if test -n "$dest"; then
- files="$files $dest"
- dest="$arg"
- continue
- fi
-
- case $arg in
- -d) isdir=yes ;;
- -f) prev="-f" ;;
- -g) prev="-g" ;;
- -m) prev="-m" ;;
- -o) prev="-o" ;;
-
- # Added to support INN's install program.
- -O) prev="-O" ;;
- -G) prev="-G" ;;
- -B) prev="-B" ;;
-
- -s)
- stripme=" -s"
- continue
- ;;
- -*) ;;
-
- *)
- # If the previous option needed an argument, then skip it.
- if test -n "$prev"; then
- prev=
- else
- dest="$arg"
- continue
- fi
- ;;
- esac
-
- # Aesthetically quote the argument.
- arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
- case $arg in
- *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
- arg="\"$arg\""
- ;;
- esac
- install_prog="$install_prog $arg"
- done
-
- if test -z "$install_prog"; then
- $echo "$modename: you must specify an install program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -n "$prev"; then
- $echo "$modename: the \`$prev' option requires an argument" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- if test -z "$files"; then
- if test -z "$dest"; then
- $echo "$modename: no file or destination specified" 1>&2
- else
- $echo "$modename: you must specify a destination" 1>&2
- fi
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Strip any trailing slash from the destination.
- dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
-
- # Check to see that the destination is a directory.
- test -d "$dest" && isdir=yes
- if test "$isdir" = yes; then
- destdir="$dest"
- destname=
- else
- destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
- test "X$destdir" = "X$dest" && destdir=.
- destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
-
- # Not a directory, so check to see that there is only one file specified.
- set dummy $files
- if test $# -gt 2; then
- $echo "$modename: \`$dest' is not a directory" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
- fi
- case $destdir in
- [\\/]* | [A-Za-z]:[\\/]*) ;;
- *)
- for file in $files; do
- case $file in
- *.lo) ;;
- *)
- $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
- done
- ;;
- esac
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- staticlibs=
- future_libdirs=
- current_libdirs=
- for file in $files; do
-
- # Do each installation.
- case $file in
- *.$libext)
- # Do the static libraries later.
- staticlibs="$staticlibs $file"
- ;;
-
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- library_names=
- old_library=
- relink_command=
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Add the libdir to current_libdirs if it is the destination.
- if test "X$destdir" = "X$libdir"; then
- case "$current_libdirs " in
- *" $libdir "*) ;;
- *) current_libdirs="$current_libdirs $libdir" ;;
- esac
- else
- # Note the libdir as a future libdir.
- case "$future_libdirs " in
- *" $libdir "*) ;;
- *) future_libdirs="$future_libdirs $libdir" ;;
- esac
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
- test "X$dir" = "X$file/" && dir=
- dir="$dir$objdir"
-
- if test -n "$relink_command"; then
- $echo "$modename: warning: relinking \`$file'" 1>&2
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- continue
- fi
- fi
-
- # See the names of the shared library.
- set dummy $library_names
- if test -n "$2"; then
- realname="$2"
- shift
- shift
-
- srcname="$realname"
- test -n "$relink_command" && srcname="$realname"T
-
- # Install the shared library and build the symlinks.
- $show "$install_prog $dir/$srcname $destdir/$realname"
- $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
- if test -n "$stripme" && test -n "$striplib"; then
- $show "$striplib $destdir/$realname"
- $run eval "$striplib $destdir/$realname" || exit $?
- fi
-
- if test $# -gt 0; then
- # Delete the old symlinks, and create new ones.
- for linkname
- do
- if test "$linkname" != "$realname"; then
- $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
- fi
- done
- fi
-
- # Do each command in the postinstall commands.
- lib="$destdir/$realname"
- eval cmds=\"$postinstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- fi
-
- # Install the pseudo-library for information purposes.
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- instname="$dir/$name"i
- $show "$install_prog $instname $destdir/$name"
- $run eval "$install_prog $instname $destdir/$name" || exit $?
-
- # Maybe install the static library, too.
- test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
- ;;
-
- *.lo)
- # Install (i.e. copy) a libtool object.
-
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Deduce the name of the destination old-style object file.
- case $destfile in
- *.lo)
- staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
- ;;
- *.$objext)
- staticdest="$destfile"
- destfile=
- ;;
- *)
- $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
- esac
-
- # Install the libtool object if requested.
- if test -n "$destfile"; then
- $show "$install_prog $file $destfile"
- $run eval "$install_prog $file $destfile" || exit $?
- fi
-
- # Install the old object if enabled.
- if test "$build_old_libs" = yes; then
- # Deduce the name of the old-style object file.
- staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
-
- $show "$install_prog $staticobj $staticdest"
- $run eval "$install_prog \$staticobj \$staticdest" || exit $?
- fi
- exit 0
- ;;
-
- *)
- # Figure out destination file name, if it wasn't already specified.
- if test -n "$destname"; then
- destfile="$destdir/$destname"
- else
- destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- destfile="$destdir/$destfile"
- fi
-
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- notinst_deplibs=
- relink_command=
-
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Check the variables that should have been set.
- if test -z "$notinst_deplibs"; then
- $echo "$modename: invalid libtool wrapper script \`$file'" 1>&2
- exit 1
- fi
-
- finalize=yes
- for lib in $notinst_deplibs; do
- # Check to see that each library is installed.
- libdir=
- if test -f "$lib"; then
- # If there is no directory component, then add one.
- case $lib in
- */* | *\\*) . $lib ;;
- *) . ./$lib ;;
- esac
- fi
- libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
- if test -n "$libdir" && test ! -f "$libfile"; then
- $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
- finalize=no
- fi
- done
-
- relink_command=
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- outputname=
- if test "$fast_install" = no && test -n "$relink_command"; then
- if test "$finalize" = yes && test -z "$run"; then
- tmpdir="/tmp"
- test -n "$TMPDIR" && tmpdir="$TMPDIR"
- tmpdir="$tmpdir/libtool-$$"
- if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
- else
- $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
- continue
- fi
- file=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- outputname="$tmpdir/$file"
- # Replace the output file specification.
- relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
-
- $show "$relink_command"
- if $run eval "$relink_command"; then :
- else
- $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
- ${rm}r "$tmpdir"
- continue
- fi
- file="$outputname"
- else
- $echo "$modename: warning: cannot relink \`$file'" 1>&2
- fi
- else
- # Install the binary that we compiled earlier.
- file=`$echo "X$file" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
- fi
- fi
-
- # remove .exe since cygwin /usr/bin/install will append another
- # one anyways
- case $install_prog,$host in
- /usr/bin/install*,*cygwin*)
- case $file:$destfile in
- *.exe:*.exe)
- # this is ok
- ;;
- *.exe:*)
- destfile=$destfile.exe
- ;;
- *:*.exe)
- destfile=`echo $destfile | sed -e 's,.exe$,,'`
- ;;
- esac
- ;;
- esac
- $show "$install_prog$stripme $file $destfile"
- $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
- test -n "$outputname" && ${rm}r "$tmpdir"
- ;;
- esac
- done
-
- for file in $staticlibs; do
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
-
- # Set up the ranlib parameters.
- oldlib="$destdir/$name"
-
- $show "$install_prog $file $oldlib"
- $run eval "$install_prog \$file \$oldlib" || exit $?
-
- if test -n "$stripme" && test -n "$striplib"; then
- $show "$old_striplib $oldlib"
- $run eval "$old_striplib $oldlib" || exit $?
- fi
-
- # Do each command in the postinstall commands.
- eval cmds=\"$old_postinstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || exit $?
- done
- IFS="$save_ifs"
- done
-
- if test -n "$future_libdirs"; then
- $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
- fi
-
- if test -n "$current_libdirs"; then
- # Maybe just do a dry run.
- test -n "$run" && current_libdirs=" -n$current_libdirs"
- exec_cmd='$SHELL $0 --finish$current_libdirs'
- else
- exit 0
- fi
- ;;
-
- # libtool finish mode
- finish)
- modename="$modename: finish"
- libdirs="$nonopt"
- admincmds=
-
- if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
- for dir
- do
- libdirs="$libdirs $dir"
- done
-
- for libdir in $libdirs; do
- if test -n "$finish_cmds"; then
- # Do each command in the finish commands.
- eval cmds=\"$finish_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd" || admincmds="$admincmds
- $cmd"
- done
- IFS="$save_ifs"
- fi
- if test -n "$finish_eval"; then
- # Do the single finish_eval.
- eval cmds=\"$finish_eval\"
- $run eval "$cmds" || admincmds="$admincmds
- $cmds"
- fi
- done
- fi
-
- # Exit here if they wanted silent mode.
- test "$show" = ":" && exit 0
-
- echo "----------------------------------------------------------------------"
- echo "Libraries have been installed in:"
- for libdir in $libdirs; do
- echo " $libdir"
- done
- echo
- echo "If you ever happen to want to link against installed libraries"
- echo "in a given directory, LIBDIR, you must either use libtool, and"
- echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
- echo "flag during linking and do at least one of the following:"
- if test -n "$shlibpath_var"; then
- echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
- echo " during execution"
- fi
- if test -n "$runpath_var"; then
- echo " - add LIBDIR to the \`$runpath_var' environment variable"
- echo " during linking"
- fi
- if test -n "$hardcode_libdir_flag_spec"; then
- libdir=LIBDIR
- eval flag=\"$hardcode_libdir_flag_spec\"
-
- echo " - use the \`$flag' linker flag"
- fi
- if test -n "$admincmds"; then
- echo " - have your system administrator run these commands:$admincmds"
- fi
- if test -f /etc/ld.so.conf; then
- echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
- fi
- echo
- echo "See any operating system documentation about shared libraries for"
- echo "more information, such as the ld(1) and ld.so(8) manual pages."
- echo "----------------------------------------------------------------------"
- exit 0
- ;;
-
- # libtool execute mode
- execute)
- modename="$modename: execute"
-
- # The first argument is the command name.
- cmd="$nonopt"
- if test -z "$cmd"; then
- $echo "$modename: you must specify a COMMAND" 1>&2
- $echo "$help"
- exit 1
- fi
-
- # Handle -dlopen flags immediately.
- for file in $execute_dlfiles; do
- if test ! -f "$file"; then
- $echo "$modename: \`$file' is not a file" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- dir=
- case $file in
- *.la)
- # Check to see that this really is a libtool archive.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
- else
- $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- # Read the libtool library.
- dlname=
- library_names=
-
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Skip this library if it cannot be dlopened.
- if test -z "$dlname"; then
- # Warn if it was a shared library.
- test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
- continue
- fi
-
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
-
- if test -f "$dir/$objdir/$dlname"; then
- dir="$dir/$objdir"
- else
- $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
- exit 1
- fi
- ;;
-
- *.lo)
- # Just add the directory containing the .lo file.
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- test "X$dir" = "X$file" && dir=.
- ;;
-
- *)
- $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
- continue
- ;;
- esac
-
- # Get the absolute pathname.
- absdir=`cd "$dir" && pwd`
- test -n "$absdir" && dir="$absdir"
-
- # Now add the directory to shlibpath_var.
- if eval "test -z \"\$$shlibpath_var\""; then
- eval "$shlibpath_var=\"\$dir\""
- else
- eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
- fi
- done
-
- # This variable tells wrapper scripts just to set shlibpath_var
- # rather than running their programs.
- libtool_execute_magic="$magic"
-
- # Check if any of the arguments is a wrapper script.
- args=
- for file
- do
- case $file in
- -*) ;;
- *)
- # Do a test to see if this is really a libtool program.
- if (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- # If there is no directory component, then add one.
- case $file in
- */* | *\\*) . $file ;;
- *) . ./$file ;;
- esac
-
- # Transform arg to wrapped name.
- file="$progdir/$program"
- fi
- ;;
- esac
- # Quote arguments (to preserve shell metacharacters).
- file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
- args="$args \"$file\""
- done
-
- if test -z "$run"; then
- if test -n "$shlibpath_var"; then
- # Export the shlibpath_var.
- eval "export $shlibpath_var"
- fi
-
- # Restore saved enviroment variables
- if test "${save_LC_ALL+set}" = set; then
- LC_ALL="$save_LC_ALL"; export LC_ALL
- fi
- if test "${save_LANG+set}" = set; then
- LANG="$save_LANG"; export LANG
- fi
-
- # Now prepare to actually exec the command.
- exec_cmd='"$cmd"$args'
- else
- # Display what would be done.
- if test -n "$shlibpath_var"; then
- eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
- $echo "export $shlibpath_var"
- fi
- $echo "$cmd$args"
- exit 0
- fi
- ;;
-
- # libtool clean and uninstall mode
- clean | uninstall)
- modename="$modename: $mode"
- rm="$nonopt"
- files=
- rmforce=
- exit_status=0
-
- # This variable tells wrapper scripts just to set variables rather
- # than running their programs.
- libtool_install_magic="$magic"
-
- for arg
- do
- case $arg in
- -f) rm="$rm $arg"; rmforce=yes ;;
- -*) rm="$rm $arg" ;;
- *) files="$files $arg" ;;
- esac
- done
-
- if test -z "$rm"; then
- $echo "$modename: you must specify an RM program" 1>&2
- $echo "$help" 1>&2
- exit 1
- fi
-
- rmdirs=
-
- for file in $files; do
- dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
- if test "X$dir" = "X$file"; then
- dir=.
- objdir="$objdir"
- else
- objdir="$dir/$objdir"
- fi
- name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
- test $mode = uninstall && objdir="$dir"
-
- # Remember objdir for removal later, being careful to avoid duplicates
- if test $mode = clean; then
- case " $rmdirs " in
- *" $objdir "*) ;;
- *) rmdirs="$rmdirs $objdir" ;;
- esac
- fi
-
- # Don't error if the file doesn't exist and rm -f was used.
- if (test -L "$file") >/dev/null 2>&1 \
- || (test -h "$file") >/dev/null 2>&1 \
- || test -f "$file"; then
- :
- elif test -d "$file"; then
- exit_status=1
- continue
- elif test "$rmforce" = yes; then
- continue
- fi
-
- rmfiles="$file"
-
- case $name in
- *.la)
- # Possibly a libtool archive, so verify it.
- if (sed -e '2q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- . $dir/$name
-
- # Delete the libtool libraries and symlinks.
- for n in $library_names; do
- rmfiles="$rmfiles $objdir/$n"
- done
- test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
- test $mode = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
-
- if test $mode = uninstall; then
- if test -n "$library_names"; then
- # Do each command in the postuninstall commands.
- eval cmds=\"$postuninstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- if test $? != 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
-
- if test -n "$old_library"; then
- # Do each command in the old_postuninstall commands.
- eval cmds=\"$old_postuninstall_cmds\"
- save_ifs="$IFS"; IFS='~'
- for cmd in $cmds; do
- IFS="$save_ifs"
- $show "$cmd"
- $run eval "$cmd"
- if test $? != 0 && test "$rmforce" != yes; then
- exit_status=1
- fi
- done
- IFS="$save_ifs"
- fi
- # FIXME: should reinstall the best remaining shared library.
- fi
- fi
- ;;
-
- *.lo)
- if test "$build_old_libs" = yes; then
- oldobj=`$echo "X$name" | $Xsed -e "$lo2o"`
- rmfiles="$rmfiles $dir/$oldobj"
- fi
- ;;
-
- *)
- # Do a test to see if this is a libtool program.
- if test $mode = clean &&
- (sed -e '4q' $file | egrep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
- relink_command=
- . $dir/$file
-
- rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
- if test "$fast_install" = yes && test -n "$relink_command"; then
- rmfiles="$rmfiles $objdir/lt-$name"
- fi
- fi
- ;;
- esac
- $show "$rm $rmfiles"
- $run $rm $rmfiles || exit_status=1
- done
-
- # Try to remove the ${objdir}s in the directories where we deleted files
- for dir in $rmdirs; do
- if test -d "$dir"; then
- $show "rmdir $dir"
- $run rmdir $dir >/dev/null 2>&1
- fi
- done
-
- exit $exit_status
- ;;
-
- "")
- $echo "$modename: you must specify a MODE" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
- ;;
- esac
-
- if test -z "$exec_cmd"; then
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$generic_help" 1>&2
- exit 1
- fi
-fi # test -z "$show_help"
-
-if test -n "$exec_cmd"; then
- eval exec $exec_cmd
- exit 1
-fi
-
-# We need to display help for each of the modes.
-case $mode in
-"") $echo \
-"Usage: $modename [OPTION]... [MODE-ARG]...
-
-Provide generalized library-building support services.
-
- --config show all configuration variables
- --debug enable verbose shell tracing
--n, --dry-run display commands without modifying any files
- --features display basic configuration information and exit
- --finish same as \`--mode=finish'
- --help display this help message and exit
- --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
- --quiet same as \`--silent'
- --silent don't print informational messages
- --version print version information
-
-MODE must be one of the following:
-
- clean remove files from the build directory
- compile compile a source file into a libtool object
- execute automatically set library path, then run a program
- finish complete the installation of libtool libraries
- install install libraries or executables
- link create a library or an executable
- uninstall remove libraries from an installed directory
-
-MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
-a more detailed description of MODE."
- exit 0
- ;;
-
-clean)
- $echo \
-"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
-
-Remove files from the build directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, object or program, all the files associated
-with it are deleted. Otherwise, only FILE itself is deleted using RM."
- ;;
-
-compile)
- $echo \
-"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
-
-Compile a source file into a libtool library object.
-
-This mode accepts the following additional options:
-
- -o OUTPUT-FILE set the output file name to OUTPUT-FILE
- -prefer-pic try to building PIC objects only
- -prefer-non-pic try to building non-PIC objects only
- -static always build a \`.o' file suitable for static linking
-
-COMPILE-COMMAND is a command to be used in creating a \`standard' object file
-from the given SOURCEFILE.
-
-The output file name is determined by removing the directory component from
-SOURCEFILE, then substituting the C source code suffix \`.c' with the
-library object suffix, \`.lo'."
- ;;
-
-execute)
- $echo \
-"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
-
-Automatically set library path, then run a program.
-
-This mode accepts the following additional options:
-
- -dlopen FILE add the directory containing FILE to the library path
-
-This mode sets the library path environment variable according to \`-dlopen'
-flags.
-
-If any of the ARGS are libtool executable wrappers, then they are translated
-into their corresponding uninstalled binary, and any of their required library
-directories are added to the library path.
-
-Then, COMMAND is executed, with ARGS as arguments."
- ;;
-
-finish)
- $echo \
-"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
-
-Complete the installation of libtool libraries.
-
-Each LIBDIR is a directory that contains libtool libraries.
-
-The commands that this mode executes may require superuser privileges. Use
-the \`--dry-run' option if you just want to see what would be executed."
- ;;
-
-install)
- $echo \
-"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
-
-Install executables or libraries.
-
-INSTALL-COMMAND is the installation command. The first component should be
-either the \`install' or \`cp' program.
-
-The rest of the components are interpreted as arguments to that command (only
-BSD-compatible install options are recognized)."
- ;;
-
-link)
- $echo \
-"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
-
-Link object files or libraries together to form another library, or to
-create an executable program.
-
-LINK-COMMAND is a command using the C compiler that you would use to create
-a program from several object files.
-
-The following components of LINK-COMMAND are treated specially:
-
- -all-static do not do any dynamic linking at all
- -avoid-version do not add a version suffix if possible
- -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
- -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
- -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
- -export-symbols SYMFILE
- try to export only the symbols listed in SYMFILE
- -export-symbols-regex REGEX
- try to export only the symbols matching REGEX
- -LLIBDIR search LIBDIR for required installed libraries
- -lNAME OUTPUT-FILE requires the installed library libNAME
- -module build a library that can dlopened
- -no-fast-install disable the fast-install mode
- -no-install link a not-installable executable
- -no-undefined declare that a library does not refer to external symbols
- -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
- -release RELEASE specify package release information
- -rpath LIBDIR the created library will eventually be installed in LIBDIR
- -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
- -static do not do any dynamic linking of libtool libraries
- -version-info CURRENT[:REVISION[:AGE]]
- specify library version info [each variable defaults to 0]
-
-All other options (arguments beginning with \`-') are ignored.
-
-Every other argument is treated as a filename. Files ending in \`.la' are
-treated as uninstalled libtool libraries, other files are standard or library
-object files.
-
-If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
-only library objects (\`.lo' files) may be specified, and \`-rpath' is
-required, except when creating a convenience library.
-
-If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
-using \`ar' and \`ranlib', or on Windows using \`lib'.
-
-If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
-is created, otherwise an executable program is created."
- ;;
-
-uninstall)
- $echo \
-"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
-
-Remove libraries from an installation directory.
-
-RM is the name of the program to use to delete files associated with each FILE
-(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
-to RM.
-
-If FILE is a libtool library, all the files associated with it are deleted.
-Otherwise, only FILE itself is deleted using RM."
- ;;
-
-*)
- $echo "$modename: invalid operation mode \`$mode'" 1>&2
- $echo "$help" 1>&2
- exit 1
- ;;
-esac
-
-echo
-$echo "Try \`$modename --help' for more information about other modes."
-
-exit 0
-
-# Local Variables:
-# mode:shell-script
-# sh-indentation:2
-# End:
+++ /dev/null
-#! /bin/sh
-
-## $Id: makedepend 5787 2002-09-29 23:32:52Z rra $
-##
-## Generate dependencies for INN makefiles
-##
-## This shell script automates the process of updating the dependencies in
-## INN's Makefiles. It uses gcc -MM to do this, since only the maintainers
-## should normally have to do this and using a compiler to parse include
-## directives is more reliable than more ad hoc methods. It takes compiler
-## flags as its first argument and then a list of all source files to
-## process.
-##
-## The Makefile is updated in place, and everything after "DO NOT DELETE
-## THIS LINE" is removed and replaced by the dependencies.
-
-flags="$1"
-shift
-sed '1,/DO NOT DELETE THIS LINE/!d' < Makefile > .makefile.tmp
-for source in "$@" ; do
- case $source in
- */*)
- base=`echo "$source" | sed 's/\..*//'`
- gcc -MM $flags "$source" | sed "s%^[^.: ][^.: ]*%$base%" \
- >> .makefile.tmp
- ;;
- *)
- gcc -MM $flags "$source" >> .makefile.tmp
- ;;
- esac
- if [ $? != 0 ] ; then
- rm .makefile.tmp
- exit
- fi
-done
-mv -f .makefile.tmp Makefile
+++ /dev/null
-#! /usr/bin/perl -w
-
-## $Id: mkchangelog 7473 2005-12-24 21:29:22Z eagle $
-##
-## Generate a ChangeLog from svn log using svn2cl.
-##
-## This script prompts the user for a date from which to pull log entries
-## and the prefix to strip from file names and generates a ChangeLog file
-## by running svn2cl.
-
-$| = 1;
-
-print "Enter prefix to strip from file names: ";
-my $prefix = <STDIN>;
-chomp $prefix;
-
-print "Enter date to start log at (YYYY-MM-DD): ";
-my $date = <STDIN>;
-chomp $date;
-
-print "\nRunning svn2cl....\n";
-system ("svn2cl --strip-prefix=$prefix --group-by-day -r 'HEAD:{$date}'") == 0
- or die "svn2cl exited with status " . ($? >> 8) . "\n";
+++ /dev/null
-#! /usr/bin/perl -w
-
-## $Id: mkmanifest 7307 2005-06-11 08:38:15Z eagle $
-##
-## Generate a filename-only manifest from an INN tree.
-##
-## This script generates a filename-only manifest from an INN tree, excluding
-## certain files according to .cvsignore files and several built-in rules.
-## It is intended to be used to support make check-manifest from the top
-## level of the INN tree.
-
-require 5.005;
-
-use strict;
-use vars qw(%CVSIGNORE @FILES @IGNORE);
-
-use File::Find qw(find);
-
-# The following regex patterns match files to be ignored wherever they are
-# in the tree. This is intended to handle files that CVS ignores by default
-# or files that are present in the tree and in CVS but which are not included
-# in releases.
-@IGNORE = (qr%(\A|/)\.cvsignore\Z%, qr/\.[ao]\Z/, qr%(\A|/)CVS(/|\Z)%,
- qr%(\A|/)\.?\#%, qr/\.(old|bak|orig|rej)$/, qr%(\A|/)core\Z%,
- qr/~$/, qr%(\A|/)\.pure%, qr%(\A|/)\.svn(/|\Z)%);
-
-# Build a list of all the files ignored by rules in .cvsignore files. Meant
-# to be run as the wanted sub of a call to File::Find. Stuff in .cvsignore
-# that contains wildcards needs to be lifted into the list of @IGNORE regexes.
-sub find_cvsignore {
- return unless $_ eq '.cvsignore';
- return unless -f;
- my $file = $_;
- $file =~ s%^\./%%;
- my @ignored;
- my $dir = $File::Find::dir;
- $dir =~ s%^\./?%%;
- if ($dir) {
- $dir .= '/';
- }
- open (CVSIGNORE, $_) or die "Cannot open $File::Find::name: $!\n";
- @ignored = map { $dir . $_ } map { split (' ', $_) } <CVSIGNORE>;
- close CVSIGNORE;
- for (@ignored) {
- if (/\*/) {
- my $pattern = $_;
- $pattern =~ s/\./\\./g;
- $pattern =~ s/\*/.*/g;
- push (@IGNORE, qr/\A$pattern\Z/);
- } else {
- $CVSIGNORE{$_}++;
- }
- }
-}
-
-# Build a list of all files in the tree that aren't ignored by .cvsignore
-# files or listed in ignore regexes.
-sub find_files {
- return if $_ eq '.';
- my $name = $File::Find::name;
- $name =~ s%^./%%;
- if ($CVSIGNORE{$name}) {
- $File::Find::prune = 1;
- return;
- }
- for my $pattern (@IGNORE) {
- return if $name =~ /$pattern/;
- }
- push (@FILES, $name);
-}
-
-find (\&find_cvsignore, '.');
-find (\&find_files, '.');
-print join ("\n", (sort @FILES), '');
+++ /dev/null
-#! /bin/sh
-
-## $Id: mksnapshot 7308 2005-06-11 08:39:54Z eagle $
-##
-## Build a snapshot of the current tree.
-##
-## Meant to be run on a fresh Subversion checkout, this script does the
-## necessary work to generate a snapshot. It expects to be invoked from the
-## top level of the source tree and leaves the generated snapshot in that
-## same directory as a .tar.gz file.
-##
-## Snapshot generation will fail if the tree will not compile or if make test
-## fails. In either case, the output is left in snapshot.log.
-##
-## This script takes one argument, a string representing what tree the
-## snapshot is being taken from. Generally this string is either CURRENT or
-## STABLE.
-
-set -e
-
-date=`date -u +%Y%m%d`
-tree="$1"
-if [ -z "$tree" ] ; then
- echo "$0: no tree name specified" >&2
- exit 1
-fi
-
-exec > snapshot.log 2>&1
-
-./configure
-make warnings
-make test
-make check-manifest
-
-cat > README.snapshot <<EOF
-This is a snapshot of the current development version of INN, pulled
-automatically from the Subversion repository. It was made on:
-
- `date -u +"%B %e, %Y @ %I:%M %p %Z"`
-
-This code should be considered experimental. Only a default compile and
-automated testing is done before it is made available. If it breaks, we'd
-like to know at inn-bugs@isc.org, but if it causes your system to explode,
-don't blame us.
-
-If you are using this code, it's highly recommended that you be on the
-inn-workers@isc.org mailing list. See README for more information.
-EOF
-
-make snapshot SNAPSHOT="$tree" SNAPDATE="$date"
+++ /dev/null
-#! /bin/sh
-
-## $Id: mksystem 6397 2003-07-12 19:14:58Z rra $
-##
-## Create include/inn/system.h from include/config.h.
-##
-## include/config.h is generated by autoconf and contains all of the test
-## results for a platform. Most of these are only used when building INN,
-## but some of them are needed for various definitions in the header files
-## for INN's libraries. We want to be able to install those header files
-## and their prerequisites, but we don't want to define the normal symbols
-## defined by autoconf since they're too likely to conflict with other
-## packages.
-##
-## This script takes the path to awk as its first argument and the path to
-## include/config.h as its second argument and generates a file suitable
-## for being included as <inn/system.h>. It contains only the autoconf
-## results needed for INN's API, and the symbols that might conflict with
-## autoconf results in other packages have INN_ prepended.
-
-cat <<EOF
-/* Automatically generated by mksystem from config.h; do not edit. */
-
-/* This header contains information obtained by INN at configure time that
- is needed by INN headers. Autoconf results that may conflict with the
- autoconf results of another package have INN_ prepended to the
- preprocessor symbols. */
-
-#ifndef INN_SYSTEM_H
-#define INN_SYSTEM_H 1
-
-EOF
-
-$1 '
-
-/^#define HAVE_C99_VAMACROS/ { print save $1 " INN_" $2 " " $3 "\n" }
-/^#define HAVE_GNU_VAMACROS/ { print save $1 " INN_" $2 " " $3 "\n" }
-/^#define HAVE_INTTYPES_H/ { print save $1 " INN_" $2 " " $3 "\n" }
-/^#define HAVE_MSYNC_3_ARG/ { print save $1 " INN_" $2 " " $3 "\n" }
-/^#define HAVE_STDBOOL_H/ { print save $1 " INN_" $2 " " $3 "\n" }
-/^#define HAVE_SYS_BITTYPES_H/ { print save $1 " INN_" $2 " " $3 "\n" }
-
-{ save = $0 "\n" }' $2
-
-cat <<EOF
-#endif /* INN_SYSTEM_H */
-EOF
+++ /dev/null
-#! /bin/sh
-
-## $Id: mkversion 7345 2005-07-02 05:04:05Z eagle $
-##
-## Create version.h from INN version information.
-##
-## Makefile.global contains the INN version number and extra version
-## information (if any). This is passed to use by lib/Makefile as our
-## first and second arguments. Print a header file suitable for use
-## as inn/version.h on stdout.
-
-version="$1"
-extra="$2"
-string="INN $version"
-if [ x"$extra" = x"prerelease" ] ; then
- date=`date +%Y%m%d`
- extra="$date $extra"
-fi
-if [ -n "$extra" ] ; then
- string="$string ($extra)"
-fi
-major=`echo "$version" | cut -d. -f1`
-minor=`echo "$version" | cut -d. -f2`
-patch=`echo "$version" | cut -d. -f3`
-
-cat <<EOF
-/* Automatically generated by mkversion, edit Makefile.global to change. */
-
-#ifndef INN_VERSION_H
-#define INN_VERSION_H 1
-
-#define INN_VERSION_MAJOR $major
-#define INN_VERSION_MINOR $minor
-#define INN_VERSION_PATCH $patch
-#define INN_VERSION_EXTRA "$extra"
-#define INN_VERSION_STRING "$string"
-
-#endif /* INN_VERSION_H */
-EOF
+++ /dev/null
-## $Id: Makefile 7494 2006-03-19 23:19:30Z eagle $
-
-include ../Makefile.global
-
-top = ..
-CFLAGS = $(GCFLAGS) -I.
-
-## The tests that need to be built. Tests in the form of shell scripts
-## or some other form that doesn't require compiling shouldn't be in this
-## list. If they need other things compiled, those other things should be
-## added to EXTRA.
-
-TESTS = lib/buffer.t lib/concat.t lib/confparse.t lib/date.t lib/hash.t \
- lib/hashtab.t lib/hstrerror.t lib/inet_aton.t lib/inet_ntoa.t \
- lib/innconf.t lib/list.t lib/md5.t lib/memcmp.t lib/messages.t \
- lib/mkstemp.t lib/pread.t lib/pwrite.t lib/qio.t lib/snprintf.t \
- lib/strerror.t lib/strlcat.t lib/strlcpy.t lib/tst.t lib/uwildmat.t \
- lib/vector.t lib/wire.t lib/xwrite.t overview/tradindexed.t
-
-## Extra stuff that needs to be built before tests can be run.
-
-EXTRA = runtests lib/setenv.tr lib/xmalloc
-
-all check test: $(TESTS) $(EXTRA)
- ./runtests TESTS
-
-build: $(TESTS) $(EXTRA)
-
-warnings:
- $(MAKE) COPT='$(WARNINGS)' build
-
-clean clobber distclean:
- rm -f *.o *.lo */*.o */*.lo .pure */.pure $(TESTS) $(EXTRA)
- rm -rf .libs */.libs
-
-.c.o: $*.c
- $(CC) $(CFLAGS) -c -o $@ $*.c
-
-LINK = $(LIBTOOL) $(CC) $(LDFLAGS) -o $@
-STORAGEDEPS = $(LIBSTORAGE) $(LIBHIST) $(LIBINN)
-STORAGELIBS = $(STORAGEDEPS) $(EXTSTORAGELIBS)
-
-runtests: runtests.o
- $(LINK) runtests.o
-
-lib/buffer.t: lib/buffer-t.o libtest.o $(LIBINN)
- $(LINK) lib/buffer-t.o libtest.o $(LIBINN)
-
-lib/concat.t: lib/concat-t.o libtest.o $(LIBINN)
- $(LINK) lib/concat-t.o libtest.o $(LIBINN)
-
-lib/confparse.t: lib/confparse-t.o libtest.o $(LIBINN)
- $(LINK) lib/confparse-t.o libtest.o $(LIBINN)
-
-lib/date.t: lib/date-t.o libtest.o $(LIBINN)
- $(LINK) lib/date-t.o libtest.o $(LIBINN)
-
-lib/hash.t: lib/hash-t.o libtest.o $(LIBINN)
- $(LINK) lib/hash-t.o libtest.o $(LIBINN)
-
-lib/hashtab.t: lib/hashtab-t.o libtest.o $(LIBINN)
- $(LINK) lib/hashtab-t.o libtest.o $(LIBINN)
-
-lib/hstrerror.o: ../lib/hstrerror.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/hstrerror.c
-
-lib/hstrerror.t: lib/hstrerror.o lib/hstrerror-t.o libtest.o
- $(LINK) lib/hstrerror.o lib/hstrerror-t.o libtest.o $(LIBINN)
-
-lib/inet_aton.o: ../lib/inet_aton.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/inet_aton.c
-
-lib/inet_aton.t: lib/inet_aton.o lib/inet_aton-t.o
- $(LINK) lib/inet_aton.o lib/inet_aton-t.o
-
-lib/inet_ntoa.o: ../lib/inet_ntoa.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/inet_ntoa.c
-
-lib/inet_ntoa.t: lib/inet_ntoa.o lib/inet_ntoa-t.o libtest.o
- $(LINK) lib/inet_ntoa.o lib/inet_ntoa-t.o libtest.o $(LIBINN)
-
-lib/innconf.t: lib/innconf-t.o libtest.o $(LIBINN)
- $(LINK) lib/innconf-t.o libtest.o $(LIBINN) $(LIBS)
-
-lib/list.t: lib/list-t.o libtest.o $(LIBINN)
- $(LINK) lib/list-t.o libtest.o $(LIBINN) $(LIBS)
-
-lib/md5.t: lib/md5-t.o libtest.o $(LIBINN)
- $(LINK) lib/md5-t.o libtest.o $(LIBINN)
-
-lib/memcmp.o: ../lib/memcmp.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/memcmp.c
-
-lib/memcmp.t: lib/memcmp.o lib/memcmp-t.o libtest.o
- $(LINK) lib/memcmp.o lib/memcmp-t.o libtest.o $(LIBINN)
-
-lib/messages.o: ../lib/messages.c
- $(CC) $(CFLAGS) -DDEBUG -c -o $@ ../lib/messages.c
-
-lib/messages-t.o: lib/messages-t.c
- $(CC) $(CFLAGS) -DDEBUG -c -o $@ lib/messages-t.c
-
-lib/messages.t: lib/messages.o lib/messages-t.o $(LIBINN)
- $(LINK) lib/messages-t.o lib/messages.o $(LIBINN)
-
-lib/mkstemp.o: ../lib/mkstemp.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/mkstemp.c
-
-lib/mkstemp.t: lib/mkstemp.o lib/mkstemp-t.o libtest.o
- $(LINK) lib/mkstemp.o lib/mkstemp-t.o libtest.o $(LIBINN)
-
-lib/pread.o: ../lib/pread.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/pread.c
-
-lib/pread.t: lib/pread.o lib/pread-t.o libtest.o $(LIBINN)
- $(LINK) lib/pread.o lib/pread-t.o libtest.o $(LIBINN)
-
-lib/pwrite.o: ../lib/pwrite.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/pwrite.c
-
-lib/pwrite.t: lib/pwrite.o lib/pwrite-t.o libtest.o $(LIBINN)
- $(LINK) lib/pwrite.o lib/pwrite-t.o libtest.o $(LIBINN)
-
-lib/qio.t: lib/qio-t.o libtest.o $(LIBINN)
- $(LINK) lib/qio-t.o libtest.o $(LIBINN)
-
-lib/setenv.o: ../lib/setenv.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/setenv.c
-
-lib/setenv.tr: lib/setenv.o lib/setenv-t.o libtest.o $(LIBINN)
- $(LINK) lib/setenv.o lib/setenv-t.o libtest.o $(LIBINN)
-
-lib/snprintf.o: ../lib/snprintf.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/snprintf.c
-
-lib/snprintf.t: lib/snprintf.o lib/snprintf-t.o libtest.o
- $(LINK) lib/snprintf.o lib/snprintf-t.o libtest.o $(LIBINN)
-
-lib/strerror.o: ../lib/strerror.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/strerror.c
-
-lib/strerror.t: lib/strerror.o lib/strerror-t.o libtest.o
- $(LINK) lib/strerror.o lib/strerror-t.o libtest.o $(LIBINN)
-
-lib/strlcat.o: ../lib/strlcat.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/strlcat.c
-
-lib/strlcat.t: lib/strlcat.o lib/strlcat-t.o libtest.o
- $(LINK) lib/strlcat.o lib/strlcat-t.o libtest.o $(LIBINN)
-
-lib/strlcpy.o: ../lib/strlcpy.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/strlcpy.c
-
-lib/strlcpy.t: lib/strlcpy.o lib/strlcpy-t.o libtest.o
- $(LINK) lib/strlcpy.o lib/strlcpy-t.o libtest.o $(LIBINN)
-
-lib/tst.t: lib/tst-t.o $(LIBINN)
- $(LINK) lib/tst-t.o libtest.o $(LIBINN)
-
-lib/uwildmat.t: lib/uwildmat-t.o $(LIBINN)
- $(LINK) lib/uwildmat-t.o $(LIBINN)
-
-lib/vector.t: lib/vector-t.o libtest.o $(LIBINN)
- $(LINK) lib/vector-t.o libtest.o $(LIBINN)
-
-lib/wire.t: lib/wire-t.o libtest.o $(LIBINN)
- $(LINK) lib/wire-t.o libtest.o $(LIBINN)
-
-lib/xmalloc: lib/xmalloc.o $(LIBINN)
- $(LINK) lib/xmalloc.o $(LIBINN)
-
-lib/xwrite.o: ../lib/xwrite.c
- $(CC) $(CFLAGS) -DTESTING -c -o $@ ../lib/xwrite.c
-
-lib/xwrite.t: lib/xwrite-t.o lib/xwrite.o lib/fakewrite.o $(LIBINN)
- $(LINK) lib/xwrite-t.o lib/xwrite.o lib/fakewrite.o $(LIBINN)
-
-overview/tradindexed.t: overview/tradindexed-t.o libtest.o $(STORAGEDEPS)
- $(LINK) overview/tradindexed-t.o libtest.o $(STORAGELIBS) $(LIBS)
+++ /dev/null
-authprogs/ckpasswd
-authprogs/domain
-lib/buffer
-lib/concat
-lib/confparse
-lib/date
-lib/hash
-lib/hashtab
-lib/inet_aton
-lib/inet_ntoa
-lib/innconf
-lib/list
-lib/md5
-lib/memcmp
-lib/messages
-lib/mkstemp
-lib/pread
-lib/pwrite
-lib/qio
-lib/setenv
-lib/snprintf
-lib/strerror
-lib/strlcat
-lib/strlcpy
-lib/tst
-lib/uwildmat
-lib/vector
-lib/wire
-lib/xmalloc
-lib/xwrite
-overview/tradindexed
-util/convdate
+++ /dev/null
-#! /bin/sh
-# $Id: ckpasswd.t 5572 2002-08-12 06:01:09Z rra $
-#
-# Test suite for ckpasswd.
-
-# The count starts at 1 and is updated each time ok is printed. printcount
-# takes "ok" or "not ok".
-count=1
-printcount () {
- echo "$1 $count $2"
- count=`expr $count + 1`
-}
-
-# Run ckpasswd, expecting it to succeed. Takes a username, a password, any
-# additional options, and the expected output string.
-runsuccess () {
- output=`$ckpasswd -u "$1" -p "$2" $3 2>&1`
- status=$?
- if test $status = 0 && test x"$output" = x"$4" ; then
- printcount "ok"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $4"
- fi
-}
-
-# Run ckpasswd, feeding it the username and password on stdin in the same way
-# that nnrpd would. Takes a username, a password, any additional options, and
-# the expected output string.
-runpipe () {
- output=`( echo ClientAuthname: $1 ; echo ClientPassword: $2 ) \
- | $ckpasswd $3 2>&1`
- status=$?
- if test $status = 0 && test x"$output" = x"$4" ; then
- printcount "ok"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $4"
- fi
-}
-
-# Run ckpasswd, expecting it to fail, and make sure it fails with status 1 and
-# prints out the right error message. Takes a username, a password, any
-# additional options, and the expected output string.
-runfailure () {
- output=`$ckpasswd -u "$1" -p "$2" $3 2>&1`
- status=$?
- if test $status = 1 && test x"$output" = x"$4" ; then
- printcount "ok"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $4"
- fi
-}
-
-# Make sure we're in the right directory.
-for dir in . authprogs tests/authprogs ; do
- test -f "$dir/passwd" && cd $dir
-done
-ckpasswd=../../authprogs/ckpasswd
-
-# Print the test count.
-echo 7
-
-# First, run the tests that we expect to succeed.
-runsuccess "foo" "foopass" "-f passwd" "User:foo"
-runsuccess "bar" "barpass" "-f passwd" "User:bar"
-runsuccess "baz" "" "-f passwd" "User:baz"
-runpipe "foo" "foopass" "-f passwd" "User:foo"
-
-# Now, run the tests that we expect to fail.
-runfailure "foo" "barpass" "-f passwd" \
- "ckpasswd: invalid password for user foo"
-runfailure "who" "foopass" "-f passwd" \
- "ckpasswd: user who unknown"
-runfailure "" "foopass" "-f passwd" \
- "ckpasswd: null username"
+++ /dev/null
-#! /bin/sh
-# $Id: domain.t 5948 2002-12-08 04:20:46Z rra $
-#
-# Test suite for domain.
-
-# The count starts at 1 and is updated each time ok is printed. printcount
-# takes "ok" or "not ok".
-count=1
-printcount () {
- echo "$1 $count $2"
- count=`expr $count + 1`
-}
-
-# Run domain, expecting it to succeed. Feed it the client host the way that
-# nnrpd would. Takes the client host, the domain to check it against, and the
-# user expected.
-runsuccess () {
- output=`( echo ClientHost: $1 ; echo ClientIP: 127.0.0.1 ; \
- echo ClientPort: 0 ; echo LocalIP: 127.0.0.1 ; \
- echo LocalPort: 119) | $domain $2 2>&1`
- status=$?
- if test $status = 0 && test x"$output" = x"$3" ; then
- printcount "ok"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $3"
- fi
-}
-
-# Run domain, expecting it to fail, and make sure it fails with status 1 and
-# prints out the right error message. Takes the client host, the domain to
-# check it against, and the expected output string.
-runfailure () {
- output=`( echo ClientHost: $1 ; echo ClientIP: 127.0.0.1 ; \
- echo ClientPort: 0 ; echo LocalIP: 127.0.0.1 ; \
- echo LocalPort: 119) | $domain $2 2>&1`
- status=$?
- if test $status = 1 && test x"$output" = x"$3" ; then
- printcount "ok"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $3"
- fi
-}
-
-# Make sure we're in the right directory.
-domain=domain
-for dir in authprogs ../authprogs ../../authprogs ; do
- test -x "$dir/domain" && domain="$dir/domain"
-done
-
-# Print the test count.
-echo 8
-
-# First, run the tests that we expect to succeed.
-runsuccess "foo.example.com" ".example.com" "User:foo"
-runsuccess "foo.example.com" "example.com" "User:foo"
-runsuccess "foo.bar.example.com" ".example.com" "User:foo.bar"
-runsuccess "foo.bar.example.com" "example.com" "User:foo.bar"
-runsuccess "foo.example.com" "com" "User:foo.example"
-
-# Now, run the tests that we expect to fail.
-runfailure "example.com" "example.com" \
- "domain: host example.com matches the domain exactly"
-runfailure "foo.example.com" "example.net" \
- "domain: host foo.example.com didn't match domain example.net"
-runfailure "fooexample.com" "example.com" \
- "domain: host fooexample.com didn't match domain example.com"
+++ /dev/null
-# This is a comment.
-foo:bZukvB.43WoX.:5:5:Foo Bar:/home/foo:/bin/sh
-
-# This is another comment.
-
-This is just some random text that someone put in this file for no good
-reason.
-
-bar:9oV.zhEh2nexE
-baz:qq2C4zterbO2k::::::::::::::::::::::
+++ /dev/null
-Path: foo!bar\r
-From: example@example.com\r
-Subject: Test\r
-Date: Mon, 23 Dec 2002 16:00:04 -0700\r
-Message-ID: <id1@example.com>\r
+++ /dev/null
-Path: foo!bar\r
-From: example@example.com\r
-Subject: Test\r
-Message-ID: <id1@example.com>\r
-Date: Mon, 23 Dec 2002 16:00:04
\ No newline at end of file
+++ /dev/null
-/* $Id: buffer-t.c 5469 2002-05-20 12:50:57Z alexk $ */
-/* buffer test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/buffer.h"
-#include "libtest.h"
-
-static const char test_string1[] = "This is a test";
-static const char test_string2[] = " of the buffer system";
-static const char test_string3[] = "This is a test\0 of the buffer system";
-
-int
-main(void)
-{
- struct buffer one = { 0, 0, 0, NULL };
- struct buffer two = { 0, 0, 0, NULL };
- struct buffer *three;
-
- puts("26");
-
- buffer_set(&one, test_string1, sizeof(test_string1));
- ok_int(1, 1024, one.size);
- ok_int(2, 0, one.used);
- ok_int(3, sizeof(test_string1), one.left);
- ok_string(4, test_string1, one.data);
- buffer_append(&one, test_string2, sizeof(test_string2));
- ok_int(5, 1024, one.size);
- ok_int(6, 0, one.used);
- ok_int(7, sizeof(test_string3), one.left);
- ok(8, memcmp(one.data, test_string3, sizeof(test_string3)) == 0);
- one.left -= sizeof(test_string1);
- one.used += sizeof(test_string1);
- buffer_append(&one, test_string1, sizeof(test_string1));
- ok_int(9, 1024, one.size);
- ok_int(10, sizeof(test_string1), one.used);
- ok_int(11, sizeof(test_string3), one.left);
- ok(12,
- memcmp(one.data + one.used, test_string2, sizeof(test_string2)) == 0);
- ok(13,
- memcmp(one.data + one.used + sizeof(test_string2), test_string1,
- sizeof(test_string1)) == 0);
- buffer_set(&one, test_string1, sizeof(test_string1));
- buffer_set(&two, test_string2, sizeof(test_string2));
- buffer_swap(&one, &two);
- ok_int(14, 1024, one.size);
- ok_int(15, 0, one.used);
- ok_int(16, sizeof(test_string2), one.left);
- ok_string(17, test_string2, one.data);
- ok_int(18, 1024, two.size);
- ok_int(19, 0, two.used);
- ok_int(20, sizeof(test_string1), two.left);
- ok_string(21, test_string1, two.data);
-
- three = buffer_new();
- ok(22, three != NULL);
- ok_int(23, 0, three->size);
- buffer_set(three, test_string1, sizeof(test_string1));
- ok_int(24, 1024, three->size);
- buffer_resize(three, 512);
- ok_int(25, 1024, three->size);
- buffer_resize(three, 1025);
- ok_int(26, 2048, three->size);
- free(three->data);
- free(three);
-
- return 0;
-}
+++ /dev/null
-/* $Id: concat-t.c 5054 2001-12-12 09:15:24Z rra $ */
-/* concat test suite. */
-
-#include <stdio.h>
-#include <string.h>
-
-#include "libinn.h"
-#include "libtest.h"
-
-#define END (char *) 0
-
-int
-main(void)
-{
- printf("11\n");
-
- ok_string( 1, "a", concat("a", END));
- ok_string( 2, "ab", concat("a", "b", END));
- ok_string( 3, "ab", concat("ab", "", END));
- ok_string( 4, "ab", concat("", "ab", END));
- ok_string( 5, "", concat("", END));
- ok_string( 6, "abcde", concat("ab", "c", "", "de", END));
- ok_string( 7, "abcde", concat("abc", "de", END, "f", END));
-
- ok_string( 8, "/foo", concatpath("/bar", "/foo"));
- ok_string( 9, "/foo/bar", concatpath("/foo", "bar"));
- ok_string(10, "./bar", concatpath("/foo", "./bar"));
- ok_string(11, "/bar/baz/foo/bar", concatpath("/bar/baz", "foo/bar"));
-
- return 0;
-}
+++ /dev/null
-foo bar
-===
-config/tmp:1: parse error: saw string, expecting parameter
-===
-parameter: value with spaces
-===
-config/tmp:1: parse error: saw string, expecting semicolon or newline
-===
-parameter: escape\tvalue
-===
-config/tmp:1: invalid character '\' in unquoted string
-===
-parameter:: value
-===
-config/tmp:1: invalid character ':' in unquoted string
-===
-parameter: "value
-===
-config/tmp:1: no close quote seen for quoted string
-===
-parameter: value ; value
-===
-config/tmp:1: parse error: saw string, expecting parameter
-===
-parameter: # value
-value
-===
-config/tmp:1: parse error: saw string, expecting semicolon or newline
-===
-"foo bar"
-===
-config/tmp:1: parse error: saw quoted string, expecting parameter
-===
-first: second
-third: fourth
-parameter: "value \
-===
-config/tmp:4: end of file encountered while parsing quoted string
-===
-parameter:value
-===
-config/tmp:1: invalid character ':' in unquoted string
-===
-parameter: value # this is a comment
-===
-config/tmp:1: parse error: saw string, expecting semicolon or newline
-===
-parameter: "value
-value"
-===
-config/tmp:1: no close quote seen for quoted string
-===
+++ /dev/null
-# This is a leading comment.
-param1: on
-param2: true
-param3: yes
-# this is a comment \
-param4: off
- # this is another
-int1: 0
-
-int2: -3
+++ /dev/null
-# Test a lack of newline at the end of the configuration file.
-parameter: value
\ No newline at end of file
+++ /dev/null
-foo: baz
-bar: baz
+++ /dev/null
-# This is a leading comment.
-param1: on
-
- param2: true
-
-
-param3: yes
-# this is a comment \
-param4: off
- # this is another
-# comment
- # on several lines
- param5: false ; param6: no
-
-int1: 0 ; int2: -3
- # int3: 5000
- int4: 5000
-int5: 2147483647
-int6: -2147483648
-
-string1: foo; string2: bar
-string3: "this is a test"
-string4: "this is \
-a test"
-string5: "this is \a\b\f\n\r\t\v a test \' of \" escapes \?\\"
-string6: "\
-# this is not a comment\
-"; string7: "lost \
-\nyet?"
+++ /dev/null
-parameter: "yes"
-===
-config/tmp:1: parameter is not a boolean
-===
-parameter: False
-===
-config/tmp:1: parameter is not a boolean
-===
-foo: bar
-parameter: 0
-===
-config/tmp:2: parameter is not a boolean
-===
+++ /dev/null
-parameter: "foo"
-===
-config/tmp:1: parameter is not an integer
-===
-# Check that line numbers are right.
-key: value; parameter: foobar
-===
-config/tmp:2: parameter is not an integer
-===
-parameter: 999999999999999999999999999999999999999999999999999999999999
-===
-config/tmp:1: parameter doesn't convert to an integer
-===
+++ /dev/null
-# Make sure line numbering copes with a leading comment.
-parameter: value
-parameter: value
-===
-config/tmp:3: duplicate parameter parameter
-===
-# Line numbering and Macs.
-parameter: value
-parameter: value
-===
-config/tmp:3: duplicate parameter parameter
-===
-# Line numbering and Windows.
-parameter: value
-parameter: value
-===
-config/tmp:3: duplicate parameter parameter
-===
+++ /dev/null
-/* $Id: confparse-t.c 5955 2002-12-08 09:28:32Z rra $ */
-/* confparse test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <unistd.h>
-
-#include "inn/confparse.h"
-#include "inn/messages.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "libtest.h"
-
-/* Given a FILE *, read from that file, putting the results into a newly
- allocated buffer, until encountering a line consisting solely of "===".
- Returns the buffer, NULL on end of file, dies on error. */
-static char *
-read_section(FILE *file)
-{
- char buf[1024] = "";
- char *data = NULL;
- char *status;
-
- status = fgets(buf, sizeof(buf), file);
- if (status == NULL)
- return false;
- while (1) {
- if (status == NULL)
- die("Unexpected end of file while reading tests");
- if (strcmp(buf, "===\n") == 0)
- break;
- if (data == NULL) {
- data = xstrdup(buf);
- } else {
- char *new_data;
-
- new_data = concat(data, buf, (char *) 0);
- free(data);
- data = new_data;
- }
- status = fgets(buf, sizeof(buf), file);
- }
- return data;
-}
-
-/* Read from the given file a configuration file and write it out to
- config/tmp. Returns true on success, false on end of file, and dies on
- any error. */
-static bool
-write_test_config(FILE *file)
-{
- FILE *tmp;
- char *config;
-
- config = read_section(file);
- if (config == NULL)
- return false;
- tmp = fopen("config/tmp", "w");
- if (tmp == NULL)
- sysdie("Cannot create config/tmp");
- if (fputs(config, tmp) == EOF)
- sysdie("Write error while writing to config/tmp");
- fclose(tmp);
- free(config);
- return true;
-}
-
-/* Parse a given config file with errors, setting the appropriate error
- handler for the duration of the parse to save errors into the errors
- global. Returns the resulting config_group. */
-static struct config_group *
-parse_error_config(const char *filename)
-{
- struct config_group *group;
-
- errors_capture();
- group = config_parse_file(filename);
- errors_uncapture();
- return group;
-}
-
-/* Read in a configuration file from the provided FILE *, write it to disk,
- parse the temporary config file, and return the resulting config_group in
- the pointer passed as the second parameter. Returns true on success,
- false on end of file. */
-static bool
-parse_test_config(FILE *file, struct config_group **group)
-{
- if (!write_test_config(file))
- return false;
- *group = parse_error_config("config/tmp");
- unlink("config/tmp");
- return true;
-}
-
-/* Test the error test cases in config/errors, ensuring that they all fail
- to parse and match the expected error messages. Takes the current test
- count and returns the new test count. */
-static int
-test_errors(int n)
-{
- FILE *errfile;
- char *expected;
- struct config_group *group;
-
- errfile = fopen("config/errors", "r");
- if (errfile == NULL)
- sysdie("Cannot open config/errors");
- while (parse_test_config(errfile, &group)) {
- expected = read_section(errfile);
- if (expected == NULL)
- die("Unexpected end of file while reading error tests");
- ok(n++, group == NULL);
- ok_string(n++, expected, errors);
- free(expected);
- }
- fclose(errfile);
- return n;
-}
-
-/* Test the warning test cases in config/warningss, ensuring that they all
- parse successfully and match the expected error messages. Takes the
- current test count and returns the new test count. */
-static int
-test_warnings(int n)
-{
- FILE *warnfile;
- char *expected;
- struct config_group *group;
-
- warnfile = fopen("config/warnings", "r");
- if (warnfile == NULL)
- sysdie("Cannot open config/warnings");
- while (parse_test_config(warnfile, &group)) {
- expected = read_section(warnfile);
- if (expected == NULL)
- die("Unexpected end of file while reading error tests");
- ok(n++, group != NULL);
- ok_string(n++, expected, errors);
- free(expected);
- }
- fclose(warnfile);
- return n;
-}
-
-/* Test the warning test cases in config/warn-bool, ensuring that they all
- parse successfully and produce the expected error messages when retrieved
- as bools. Takes the current test count and returns the new test count. */
-static int
-test_warnings_bool(int n)
-{
- FILE *warnfile;
- char *expected;
- struct config_group *group;
- bool b_value = false;
-
- warnfile = fopen("config/warn-bool", "r");
- if (warnfile == NULL)
- sysdie("Cannot open config/warn-bool");
- while (parse_test_config(warnfile, &group)) {
- expected = read_section(warnfile);
- if (expected == NULL)
- die("Unexpected end of file while reading error tests");
- ok(n++, group != NULL);
- ok(n++, errors == NULL);
- errors_capture();
- ok(n++, !config_param_boolean(group, "parameter", &b_value));
- ok_string(n++, expected, errors);
- errors_uncapture();
- free(expected);
- }
- fclose(warnfile);
- return n;
-}
-
-/* Test the warning test cases in config/warn-int, ensuring that they all
- parse successfully and produce the expected error messages when retrieved
- as bools. Takes the current test count and returns the new test count. */
-static int
-test_warnings_int(int n)
-{
- FILE *warnfile;
- char *expected;
- struct config_group *group;
- long l_value = 1;
-
- warnfile = fopen("config/warn-int", "r");
- if (warnfile == NULL)
- sysdie("Cannot open config/warn-int");
- while (parse_test_config(warnfile, &group)) {
- expected = read_section(warnfile);
- if (expected == NULL)
- die("Unexpected end of file while reading error tests");
- ok(n++, group != NULL);
- ok(n++, errors == NULL);
- errors_capture();
- ok(n++, !config_param_integer(group, "parameter", &l_value));
- ok_string(n++, expected, errors);
- errors_uncapture();
- free(expected);
- }
- fclose(warnfile);
- return n;
-}
-
-int
-main(void)
-{
- struct config_group *group;
- bool b_value = false;
- long l_value = 1;
- const char *s_value;
- struct vector *v_value;
- char *long_param, *long_value;
- size_t length;
- int n;
- FILE *tmpconfig;
-
- puts("125");
-
- if (access("config/valid", F_OK) < 0)
- if (access("lib/config/valid", F_OK) == 0)
- chdir("lib");
- group = config_parse_file("config/valid");
- ok(1, group != NULL);
- if (group == NULL)
- exit(1);
-
- /* Booleans. */
- ok(2, config_param_boolean(group, "param1", &b_value));
- ok(3, b_value);
- b_value = false;
- ok(4, config_param_boolean(group, "param2", &b_value));
- ok(5, b_value);
- b_value = false;
- ok(6, config_param_boolean(group, "param3", &b_value));
- ok(7, b_value);
- ok(8, config_param_boolean(group, "param4", &b_value));
- ok(9, !b_value);
- b_value = true;
- ok(10, config_param_boolean(group, "param5", &b_value));
- ok(11, !b_value);
- b_value = true;
- ok(12, config_param_boolean(group, "param6", &b_value));
- ok(13, !b_value);
-
- /* Integers. */
- ok(14, config_param_integer(group, "int1", &l_value));
- ok(15, l_value == 0);
- ok(16, config_param_integer(group, "int2", &l_value));
- ok(17, l_value == -3);
- ok(18, !config_param_integer(group, "int3", &l_value));
- ok(19, l_value == -3);
- ok(20, config_param_integer(group, "int4", &l_value));
- ok(21, l_value == 5000);
- ok(22, config_param_integer(group, "int5", &l_value));
- ok(23, l_value == 2147483647L);
- ok(24, config_param_integer(group, "int6", &l_value));
- ok(25, l_value == (-2147483647L - 1));
-
- /* Strings. */
- ok(26, config_param_string(group, "string1", &s_value));
- ok_string(27, "foo", s_value);
- ok(28, config_param_string(group, "string2", &s_value));
- ok_string(29, "bar", s_value);
- ok(30, config_param_string(group, "string3", &s_value));
- ok_string(31, "this is a test", s_value);
- ok(32, config_param_string(group, "string4", &s_value));
- ok_string(33, "this is a test", s_value);
- ok(34, config_param_string(group, "string5", &s_value));
- ok_string(35, "this is \a\b\f\n\r\t\v a test \' of \" escapes \?\\",
- s_value);
- ok(36, config_param_string(group, "string6", &s_value));
- ok_string(37, "# this is not a comment", s_value);
- ok(38, config_param_string(group, "string7", &s_value));
- ok_string(39, "lost \nyet?", s_value);
-
- config_free(group);
-
- /* Missing newline. */
- group = config_parse_file("config/no-newline");
- ok(40, group != NULL);
- if (group == NULL) {
- ok(41, false);
- ok(42, false);
- } else {
- ok(41, config_param_string(group, "parameter", &s_value));
- ok_string(42, "value", s_value);
- config_free(group);
- }
-
- /* Extremely long parameter and value. */
- tmpconfig = fopen("config/tmp", "w");
- if (tmpconfig == NULL)
- sysdie("cannot create config/tmp");
- long_param = xcalloc(20001, 1);
- memset(long_param, 'a', 20000);
- long_value = xcalloc(64 * 1024 + 1, 1);
- memset(long_value, 'b', 64 * 1024);
- fprintf(tmpconfig, "%s: \"%s\"; two: %s", long_param, long_value,
- long_value);
- fclose(tmpconfig);
- group = config_parse_file("config/tmp");
- ok(43, group != NULL);
- if (group == NULL) {
- ok(44, false);
- ok(45, false);
- ok(46, false);
- ok(47, false);
- } else {
- ok(44, config_param_string(group, long_param, &s_value));
- ok_string(45, long_value, s_value);
- ok(46, config_param_string(group, "two", &s_value));
- ok_string(47, long_value, s_value);
- config_free(group);
- }
- unlink("config/tmp");
- free(long_param);
- free(long_value);
-
- /* Parsing problems exactly on the boundary of a buffer. This test
- catches a bug in the parser that caused it to miss the colon at the end
- of a parameter because the colon was the first character read in a new
- read of the file buffer. */
- tmpconfig = fopen("config/tmp", "w");
- if (tmpconfig == NULL)
- sysdie("cannot create config/tmp");
- length = 16 * 1024 - strlen(": baz\nfoo:");
- long_param = xcalloc(length + 1, 1);
- memset(long_param, 'c', length);
- fprintf(tmpconfig, "%s: baz\nfoo: bar\n", long_param);
- fclose(tmpconfig);
- group = config_parse_file("config/tmp");
- ok(48, group != NULL);
- if (group == NULL) {
- ok(49, false);
- ok(50, false);
- ok(51, false);
- ok(52, false);
- } else {
- ok(49, config_param_string(group, long_param, &s_value));
- ok_string(50, "baz", s_value);
- ok(51, config_param_string(group, "foo", &s_value));
- ok_string(52, "bar", s_value);
- config_free(group);
- }
- unlink("config/tmp");
- free(long_param);
-
- /* Alternate line endings. */
- group = config_parse_file("config/line-endings");
- ok(53, group != NULL);
- if (group == NULL)
- exit(1);
- ok(54, config_param_boolean(group, "param1", &b_value));
- ok(55, b_value);
- b_value = false;
- ok(56, config_param_boolean(group, "param2", &b_value));
- ok(57, b_value);
- b_value = false;
- ok(58, config_param_boolean(group, "param3", &b_value));
- ok(59, b_value);
- ok(60, config_param_boolean(group, "param4", &b_value));
- ok(61, !b_value);
- ok(62, config_param_integer(group, "int1", &l_value));
- ok(63, l_value == 0);
- ok(64, config_param_integer(group, "int2", &l_value));
- ok(65, l_value == -3);
- config_free(group);
-
- /* Listing parameters. */
- group = config_parse_file("config/simple");
- ok(66, group != NULL);
- if (group == NULL)
- exit(1);
- v_value = config_params(group);
- ok_int(67, 2, v_value->count);
- ok_int(68, 2, v_value->allocated);
- if (strcmp(v_value->strings[0], "foo") == 0)
- ok_string(69, "bar", v_value->strings[1]);
- else if (strcmp(v_value->strings[0], "bar") == 0)
- ok_string(69, "foo", v_value->strings[1]);
- else
- ok(69, false);
- vector_free(v_value);
- config_free(group);
-
- /* Errors. */
- group = parse_error_config("config/null");
- ok(70, group == NULL);
- ok_string(71, "config/null: invalid NUL character found in file\n",
- errors);
- n = test_errors(72);
- n = test_warnings(n);
- n = test_warnings_bool(n);
- n = test_warnings_int(n);
-
- return 0;
-}
+++ /dev/null
-/* $Id: date-t.c 7495 2006-03-19 23:21:38Z eagle $ */
-/* makedate test suite */
-
-#include "config.h"
-#include "clibrary.h"
-#include <time.h>
-
-#include "libinn.h"
-#include "libtest.h"
-
-static const time_t test_times[] = {
- 28800UL, /* Thu, 1 Jan 1970 00:00:00 -0800 (PST) */
- 362762400UL, /* Tue, 30 Jun 1981 15:20:00 +0000 (UTC) */
- 396977449UL, /* Sat, 31 Jul 1982 15:30:49 +0000 (UTC) */
- 825597049UL, /* Thu, 29 Feb 1996 12:30:49 +0000 (UTC) */
- 850435199UL, /* Thu, 12 Dec 1996 23:59:59 +0000 (UTC) */
- 852101999UL, /* Wed, 1 Jan 1997 06:59:59 +0000 (UTC) */
- 934288249UL, /* Tue, 10 Aug 1999 12:30:49 +0000 (UTC) */
- 946684800UL, /* Sat, 1 Jan 2000 00:00:00 +0000 (UTC) */
- 946713599UL, /* Fri, 31 Dec 1999 23:59:59 -0800 (PST) */
- 946713600UL, /* Sat, 1 Jan 2000 00:00:00 -0800 (PST) */
- 951827449UL, /* Tue, 29 Feb 2000 12:30:49 +0000 (UTC) */
- 954669599UL, /* Sun, 2 Apr 2000 01:59:59 -0800 (PST) */
- 954669600UL, /* Sun, 2 Apr 2000 03:00:00 -0700 (PDT) */
- 967707668UL, /* Thu, 31 Aug 2000 07:41:08 +0000 (UTC) */
- 972813600UL /* Sun, 29 Oct 2000 02:00:00 -0800 (PST) */
-};
-
-static void
-ok_time(int n, time_t right, const char *date, const char *hour, bool local)
-{
- time_t seen;
-
- seen = parsedate_nntp(date, hour, local);
- if (right == seen)
- printf("ok %d\n", n);
- else
- printf("not ok %d\n wanted %lu seen %lu\n %s %s %d\n", n,
- (unsigned long) right, (unsigned long) seen, date, hour,
- local);
-}
-
-static void
-check_nntp(int *n, time_t timestamp)
-{
- char date[9], hour[7];
- struct tm *tmp_tm, tm;
-
- tmp_tm = localtime(×tamp);
- tm = *tmp_tm;
- sprintf(date, "%02d%02d%02d", tm.tm_year % 100, tm.tm_mon + 1,
- tm.tm_mday);
- sprintf(hour, "%02d%02d%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
- ok_time((*n)++, timestamp, date, hour, true);
- sprintf(date, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1,
- tm.tm_mday);
- ok_time((*n)++, timestamp, date, hour, true);
- tmp_tm = gmtime(×tamp);
- tm = *tmp_tm;
- sprintf(date, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1,
- tm.tm_mday);
- sprintf(hour, "%02d%02d%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
- ok_time((*n)++, timestamp, date, hour, false);
-}
-
-int
-main(void)
-{
- char buff[64] = "";
- bool status;
- time_t now, result;
- double diff = 0;
- int n;
- unsigned int i;
-
- char PST8PDT[] = "TZ=PST8PDT";
- char Newfoundland[] = "TZ=Canada/Newfoundland";
-
- printf("%d\n", 44 + ARRAY_SIZE(test_times) * 3 + 3);
-
- now = time(NULL);
- status = makedate(-1, false, buff, sizeof(buff));
- if (status) {
- result = parsedate(buff, NULL);
- diff = difftime(result, now);
- }
- ok(1, status && diff >= 0 && diff < 10);
- now = time(NULL);
- status = makedate(-1, true, buff, sizeof(buff));
- if (status) {
- result = parsedate(buff, NULL);
- diff = difftime(result, now);
- }
- ok(2, status && diff >= 0 && diff < 10);
-
- putenv(PST8PDT);
- tzset();
-
- status = makedate(100000000UL, false, buff, sizeof(buff));
- ok(3, status);
- ok_string(4, "Sat, 3 Mar 1973 09:46:40 +0000 (UTC)", buff);
- status = makedate(100000000UL, true, buff, sizeof(buff));
- ok(5, status);
- ok_string(6, "Sat, 3 Mar 1973 01:46:40 -0800 (PST)", buff);
- status = makedate(300000000UL, false, buff, sizeof(buff));
- ok(7, status);
- ok_string(8, "Thu, 5 Jul 1979 05:20:00 +0000 (UTC)", buff);
- status = makedate(300000000UL, true, buff, sizeof(buff));
- ok(9, status);
- ok_string(10, "Wed, 4 Jul 1979 22:20:00 -0700 (PDT)", buff);
-
- status = makedate(300000000UL, false, buff, 31);
- ok(11, !status);
- status = makedate(300000000UL, false, buff, 32);
- ok(12, status);
- ok_string(13, "Thu, 5 Jul 1979 05:20:00 +0000", buff);
- status = makedate(300000000UL, true, buff, 32);
- ok(14, status);
- ok_string(15, "Wed, 4 Jul 1979 22:20:00 -0700", buff);
-
- putenv(Newfoundland);
- tzset();
-
- status = makedate(900000045UL, true, buff, sizeof(buff));
- ok(16, status);
- if (memcmp(buff, "Thu, 9 Jul 1998 16:00:45 +0000", 30) == 0)
- printf("ok 17 # skip - Newfoundland time zone not installed\n");
- else
- ok_string(17, "Thu, 9 Jul 1998 13:30:45 -0230 (NDT)", buff);
-
- putenv(PST8PDT);
- tzset();
-
- ok_time(18, (time_t) -1, "20000132", "000000", false);
- ok_time(19, (time_t) -1, "20000132", "000000", true);
- ok_time(20, (time_t) -1, "20000230", "000000", false);
- ok_time(21, (time_t) -1, "20000230", "000000", true);
- ok_time(22, (time_t) -1, "19990229", "000000", false);
- ok_time(23, (time_t) -1, "19990229", "000000", true);
- ok_time(24, (time_t) -1, "19990020", "000000", false);
- ok_time(25, (time_t) -1, "19990120", "240000", false);
- ok_time(26, (time_t) -1, "19990120", "146000", false);
- ok_time(27, (time_t) -1, "19990120", "145961", false);
- ok_time(28, (time_t) -1, "691231", "235959", false);
- ok_time(29, (time_t) -1, "19691231", "235959", false);
- ok_time(30, (time_t) -1, "19700100", "000000", false);
- ok_time(31, 0, "19700101", "000000", false);
- ok_time(32, 0, "700101", "000000", false);
- ok_time(33, (time_t) -1, "2000010101", "000000", false);
- ok_time(34, (time_t) -1, "00101", "000000", false);
- ok_time(35, (time_t) -1, "20000101", "11111", false);
- ok_time(36, (time_t) -1, "20000101", "1111111", false);
- ok_time(37, (time_t) -1, "200001a1", "000000", false);
- ok_time(38, (time_t) -1, "20000101", "00a000", false);
-
- /* Times around the fall daylight savings change are ambiguous; accept
- either of the possible interpretations, but make sure we get one or
- the other. */
- result = parsedate_nntp("20001029", "010000", true);
- ok(39, result == 972806400UL || result == 972810000UL);
- result = parsedate_nntp("001029", "013000", true);
- ok(40, result == 972808200UL || result == 972811800UL);
- result = parsedate_nntp("20001029", "013000", true);
- ok(41, result == 972808200UL || result == 972811800UL);
- result = parsedate_nntp("001029", "013000", true);
- ok(42, result == 972808200UL || result == 972811800UL);
- result = parsedate_nntp("20001029", "015959", true);
- ok(43, result == 972809999UL || result == 972813599UL);
- result = parsedate_nntp("001029", "015959", true);
- ok(44, result == 972809999UL || result == 972813599UL);
-
- n = 45;
- for (i = 0; i < ARRAY_SIZE(test_times); i++)
- check_nntp(&n, test_times[i]);
- check_nntp(&n, time(NULL));
-
- return 0;
-}
+++ /dev/null
-/* $Id: fakewrite.c 5417 2002-04-15 08:40:20Z rra $ */
-/* Fake write and writev functions for testing xwrite and xwritev. */
-
-#include "config.h"
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include "libinn.h"
-
-ssize_t fake_write(int, const void *, size_t);
-ssize_t fake_pwrite(int, const void *, size_t, off_t);
-ssize_t fake_writev(int, const struct iovec *, int);
-
-/* All the data is actually written into this buffer. We use write_offset
- to track how far we've written. */
-char write_buffer[256];
-size_t write_offset = 0;
-
-/* If write_interrupt is non-zero, then half of the calls to write or writev
- will fail, returning -1 with errno set to EINTR. */
-int write_interrupt = 0;
-
-/* If write_fail is non-zero, all writes or writevs will return 0,
- indicating no progress in writing out the buffer. */
-int write_fail = 0;
-
-/* Accept a write request and write only the first 32 bytes of it into
- write_buffer (or as much as will fit), returning the amount written. */
-ssize_t
-fake_write(int fd UNUSED, const void *data, size_t n)
-{
- size_t total;
-
- if (write_fail)
- return 0;
- if (write_interrupt && (write_interrupt++ % 2) == 0) {
- errno = EINTR;
- return -1;
- }
- total = (n < 32) ? n : 32;
- if (256 - write_offset < total)
- total = 256 - write_offset;
- memcpy(write_buffer + write_offset, data, total);
- write_offset += total;
- return total;
-}
-
-/* Accept a pwrite request and write only the first 32 bytes of it into
- write_buffer at the specified offset (or as much as will fit), returning
- the amount written. */
-ssize_t
-fake_pwrite(int fd UNUSED, const void *data, size_t n, off_t offset)
-{
- size_t total;
-
- if (write_fail)
- return 0;
- if (write_interrupt && (write_interrupt++ % 2) == 0) {
- errno = EINTR;
- return -1;
- }
- total = (n < 32) ? n : 32;
- if (offset > 256) {
- errno = ENOSPC;
- return -1;
- }
- if ((size_t) (256 - offset) < total)
- total = 256 - offset;
- memcpy(write_buffer + offset, data, total);
- return total;
-}
-
-/* Accept an xwrite request and write only the first 32 bytes of it into
- write_buffer (or as much as will fit), returning the amount written. */
-ssize_t
-fake_writev(int fd UNUSED, const struct iovec *iov, int iovcnt)
-{
- int total, i;
- size_t left, n;
-
- if (write_fail)
- return 0;
- if (write_interrupt && (write_interrupt++ % 2) == 0) {
- errno = EINTR;
- return -1;
- }
- left = 256 - write_offset;
- if (left > 32)
- left = 32;
- total = 0;
- for (i = 0; i < iovcnt && left != 0; i++) {
- n = ((size_t) iov[i].iov_len < left) ? iov[i].iov_len : left;
- memcpy(write_buffer + write_offset, iov[i].iov_base, n);
- write_offset += n;
- total += n;
- left -= n;
- }
- return total;
-}
+++ /dev/null
-/* $Id: hash-t.c 5623 2002-08-21 19:35:37Z alexk $ */
-/* hash test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "libinn.h"
-#include "libtest.h"
-
-int
-main(void)
-{
- HASH h1, h2;
-
- puts("12");
-
- h1 = HashMessageID("<lhs@test.invalid>");
- h2 = HashMessageID("<lhs@TEST.invalid>");
- ok(1, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<lhs@test.INVALID>");
- ok(2, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<Lhs@test.invalid>");
- ok(3, HashCompare(&h1, &h2) != 0);
- h2 = HashMessageID("<lhS@test.invalid>");
- ok(4, HashCompare(&h1, &h2) != 0);
- h1 = HashMessageID("<test.invalid>");
- h2 = HashMessageID("<TEST.invalid>");
- ok(5, HashCompare(&h1, &h2) != 0);
- h2 = HashMessageID("<test.INVALID>");
- ok(6, HashCompare(&h1, &h2) != 0);
- h1 = HashMessageID("<postmaster@test.invalid>");
- h2 = HashMessageID("<POSTMASTER@test.invalid>");
- ok(7, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<PostMaster@test.invalid>");
- ok(8, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<postmasteR@test.invalid>");
- ok(9, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<postmaster@TEST.invalid>");
- ok(10, HashCompare(&h1, &h2) == 0);
- h2 = HashMessageID("<postmaster@test.INVALID>");
- ok(11, HashCompare(&h1, &h2) == 0);
- h1 = HashMessageID("<postmaster.test.invalid>");
- h2 = HashMessageID("<POSTMASTER.test.invalid>");
- ok(12, HashCompare(&h1, &h2) != 0);
-
- return 0;
-}
+++ /dev/null
-/* $Id: hashtab-t.c 6026 2002-12-24 05:02:51Z rra $ */
-/* Test suite for lib/hashtab.c. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <sys/stat.h>
-
-#include "inn/hashtab.h"
-#include "inn/messages.h"
-#include "libinn.h"
-#include "libtest.h"
-
-struct wordref {
- const char *word;
- int count;
-};
-
-static const void *
-string_key(const void *entry)
-{
- return entry;
-}
-
-static bool
-string_equal(const void *key, const void *entry)
-{
- const char *p, *q;
-
- p = key;
- q = entry;
- return !strcmp(p, q);
-}
-
-static void
-string_delete(void *entry)
-{
- free(entry);
-}
-
-static void
-string_traverse(void *entry, void *data)
-{
- int i;
- struct wordref *wordrefs = data;
-
- for (i = 0; wordrefs[i].word != NULL; i++)
- if (!strcmp(entry, wordrefs[i].word)) {
- wordrefs[i].count++;
- return;
- }
- wordrefs[3].count++;
-}
-
-int
-main(void)
-{
- struct hash *hash;
- FILE *words;
- int reported, i;
- char buffer[1024];
- char *word;
- char *test, *testing, *strange, *change, *foo, *bar;
-
- struct wordref wordrefs[4] = {
- { "test", 0 }, { "testing", 0 }, { "change", 0 }, { NULL, 0 }
- };
-
- test = xstrdup("test");
- testing = xstrdup("testing");
- strange = xstrdup("strange");
- change = xstrdup("change");
-
- puts("38");
- hash = hash_create(4, hash_string, string_key, string_equal,
- string_delete);
- ok(1, hash != NULL);
- if (hash == NULL)
- die("Unable to create hash, cannot continue");
-
- ok(2, hash_insert(hash, "test", test));
- ok(3, hash_collisions(hash) == 0);
- ok(4, hash_expansions(hash) == 0);
- ok(5, hash_searches(hash) == 1);
- ok(6, hash_count(hash) == 1);
- word = hash_lookup(hash, "test");
- ok(7, word != NULL && !strcmp("test", word));
- ok(8, hash_delete(hash, "test"));
- test = xstrdup("test");
- ok(9, hash_lookup(hash, "test") == NULL);
- ok(10, !hash_delete(hash, "test"));
- ok(11, !hash_replace(hash, "test", testing));
- ok(12, hash_count(hash) == 0);
- ok(13, hash_insert(hash, "test", test));
- ok(14, hash_insert(hash, "testing", testing));
- ok(15, hash_insert(hash, "strange", strange));
- ok(16, hash_expansions(hash) == 0);
- ok(17, hash_insert(hash, "change", change));
- ok(18, hash_expansions(hash) == 1);
- ok(19, hash_count(hash) == 4);
- word = hash_lookup(hash, "testing");
- ok(20, word != NULL && !strcmp("testing", word));
- word = hash_lookup(hash, "strange");
- ok(21, word != NULL && !strcmp("strange", word));
- ok(22, hash_lookup(hash, "thingie") == NULL);
- ok(23, !hash_delete(hash, "thingie"));
- ok(24, hash_delete(hash, "strange"));
- ok(25, hash_lookup(hash, "strange") == NULL);
- ok(26, hash_count(hash) == 3);
-
- hash_traverse(hash, string_traverse, &wordrefs[0]);
- reported = 0;
- for (i = 0; wordrefs[i].word != NULL; i++)
- if (wordrefs[i].count != 1 && !reported) {
- printf("not ");
- reported = 1;
- }
- puts("ok 27");
- ok(28, wordrefs[3].count == 0);
-
- hash_free(hash);
-
- /* Test hash creation with an odd size. This previously could result
- in the wrong table size being allocated. */
- test = xstrdup("test");
- testing = xstrdup("testing");
- strange = xstrdup("strange");
- change = xstrdup("change");
- foo = xstrdup("foo");
- bar = xstrdup("bar");
- hash = hash_create(5, hash_string, string_key, string_equal,
- string_delete);
- ok(29, hash != NULL);
- if (hash == NULL)
- die("Unable to create hash, cannot continue");
- ok(30, hash_insert(hash, "test", test));
- ok(31, hash_insert(hash, "testing", testing));
- ok(32, hash_insert(hash, "strange", strange));
- ok(33, hash_insert(hash, "change", change));
- ok(34, hash_insert(hash, "foo", foo));
- ok(35, hash_insert(hash, "bar", bar));
- ok(36, hash_count(hash) == 6);
- hash_free(hash);
-
- words = fopen("/usr/dict/words", "r");
- if (words == NULL)
- words = fopen("/usr/share/dict/words", "r");
- if (words == NULL) {
- puts("ok 37 # skip\nok 38 # skip");
- exit(0);
- }
-
- hash = hash_create(4, hash_string, string_key, string_equal,
- string_delete);
- reported = 0;
- if (hash == NULL)
- printf("not ");
- else {
- while (fgets(buffer, sizeof(buffer), words)) {
- buffer[strlen(buffer) - 1] = '\0';
- word = xstrdup(buffer);
- if (!hash_insert(hash, word, word)) {
- if (!reported)
- printf("not ");
- reported = 1;
- }
- }
- }
- puts("ok 37");
-
- if (fseek(words, 0, SEEK_SET) < 0)
- sysdie("Unable to rewind words file");
- reported = 0;
- if (hash == NULL)
- printf("not ");
- else {
- while (fgets(buffer, sizeof(buffer), words)) {
- buffer[strlen(buffer) - 1] = '\0';
- word = hash_lookup(hash, buffer);
- if (!word || strcmp(word, buffer) != 0) {
- if (!reported)
- printf("not ");
- reported = 1;
- }
- }
- }
- puts("ok 38");
-
- hash_free(hash);
-
- return 0;
-}
+++ /dev/null
-/* $Id: hstrerror-t.c 5060 2001-12-12 09:20:10Z rra $ */
-/* hstrerror test suite. */
-
-#include "config.h"
-#include <netdb.h>
-#include <stdio.h>
-
-#include "libtest.h"
-
-const char *test_hstrerror(int);
-
-static void
-test_error(int n, const char *expected, int error)
-{
- ok_string(n, expected, test_hstrerror(error));
-}
-
-int
-main(void)
-{
- puts("7");
-
- test_error(1, "Internal resolver error", -1);
- test_error(2, "No resolver error", 0);
- test_error(3, "No address associated with name", NO_ADDRESS);
- test_error(4, "Resolver error 777777", 777777);
- test_error(5, "Resolver error -99999", -99999);
- test_error(6, "", 1000000);
- test_error(7, "", -100000);
-
- return 0;
-}
+++ /dev/null
-/* $Id: inet_aton-t.c 5061 2001-12-12 09:21:17Z rra $ */
-/* inet_aton test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <netinet/in.h>
-
-int test_inet_aton(const char *, struct in_addr *);
-
-static void
-test_addr(int n, const char *string, unsigned long addr)
-{
- bool success, okay;
- struct in_addr in;
-
- success = test_inet_aton(string, &in);
- okay = (success && in.s_addr == htonl(addr));
-
- printf("%sok %d\n", okay ? "" : "not ", n);
- if (!okay && !success) printf(" success: %d\n", success);
- if (!okay && in.s_addr != htonl(addr))
- printf(" want: %lx\n saw: %lx\n", (unsigned long) htonl(addr),
- (unsigned long) in.s_addr);
-}
-
-static void
-test_fail(int n, const char *string)
-{
- struct in_addr in;
- int success;
-
- in.s_addr = htonl(0x01020304UL);
- success = test_inet_aton(string, &in);
- success = (success == 0 && in.s_addr == htonl(0x01020304UL));
- printf("%sok %d\n", success ? "" : "not ", n);
-}
-
-int
-main(void)
-{
- puts("46");
-
- test_addr( 1, "0.0.0.0", 0);
- test_addr( 2, "127.0.0.000000", 0x7f000000UL);
- test_addr( 3, "255.255.255.255", 0xffffffffUL);
- test_addr( 4, "172.200.232.199", 0xacc8e8c7UL);
- test_addr( 5, "1.2.3.4", 0x01020304UL);
-
- test_addr( 6, "0x0.0x0.0x0.0x0", 0);
- test_addr( 7, "0x7f.0x000.0x0.0x00", 0x7f000000UL);
- test_addr( 8, "0xff.0xFf.0xFF.0xff", 0xffffffffUL);
- test_addr( 9, "0xAC.0xc8.0xe8.0xC7", 0xacc8e8c7UL);
- test_addr(10, "0xAa.0xbB.0xCc.0xdD", 0xaabbccddUL);
- test_addr(11, "0xEe.0xfF.0.0x00000", 0xeeff0000UL);
- test_addr(12, "0x1.0x2.0x00003.0x4", 0x01020304UL);
-
- test_addr(13, "000000.00.000.00", 0);
- test_addr(14, "0177.0", 0x7f000000UL);
- test_addr(15, "0377.0377.0377.0377", 0xffffffffUL);
- test_addr(16, "0254.0310.0350.0307", 0xacc8e8c7UL);
- test_addr(17, "00001.02.3.00000004", 0x01020304UL);
-
- test_addr(18, "16909060", 0x01020304UL);
- test_addr(19, "172.062164307", 0xacc8e8c7UL);
- test_addr(20, "172.0xc8.0xe8c7", 0xacc8e8c7UL);
- test_addr(21, "127.1", 0x7f000001UL);
- test_addr(22, "0xffffffff", 0xffffffffUL);
- test_addr(23, "127.0xffffff", 0x7fffffffUL);
- test_addr(24, "127.127.0xffff", 0x7f7fffffUL);
-
- test_fail(25, "");
- test_fail(26, "Donald Duck!");
- test_fail(27, "a127.0.0.1");
- test_fail(28, "aaaabbbb");
- test_fail(29, "0x100000000");
- test_fail(30, "0xfffffffff");
- test_fail(31, "127.0xfffffff");
- test_fail(32, "127.376926742");
- test_fail(33, "127.127.01452466");
- test_fail(34, "127.127.127.0x100");
- test_fail(35, "256.0");
- test_fail(36, "127.0378.127.127");
- test_fail(37, "127.127.0x100.127");
- test_fail(38, "127.0.o.1");
- test_fail(39, "127.127.127.127v");
- test_fail(40, "ef.127.127.127");
- test_fail(41, "0128.127.127.127");
- test_fail(42, "0xeg.127");
- test_fail(43, ".127.127");
- test_fail(44, "127.127.");
- test_fail(45, "127..127");
- test_fail(46, "de.ad.be.ef");
-
- return 0;
-}
+++ /dev/null
-/* $Id: inet_ntoa-t.c 5061 2001-12-12 09:21:17Z rra $ */
-/* inet_ntoa test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <netinet/in.h>
-
-#include "libtest.h"
-
-const char *test_inet_ntoa(const struct in_addr);
-
-static void
-test_addr(int n, const char *expected, unsigned long addr)
-{
- struct in_addr in;
-
- in.s_addr = htonl(addr);
- ok_string(n, expected, test_inet_ntoa(in));
-}
-
-int
-main(void)
-{
- puts("5");
-
- test_addr(1, "0.0.0.0", 0x0);
- test_addr(2, "127.0.0.0", 0x7f000000UL);
- test_addr(3, "255.255.255.255", 0xffffffffUL);
- test_addr(4, "172.200.232.199", 0xacc8e8c7UL);
- test_addr(5, "1.2.3.4", 0x01020304UL);
-
- return 0;
-}
+++ /dev/null
-/* $Id: innconf-t.c 7748 2008-04-06 13:49:56Z iulius $ */
-/* innconf test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/innconf.h"
-#include "inn/messages.h"
-#include "libtest.h"
-
-static const char grep[] =
-"egrep 'mta|organization|ovmethod|hismethod|path|pgpverify'\
- ../../samples/inn.conf > config/tmp";
-
-int
-main(void)
-{
- struct innconf *standard;
- FILE *config;
-
- if (access("config/valid", F_OK) < 0)
- if (access("lib/config/valid", F_OK) == 0)
- chdir("lib");
-
- puts("9");
-
- ok(1, innconf_read("../../samples/inn.conf"));
- standard = innconf;
- innconf = NULL;
- if (system(grep) != 0)
- die("Unable to create stripped configuration file");
- ok(2, innconf_read("config/tmp"));
- unlink("config/tmp");
- ok(3, innconf_compare(standard, innconf));
- innconf_free(standard);
- innconf_free(innconf);
- innconf = NULL;
- ok(4, true);
-
- /* Checking inn.conf. */
- errors_capture();
- if (system(grep) != 0)
- die("Unable to create stripped configuration file");
- ok(5, innconf_check("config/tmp"));
- ok(6, errors == NULL);
- innconf_free(innconf);
- innconf = NULL;
- config = fopen("config/tmp", "a");
- if (config == NULL)
- sysdie("Unable to open stripped configuration file for append");
- fputs("foo: bar\n", config);
- fclose(config);
- ok(7, !innconf_check("config/tmp"));
- unlink("config/tmp");
- ok_string(8, "config/tmp:26: unknown parameter foo\n", errors);
- errors_uncapture();
- free(errors);
- errors = NULL;
- innconf_free(innconf);
- innconf = NULL;
- ok(9, true);
-
- return 0;
-}
+++ /dev/null
-/* $Id: list-t.c 6294 2003-04-15 03:43:45Z rra $ */
-/* Test suite for list routines. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "inn/list.h"
-#include "libinn.h"
-#include "libtest.h"
-
-int
-main(void)
-{
- struct list list;
- struct node a, b, c;
-
- puts("28");
-
- list_new(&list);
- ok(1, list_isempty(&list));
-
- ok(2, list_addhead(&list, &a) == &a);
- ok(3, !list_isempty(&list));
- ok(4, list_head(&list) == &a);
- ok(5, list_tail(&list) == &a);
- ok(6, list_remhead(&list) == &a);
- ok(7, list_isempty(&list));
-
- ok(8, list_addhead(&list, &a) == &a);
- ok(9, list_remtail(&list) == &a);
- ok(10, list_isempty(&list));
-
- ok(11, list_addtail(&list, &a) == &a);
- ok(12, !list_isempty(&list));
- ok(13, list_head(&list) == &a);
- ok(14, list_tail(&list) == &a);
- ok(15, list_remhead(&list) == &a);
- ok(16, list_isempty(&list));
-
- list_addtail(&list, &a);
- ok(17, list_remtail(&list) == &a);
- ok(18, list_isempty(&list));
-
- list_addhead(&list, &a);
- ok(19, list_remove(&a) == &a);
- ok(20, list_isempty(&list));
-
- list_addtail(&list, &a);
- list_addtail(&list, &b);
- list_insert(&list, &c, &a);
- ok(21, list_succ(&c) == &b);
- ok(22, list_pred(&c) == &a);
- list_remove(&c);
- list_insert(&list, &c, &b);
- ok(23, list_succ(&c) == NULL);
- ok(24, list_pred(&c) == &b);
- list_remove(&c);
- list_insert(&list, &c, NULL);
- ok(25, list_succ(&c) == &a);
- ok(26, list_pred(&c) == NULL);
- list_remove(&c);
- ok(27, list_head(&list) == &a);
- ok(28, list_tail(&list) == &b);
-
- return 0;
-}
+++ /dev/null
-/* $Id: md5-t.c 6128 2003-01-18 22:26:49Z rra $ */
-/* MD5 hashing test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include "inn/md5.h"
-#include "libinn.h"
-#include "libtest.h"
-
-/* Used to initialize strings of unsigned characters. */
-#define U (const unsigned char *)
-
-/* An unsigned char version of strlen. */
-#define ustrlen(s) strlen((const char *) s)
-
-/* Used for converting digests to hex to make them easier to deal with. */
-static const char hex[] = "0123456789abcdef";
-
-/* A set of data strings and resulting digests to check. It's not easy to
- get nulls into this data structure, so data containing nulls should be
- checked separately. */
-static const unsigned char * const testdata[] = {
- /* First five tests of the MD5 test suite from RFC 1321. */
- U"",
- U"a",
- U"abc",
- U"message digest",
- U"abcdefghijklmnopqrstuvwxyz",
-
- /* Three real message IDs to ensure compatibility with old INN versions;
- the corresponding MD5 hashes were taken directly out of the history
- file of a server running INN 2.3. */
- U"<J3Ds5.931$Vg6.7556@news01.chello.no>",
- U"<sr5v7ooea6e17@corp.supernews.com>",
- U"<cancel.Y2Ds5.26391$oH5.540535@news-east.usenetserver.com>",
-
- /* Other random stuff, including high-bit characters. */
- U"example.test",
- U"||",
- U"|||",
- U"\375\277\277\277\277\276",
- U"\377\277\277\277\277\277"
-};
-
-/* The hashes corresonding to the above data. */
-static const char * const testhash[] = {
- "d41d8cd98f00b204e9800998ecf8427e",
- "0cc175b9c0f1b6a831c399e269772661",
- "900150983cd24fb0d6963f7d28e17f72",
- "f96b697d7cb7938d525a2f31aaf161d0",
- "c3fcd3d76192e4007dfb496cca67e13b",
- "c4a70fb19af37bed6b7c77f1e1187f00",
- "7f70531c7027c20b0ddba0a649cf8691",
- "9d9f0423f38b731c9bf69607cea6be76",
- "09952be409a7d6464cd7661beeeb966e",
- "7d010443693eec253a121e2aa2ba177c",
- "2edf2958166561c5c08cd228e53bbcdc",
- "c18293a6fe0a09720e841c8ebc697b97",
- "ce23eb027c63215b999b9f86d6a4f9cb"
-};
-
-static void
-digest2hex(const unsigned char *digest, char *result)
-{
- const unsigned char *p;
- unsigned int i;
-
- for (p = digest, i = 0; i < 32; i += 2, p++) {
- result[i] = hex[(*p & 0xf0) >> 4];
- result[i + 1] = hex[*p & 0x0f];
- }
- result[32] = '\0';
-}
-
-static void
-test_md5(int n, const char *expected, const unsigned char *data,
- size_t length)
-{
- unsigned char digest[16];
- char hexdigest[33];
-
- md5_hash(data, length, digest);
- digest2hex(digest, hexdigest);
- ok_string(n, expected, hexdigest);
-}
-
-int
-main(void)
-{
- unsigned int i;
- int j, n;
- unsigned char *data;
- struct md5_context context;
- char hexdigest[33];
-
- printf("%d\n", 12 + ARRAY_SIZE(testdata));
-
- test_md5(1, "93b885adfe0da089cdf634904fd59f71", U"\0", 1);
- test_md5(2, "e94a053c3fbfcfb22b4debaa11af7718", U"\0ab\n", 4);
-
- data = xmalloc(64 * 1024);
- memset(data, 0, 64 * 1024);
- test_md5(3, "fcd6bcb56c1689fcef28b57c22475bad", data, 64 * 1024);
- memset(data, 1, 32 * 1024);
- test_md5(4, "3d8897b14254c9f86fbad3fe22f62edd", data, 64 * 1024);
- test_md5(5, "25364962aa23b187942a24ae736c4e8c", data, 65000);
- test_md5(6, "f9816b5d5363d15f14bb98d548309dcc", data, 55);
- test_md5(7, "5e99dfddfb51c18cfc55911dee24ae7b", data, 56);
- test_md5(8, "0871ffa021e2bc4da87eb93ac22d293c", data, 63);
- test_md5(9, "784d68ba9112308689114a6816c628ce", data, 64);
-
- /* Check the individual functions. */
- md5_init(&context);
- md5_update(&context, data, 32 * 1024);
- md5_update(&context, data + 32 * 1024, 32 * 1024 - 42);
- md5_update(&context, data + 64 * 1024 - 42, 42);
- md5_final(&context);
- digest2hex(context.digest, hexdigest);
- ok_string(10, "3d8897b14254c9f86fbad3fe22f62edd", hexdigest);
-
- /* Part of the MD5 test suite from RFC 1321. */
- for (i = 0, n = 'A'; n <= 'Z'; i++, n++)
- data[i] = n;
- for (i = 26, n = 'a'; n <= 'z'; i++, n++)
- data[i] = n;
- for (i = 52, n = '0'; n <= '9'; i++, n++)
- data[i] = n;
- test_md5(11, "d174ab98d277d9f5a5611c2c9f419d9f", data, 62);
- for (i = 0, j = 0; j < 8; j++) {
- for (n = '1'; n <= '9'; i++, n++)
- data[i] = n;
- data[i++] = '0';
- }
- test_md5(12, "57edf4a22be3c955ac49da2e2107b67a", data, 80);
-
- n = 13;
- for (i = 0; i < ARRAY_SIZE(testdata); i++)
- test_md5(n++, testhash[i], testdata[i], ustrlen(testdata[i]));
-
- return 0;
-}
+++ /dev/null
-/* $Id: memcmp-t.c 5054 2001-12-12 09:15:24Z rra $ */
-/* memcmp test suite. */
-
-#include "config.h"
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "libtest.h"
-
-int test_memcmp(const void *, const void *, size_t);
-
-int
-main(void)
-{
- puts("15");
-
- ok( 1, test_memcmp("", "", 0) == 0);
- ok( 2, test_memcmp("", "", 1) == 0);
- ok( 3, test_memcmp("alpha", "alpha", 6) == 0);
- ok( 4, test_memcmp("alpha", "beta", 5) < 0);
- ok( 5, test_memcmp("beta", "alpha", 5) > 0);
- ok( 6, test_memcmp("alpha", "apple", 1) == 0);
- ok( 7, test_memcmp("alpha", "apple", 2) < 0);
- ok( 8, test_memcmp("\0v", "\0w", 2) < 0);
- ok( 9, test_memcmp("\200\201\202", "\200\201\202", 4) == 0);
- ok(10, test_memcmp("\200\201\202", "\200\201\203", 4) < 0);
- ok(11, test_memcmp("\200\201\203", "\200\201\202", 4) > 0);
- ok(12, test_memcmp("al\0po", "al\0pha", 6) > 0);
- ok(13, test_memcmp("\100", "\201", 1) < 0);
- ok(14, test_memcmp("\200", "\201", 1) < 0);
- ok(15, test_memcmp("a", "b", 0) == 0);
-
- return 0;
-}
+++ /dev/null
-/* $Id: messages-t.c 5638 2002-08-23 22:52:53Z rra $ */
-/* Test suite for error handling routines. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-#define END (char *) 0
-
-/* Test function type. */
-typedef void (*test_function_t)(void);
-
-/* Fork and execute the provided function, connecting stdout and stderr to a
- pipe. Captures the output into the provided buffer and returns the exit
- status as a waitpid status value. */
-static int
-run_test(test_function_t function, char *buf, size_t buflen)
-{
- int fds[2];
- pid_t child;
- ssize_t count, status;
-
- /* Flush stdout before we start to avoid odd forking issues. */
- fflush(stdout);
-
- /* Set up the pipe and call the function, collecting its output. */
- if (pipe(fds) == -1)
- sysdie("can't create pipe");
- child = fork();
- if (child == (pid_t) -1) {
- sysdie("can't fork");
- } else if (child == 0) {
- /* In child. Set up our stdout and stderr. */
- close(fds[0]);
- if (dup2(fds[1], 1) == -1)
- _exit(255);
- if (dup2(fds[1], 2) == -1)
- _exit(255);
-
- /* Now, run the function and exit successfully if it returns. */
- (*function)();
- fflush(stdout);
- _exit(0);
- } else {
- /* In the parent; close the extra file descriptor, read the output
- if any, and then collect the exit status. */
- close(fds[1]);
- count = 0;
- do {
- status = read(fds[0], buf + count, buflen - count - 1);
- if (status > 0)
- count += status;
- } while (status > 0);
- buf[count < 0 ? 0 : count] = '\0';
- if (waitpid(child, &status, 0) == (pid_t) -1)
- sysdie("waitpid failed");
- }
- return status;
-}
-
-/* Test functions. */
-static void test1(void) { warn("warning"); }
-static void test2(void) { die("fatal"); }
-static void test3(void) { errno = EPERM; syswarn("permissions"); }
-static void test4(void) { errno = EACCES; sysdie("fatal access"); }
-static void test5(void) {
- message_program_name = "test5";
- warn("warning");
-}
-static void test6(void) {
- message_program_name = "test6";
- die("fatal");
-}
-static void test7(void) {
- message_program_name = "test7";
- errno = EPERM;
- syswarn("perms %d", 7);
-}
-static void test8(void) {
- message_program_name = "test8";
- errno = EACCES;
- sysdie("%st%s", "fa", "al");
-}
-
-static int return10(void) { return 10; }
-
-static void test9(void) {
- message_fatal_cleanup = return10;
- die("fatal");
-}
-static void test10(void) {
- message_program_name = 0;
- message_fatal_cleanup = return10;
- errno = EPERM;
- sysdie("fatal perm");
-}
-static void test11(void) {
- message_program_name = "test11";
- message_fatal_cleanup = return10;
- errno = EPERM;
- fputs("1st ", stdout);
- sysdie("fatal");
-}
-
-static void log(int len, const char *format, va_list args, int error) {
- fprintf(stderr, "%d %d ", len, error);
- vfprintf(stderr, format, args);
- fprintf(stderr, "\n");
-}
-
-static void test12(void) {
- message_handlers_warn(1, log);
- warn("warning");
-}
-static void test13(void) {
- message_handlers_die(1, log);
- die("fatal");
-}
-static void test14(void) {
- message_handlers_warn(2, log, log);
- errno = EPERM;
- syswarn("warning");
-}
-static void test15(void) {
- message_handlers_die(2, log, log);
- message_fatal_cleanup = return10;
- errno = EPERM;
- sysdie("fatal");
-}
-static void test16(void) {
- message_handlers_warn(2, message_log_stderr, log);
- message_program_name = "test16";
- errno = EPERM;
- syswarn("warning");
-}
-static void test17(void) { notice("notice"); }
-static void test18(void) {
- message_program_name = "test18";
- notice("notice");
-}
-static void test19(void) { trace(TRACE_PROGRAM, "tracing"); }
-static void test20(void) { debug("debug"); }
-static void test21(void) {
- message_handlers_notice(1, log);
- notice("foo");
-}
-static void test22(void) {
- message_handlers_trace(1, log);
- message_trace_enable(TRACE_PROGRAM, true);
- trace(TRACE_PROGRAM, "foo");
- trace(TRACE_NETWORK, "bar");
-}
-static void test23(void) {
- message_handlers_debug(1, message_log_stdout);
- message_program_name = "test23";
- debug("baz");
-}
-static void test24(void) {
- message_handlers_die(0);
- die("hi mom!");
-}
-static void test25(void) {
- message_handlers_warn(0);
- warn("this is a test");
-}
-static void test26(void) {
- notice("first");
- message_handlers_notice(0);
- notice("second");
- message_handlers_notice(1, message_log_stdout);
- notice("third");
-}
-
-/* Given the test number, intended exit status and message, and the function
- to run, print ok or not ok. */
-static void
-test_error(int n, int status, const char *output, test_function_t function)
-{
- int real_status;
- char buf[256];
- int succeeded = 1;
-
- real_status = run_test(function, buf, sizeof(buf));
- if (!WIFEXITED(real_status) || status != WEXITSTATUS(real_status)) {
- printf(" unexpected exit status %d\n", real_status);
- succeeded = 0;
- }
- if (strcmp(output, buf)) {
- printf(" unexpected output: %s", buf);
- printf(" expected output: %s", output);
- succeeded = 0;
- }
- printf("%sok %d\n", succeeded ? "" : "not ", n);
-}
-
-/* Given the test number, intended status, intended message sans the
- appended strerror output, errno, and the function to run, print ok or not
- ok. */
-static void
-test_strerror(int n, int status, const char *output, int error,
- test_function_t function)
-{
- char *full_output;
-
- full_output = concat(output, ": ", strerror(error), "\n", END);
- test_error(n, status, full_output, function);
- free(full_output);
-}
-
-/* Run the tests. */
-int
-main(void)
-{
- char buff[32];
-
- puts("26");
-
- test_error(1, 0, "warning\n", test1);
- test_error(2, 1, "fatal\n", test2);
- test_strerror(3, 0, "permissions", EPERM, test3);
- test_strerror(4, 1, "fatal access", EACCES, test4);
- test_error(5, 0, "test5: warning\n", test5);
- test_error(6, 1, "test6: fatal\n", test6);
- test_strerror(7, 0, "test7: perms 7", EPERM, test7);
- test_strerror(8, 1, "test8: fatal", EACCES, test8);
- test_error(9, 10, "fatal\n", test9);
- test_strerror(10, 10, "fatal perm", EPERM, test10);
- test_strerror(11, 10, "1st test11: fatal", EPERM, test11);
- test_error(12, 0, "7 0 warning\n", test12);
- test_error(13, 1, "5 0 fatal\n", test13);
-
- sprintf(buff, "%d", EPERM);
-
- test_error(14, 0,
- concat("7 ", buff, " warning\n7 ", buff, " warning\n", END),
- test14);
- test_error(15, 10,
- concat("5 ", buff, " fatal\n5 ", buff, " fatal\n", END),
- test15);
- test_error(16, 0,
- concat("test16: warning: ", strerror(EPERM), "\n7 ", buff,
- " warning\n", END),
- test16);
-
- test_error(17, 0, "notice\n", test17);
- test_error(18, 0, "test18: notice\n", test18);
- test_error(19, 0, "", test19);
- test_error(20, 0, "", test20);
- test_error(21, 0, "3 0 foo\n", test21);
- test_error(22, 0, "3 0 foo\n", test22);
- test_error(23, 0, "test23: baz\n", test23);
-
- /* Make sure that it's possible to turn off a message type entirely. */
- test_error(24, 1, "", test24);
- test_error(25, 0, "", test25);
- test_error(26, 0, "first\nthird\n", test26);
-
- return 0;
-}
+++ /dev/null
-/* $Id: mkstemp-t.c 5329 2002-03-17 07:39:14Z rra $ */
-/* mkstemp test suite */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "libtest.h"
-
-int test_mkstemp(char *template);
-
-int
-main(void)
-{
- int fd;
- char template[] = "tsXXXXXXX";
- char tooshort[] = "XXXXX";
- char bad1[] = "/foo/barXXXXX";
- char bad2[] = "/foo/barXXXXXX.out";
- char buffer[256];
- struct stat st1, st2;
- ssize_t length;
-
- puts("20");
-
- /* First, test a few error messages. */
- errno = 0;
- ok_int(1, -1, test_mkstemp(tooshort));
- ok(2, errno == EINVAL);
- ok_string(3, "XXXXX", tooshort);
- errno = 0;
- ok_int(4, -1, test_mkstemp(bad1));
- ok(5, errno == EINVAL);
- ok_string(6, "/foo/barXXXXX", bad1);
- errno = 0;
- ok_int(7, -1, test_mkstemp(bad2));
- ok(8, errno == EINVAL);
- ok_string(9, "/foo/barXXXXXX.out", bad2);
- errno = 0;
-
- /* Now try creating a real file. */
- fd = test_mkstemp(template);
- ok(10, fd >= 0);
- ok(11, strcmp(template, "tsXXXXXXX") != 0);
- ok(12, strncmp(template, "tsX", 3) == 0);
- ok(13, access(template, F_OK) == 0);
-
- /* Make sure that it's the same file as template refers to now. */
- ok(14, stat(template, &st1) == 0);
- ok(15, fstat(fd, &st2) == 0);
- ok(16, st1.st_ino == st2.st_ino);
- unlink(template);
-
- /* Make sure the open mode is correct. */
- length = strlen(template);
- ok(17, write(fd, template, length) == length);
- ok(18, lseek(fd, 0, SEEK_SET) == 0);
- ok(19, read(fd, buffer, length) == length);
- buffer[length] = '\0';
- ok_string(20, template, buffer);
- close(fd);
-
- return 0;
-}
+++ /dev/null
-/* $Id: pread-t.c 5379 2002-03-31 21:45:12Z rra $ */
-/* pread test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "libtest.h"
-
-ssize_t test_pread(int fd, void *buf, size_t nbyte, off_t offset);
-
-int
-main(void)
-{
- unsigned char buf[256], result[256];
- unsigned char c;
- int i, fd;
- ssize_t status;
- off_t position;
-
- for (c = 0, i = 0; i < 256; i++, c++)
- buf[i] = c;
- fd = open(".testout", O_RDWR | O_CREAT | O_TRUNC, 0644);
- if (fd < 0)
- sysdie("Can't create .testout");
- if (unlink(".testout") < 0)
- sysdie("Can't unlink .testout");
- if (xwrite(fd, buf, 256) < 0)
- sysdie("Can't write to .testout");
- if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
- sysdie("Can't rewind .testout");
- memset(result, 0, sizeof(result));
-
- puts("6");
-
- status = test_pread(fd, result, 128, 128);
- ok(1, (status == 128) && !memcmp(result, buf + 128, 128));
- status = read(fd, result, 64);
- ok(2, (status == 64) && !memcmp(result, buf, 64));
- status = test_pread(fd, result, 1, 256);
- ok(3, status == 0);
- status = test_pread(fd, result, 256, 0);
- ok(4, (status == 256) && !memcmp(result, buf, 256));
- position = lseek(fd, 0, SEEK_CUR);
- ok(5, position == 64);
-
- close(20);
- errno = 0;
- status = test_pread(20, result, 1, 0);
- ok(6, (status == -1) && (errno == EBADF));
-
- return 0;
-}
+++ /dev/null
-/* $Id: pwrite-t.c 5379 2002-03-31 21:45:12Z rra $ */
-/* pwrite test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-#include "libtest.h"
-
-ssize_t test_pwrite(int fd, const void *buf, size_t nbyte, off_t offset);
-
-int
-main(void)
-{
- unsigned char buf[256], result[256];
- unsigned char c;
- int i, fd;
- ssize_t status;
-
- for (c = 0, i = 0; i < 256; i++, c++)
- buf[i] = c;
- fd = open(".testout", O_RDWR | O_CREAT | O_TRUNC, 0644);
- if (fd < 0)
- sysdie("Can't create .testout");
- if (unlink(".testout") < 0)
- sysdie("Can't unlink .testout");
- memset(result, 0, sizeof(result));
-
- puts("6");
-
- ok(1, test_pwrite(fd, buf + 129, 127, 129) == 127);
- ok(2, write(fd, buf, 64) == 64);
- ok(3, test_pwrite(fd, buf + 64, 65, 64) == 65);
- status = read(fd, result, 64);
- ok(4, (status == 64) && !memcmp(result, buf + 64, 64));
-
- if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
- sysdie("Can't rewind .testout");
- status = read(fd, result, 256);
- ok(5, (status == 256) && !memcmp(result, buf, 256));
-
- close(20);
- errno = 0;
- status = test_pwrite(20, result, 1, 0);
- ok(6, (status == -1) && (errno == EBADF));
-
- return 0;
-}
+++ /dev/null
-/* $Id: qio-t.c 6939 2004-06-10 22:04:58Z hkehoe $ */
-/* Test suite for the Quick I/O library */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-#include "inn/qio.h"
-#include "libinn.h"
-#include "libtest.h"
-
-static void
-output(int fd, const void *data, size_t size)
-{
- if (xwrite(fd, data, size) < 0)
- sysdie("Can't write to .testout");
-}
-
-int
-main(void)
-{
- unsigned char data[256], line[256], out[256];
- unsigned char c;
- char *result;
- int i, count, fd;
- size_t size = 8192;
- QIOSTATE *qio;
- bool success;
-
-#if HAVE_ST_BLKSIZE
- struct stat st;
-#endif
-
- for (c = 1, i = 0; i < 255; i++, c++)
- data[i] = c;
- data[9] = ' ';
- data[255] = '\255';
- memcpy(line, data, 255);
- line[255] = '\n';
- memcpy(out, data, 255);
- out[255] = '\0';
- fd = open(".testout", O_RDWR | O_CREAT | O_TRUNC, 0644);
- if (fd < 0) sysdie("Can't create .testout");
-
-#if HAVE_ST_BLKSIZE
- /* Mostly duplicate the code from qio.c so that we can test with lines
- exactly as large as the buffer. */
- if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
- size = st.st_blksize;
- if (size > 4 * 8192)
- size = 8192;
- else
- while(size < 8192)
- size += st.st_blksize;
- }
-#endif /* HAVE_ST_BLKSIZE */
-
- /* Start with small, equally sized lines exactly equal to the buffer.
- Then a line equal in size to the buffer, then a short line and
- another line equal in size to the buffer, then a half line and lines
- repeated to fill another buffer, then a line that's one character too
- long. */
- count = size / 256;
- for (i = 0; i < count; i++)
- output(fd, line, 256);
- for (i = 0; i < count - 1; i++)
- output(fd, data, 256);
- output(fd, line, 256);
- output(fd, "\n", 1);
- for (i = 0; i < count - 1; i++)
- output(fd, data, 256);
- output(fd, line, 256);
- output(fd, data, 127);
- output(fd, "\n", 1);
- for (i = 0; i < count; i++)
- output(fd, line, 256);
- for (i = 0; i < count; i++)
- output(fd, data, 256);
- output(fd, "\n", 1);
- close(fd);
-
- puts("30");
-
- /* Now make sure we can read all that back correctly. */
- qio = QIOopen(".testout");
- ok(1, qio != NULL);
- ok(2, !QIOerror(qio));
- ok(3, QIOfileno(qio) > 0);
- if (unlink(".testout") < 0)
- sysdie("Can't unlink .testout");
- for (success = true, i = 0; i < count; i++) {
- result = QIOread(qio);
- success = (success && !QIOerror(qio) && (QIOlength(qio) == 255)
- && !strcmp(result, (char *) out));
- }
- ok(4, success);
- ok(5, QIOtell(qio) == (off_t) size);
- result = QIOread(qio);
- if (strlen(result) < size - 1) {
- ok(6, false);
- } else {
- for (success = true, i = 0; i < count - 1; i++)
- success = success && !memcmp(result + i * 256, data, 256);
- success = success && !memcmp(result + i * 256, data, 255);
- ok(6, success);
- }
- ok(7, QIOtell(qio) == (off_t) (2 * size));
- result = QIOread(qio);
- ok(8, !QIOerror(qio));
- ok(9, QIOlength(qio) == 0);
- ok(10, *result == 0);
- result = QIOread(qio);
- if (strlen(result) < size - 1) {
- ok(11, false);
- } else {
- for (success = true, i = 0; i < count - 1; i++)
- success = success && !memcmp(result + i * 256, data, 256);
- success = success && !memcmp(result + i * 256, data, 255);
- ok(11, success);
- }
- ok(12, QIOtell(qio) == (off_t) (3 * size + 1));
- result = QIOread(qio);
- ok(13, !QIOerror(qio));
- ok(14, QIOlength(qio) == 127);
- ok(15, strlen(result) == 127);
- ok(16, !memcmp(result, data, 127));
- for (success = true, i = 0; i < count; i++) {
- result = QIOread(qio);
- success = (success && !QIOerror(qio) && (QIOlength(qio) == 255)
- && !strcmp(result, (char *) out));
- }
- ok(17, success);
- ok(18, QIOtell(qio) == (off_t) (4 * size + 129));
- result = QIOread(qio);
- ok(19, !result);
- ok(20, QIOerror(qio));
- ok(21, QIOtoolong(qio));
- ok(22, QIOrewind(qio) == 0);
- ok(23, QIOtell(qio) == 0);
- result = QIOread(qio);
- ok(24, !QIOerror(qio));
- ok(25, QIOlength(qio) == 255);
- ok(26, strlen(result) == 255);
- ok(27, !strcmp(result, (char *) out));
- ok(28, QIOtell(qio) == 256);
- fd = QIOfileno(qio);
- QIOclose(qio);
- ok(29, close(fd) < 0);
- ok(30, errno == EBADF);
-
- return 0;
-}
+++ /dev/null
-/* $Id: setenv-t.c 7492 2006-03-19 23:07:34Z eagle $ */
-/* setenv test suite. */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "libtest.h"
-
-int test_setenv(const char *name, const char *value, int overwrite);
-
-static const char test_var[] = "SETENV_TEST";
-static const char test_value1[] = "Do not taunt Happy Fun Ball.";
-static const char test_value2[] = "Do not use Happy Fun Ball on concrete.";
-
-int
-main(void)
-{
- char *value;
- int status;
-
- if (getenv(test_var))
- die("%s already in the environment!", test_var);
-
- puts("12");
-
- ok(1, test_setenv(test_var, test_value1, 0) == 0);
- ok_string(2, test_value1, getenv(test_var));
- ok(3, test_setenv(test_var, test_value2, 0) == 0);
- ok_string(4, test_value1, getenv(test_var));
- ok(5, test_setenv(test_var, test_value2, 1) == 0);
- ok_string(6, test_value2, getenv(test_var));
- ok(7, test_setenv(test_var, "", 1) == 0);
- ok_string(8, "", getenv(test_var));
-
- /* We're run by a shell script wrapper that sets resource limits such
- that we can allocate one string of this size but not two. Note that
- Linux doesn't support data limits, so skip if we get an unexpected
- success here. */
- value = xmalloc(100 * 1024);
- memset(value, 'A', 100 * 1024 - 1);
- value[100 * 1024 - 1] = 0;
- ok(9, test_setenv(test_var, value, 0) == 0);
- ok_string(10, "", getenv(test_var));
- status = test_setenv(test_var, value, 1);
- if (status == 0) {
- puts("ok 11 # skip - no data limit support");
- puts("ok 12 # skip - no data limit support");
- } else {
- ok(11, (status == -1) && (errno == ENOMEM));
- ok_string(12, "", getenv(test_var));
- }
-
- return 0;
-}
+++ /dev/null
-#! /bin/sh
-# $Id: setenv.t 7492 2006-03-19 23:07:34Z eagle $
-#
-# Wrapper around the setenv test suite to set a resource limit low enough
-# that two strings over 100KB can't both be allocated, allowing the memory
-# allocation failure code in setenv to be exercised. Done with this
-# wrapper because ulimit is more easily portable than the corresponding C
-# code.
-
-# Find where the test suite is.
-setenv=setenv.tr
-for file in ./setenv.tr lib/setenv.tr tests/lib/setenv.tr ; do
- [ -x $file ] && setenv=$file
-done
-
-ulimit -d 150
-exec $setenv
+++ /dev/null
-/* $Id: snprintf-t.c 7510 2006-04-02 18:31:51Z eagle $ */
-/* snprintf test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "libtest.h"
-
-int test_snprintf(char *str, size_t count, const char *fmt, ...);
-int test_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
-
-static const char string[] = "abcdefghijklmnopqrstuvwxyz0123456789";
-
-static const char *const fp_formats[] = {
- "%-1.5f", "%1.5f", "%31.9f", "%10.5f", "% 10.5f", "%+22.9f",
- "%+4.9f", "%01.3f", "%3.1f", "%3.2f", "%.0f", "%.1f",
- "%f", NULL
-};
-static const char *const int_formats[] = {
- "%-1.5d", "%1.5d", "%31.9d", "%5.5d", "%10.5d", "% 10.5d",
- "%+22.30d", "%01.3d", "%4d", "%d", "%ld", NULL
-};
-static const char *const uint_formats[] = {
- "%-1.5lu", "%1.5lu", "%31.9lu", "%5.5lu", "%10.5lu", "% 10.5lu",
- "%+6.30lu", "%01.3lu", "%4lu", "%lu", "%4lx", "%4lX",
- "%01.3lx", "%1lo", NULL
-};
-static const char *const llong_formats[] = {
- "%lld", "%-1.5lld", "%1.5lld", "%123.9lld", "%5.5lld",
- "%10.5lld", "% 10.5lld", "%+22.33lld", "%01.3lld", "%4lld",
- NULL
-};
-static const char *const ullong_formats[] = {
- "%llu", "%-1.5llu", "%1.5llu", "%123.9llu", "%5.5llu",
- "%10.5llu", "% 10.5llu", "%+22.33llu", "%01.3llu", "%4llu",
- "%llx", "%llo", NULL
-};
-
-static const double fp_nums[] = {
- -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996, 0.9996, 1.996,
- 4.136, 0
-};
-static long int_nums[] = {
- -1, 134, 91340, 341, 0203, 0
-};
-static unsigned long uint_nums[] = {
- (unsigned long) -1, 134, 91340, 341, 0203, 0
-};
-static long long llong_nums[] = {
- ~(long long) 0, /* All-1 bit pattern. */
- (~(unsigned long long) 0) >> 1, /* Largest signed long long. */
- -150, 134, 91340, 341,
- 0
-};
-static unsigned long long ullong_nums[] = {
- ~(unsigned long long) 0, /* All-1 bit pattern. */
- (~(unsigned long long) 0) >> 1, /* Largest signed long long. */
- 134, 91340, 341,
- 0
-};
-
-static void
-test_format(int n, bool truncate, const char *expected, int count,
- const char *format, ...)
-{
- char buf[128];
- int result;
- va_list args;
-
- va_start(args, format);
- result = test_vsnprintf(buf, truncate ? 32 : sizeof(buf), format, args);
- va_end(args);
- if (!strcmp(buf, expected) && result == count) {
- printf("ok %d\n", n);
- } else {
- printf("not ok %d\n", n);
- printf(" format: %s\n", format);
- if (strcmp(buf, expected))
- printf(" saw: %s\n want: %s\n", buf, expected);
- if (result != count) printf(" %d != %d\n", result, count);
- }
-}
-
-int
-main(void)
-{
- int n, i, count;
- unsigned int j;
- long lcount;
- char lgbuf[128];
-
- printf("%d\n",
- (25 + (ARRAY_SIZE(fp_formats) - 1) * ARRAY_SIZE(fp_nums)
- + (ARRAY_SIZE(int_formats) - 1) * ARRAY_SIZE(int_nums)
- + (ARRAY_SIZE(uint_formats) - 1) * ARRAY_SIZE(uint_nums)
- + (ARRAY_SIZE(llong_formats) - 1) * ARRAY_SIZE(llong_nums)
- + (ARRAY_SIZE(ullong_formats) - 1) * ARRAY_SIZE(ullong_nums)));
-
- ok(1, test_snprintf(NULL, 0, "%s", "abcd") == 4);
- ok(2, test_snprintf(NULL, 0, "%d", 20) == 2);
- ok(3, test_snprintf(NULL, 0, "Test %.2s", "abcd") == 7);
- ok(4, test_snprintf(NULL, 0, "%c", 'a') == 1);
- ok(5, test_snprintf(NULL, 0, "") == 0);
-
- test_format(6, true, "abcd", 4, "%s", "abcd");
- test_format(7, true, "20", 2, "%d", 20);
- test_format(8, true, "Test ab", 7, "Test %.2s", "abcd");
- test_format(9, true, "a", 1, "%c", 'a');
- test_format(10, true, "", 0, "");
- test_format(11, true, "abcdefghijklmnopqrstuvwxyz01234", 36, "%s",
- string);
- test_format(12, true, "abcdefghij", 10, "%.10s", string);
- test_format(13, true, " abcdefghij", 12, "%12.10s", string);
- test_format(14, true, " abcdefghijklmnopqrstuvwxyz0", 40, "%40s",
- string);
- test_format(15, true, "abcdefghij ", 14, "%-14.10s", string);
- test_format(16, true, " abcdefghijklmnopq", 50, "%50s",
- string);
- test_format(17, true, "%abcd%", 6, "%%%0s%%", "abcd");
- test_format(18, true, "", 0, "%.0s", string);
- test_format(19, true, "abcdefghijklmnopqrstuvwxyz 444", 32, "%.26s %d",
- string, 4444);
- test_format(20, true, "abcdefghijklmnopqrstuvwxyz -2.", 32,
- "%.26s %.1f", string, -2.5);
- test_format(21, true, "abcdefghij4444", 14, "%.10s%n%d", string, &count,
- 4444);
- ok(22, count == 10);
- test_format(23, true, "abcdefghijklmnopqrstuvwxyz01234", 36, "%n%s%ln",
- &count, string, &lcount);
- ok(24, count == 0);
- ok(25, lcount == 31);
-
- n = 25;
- for (i = 0; fp_formats[i] != NULL; i++)
- for (j = 0; j < ARRAY_SIZE(fp_nums); j++) {
- count = sprintf(lgbuf, fp_formats[i], fp_nums[j]);
- test_format(++n, false, lgbuf, count, fp_formats[i], fp_nums[j]);
- }
- for (i = 0; int_formats[i] != NULL; i++)
- for (j = 0; j < ARRAY_SIZE(int_nums); j++) {
- count = sprintf(lgbuf, int_formats[i], int_nums[j]);
- test_format(++n, false, lgbuf, count, int_formats[i],
- int_nums[j]);
- }
- for (i = 0; uint_formats[i] != NULL; i++)
- for (j = 0; j < ARRAY_SIZE(uint_nums); j++) {
- count = sprintf(lgbuf, uint_formats[i], uint_nums[j]);
- test_format(++n, false, lgbuf, count, uint_formats[i],
- uint_nums[j]);
- }
- for (i = 0; llong_formats[i] != NULL; i++)
- for (j = 0; j < ARRAY_SIZE(llong_nums); j++) {
- count = sprintf(lgbuf, llong_formats[i], llong_nums[j]);
- test_format(++n, false, lgbuf, count, llong_formats[i],
- llong_nums[j]);
- }
- for (i = 0; ullong_formats[i] != NULL; i++)
- for (j = 0; j < ARRAY_SIZE(ullong_nums); j++) {
- count = sprintf(lgbuf, ullong_formats[i], ullong_nums[j]);
- test_format(++n, false, lgbuf, count, ullong_formats[i],
- ullong_nums[j]);
- }
-
- return 0;
-}
+++ /dev/null
-/* $Id: strerror-t.c 5559 2002-08-11 23:43:48Z rra $ */
-/* strerror test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-
-#include "libtest.h"
-
-const char *test_strerror(int);
-
-int
-main(void)
-{
- puts("5");
-
-#if HAVE_STRERROR
- ok_string(1, strerror(EACCES), test_strerror(EACCES));
- ok_string(2, strerror(0), test_strerror(0));
-#else
- ok(1, strerror(EACCES) != NULL);
- ok(2, strerror(0) != NULL);
-#endif
- ok_string(3, "Error code 77777", test_strerror(77777));
- ok_string(4, "Error code -4000", test_strerror(-4000));
- ok_string(5, "Error code -100000", test_strerror(-100000));
-
- return 0;
-}
+++ /dev/null
-/* $Id: strlcat-t.c 5656 2002-08-25 21:54:57Z rra $ */
-/* strlcat test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "libtest.h"
-
-size_t test_strlcat(char *, const char *, size_t);
-
-int
-main(void)
-{
- char buffer[10] = "";
-
- puts("27");
-
- ok_int(1, 3, test_strlcat(buffer, "foo", sizeof(buffer)));
- ok_string(2, "foo", buffer);
- ok_int(3, 7, test_strlcat(buffer, " bar", sizeof(buffer)));
- ok_string(4, "foo bar", buffer);
- ok_int(5, 9, test_strlcat(buffer, "!!", sizeof(buffer)));
- ok_string(6, "foo bar!!", buffer);
- ok_int(7, 10, test_strlcat(buffer, "!", sizeof(buffer)));
- ok_string(8, "foo bar!!", buffer);
- ok(9, buffer[9] == '\0');
- buffer[0] = '\0';
- ok_int(10, 11, test_strlcat(buffer, "hello world", sizeof(buffer)));
- ok_string(11, "hello wor", buffer);
- ok(12, buffer[9] == '\0');
- buffer[0] = '\0';
- ok_int(13, 7, test_strlcat(buffer, "sausage", 5));
- ok_string(14, "saus", buffer);
- ok_int(15, 14, test_strlcat(buffer, "bacon eggs", sizeof(buffer)));
- ok_string(16, "sausbacon", buffer);
-
- /* Make sure that with a size of 0, the destination isn't changed. */
- ok_int(17, 11, test_strlcat(buffer, "!!", 0));
- ok_string(18, "sausbacon", buffer);
-
- /* Now play with empty strings. */
- ok_int(19, 9, test_strlcat(buffer, "", 0));
- ok_string(20, "sausbacon", buffer);
- buffer[0] = '\0';
- ok_int(21, 0, test_strlcat(buffer, "", sizeof(buffer)));
- ok_string(22, "", buffer);
- ok_int(23, 3, test_strlcat(buffer, "foo", 2));
- ok_string(24, "f", buffer);
- ok(25, buffer[1] == '\0');
- ok_int(26, 1, test_strlcat(buffer, "", sizeof(buffer)));
- ok(27, buffer[1] == '\0');
-
- return 0;
-}
+++ /dev/null
-/* $Id: strlcpy-t.c 5568 2002-08-12 02:06:44Z rra $ */
-/* strlcpy test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "libtest.h"
-
-size_t test_strlcpy(char *, const char *, size_t);
-
-int
-main(void)
-{
- char buffer[10];
-
- puts("23");
-
- ok_int(1, 3, test_strlcpy(buffer, "foo", sizeof(buffer)));
- ok_string(2, "foo", buffer);
- ok_int(3, 9, test_strlcpy(buffer, "hello wor", sizeof(buffer)));
- ok_string(4, "hello wor", buffer);
- ok_int(5, 10, test_strlcpy(buffer, "world hell", sizeof(buffer)));
- ok_string(6, "world hel", buffer);
- ok(7, buffer[9] == '\0');
- ok_int(8, 11, test_strlcpy(buffer, "hello world", sizeof(buffer)));
- ok_string(9, "hello wor", buffer);
- ok(10, buffer[9] == '\0');
-
- /* Make sure that with a size of 0, the destination isn't changed. */
- ok_int(11, 3, test_strlcpy(buffer, "foo", 0));
- ok_string(12, "hello wor", buffer);
-
- /* Now play with empty strings. */
- ok_int(13, 0, test_strlcpy(buffer, "", 0));
- ok_string(14, "hello wor", buffer);
- ok_int(15, 0, test_strlcpy(buffer, "", sizeof(buffer)));
- ok_string(16, "", buffer);
- ok_int(17, 3, test_strlcpy(buffer, "foo", 2));
- ok_string(18, "f", buffer);
- ok(19, buffer[1] == '\0');
- ok_int(20, 0, test_strlcpy(buffer, "", 1));
- ok(21, buffer[0] == '\0');
-
- /* Finally, check using strlcpy as strlen. */
- ok_int(22, 3, test_strlcpy(NULL, "foo", 0));
- ok_int(23, 11, test_strlcpy(NULL, "hello world", 0));
-
- return 0;
-}
+++ /dev/null
-/* $Id: tst-t.c 7262 2005-06-06 04:45:48Z eagle $ */
-/* Test suite for ternary search tries. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "inn/tst.h"
-#include "libinn.h"
-#include "libtest.h"
-
-/* Used for strings of unsigned characters. */
-#define U (const unsigned char *)
-
-/* An unsigned char version of strlen. */
-#define ustrlen(s) strlen((const char *) s)
-
-int
-main(void)
-{
- struct tst *tst;
- FILE *words;
- unsigned char buffer[1024];
- bool reported;
- void *existing;
- unsigned char *word;
-
- char test[] = "test";
- char t[] = "t";
- char foo[] = "foo";
- char testing[] = "testing";
- char Strange[] = "Strange";
- char change[] = "çhange";
-
- puts("38");
-
- tst = tst_init(2);
- ok(1, tst != NULL);
- ok(2, tst_insert(tst, U"test", test, 0, NULL) == TST_OK);
- ok_string(3, "test", tst_search(tst, U"test"));
- ok(4, tst_insert(tst, U"test", foo, 0, &existing) == TST_DUPLICATE_KEY);
- ok_string(5, "test", existing);
- ok(6, tst_insert(tst, U"test", foo, TST_REPLACE, &existing) == TST_OK);
- ok_string(7, "test", existing);
- ok_string(8, "foo", tst_search(tst, U"test"));
- ok(9, tst_insert(tst, U"testing", testing, 0, NULL) == TST_OK);
- ok(10, tst_insert(tst, U"t", t, 0, NULL) == TST_OK);
- ok(11, tst_insert(tst, U"Strange", Strange, 0, NULL) == TST_OK);
- ok(12, tst_insert(tst, U"çhange", change, 0, NULL) == TST_OK);
- ok(13, tst_insert(tst, U"", foo, 0, NULL) == TST_NULL_KEY);
- ok(14, tst_insert(tst, NULL, foo, 0, NULL) == TST_NULL_KEY);
- ok_string(15, "testing", tst_search(tst, U"testing"));
- ok_string(16, "t", tst_search(tst, U"t"));
- ok_string(17, "Strange", tst_search(tst, U"Strange"));
- ok_string(18, "çhange", tst_search(tst, U"çhange"));
- ok_string(19, "foo", tst_search(tst, U"test"));
- ok(20, tst_search(tst, U"") == NULL);
- ok(21, tst_search(tst, U"Peter") == NULL);
- ok(22, tst_search(tst, U"foo") == NULL);
- ok(23, tst_search(tst, U"te") == NULL);
- ok_string(24, "Strange", tst_delete(tst, U"Strange"));
- ok(25, tst_search(tst, U"Strange") == NULL);
- ok_string(26, "t", tst_delete(tst, U"t"));
- ok(27, tst_search(tst, U"t") == NULL);
- ok_string(28, "testing", tst_search(tst, U"testing"));
- ok_string(29, "foo", tst_search(tst, U"test"));
- ok_string(30, "testing", tst_delete(tst, U"testing"));
- ok_string(31, "foo", tst_search(tst, U"test"));
- ok_string(32, "çhange", tst_delete(tst, U"çhange"));
- ok_string(33, "foo", tst_delete(tst, U"test"));
- ok(34, tst_search(tst, NULL) == NULL);
- ok(35, tst_delete(tst, NULL) == NULL);
- tst_cleanup(tst);
- ok(36, true);
-
- words = fopen("/usr/dict/words", "r");
- if (words == NULL)
- words = fopen("/usr/share/dict/words", "r");
- if (words == NULL) {
- puts("ok 37 # skip\nok 38 # skip");
- exit(0);
- }
-
- tst = tst_init(1000);
- reported = false;
- if (tst == NULL)
- printf("not ");
- else {
- while (fgets((char *) buffer, sizeof(buffer), words)) {
- buffer[ustrlen(buffer) - 1] = '\0';
- if (buffer[0] == '\0')
- continue;
- word = (unsigned char *) xstrdup((char *) buffer);
- if (tst_insert(tst, buffer, word, 0, NULL) != TST_OK) {
- if (!reported)
- printf("not ");
- reported = true;
- }
- }
- }
- puts("ok 37");
-
- if (fseek(words, 0, SEEK_SET) < 0)
- sysdie("Unable to rewind words file");
- reported = false;
- if (tst == NULL)
- printf("not ");
- else {
- while (fgets((char *) buffer, sizeof(buffer), words)) {
- buffer[ustrlen(buffer) - 1] = '\0';
- if (buffer[0] == '\0')
- continue;
- word = tst_search(tst, buffer);
- if (word == NULL || strcmp((char *) word, buffer) != 0) {
- if (!reported)
- printf("not ");
- reported = true;
- }
- word = tst_delete(tst, buffer);
- if (word == NULL || strcmp((char *) word, buffer) != 0) {
- if (!reported)
- printf("not ");
- reported = true;
- }
- free(word);
- }
- }
- tst_cleanup(tst);
- puts("ok 38");
-
- return 0;
-}
+++ /dev/null
-/* $Id: uwildmat-t.c 7262 2005-06-06 04:45:48Z eagle $
-**
-** wildmat test suite.
-**
-** As of March 11, 2001, this test suite achieves 100% coverage of the
-** wildmat source code at that time.
-*/
-
-#include "clibrary.h"
-#include "libinn.h"
-
-static void
-test_r(int n, const char *text, const char *pattern, bool matches)
-{
- bool matched;
-
- matched = uwildmat(text, pattern);
- printf("%sok %d\n", matched == matches ? "" : "not ", n);
- if (matched != matches)
- printf(" %s\n %s\n expected %d\n", text, pattern, matches);
-}
-
-static void
-test_p(int n, const char *text, const char *pattern, enum uwildmat matches)
-{
- enum uwildmat matched;
-
- matched = uwildmat_poison(text, pattern);
- printf("%sok %d\n", matched == matches ? "" : "not ", n);
- if (matched != matches)
- printf(" %s\n %s\n expected %d got %d\n", text, pattern,
- (int) matches, (int) matched);
-}
-
-static void
-test_s(int n, const char *text, const char *pattern, bool matches)
-{
- bool matched;
-
- matched = uwildmat_simple(text, pattern);
- printf("%sok %d\n", matched == matches ? "" : "not ", n);
- if (matched != matches)
- printf(" %s\n %s\n expected %d\n", text, pattern, matches);
-}
-
-int
-main(void)
-{
- puts("166");
-
- /* Basic wildmat features. */
- test_r( 1, "foo", "foo", true);
- test_r( 2, "foo", "bar", false);
- test_r( 3, "", "", true);
- test_r( 4, "foo", "???", true);
- test_r( 5, "foo", "??", false);
- test_r( 6, "foo", "*", true);
- test_r( 7, "foo", "f*", true);
- test_r( 8, "foo", "*f", false);
- test_r( 9, "foo", "*foo*", true);
- test_r( 10, "foobar", "*ob*a*r*", true);
- test_r( 11, "aaaaaaabababab", "*ab", true);
- test_r( 12, "foo*", "foo\\*", true);
- test_r( 13, "foobar", "foo\\*bar", false);
- test_r( 14, "\\", "\\\\", true);
- test_r( 15, "ball", "*[al]?", true);
- test_r( 16, "ten", "[ten]", false);
- test_r( 17, "ten", "**[^te]", true);
- test_r( 18, "ten", "**[^ten]", false);
- test_r( 19, "ten", "t[a-g]n", true);
- test_r( 20, "ten", "t[^a-g]n", false);
- test_r( 21, "ton", "t[^a-g]n", true);
- test_r( 22, "]", "]", true);
- test_r( 23, "a]b", "a[]]b", true);
- test_r( 24, "a-b", "a[]-]b", true);
- test_r( 25, "a]b", "a[]-]b", true);
- test_r( 26, "aab", "a[]-]b", false);
- test_r( 27, "aab", "a[]a-]b", true);
-
- /* Multiple and negation. */
- test_r( 28, "foo", "!foo", false);
- test_r( 29, "foo", "!bar", false);
- test_r( 30, "foo", "*,!foo", false);
- test_r( 31, "foo", "*,!bar", true);
- test_r( 32, "foo", "foo,bar", true);
- test_r( 33, "bar", "foo,bar", true);
- test_r( 34, "baz", "foo,bar", false);
- test_r( 35, "baz", "foo,ba?", true);
- test_r( 36, "", "!", false);
- test_r( 37, "foo", "!", false);
- test_r( 38, "a", "a,!b,c", true);
- test_r( 39, "b", "a,!b,c", false);
- test_r( 40, "c", "a,!b,c", true);
- test_r( 41, "ab", "a*,!ab", false);
- test_r( 42, "abc", "a*,!ab", true);
- test_r( 43, "dabc", "a*,!ab", false);
- test_r( 44, "abc", "a*,!ab*,abc", true);
- test_r( 45, "", ",", true);
- test_r( 46, "a", ",a", true);
- test_r( 47, "a", "a,,,", true);
- test_r( 48, "b", ",a", false);
- test_r( 49, "b", "a,,,", false);
- test_r( 50, "a,b", "a\\,b", true);
- test_r( 51, "a,b", "a\\\\,b", false);
- test_r( 52, "a\\", "a\\\\,b", true);
- test_r( 53, "a\\,b", "a\\\\,b", false);
- test_r( 54, "a\\,b", "a\\\\\\,b", true);
- test_r( 55, ",", "\\,", true);
- test_r( 56, ",\\", "\\,", false);
- test_r( 57, ",\\", "\\,\\\\,", true);
- test_r( 58, "", "\\,\\\\,", true);
- test_r( 59, "", "\\,,!", false);
- test_r( 60, "", "\\,!,", true);
-
- /* Various additional tests. */
- test_r( 61, "acrt", "a[c-c]st", false);
- test_r( 62, "]", "[^]-]", false);
- test_r( 63, "a", "[^]-]", true);
- test_r( 64, "", "\\", false);
- test_r( 65, "\\", "\\", false);
- test_r( 66, "foo", "*,@foo", true);
- test_r( 67, "@foo", "@foo", true);
- test_r( 68, "foo", "@foo", false);
- test_r( 69, "[ab]", "\\[ab]", true);
- test_r( 70, "?a?b", "\\??\\?b", true);
- test_r( 71, "abc", "\\a\\b\\c", true);
-
- /* Poison negation. */
- test_p( 72, "abc", "*", UWILDMAT_MATCH);
- test_p( 73, "abc", "def", UWILDMAT_FAIL);
- test_p( 74, "abc", "*,!abc", UWILDMAT_FAIL);
- test_p( 75, "a", "*,@a", UWILDMAT_POISON);
- test_p( 76, "ab", "*,@a*,ab", UWILDMAT_MATCH);
- test_p( 77, "ab", "*,@a**,!ab", UWILDMAT_FAIL);
- test_p( 78, "@ab", "\\@ab", UWILDMAT_MATCH);
- test_p( 79, "@ab", "@\\@ab", UWILDMAT_POISON);
-
- /* UTF-8 characters. */
- test_r( 80, "S\303\256ne", "S\303\256ne", true);
- test_r( 81, "S\303\256ne", "S\303\257ne", false);
- test_r( 82, "S\303\256ne", "S?ne", true);
- test_r( 83, "S\303\256ne", "S*e", true);
- test_r( 84, "S\303\256ne", "S[a-\330\200]ne", true);
- test_r( 85, "S\303\256ne", "S[a-\300\256]ne", false);
- test_r( 86, "S\303\256ne", "S[^\1-\177]ne", true);
- test_r( 87, "S\303\256ne", "S[0\303\256$]ne", true);
- test_r( 88, "\2", "[\1-\3]", true);
- test_r( 89, "\330\277", "[\330\276-\331\200]", true);
- test_r( 90, "\337\277", "[\337\276-\350\200\200]", true);
- test_r( 91, "\357\277\277", "[\357\277\276-\364\200\200\200]", true);
- test_r( 92, "\357\276\277", "[\357\277\276-\364\200\200\200]", false);
- test_r( 93, "\367\277\277\277",
- "[\310\231-\372\200\200\200\200]", true);
- test_r( 94, "\373\277\277\277\277",
- "[\1-\375\200\200\200\200\200]", true);
- test_r( 95, "\375\200\200\200\200\200",
- "[\5-\375\200\200\200\200\200]", true);
- test_r( 96, "\375\277\277\277\277\276",
- "[\375\277\277\277\277\275-\375\277\277\277\277\277]", true);
- test_r( 97, "b\357\277\277a", "b?a", true);
- test_r( 98, "b\367\277\277\277a", "b?a", true);
- test_r( 99, "b\373\277\277\277\277a", "b?a", true);
- test_r(100, "b\375\277\277\277\277\276a", "b?a", true);
- test_r(101, "\357\240\275S\313\212\375\206\203\245\260\211",
- "????", true);
- test_r(102, "S\303\256ne", "S\\\303\256ne", true);
- test_r(103, "s", "[^\330\277-\375\277\277\277\277\277]", true);
- test_r(104, "\367\277\277\277",
- "[^\330\277-\375\277\277\277\277\277]", false);
-
- /* Malformed UTF-8. */
- test_r(105, "S\303\256ne", "S?\256ne", false);
- test_r(106, "\303\303", "?", false);
- test_r(107, "\303\303", "??", true);
- test_r(108, "\200", "[\177-\201]", true);
- test_r(109, "abc\206d", "*\206d", true);
- test_r(110, "\303\206", "*\206", false);
- test_r(111, "\40", "\240", false);
- test_r(112, "\323", "[a-\377]", true);
- test_r(113, "\376\277\277\277\277\277", "?", false);
- test_r(114, "\376\277\277\277\277\277", "??????", true);
- test_r(115, "\377\277\277\277\277\277", "?", false);
- test_r(116, "\377\277\277\277\277\277", "??????", true);
- test_r(117, "\303\323\206", "??", true);
- test_r(118, "\206", "[\341\206f]", true);
- test_r(119, "f", "[\341\206f]", true);
- test_r(120, "\207", "[\341\206-\277]", true);
- test_r(121, "\207", "[\341\206\206-\277]", false);
- test_r(122, "\300", "[\277-\341\206]", true);
- test_r(123, "\206", "[\277-\341\206]", true);
- test_r(124, "\341\206", "[\341\206-\277]?", true);
-
- /* Additional tests, including some malformed wildmats. */
- test_r(125, "ab", "a[]b", false);
- test_r(126, "a[]b", "a[]b", false);
- test_r(127, "ab[", "ab[", false);
- test_r(128, "ab", "[^", false);
- test_r(129, "ab", "[-", false);
- test_r(130, "-", "[-]", true);
- test_r(131, "-", "[a-", false);
- test_r(132, "-", "[^a-", false);
- test_r(133, "-", "[--A]", true);
- test_r(134, "5", "[--A]", true);
- test_r(135, "\303\206", "[--A]", false);
- test_r(136, " ", "[ --]", true);
- test_r(137, "$", "[ --]", true);
- test_r(138, "-", "[ --]", true);
- test_r(139, "0", "[ --]", false);
- test_r(140, "-", "[---]", true);
- test_r(141, "-", "[------]", true);
- test_r(142, "j", "[a-e-n]", false);
- test_r(143, "a", "[^------]", true);
- test_r(144, "[", "[]-a]", false);
- test_r(145, "^", "[]-a]", true);
- test_r(146, "^", "[^]-a]", false);
- test_r(147, "[", "[^]-a]", true);
- test_r(148, "^", "[a^bc]", true);
- test_r(149, "-b]", "[a-]b]", true);
- test_r(150, "\\]", "[\\]]", true);
- test_r(151, "]", "[\\-^]", true);
- test_r(152, "[", "[\\-^]", false);
- test_r(153, "G", "[A-\\]", true);
- test_r(154, "aaabbb", "b*a", false);
- test_r(155, "aabcaa", "*ba*", false);
- test_r(156, ",", "[,]", true);
- test_r(157, ",", "[\\,]", true);
- test_r(158, "\\", "[\\,]", true);
- test_r(159, "-", "[,-.]", true);
- test_r(160, "+", "[,-.]", false);
- test_r(161, "-.]", "[,-.]", false);
-
- /* Tests for the wildmat_simple interface. */
- test_s(162, "ab,cd", "ab,cd", true);
- test_s(163, "ab", "ab,cd", false);
- test_s(164, "!aaabbb", "!a*b*", true);
- test_s(165, "ccc", "*,!a*", false);
- test_s(166, "foo", "*", true);
-
- return 0;
-}
+++ /dev/null
-/* $Id: vector-t.c 5678 2002-08-28 23:21:32Z rra $ */
-/* vector test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/vector.h"
-#include "libinn.h"
-#include "libtest.h"
-
-int
-main(void)
-{
- struct vector *vector;
- struct cvector *cvector;
- const char cstring[] = "This is a\ttest. ";
- const char tabs[] = "test\t\ting\t";
- static const char nulls1[] = "This\0is\0a\0test.";
- static const char nulls2[] = "This is a\t\0es\0. ";
- char empty[] = "";
- char *string;
- char *p;
-
- puts("87");
-
- vector = vector_new();
- ok(1, vector != NULL);
- vector_add(vector, cstring);
- ok_int(2, 1, vector->count);
- ok(3, vector->strings[0] != cstring);
- vector_resize(vector, 4);
- ok_int(4, 4, vector->allocated);
- vector_add(vector, cstring);
- vector_add(vector, cstring);
- vector_add(vector, cstring);
- ok_int(5, 4, vector->allocated);
- ok_int(6, 4, vector->count);
- ok(7, vector->strings[1] != vector->strings[2]);
- ok(8, vector->strings[2] != vector->strings[3]);
- ok(9, vector->strings[3] != vector->strings[0]);
- ok(10, vector->strings[0] != cstring);
- vector_clear(vector);
- ok_int(11, 0, vector->count);
- ok_int(12, 4, vector->allocated);
- string = xstrdup(cstring);
- vector_add(vector, cstring);
- vector_add(vector, string);
- ok_int(13, 2, vector->count);
- ok(14, vector->strings[1] != string);
- vector_resize(vector, 1);
- ok_int(15, 1, vector->count);
- ok(16, vector->strings[0] != cstring);
- vector_free(vector);
- free(string);
-
- cvector = cvector_new();
- ok(17, cvector != NULL);
- cvector_add(cvector, cstring);
- ok_int(18, 1, cvector->count);
- ok(19, cvector->strings[0] == cstring);
- cvector_resize(cvector, 4);
- ok_int(20, 4, cvector->allocated);
- cvector_add(cvector, cstring);
- cvector_add(cvector, cstring);
- cvector_add(cvector, cstring);
- ok_int(21, 4, cvector->allocated);
- ok_int(22, 4, cvector->count);
- ok(23, cvector->strings[1] == cvector->strings[2]);
- ok(24, cvector->strings[2] == cvector->strings[3]);
- ok(25, cvector->strings[3] == cvector->strings[0]);
- ok(26, cvector->strings[0] == cstring);
- cvector_clear(cvector);
- ok_int(27, 0, cvector->count);
- ok_int(28, 4, cvector->allocated);
- string = xstrdup(cstring);
- cvector_add(cvector, cstring);
- cvector_add(cvector, string);
- ok_int(29, 2, cvector->count);
- ok(30, cvector->strings[1] == string);
- cvector_resize(cvector, 1);
- ok_int(31, 1, cvector->count);
- ok(32, cvector->strings[0] == cstring);
- cvector_free(cvector);
- free(string);
-
- vector = vector_split_space("This is a\ttest. ", NULL);
- ok_int(33, 4, vector->count);
- ok_int(34, 4, vector->allocated);
- ok_string(35, "This", vector->strings[0]);
- ok_string(36, "is", vector->strings[1]);
- ok_string(37, "a", vector->strings[2]);
- ok_string(38, "test.", vector->strings[3]);
- vector_add(vector, cstring);
- ok_string(39, cstring, vector->strings[4]);
- ok(40, vector->strings[4] != cstring);
- ok_int(41, 5, vector->allocated);
- vector = vector_split(cstring, 't', vector);
- ok_int(42, 3, vector->count);
- ok_int(43, 5, vector->allocated);
- ok_string(44, "This is a\t", vector->strings[0]);
- ok_string(45, "es", vector->strings[1]);
- ok_string(46, ". ", vector->strings[2]);
- ok(47, vector->strings[0] != cstring);
- p = vector_join(vector, "fe");
- ok_string(48, "This is a\tfeesfe. ", p);
- free(p);
- vector_free(vector);
-
- string = xstrdup(cstring);
- cvector = cvector_split_space(string, NULL);
- ok_int(49, 4, cvector->count);
- ok_int(50, 4, cvector->allocated);
- ok_string(51, "This", cvector->strings[0]);
- ok_string(52, "is", cvector->strings[1]);
- ok_string(53, "a", cvector->strings[2]);
- ok_string(54, "test.", cvector->strings[3]);
- ok(55, memcmp(string, nulls1, 16) == 0);
- cvector_add(cvector, cstring);
- ok(56, cvector->strings[4] == cstring);
- ok_int(57, 5, cvector->allocated);
- free(string);
- string = xstrdup(cstring);
- cvector = cvector_split(string, 't', cvector);
- ok_int(58, 3, cvector->count);
- ok_int(59, 5, cvector->allocated);
- ok_string(60, "This is a\t", cvector->strings[0]);
- ok_string(61, "es", cvector->strings[1]);
- ok_string(62, ". ", cvector->strings[2]);
- ok(63, cvector->strings[0] == string);
- ok(64, memcmp(string, nulls2, 18) == 0);
- p = cvector_join(cvector, "oo");
- ok_string(65, "This is a\tooesoo. ", p);
- free(p);
- cvector_free(cvector);
- free(string);
-
- vector = vector_split("", ' ', NULL);
- ok_int(66, 1, vector->count);
- ok_string(67, "", vector->strings[0]);
- vector_free(vector);
- cvector = cvector_split(empty, ' ', NULL);
- ok_int(68, 1, cvector->count);
- ok_string(69, "", vector->strings[0]);
- cvector_free(cvector);
-
- vector = vector_split_space("", NULL);
- ok_int(70, 0, vector->count);
- vector_free(vector);
- cvector = cvector_split_space(empty, NULL);
- ok_int(71, 0, cvector->count);
- cvector_free(cvector);
-
- vector = vector_split(tabs, '\t', NULL);
- ok_int(72, 4, vector->count);
- ok_string(73, "test", vector->strings[0]);
- ok_string(74, "", vector->strings[1]);
- ok_string(75, "ing", vector->strings[2]);
- ok_string(76, "", vector->strings[3]);
- p = vector_join(vector, "");
- ok_string(77, "testing", p);
- free(p);
- vector_free(vector);
-
- string = xstrdup(tabs);
- cvector = cvector_split(string, '\t', NULL);
- ok_int(78, 4, cvector->count);
- ok_string(79, "test", cvector->strings[0]);
- ok_string(80, "", cvector->strings[1]);
- ok_string(81, "ing", cvector->strings[2]);
- ok_string(82, "", cvector->strings[3]);
- p = cvector_join(cvector, "");
- ok_string(83, "testing", p);
- free(p);
- cvector_free(cvector);
- free(string);
-
- vector = vector_split_space("foo\nbar", NULL);
- ok_int(84, 1, vector->count);
- ok_string(85, "foo\nbar", vector->strings[0]);
- vector_free(vector);
-
- string = xstrdup("foo\nbar");
- cvector = cvector_split_space(string, NULL);
- ok_int(86, 1, cvector->count);
- ok_string(87, "foo\nbar", cvector->strings[0]);
- cvector_free(cvector);
-
- return 0;
-}
+++ /dev/null
-/* $Id: wire-t.c 6084 2002-12-27 07:24:55Z rra $ */
-/* wire test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "inn/messages.h"
-#include "inn/wire.h"
-#include "libinn.h"
-#include "libtest.h"
-
-/* Read in a file and return the contents in newly allocated memory. Fills in
- the provided stat buffer. */
-static char *
-read_file(const char *name, struct stat *st)
-{
- int fd;
- char *article;
- ssize_t count;
-
- if (stat(name, st) < 0)
- sysdie("cannot stat %s", name);
- article = xmalloc(st->st_size);
- fd = open(name, O_RDONLY);
- if (fd < 0)
- sysdie("cannot open %s", name);
- count = read(fd, article, st->st_size);
- if (count < st->st_size)
- die("unable to read all of %s", name);
- close(fd);
- return article;
-}
-
-
-/* Test article for wire_findbody. */
-const char ta[] = "Path: \r\nFrom: \r\n\r\n";
-
-int
-main(void)
-{
- const char *p, *end;
- char *article;
- struct stat st;
-
- puts("34");
-
- end = ta + sizeof(ta) - 1;
- p = end - 4;
- ok(1, wire_findbody(ta, sizeof(ta) - 1) == end);
- ok(2, wire_findbody(ta, sizeof(ta) - 2) == NULL);
- ok(3, wire_findbody(ta, sizeof(ta) - 3) == NULL);
- ok(4, wire_findbody(ta, sizeof(ta) - 4) == NULL);
- ok(5, wire_findbody(ta, sizeof(ta) - 5) == NULL);
- ok(6, wire_findbody(p, 4) == end);
- ok(7, wire_findbody(p, 3) == NULL);
- ok(8, wire_findbody(p, 2) == NULL);
- ok(9, wire_findbody(p, 1) == NULL);
- ok(10, wire_findbody(p, 0) == NULL);
-
- if (access("articles/strange", F_OK) < 0)
- if (access("lib/articles/strange", F_OK) == 0)
- chdir("lib");
- article = read_file("articles/strange", &st);
-
- p = wire_findbody(article, st.st_size);
- ok(11, strncmp(p, "Path: This is", strlen("Path: This is")) == 0);
- p = wire_nextline(p, article + st.st_size - 1);
- ok(12, strncmp(p, "Second: Not", strlen("Second: Not")) == 0);
- p = wire_nextline(p, article + st.st_size - 1);
- ok(13, p == NULL);
- p = wire_findheader(article, st.st_size, "Path");
- ok(14, p == article + 6);
- p = wire_findheader(article, st.st_size, "From");
- ok(15, strncmp(p, "This is the real", strlen("This is the real")) == 0);
- p = wire_findheader(article, st.st_size, "SUMMARY");
- ok(16, strncmp(p, "First text", strlen("First text")) == 0);
- p = wire_findheader(article, st.st_size, "Header");
- ok(17, strncmp(p, "This one is real", strlen("This one is real")) == 0);
- p = wire_findheader(article, st.st_size, "message-id");
- ok(18, strncmp(p, "<foo@example.com>", strlen("<foo@example.com>")) == 0);
- p = wire_findheader(article, st.st_size, "Second");
- ok(19, p == NULL);
- p = wire_findheader(article, st.st_size, "suBJect");
- ok(20, strncmp(p, "This is\rnot", strlen("This is\rnot")) == 0);
- end = wire_endheader(p, article + st.st_size - 1);
- ok(21, strncmp(end, "\nFrom: This is", strlen("\nFrom: This is")) == 0);
- p = wire_findheader(article, st.st_size, "keywordS");
- ok(22, strncmp(p, "this is --", strlen("this is --")) == 0);
- end = wire_endheader(p, article + st.st_size - 1);
- ok(23, strncmp(end, "\nSummary: ", strlen("\nSummary: ")) == 0);
- p = wire_findheader(article, st.st_size, "strange");
- ok(24, strncmp(p, "This is\n\nnot", strlen("This is\n\nnot")) == 0);
- end = wire_endheader(p, article + st.st_size - 1);
- ok(25, strncmp(end, "\nMessage-ID: ", strlen("\nMessage-ID: ")) == 0);
- p = wire_findheader(article, st.st_size, "Message");
- ok(26, p == NULL);
-
- free(article);
- article = read_file("articles/no-body", &st);
-
- ok(27, wire_findbody(article, st.st_size) == NULL);
- p = wire_findheader(article, st.st_size, "message-id");
- ok(28, strncmp(p, "<id1@example.com>\r\n",
- strlen("<id1@example.com>\r\n")) == 0);
- end = wire_endheader(p, article + st.st_size - 1);
- ok(29, end == article + st.st_size - 1);
- ok(30, wire_nextline(p, article + st.st_size - 1) == NULL);
-
- free(article);
- article = read_file("articles/truncated", &st);
-
- ok(31, wire_findbody(article, st.st_size) == NULL);
- p = wire_findheader(article, st.st_size, "date");
- ok(32, strncmp(p, "Mon, 23 Dec", strlen("Mon, 23 Dec")) == 0);
- ok(33, wire_endheader(p, article + st.st_size - 1) == NULL);
- ok(34, wire_nextline(p, article + st.st_size - 1) == NULL);
-
- free(article);
-
- return 0;
-}
+++ /dev/null
-/* $Id: xmalloc.c 5379 2002-03-31 21:45:12Z rra $ */
-/* Test suite for xmalloc and family. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-
-/* Linux requires sys/time.h be included before sys/resource.h. */
-#if HAVE_SYS_TIME_H
-# include <sys/time.h>
-#endif
-#include <sys/resource.h>
-
-#include "inn/messages.h"
-#include "libinn.h"
-
-/* A customized error handler for checking xmalloc's support of them.
- Prints out the error message and exits with status 1. */
-static void
-test_handler(const char *function, size_t size, const char *file, int line)
-{
- die("%s %lu %s %d", function, (unsigned long) size, file, line);
-}
-
-/* Allocate the amount of memory given and write to all of it to make sure
- we can, returning true if that succeeded and false on any sort of
- detectable error. */
-static int
-test_malloc(size_t size)
-{
- char *buffer;
- size_t i;
-
- buffer = xmalloc(size);
- if (buffer == NULL)
- return 0;
- if (size > 0)
- memset(buffer, 1, size);
- for (i = 0; i < size; i++)
- if (buffer[i] != 1)
- return 0;
- free(buffer);
- return 1;
-}
-
-/* Allocate half the memory given, write to it, then reallocate to the
- desired size, writing to the rest and then checking it all. Returns true
- on success, false on any failure. */
-static int
-test_realloc(size_t size)
-{
- char *buffer;
- size_t i;
-
- buffer = xmalloc(size / 2);
- if (buffer == NULL)
- return 0;
- if (size / 2 > 0)
- memset(buffer, 1, size / 2);
- buffer = xrealloc(buffer, size);
- if (buffer == NULL)
- return 0;
- if (size > 0)
- memset(buffer + size / 2, 2, size - size / 2);
- for (i = 0; i < size / 2; i++)
- if (buffer[i] != 1)
- return 0;
- for (i = size / 2; i < size; i++)
- if (buffer[i] != 2)
- return 0;
- free(buffer);
- return 1;
-}
-
-/* Generate a string of the size indicated, call xstrdup on it, and then
- ensure the result matches. Returns true on success, false on any
- failure. */
-static int
-test_strdup(size_t size)
-{
- char *string, *copy;
- int match;
-
- string = xmalloc(size);
- if (string == NULL)
- return 0;
- memset(string, 1, size - 1);
- string[size - 1] = '\0';
- copy = xstrdup(string);
- if (copy == NULL)
- return 0;
- match = strcmp(string, copy);
- free(string);
- free(copy);
- return (match == 0);
-}
-
-/* Generate a string of the size indicated plus some, call xstrndup on it, and
- then ensure the result matches. Returns true on success, false on any
- failure. */
-static int
-test_strndup(size_t size)
-{
- char *string, *copy;
- int match, toomuch;
-
- string = xmalloc(size + 1);
- if (string == NULL)
- return 0;
- memset(string, 1, size - 1);
- string[size - 1] = 2;
- string[size] = '\0';
- copy = xstrndup(string, size - 1);
- if (copy == NULL)
- return 0;
- match = strncmp(string, copy, size - 1);
- toomuch = strcmp(string, copy);
- free(string);
- free(copy);
- return (match == 0 && toomuch != 0);
-}
-
-/* Allocate the amount of memory given and check that it's all zeroed,
- returning true if that succeeded and false on any sort of detectable
- error. */
-static int
-test_calloc(size_t size)
-{
- char *buffer;
- size_t i, nelems;
-
- nelems = size / 4;
- if (nelems * 4 != size)
- return 0;
- buffer = xcalloc(nelems, 4);
- if (buffer == NULL)
- return 0;
- for (i = 0; i < size; i++)
- if (buffer[i] != 0)
- return 0;
- free(buffer);
- return 1;
-}
-
-/* Take the amount of memory to allocate in bytes as a command-line argument
- and call test_malloc with that amount of memory. */
-int
-main(int argc, char *argv[])
-{
- size_t size, max;
- size_t limit = 0;
- int willfail = 0;
- unsigned char code;
- struct rlimit rl;
-
- if (argc < 3)
- die("Usage error. Type, size, and limit must be given.");
- errno = 0;
- size = strtol(argv[2], 0, 10);
- if (size == 0 && errno != 0)
- sysdie("Invalid size");
- errno = 0;
- limit = strtol(argv[3], 0, 10);
- if (limit == 0 && errno != 0)
- sysdie("Invalid limit");
-
- /* If a memory limit was given and we can set memory limits, set it.
- Otherwise, exit 2, signalling to the driver that the test should be
- skipped. We do this here rather than in the driver due to some
- pathological problems with Linux (setting ulimit in the shell caused
- the shell to die). */
- if (limit > 0) {
-#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
- rl.rlim_cur = limit;
- rl.rlim_max = limit;
- if (setrlimit(RLIMIT_DATA, &rl) < 0) {
- syswarn("Can't set data limit to %lu", (unsigned long) limit);
- exit(2);
- }
-#else
- warn("Data limits aren't supported.");
- exit(2);
-#endif
- }
-
- /* If the code is capitalized, install our customized error handler. */
- code = argv[1][0];
- if (isupper(code)) {
- xmalloc_error_handler = test_handler;
- code = tolower(code);
- }
-
- /* Decide if the allocation should fail. If it should, set willfail to
- 2, so that if it unexpectedly succeeds, we exit with a status
- indicating that the test should be skipped. */
- max = size;
- if (code == 's' || code == 'n')
- max *= 2;
- if (limit > 0 && max > limit)
- willfail = 2;
-
- switch (code) {
- case 'c': exit(test_calloc(size) ? willfail : 1);
- case 'm': exit(test_malloc(size) ? willfail : 1);
- case 'r': exit(test_realloc(size) ? willfail : 1);
- case 's': exit(test_strdup(size) ? willfail : 1);
- case 'n': exit(test_strndup(size) ? willfail : 1);
- default:
- die("Unknown mode %c", argv[1][0]);
- break;
- }
- exit(1);
-}
+++ /dev/null
-#! /bin/sh
-# $Id: xmalloc.t 5379 2002-03-31 21:45:12Z rra $
-#
-# Test suite for xmalloc and friends.
-
-# The count starts at 1 and is updated each time ok is printed. printcount
-# takes "ok" or "not ok".
-count=1
-printcount () {
- echo "$1 $count $2"
- count=`expr $count + 1`
-}
-
-# Run a program expected to succeed, and print ok if it does.
-runsuccess () {
- output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
- status=$?
- if test $status = 0 && test -z "$output" ; then
- printcount "ok"
- else
- if test $status = 2 ; then
- printcount "ok" "# skip - no data limit support"
- else
- printcount "not ok"
- echo " $output"
- fi
- fi
-}
-
-# Run a program expected to fail and make sure it fails with an exit status
-# of 2 and the right failure message. Strip the colon and everything after
-# it off the error message since it's system-specific.
-runfailure () {
- output=`$xmalloc "$1" "$2" "$3" 2>&1 >/dev/null`
- status=$?
- output=`echo "$output" | sed 's/:.*//'`
- if test $status = 1 && test x"$output" = x"$4" ; then
- printcount "ok"
- else
- if test $status = 2 ; then
- printcount "ok" "# skip - no data limit support"
- else
- printcount "not ok"
- echo " saw: $output"
- echo " not: $4"
- fi
- fi
-}
-
-# Find where the helper program is.
-xmalloc=xmalloc
-for file in ./xmalloc lib/xmalloc ../xmalloc ; do
- [ -x $file ] && xmalloc=$file
-done
-
-# Total tests.
-echo 26
-
-# First run the tests expected to succeed.
-runsuccess "m" "21" "0"
-runsuccess "m" "128000" "0"
-runsuccess "m" "0" "0"
-runsuccess "r" "21" "0"
-runsuccess "r" "128000" "0"
-runsuccess "s" "21" "0"
-runsuccess "s" "128000" "0"
-runsuccess "n" "21" "0"
-runsuccess "n" "128000" "0"
-runsuccess "c" "24" "0"
-runsuccess "c" "128000" "0"
-
-# Now limit our memory to 96KB and then try the large ones again, all of
-# which should fail.
-runfailure "m" "128000" "96000" \
- "failed to malloc 128000 bytes at lib/xmalloc.c line 36"
-runfailure "r" "128000" "96000" \
- "failed to realloc 128000 bytes at lib/xmalloc.c line 62"
-runfailure "s" "64000" "96000" \
- "failed to strdup 64000 bytes at lib/xmalloc.c line 91"
-runfailure "n" "64000" "96000" \
- "failed to strndup 64000 bytes at lib/xmalloc.c line 115"
-runfailure "c" "128000" "96000" \
- "failed to calloc 128000 bytes at lib/xmalloc.c line 137"
-
-# Check our custom error handler.
-runfailure "M" "128000" "96000" "malloc 128000 lib/xmalloc.c 36"
-runfailure "R" "128000" "96000" "realloc 128000 lib/xmalloc.c 62"
-runfailure "S" "64000" "96000" "strdup 64000 lib/xmalloc.c 91"
-runfailure "N" "64000" "96000" "strndup 64000 lib/xmalloc.c 115"
-runfailure "C" "128000" "96000" "calloc 128000 lib/xmalloc.c 137"
-
-# Check the smaller ones again just for grins.
-runsuccess "m" "21" "96000"
-runsuccess "r" "32" "96000"
-runsuccess "s" "64" "96000"
-runsuccess "n" "20" "96000"
-runsuccess "c" "24" "96000"
+++ /dev/null
-/* $Id: xwrite-t.c 5790 2002-09-30 01:05:09Z rra $ */
-/* Test suite for xwrite and xwritev. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <sys/uio.h>
-
-#include "libinn.h"
-
-/* The data array we'll use to do testing. */
-char data[256];
-
-/* These come from fakewrite. */
-extern char write_buffer[];
-extern size_t write_offset;
-extern int write_interrupt;
-extern int write_fail;
-
-static void
-test_write(int n, int status, int total)
-{
- int success;
-
- success = (status == total && memcmp(data, write_buffer, 256) == 0);
- printf("%sok %d\n", success ? "" : "not ", n);
- if (!success && status != total)
- printf(" status %d, total %d\n", status, total);
-}
-
-int
-main(void)
-{
- int i;
- struct iovec iov[4];
-
- puts("19");
-
- /* Test xwrite. */
- for (i = 0; i < 256; i++)
- data[i] = i;
- test_write(1, xwrite(0, data, 256), 256);
- write_offset = 0;
- write_interrupt = 1;
- memset(data, 0, 256);
- test_write(2, xwrite(0, data, 256), 256);
- write_offset = 0;
- for (i = 0; i < 32; i++)
- data[i] = i * 2;
- test_write(3, xwrite(0, data, 32), 32);
- for (i = 32; i < 65; i++)
- data[i] = i * 2;
- test_write(4, xwrite(0, data + 32, 33), 33);
- write_offset = 0;
- write_interrupt = 0;
-
- /* Test xwritev. */
- memset(data, 0, 256);
- iov[0].iov_base = data;
- iov[0].iov_len = 256;
- test_write(5, xwritev(0, iov, 1), 256);
- write_offset = 0;
- for (i = 0; i < 256; i++)
- data[i] = i;
- iov[0].iov_len = 128;
- iov[1].iov_base = &data[128];
- iov[1].iov_len = 16;
- iov[2].iov_base = &data[144];
- iov[2].iov_len = 112;
- test_write(6, xwritev(0, iov, 3), 256);
- write_offset = 0;
- write_interrupt = 1;
- memset(data, 0, 256);
- iov[0].iov_len = 32;
- iov[1].iov_base = &data[32];
- iov[1].iov_len = 224;
- test_write(7, xwritev(0, iov, 2), 256);
- for (i = 0; i < 32; i++)
- data[i] = i * 2;
- write_offset = 0;
- test_write(8, xwritev(0, iov, 1), 32);
- for (i = 32; i < 65; i++)
- data[i] = i * 2;
- iov[0].iov_base = &data[32];
- iov[0].iov_len = 16;
- iov[1].iov_base = &data[48];
- iov[1].iov_len = 1;
- iov[2].iov_base = &data[49];
- iov[2].iov_len = 8;
- iov[3].iov_base = &data[57];
- iov[3].iov_len = 8;
- test_write(9, xwritev(0, iov, 4), 33);
- write_offset = 0;
- write_interrupt = 0;
-
- /* Test xpwrite. */
- for (i = 0; i < 256; i++)
- data[i] = i;
- test_write(10, xpwrite(0, data, 256, 0), 256);
- write_interrupt = 1;
- memset(data + 1, 0, 255);
- test_write(11, xpwrite(0, data + 1, 255, 1), 255);
- for (i = 0; i < 32; i++)
- data[i + 32] = i * 2;
- test_write(12, xpwrite(0, data + 32, 32, 32), 32);
- for (i = 32; i < 65; i++)
- data[i + 32] = i * 2;
- test_write(13, xpwrite(0, data + 64, 33, 64), 33);
- write_interrupt = 0;
-
- /* Test failures. */
- write_fail = 1;
- test_write(14, xwrite(0, data + 1, 255), -1);
- iov[0].iov_base = data + 1;
- iov[0].iov_len = 255;
- test_write(15, xwritev(0, iov, 1), -1);
- test_write(16, xpwrite(0, data + 1, 255, 0), -1);
-
- /* Test zero-length writes. */
- test_write(17, xwrite(0, " ", 0), 0);
- test_write(18, xpwrite(0, " ", 0, 2), 0);
- iov[0].iov_base = data + 1;
- iov[0].iov_len = 2;
- test_write(19, xwritev(0, iov, 0), 0);
-
- return 0;
-}
+++ /dev/null
-/* $Id: libtest.c 5955 2002-12-08 09:28:32Z rra $
-**
-** Some utility routines for writing tests.
-**
-** Herein are a variety of utility routines for writing tests. All
-** routines of the form ok*() take a test number and some number of
-** appropriate arguments, check to be sure the results match the expected
-** output using the arguments, and print out something appropriate for that
-** test number. Other utility routines help in constructing more complex
-** tests.
-*/
-
-#include "config.h"
-#include "clibrary.h"
-
-#include "inn/messages.h"
-#include "libinn.h"
-#include "libtest.h"
-
-/* A global buffer into which message_log_buffer stores error messages. */
-char *errors = NULL;
-
-
-/*
-** Takes a boolean success value and assumes the test passes if that value
-** is true and fails if that value is false.
-*/
-void
-ok(int n, int success)
-{
- printf("%sok %d\n", success ? "" : "not ", n);
-}
-
-
-/*
-** Takes an expected integer and a seen integer and assumes the test passes
-** if those two numbers match.
-*/
-void
-ok_int(int n, int wanted, int seen)
-{
- if (wanted == seen)
- printf("ok %d\n", n);
- else
- printf("not ok %d\n wanted: %d\n seen: %d\n", n, wanted, seen);
-}
-
-
-/*
-** Takes a string and what the string should be, and assumes the test
-** passes if those strings match (using strcmp).
-*/
-void
-ok_string(int n, const char *wanted, const char *seen)
-{
- if (wanted == NULL)
- wanted = "(null)";
- if (seen == NULL)
- seen = "(null)";
- if (strcmp(wanted, seen) != 0)
- printf("not ok %d\n wanted: %s\n seen: %s\n", n, wanted, seen);
- else
- printf("ok %d\n", n);
-}
-
-
-/*
-** An error handler that appends all errors to the errors global. Used by
-** error_capture.
-*/
-static void
-message_log_buffer(int len, const char *fmt, va_list args, int error UNUSED)
-{
- char *message;
-
- message = xmalloc(len + 1);
- vsnprintf(message, len + 1, fmt, args);
- if (errors == NULL) {
- errors = concat(message, "\n", (char *) 0);
- } else {
- char *new_errors;
-
- new_errors = concat(errors, message, "\n", (char *) 0);
- free(errors);
- errors = new_errors;
- }
- free(message);
-}
-
-
-/*
-** Turn on the capturing of errors. Errors will be stored in the global
-** errors variable where they can be checked by the test suite. Capturing is
-** turned off with errors_uncapture.
-*/
-void
-errors_capture(void)
-{
- if (errors != NULL) {
- free(errors);
- errors = NULL;
- }
- message_handlers_warn(1, message_log_buffer);
-}
-
-
-/*
-** Turn off the capturing of errors again.
-*/
-void
-errors_uncapture(void)
-{
- message_handlers_warn(1, message_log_stderr);
-}
+++ /dev/null
-/* $Id: libtest.h 5955 2002-12-08 09:28:32Z rra $
-**
-** Some utility routines for writing tests.
-*/
-
-#ifndef TESTLIB_H
-#define TESTLIB_H 1
-
-#include "config.h"
-#include <inn/defines.h>
-
-/* A global buffer into which errors_capture stores errors. */
-extern char *errors;
-
-BEGIN_DECLS
-
-void ok(int n, int success);
-void ok_int(int n, int wanted, int seen);
-void ok_string(int n, const char *wanted, const char *seen);
-
-/* Turn on capturing of errors with errors_capture. Errors reported by warn
- will be stored in the global errors variable. Turn this off again with
- errors_uncapture. Caller is responsible for freeing errors when done. */
-void errors_capture(void);
-void errors_uncapture(void);
-
-END_DECLS
-
-#endif /* TESTLIB_H */
+++ /dev/null
-news.groups:1 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 15:30:16 -0800 <ylvgdgye47.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> 3124 58 Xref: inn.example.com news.groups:1
-news.groups:2 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 15:32:03 -0800 <ylofj8ye18.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3eep7$q6r$1@samba.rahul.net> <a3epeq$rt$1@gw.retro.com> <a3f201$n8$1@samba.rahul.net> <a3f7v9$3kg$1@gw.retro.com> 448 11 Xref: inn.example.com news.groups:2
-news.groups:7 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 16:34:02 -0800 <ylhep0vi11.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> 2834 55 Xref: inn.example.com news.groups:7
-news.groups:8 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 17:10:47 -0800 <yladusu1rc.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <3ndm5u8fgomord7vmh164ce7pcteh496sp@4ax.com> 2363 47 Xref: inn.example.com news.groups:8
-news.groups:12 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 17:20:57 -0800 <yl4rl0u1ae.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> 1651 36 Xref: inn.example.com news.groups:12
-news.groups:13 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 18:10:18 -0800 <ylu1t03a7p.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <v1hm5u4mrhllm98ng1jhp5gco7sflbm4jq@4ax.com> 902 27 Xref: inn.example.com news.groups:13
-news.groups:14 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:08:02 -0800 <ylg04k37jh.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3fgk302sdn@enews1.newsguy.com> 808 18 Xref: inn.example.com news.groups:14
-news.groups:15 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:12:32 -0800 <yladus37bz.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <i8jm5u4l8bt7lk93mramtmbouhtg58tpnb@4ax.com> 643 14 Xref: inn.example.com news.groups:15
-news.groups:16 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:35:38 -0800 <yl4rl0369h.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <Xns91A8BC08432FEpeskyirritantcom@209.155.56.83> 326 12 Xref: inn.example.com news.groups:16
-news.groups:17 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 10:20:43 -0800 <ylg04j7nk4.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3g0i9$6ch$1@samba.rahul.net> 680 16 Xref: inn.example.com news.groups:17
-news.groups:18 Re: The beer truck (was Re: Pre-RFD - Exec Board Newsgroup Creation) Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 10:23:15 -0800 <yladur7nfw.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3h7be$dec$1@panix2.panix.com> 375 11 Xref: inn.example.com news.groups:18
-news.groups:19 Re: The beer truck (was Re: Pre-RFD - Exec Board Newsgroup Creation) Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <yl8zab38v3.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylhep0vi11.fsf@windlord.stanford.edu> <a3h7be$dec$1@panix2.panix.com> <yladur7nfw.fsf@windlord.stanford.edu> <a3hd8t$sin$1@panix2.panix.com> 481 16 Xref: inn.example.com news.groups:19
-news.groups:21 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 17:38:39 -0800 <ylwuxvwdi8.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <20020202150653$4dbb@babylon.ks.uiuc.edu> <fo1o5uoo90uh1qreh20u6n1ci70jt28mmg@4ax.com> <1f6z4v6.1fbjkdq18w29f4N%kmorgan@aptalaska.net> <lqto5u0p5sblo0ui9hal0nil52e3nlbssm@4ax.com> 316 9 Xref: inn.example.com news.groups:21
-news.groups:22 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 17:42:27 -0800 <ylr8o3wdbw.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <08_68.11847$gW4.9091001@news1.rdc1.mi.home.com> 1405 29 Xref: inn.example.com news.groups:22
-news.groups:23 Re: [History] Re: A Chronology of Usenet Newsgroups: Start Post Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 09:34:04 -0800 <yl665e4ghf.fsf@windlord.stanford.edu> <3c4a31e3$0$95685$892e7fe2@authen.puce.readfreenews.net> <a301ve02s1r@enews2.newsguy.com> <dbc8daca.0201280231.791aeb03@posting.google.com> <8I07QDHHw-B@khms.westfalen.de> <3c5d3981$0$36784$892e7fe2@authen.puce.readfreenews.net> 617 15 Xref: inn.example.com news.groups:23
-news.groups:24 Re: Guidelines for Big Eight Newsgroup Creation Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 09:38:27 -0800 <ylzo2q31po.fsf@windlord.stanford.edu> <big-eight-faq-1012550404$22697@windlord.stanford.edu> <vvjq5u8l1dnrdankh4q7l2d043ud8kt11o@4ax.com> 971 22 Xref: inn.example.com news.groups:24
-news.admin.net-abuse.policy:1 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 10:22:36 -0800 <ylelk21l3n.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> 1448 31 Xref: inn.example.com news.admin.net-abuse.policy:1
-news.groups:25 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 13:21:34 -0800 <ylwuxuz2g1.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <20020202150653$4dbb@babylon.ks.uiuc.edu> <FRRtIeAzyYX8Ewxl@merlyn.demon.co.uk> 668 15 Xref: inn.example.com news.groups:25
-news.admin.net-abuse.policy:4 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 13:23:54 -0800 <ylr8o2z2c5.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> 533 12 Xref: inn.example.com news.admin.net-abuse.policy:4
-gnu.misc.discuss:1 Re: want to learn perl from free sources Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 09:51:12 -0800 <yln0yp87an.fsf@windlord.stanford.edu> <m2r8o1iu11.fsf@dan.jacobson.tw> 641 15 Xref: inn.example.com gnu.misc.discuss:1
-comp.lang.perl.misc:1 Re: want to learn perl from free sources Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 09:51:12 -0800 <yln0yp87an.fsf@windlord.stanford.edu> <m2r8o1iu11.fsf@dan.jacobson.tw> 641 15 Xref: inn.example.com comp.lang.perl.misc:1
-csd.bboard:1 comp.doc.techreports submissions from Stanford Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 10:28:11 -0800 <yl4rkx3xvo.fsf@windlord.stanford.edu> 672 18 Xref: inn.example.com csd.bboard:1
-news.admin.net-abuse.policy:5 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 12:09:24 -0800 <ylr8o1xb4b.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> 1751 38 Xref: inn.example.com news.admin.net-abuse.policy:5
-csd.bboard:2 Re: comp.doc.techreports submissions from Stanford Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 12:31:16 -0800 <yl3d0hxa3v.fsf@windlord.stanford.edu> <yl4rkx3xvo.fsf@windlord.stanford.edu> 794 16 Xref: inn.example.com csd.bboard:2
-gnu.utils.bug:1 Re: let's beef up the tsort info page Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 14:03:41 -0800 <yl4rkwx5tu.fsf@windlord.stanford.edu> <m2wuxtj3gh.fsf@dan.jacobson.tw> 2409 73 Xref: inn.example.com gnu.utils.bug:1
-news.groups:26 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 15:31:18 -0800 <yl4rkwu8mx.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> 578 15 Xref: inn.example.com news.groups:26
-news.groups:27 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 16:37:55 -0800 <ylofj4rcf0.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> <yl4rkwu8mx.fsf@windlord.stanford.edu> <a3n74c026se@enews4.newsguy.com> 899 22 Xref: inn.example.com news.groups:27
-news.admin.net-abuse.policy:6 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 17:56:53 -0800 <ylk7tsofmi.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> <ylr8o1xb4b.fsf@windlord.stanford.edu> <Gr1CnE.Iny@world.std.com> 961 18 Xref: inn.example.com news.admin.net-abuse.policy:6
-news.groups:32 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 19:02:56 -0800 <yln0yobpgf.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> <yl4rkwu8mx.fsf@windlord.stanford.edu> <a3n74c026se@enews4.newsguy.com> <ylofj4rcf0.fsf@windlord.stanford.edu> <a3nbva02f0r@enews4.newsguy.com> 1280 26 Xref: inn.example.com news.groups:32
-news.groups:33 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 19:04:16 -0800 <ylheowbpe7.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> 851 17 Xref: inn.example.com news.groups:33
-news.admin.net-abuse.policy:7 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 08:52:18 -0800 <yl4rkvx459.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> <ylr8o1xb4b.fsf@windlord.stanford.edu> <Gr1CnE.Iny@world.std.com> <ylk7tsofmi.fsf@windlord.stanford.edu> <Gr1LLx.6xF@world.std.com> 3618 69 Xref: inn.example.com news.admin.net-abuse.policy:7
-news.software.nntp:1 Re: peering under the storage API Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:04:13 -0800 <ylit9bl8tu.fsf@windlord.stanford.edu> <slrna60q6l.3fo.br@panix2.panix.com> 546 14 Xref: inn.example.com news.software.nntp:1
-news.groups:34 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:46:28 -0800 <ylofj3jsaz.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> <m2k7trcxes.fsf@dan.jacobson.tw> <3C6077F5.AE1C5ED8@sfo.com> 882 22 Xref: inn.example.com news.groups:34
-news.groups:36 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:51:33 -0800 <ylit9bjs2i.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <Xns91AD188E6226grahamdrabblelineone@ID-77355.user.dfncis.de> 1067 21 Xref: inn.example.com news.groups:36
-news.admin.technical:1 Re: nnrpd Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:53:18 -0800 <yld6zjjrzl.fsf@windlord.stanford.edu> <a3psen$7p4$1@quasar.ctc.edu> 543 13 Xref: inn.example.com news.admin.technical:1
-news.admin.hierarchies:1 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:54:47 -0800 <yl7kprjrx4.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> 877 21 Xref: inn.example.com news.admin.hierarchies:1
-news.groups:37 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 18:07:55 -0800 <ylvgdbicqs.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> <3C608D3D.C87E3610@diogenes.sacramento.ca.us> 623 13 Xref: inn.example.com news.groups:37
-news.software.nntp:2 Re: INN on another user/group Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 19:14:03 -0800 <ylg04fs3no.fsf@windlord.stanford.edu> <3c609757$0$20968$afc38c87@news.optusnet.com.au> 593 15 Xref: inn.example.com news.software.nntp:2
-news.admin.hierarchies:2 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 21:56:17 -0800 <yl665bqhku.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> 828 19 Xref: inn.example.com news.admin.hierarchies:2
-news.admin.net-abuse.policy:8 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 08:42:16 -0800 <ylr8ny7eaf.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> 740 18 Xref: inn.example.com news.admin.net-abuse.policy:8
-news.software.nntp:3 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 08:45:04 -0800 <yllme67e5r.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> 852 21 Xref: inn.example.com news.software.nntp:3
-news.software.nntp:4 Re: first > last Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:50:15 -0800 <yly9i6uvoo.fsf@windlord.stanford.edu> <3C61951F.8080606@gemal.dk> 850 19 Xref: inn.example.com news.software.nntp:4
-news.admin.net-abuse.policy:9 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:57:38 -0800 <ylk7tqtgrx.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> <ylr8ny7eaf.fsf@windlord.stanford.edu> <878za6o8h5.fsf@erlenstar.demon.co.uk> 578 16 Xref: inn.example.com news.admin.net-abuse.policy:9
-news.admin.net-abuse.policy:10 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:58:09 -0800 <yleljytgr2.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> <ylr8ny7eaf.fsf@windlord.stanford.edu> <1013015167.535798@ok-corral.gunslinger.net> 548 13 Xref: inn.example.com news.admin.net-abuse.policy:10
-news.admin.hierarchies:3 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 14:00:23 -0800 <yl8za6tgnc.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> <yl665bqhku.fsf@windlord.stanford.edu> <m3lme68jz6.fsf@defun.localdomain> 478 17 Xref: inn.example.com news.admin.hierarchies:3
-news.admin.hierarchies:4 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 14:09:30 -0800 <yllme6s1np.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3ptk7.3vuai51.1@mid.glglgl.de> <a3qmdq$1akiad$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> 972 20 Xref: inn.example.com news.admin.hierarchies:4
-news.admin.hierarchies:7 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 16:19:10 -0800 <ylk7tqp2ip.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3ptk7.3vuai51.1@mid.glglgl.de> <a3qmdq$1akiad$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> <yllme6s1np.fsf@windlord.stanford.edu> <a3sbmu$1ao4a2$1@ID-80930.news.dfncis.de> 421 11 Xref: inn.example.com news.admin.hierarchies:7
-news.admin.hierarchies:11 Re: control.ctl maintenance (was: [INFO] bc.* and van.*) Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 16:20:13 -0800 <yleljyp2gy.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> <yllme6s1np.fsf@windlord.stanford.edu> <EKi88.17124$gW4.11422684@news1.rdc1.mi.home.com> 688 18 Xref: inn.example.com news.admin.hierarchies:11
-news.groups:38 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 22:21:34 -0800 <yl8za5n769.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <1j6l5u499l6ru00rn6ibje0cgsv32jkrk1@4ax.com> <a3f1oq02gd2@enews3.newsguy.com> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> 1093 26 Xref: inn.example.com news.groups:38
-news.groups:39 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Thu, 07 Feb 2002 00:46:46 -0800 <yl3d0dn0g9.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> <yl8za5n769.fsf@windlord.stanford.edu> <a3tb6q$i69$1@gw.retro.com> 5108 96 Xref: inn.example.com news.groups:39
-news.software.nntp:5 Re: innd and Microsoft Exchange Russ Allbery <rra@stanford.edu> Thu, 07 Feb 2002 10:01:40 -0800 <yleljx41dn.fsf@windlord.stanford.edu> <623f5703.0202070541.2b943211@posting.google.com> 1013 21 Xref: inn.example.com news.software.nntp:5
-news.software.nntp:6 Re: innd and Microsoft Exchange Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 11:04:25 -0800 <ylofiz23t2.fsf@windlord.stanford.edu> <623f5703.0202070541.2b943211@posting.google.com> <yleljx41dn.fsf@windlord.stanford.edu> <3C63AD90.492F3C00@eproduction.ch> 541 14 Xref: inn.example.com news.software.nntp:6
-news.software.nntp:9 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 11:05:28 -0800 <ylit9723rb.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> 556 16 Xref: inn.example.com news.software.nntp:9
-news.software.nntp:10 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 12:15:43 -0800 <ylsn8bwx00.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <ylit9723rb.fsf@windlord.stanford.edu> <C2W88.119862$i3.977629@news.easynews.com> 749 19 Xref: inn.example.com news.software.nntp:10
-news.groups:40 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 18:11:54 -0800 <ylsn8b76ad.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3tb6q$i69$1@gw.retro.com> <a3uq5f$n81$1@news.orst.edu> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> 1995 40 Xref: inn.example.com news.groups:40
-news.admin.hierarchies:12 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 20:42:25 -0800 <ylu1srclla.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> 505 14 Xref: inn.example.com news.admin.hierarchies:12
-news.groups:41 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 23:24:31 -0800 <yllme3azio.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> 1282 26 Xref: inn.example.com news.groups:41
-news.admin.hierarchies:13 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:00:56 -0800 <yl8za2a0hz.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> 905 23 Xref: inn.example.com news.admin.hierarchies:13
-news.groups:42 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:20:01 -0800 <yl1yfu9zm6.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3uq5f$n81$1@news.orst.edu> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <3c651972$0$67480$892e7fe2@authen.puce.readfreenews.net> 990 19 Xref: inn.example.com news.groups:42
-news.admin.hierarchies:18 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:25:07 -0800 <ylvgd68kt8.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> <ylu1srclla.fsf@windlord.stanford.edu> <m37kpmdayt.fsf@defun.localdomain> 580 18 Xref: inn.example.com news.admin.hierarchies:18
-comp.lang.perl.moderated:1 Re: perldoc vs man why so much slower Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:47:26 -0800 <yl8za28js1.fsf@windlord.stanford.edu> <m1d6zfnl9h.fsf@reader.newsguy.com> <20020209180911.23756.qmail@plover.com> 799 20 Xref: inn.example.com comp.lang.perl.moderated:1
-news.software.nntp:11 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 13:18:51 -0800 <yl3d0a8ibo.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <ylit9723rb.fsf@windlord.stanford.edu> <2504c.922202@archiver.winews.net> 1075 27 Xref: inn.example.com news.software.nntp:11
-news.groups:43 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 23:47:28 -0800 <yln0yh22y7.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> 2306 45 Xref: inn.example.com news.groups:43
-news.groups:44 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 23:49:43 -0800 <ylheop22ug.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <a44mu80urn@enews2.newsguy.com> 810 16 Xref: inn.example.com news.groups:44
-news.software.nntp:12 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 09:32:55 -0800 <yl8za1kzso.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <yl3d0a8ibo.fsf@windlord.stanford.edu> <21049.a22200@archiver.winews.net> 1915 40 Xref: inn.example.com news.software.nntp:12
-news.groups:46 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 10:47:13 -0800 <ylpu3dgoni.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yllme3azio.fsf@windlord.stanford.edu> <a44mu80urn@enews2.newsguy.com> <ylheop22ug.fsf@windlord.stanford.edu> <a46ec6$lee$1@samba.rahul.net> 1052 28 Xref: inn.example.com news.groups:46
-news.groups:47 Re: 2nd RFD: sci.space.moderated moderated Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 10:54:24 -0800 <ylk7tlgobj.fsf@windlord.stanford.edu> <1010713186.32070@isc.org> <3N898.13340$Zu6.55955@news-server.bigpond.net.au> <u6argep8r8l2c2@corp.supernews.com> <Xns91B0C720E8590grahamdrabblelineone@ID-77355.user.dfncis.de> <a440uv$r73$2@dent.deepthot.org> <u6b36tthfaecfb@corp.supernews.com> 1235 23 Xref: inn.example.com news.groups:47
-news.groups:48 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 11:48:18 -0800 <yly9i1f799.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylheop22ug.fsf@windlord.stanford.edu> <a46ec6$lee$1@samba.rahul.net> <ylpu3dgoni.fsf@windlord.stanford.edu> <a46i88$m4m$1@samba.rahul.net> 1563 32 Xref: inn.example.com news.groups:48
-news.groups:49 Re: 2nd RFD: sci.space.moderated moderated Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 12:12:17 -0800 <ylsn89f65a.fsf@windlord.stanford.edu> <1010713186.32070@isc.org> <a440uv$r73$2@dent.deepthot.org> <u6b36tthfaecfb@corp.supernews.com> <a448lr$il$1@dent.deepthot.org> <3c65d1dc$0$67479$892e7fe2@authen.puce.readfreenews.net> 3599 70 Xref: inn.example.com news.groups:49
-news.groups:50 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 14:31:08 -0800 <yly9i1as0j.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> 1723 38 Xref: inn.example.com news.groups:50
-gnu.emacs.gnus:1 Re: Gnus, Postings, and Anti-spam? Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 14:37:51 -0800 <ylheoparpc.fsf@windlord.stanford.edu> <ubsezbqfg.fsf@synopsys.com> <geg.y1ysn8apwb0.fsf@fly.verified.de> <eljuvgy6.fsf@ichimusai.org> <geg.y1y3d0apg8z.fsf@fly.verified.de> <vgd52d4a.fsf@ichimusai.org> 862 23 Xref: inn.example.com gnu.emacs.gnus:1
-news.groups:53 Re: Professional practice (was Re: RESULT: sci.military.nuclear-bio-chem fails 73:25) Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 18:37:01 -0800 <yl8za0agmq.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> <yly9i1as0j.fsf@windlord.stanford.edu> <a474cg$qou$1@panix2.panix.com> 1274 30 Xref: inn.example.com news.groups:53
-news.groups:56 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 20:01:15 -0800 <yleljs8y5w.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> <yly9i1as0j.fsf@windlord.stanford.edu> <a47aeg01e39@enews3.newsguy.com> 1482 35 Xref: inn.example.com news.groups:56
-news.admin.technical:2 Re: Maximum Length of Newsgroup Description field Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 13:05:47 -0800 <ylit9391as.fsf@windlord.stanford.edu> <Xns91B278CC1107Djaydejaydenet@157.54.3.22> 526 12 Xref: inn.example.com news.admin.technical:2
-gnu.emacs.gnus:2 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 15:55:01 -0800 <ylheon7ewa.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <m0it9339nj.fsf@k2.onsight.com> 175 8 Xref: inn.example.com gnu.emacs.gnus:2
-gnu.emacs.gnus:6 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 15:56:50 -0800 <ylbsev7et9.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> 1021 23 Xref: inn.example.com gnu.emacs.gnus:6
-news.software.nntp:13 Re: rebuilding overview with makehistory Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 18:14:40 -0800 <ylofiv5tv3.fsf@windlord.stanford.edu> <slrna6gcn5.nmf.br@panix2.panix.com> 687 20 Xref: inn.example.com news.software.nntp:13
-news.software.nntp:14 Re: rebuilding overview with makehistory Russ Allbery <rra@stanford.edu> Tue, 12 Feb 2002 11:15:20 -0800 <yladuefr5j.fsf@windlord.stanford.edu> <slrna6gcn5.nmf.br@panix2.panix.com> <ylofiv5tv3.fsf@windlord.stanford.edu> <slrna6ig0n.qig.br@panix2.panix.com> 505 13 Xref: inn.example.com news.software.nntp:14
-gnu.emacs.gnus:7 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Tue, 12 Feb 2002 12:07:06 -0800 <ylwuxia2hh.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> <ylbsev7et9.fsf@windlord.stanford.edu> <ilu665235iy.fsf@extundo.com> 426 11 Xref: inn.example.com gnu.emacs.gnus:7
-gnu.emacs.gnus:8 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Wed, 13 Feb 2002 13:46:55 -0800 <yl3d05awc0.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> <ylbsev7et9.fsf@windlord.stanford.edu> <ilu665235iy.fsf@extundo.com> <ylwuxia2hh.fsf@windlord.stanford.edu> <1yfpzc36.fsf@hschmi22.userfqdn.rz-online.de> 326 11 Xref: inn.example.com gnu.emacs.gnus:8
-news.software.nntp:15 Re: chan.c problem with INN 2.3.[012] on AIX 4.2 Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 11:49:28 -0800 <yl7kpfq1x3.fsf@windlord.stanford.edu> <fa8727e8.0202141109.7875ddc@posting.google.com> 1449 42 Xref: inn.example.com news.software.nntp:15
-news.groups:57 Re: comp.distributed again? Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 13:43:52 -0800 <ylu1sjkacn.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a4co04$d94$1@slb2.atl.mindspring.net> <a4edc2$uds$5@dent.deepthot.org> <a4frn0$71f$1@slb3.atl.mindspring.net> <a4frot$inj$8@dent.deepthot.org> 360 10 Xref: inn.example.com news.groups:57
-news.groups:58 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 21:40:08 -0800 <ylvgczi9qf.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> <3c6038d6.774936@news.storm.ca> <a3pg75$3vk$1@gw.retro.com> <3c604f11.3004891@news.storm.ca> <3n516u0ahojobsdiknc99l00f0euoujb60@4ax.com> <3C60A31C.A5D832F7@elepar.com> <slrna6lpis.6k8.dbt@pianosa.catch22.org> <3C6B5EA3.4A10@mcimail.com> <slrna6p6q1.4c8.dbt@pianosa.catch22.org> 718 17 Xref: inn.example.com news.groups:58
-news.groups:59 Re: Professional practice (was Re: RESULT: sci.military.nuclear-bio-chem fails 73:25) Russ Allbery <rra@stanford.edu> Fri, 15 Feb 2002 19:59:06 -0800 <ylofiq6prp.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yly9i1as0j.fsf@windlord.stanford.edu> <a474cg$qou$1@panix2.panix.com> <yl8za0agmq.fsf@windlord.stanford.edu> <a4jcua$nqo$1@panix2.panix.com> 500 12 Xref: inn.example.com news.groups:59
-news.groups:260 Re: [History] The Guidelines: a preliminary revision history Russ Allbery <rra@stanford.edu> Sat, 16 Feb 2002 12:47:46 -0800 <yleljlnogd.fsf@windlord.stanford.edu> <dbc8daca.0202161159.4c0a1eee@posting.google.com> 7082 173 Xref: inn.example.com news.groups:60
-news.groups:464 Re: [History] The Guidelines: a preliminary revision history Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 00:05:02 -0800 <ylbseoh6tt.fsf@windlord.stanford.edu> <dbc8daca.0202161159.4c0a1eee@posting.google.com> <yleljlnogd.fsf@windlord.stanford.edu> <dbc8daca.0202162324.1ce3b411@posting.google.com> 845 22 Xref: inn.example.com news.groups:64
-news.admin.net-abuse.policy:11 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 13:58:51 -0800 <yllmdrdb38.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <87pu3mj826.fsf@erlenstar.demon.co.uk> <3mqs5us2puq2ov9gpqn7cqn8hhstojsesj@4ax.com> <b2059324.0202170829.47a7abce@posting.google.com> <3C7022DC.2F2E87DF@trin.ity> 546 11 Xref: inn.example.com news.admin.net-abuse.policy:11
-news.software.nntp:16 Re: [yEnc] some newbie questions Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 15:43:07 -0800 <ylpu33brp0.fsf@windlord.stanford.edu> <3c6e6798.9093644@news> <a4kc41$ou1$2@pegasus.csx.cam.ac.uk> <3c702e8c.7007252@news> 1000 24 Xref: inn.example.com news.software.nntp:16
-news.software.nntp:17 Re: RFC 977 extensions? Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 13:46:21 -0800 <ylvgcu31le.fsf@windlord.stanford.edu> <Xns91B9E610EE161M8@62.2.16.82> 786 21 Xref: inn.example.com news.software.nntp:17
-gnu.misc.discuss:2 Re: Money matters Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 18:27:36 -0800 <yl3czyyzmv.fsf@windlord.stanford.edu> <1629dcd9.0202160842.36e8bdab@posting.google.com> <C4cc8.17$X5.109616@burlma1-snr2> <87heoek2h5.fsf@toncho.dhh.gt.org> <Rvhc8.29$X5.122317@burlma1-snr2> 1014 21 Xref: inn.example.com gnu.misc.discuss:2
-gnu.misc.discuss:3 Re: Money matters Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 20:12:07 -0800 <ylr8nixg88.fsf@windlord.stanford.edu> <1629dcd9.0202160842.36e8bdab@posting.google.com> <C4cc8.17$X5.109616@burlma1-snr2> <87heoek2h5.fsf@toncho.dhh.gt.org> <Rvhc8.29$X5.122317@burlma1-snr2> <yl3czyyzmv.fsf@windlord.stanford.edu> <slrna73glj.9cp.jmaynard@thebrain.conmicro.cx> 1896 35 Xref: inn.example.com gnu.misc.discuss:3
-news.software.nntp:18 Re: [yEnc] some newbie questions Russ Allbery <rra@stanford.edu> Tue, 19 Feb 2002 10:34:36 -0800 <yleljh722r.fsf@windlord.stanford.edu> <3c6e6798.9093644@news> <a4kc41$ou1$2@pegasus.csx.cam.ac.uk> <3c702e8c.7007252@news> <a4pknt$4pg$2@pegasus.csx.cam.ac.uk> <53488.j22209@archiver.winews.net> 872 21 Xref: inn.example.com news.software.nntp:18
-news.software.nntp:19 Re: Usefor: Message/external-body - any experiences ? Russ Allbery <rra@stanford.edu> Tue, 19 Feb 2002 10:36:56 -0800 <yl8z9p71yv.fsf@windlord.stanford.edu> <5955a.j22200@archiver.winews.net> 921 22 Xref: inn.example.com news.software.nntp:19
-news.software.nntp:20 Re: "Recomended Format of Usenet Articles with 8-bit Attachements" (yEnc) Russ Allbery <rra@stanford.edu> Wed, 20 Feb 2002 13:49:54 -0800 <ylwux7su0t.fsf@windlord.stanford.edu> <3c7615d0.11232095@news> 1280 30 Xref: inn.example.com news.software.nntp:20
-news.software.nntp:21 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 16:40:59 -0800 <yleljecpr8.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> 1560 35 Xref: inn.example.com news.software.nntp:21
-news.software.nntp:22 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 21:35:01 -0800 <ylr8ne6pve.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> 1560 38 Xref: inn.example.com news.software.nntp:22
-news.software.nntp:23 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 23:57:04 -0800 <ylvgcq3q5r.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> <ylr8ne6pve.fsf@windlord.stanford.edu> <20020222021334.828$pl@newsreader.com> 2024 48 Xref: inn.example.com news.software.nntp:23
-news.software.nntp:24 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Fri, 22 Feb 2002 10:24:51 -0800 <ylu1s9nzm4.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> <ylr8ne6pve.fsf@windlord.stanford.edu> <20020222021334.828$pl@newsreader.com> <ylvgcq3q5r.fsf@windlord.stanford.edu> <20020222120943.799$AG@newsreader.com> 1353 29 Xref: inn.example.com news.software.nntp:24
-news.admin.hierarchies:19 Re: Draft hierarchies intro for news.announce.newusers Russ Allbery <rra@stanford.edu> Fri, 22 Feb 2002 12:35:43 -0800 <ylbsehjluo.fsf@windlord.stanford.edu> <Grp0uH.Gop@presby.edu> <3ik45a.06k.ln@erik.selwerd.nl> <wVpd8.37121$gW4.19914136@news1.rdc1.mi.home.com> <duac7uk00n416m5vn6lo21qupuo9il6mtk@4ax.com> 888 23 Xref: inn.example.com news.admin.hierarchies:19
+++ /dev/null
-..foo..:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-1@example.com> 481 16 Xref: inn.example.com ..foo..:7498
-../..:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-2@example.com> 481 16 Xref: inn.example.com ../..:7498
-/:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-3@example.com> 481 16 Xref: inn.example.com /:7498
-bar..:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-4@example.com> 481 16 Xref: inn.example.com bar..:7498
-bar../:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-5@example.com> 481 16 Xref: inn.example.com bar../:7498
-/../foo:1 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-6@example.com> 481 16 Xref: inn.example.com /../foo:1
-.:1 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-7@example.com> 481 16 Xref: inn.example.com .:1
-////:7498 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-8@example.com> 481 16 Xref: inn.example.com ////:7498
-foo..bar:1 Bogus newsgroup name Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-9@example.com> 481 16 Xref: inn.example.com foo..bar:1
+++ /dev/null
-example.test:7498 High-numbered test article Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-1@example.com> 481 16 Xref: inn.example.com example.test:7498
-example.test:7499 High-numbered test article Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <test-2@example.com> <test-1@example.com> 481 16 Xref: inn.example.com example.test:7499
+++ /dev/null
-news.admin.hierarchies:19 Re: Draft hierarchies intro for news.announce.newusers Russ Allbery <rra@stanford.edu> Fri, 22 Feb 2002 12:35:43 -0800 <ylbsehjluo.fsf@windlord.stanford.edu> <Grp0uH.Gop@presby.edu> <3ik45a.06k.ln@erik.selwerd.nl> <wVpd8.37121$gW4.19914136@news1.rdc1.mi.home.com> <duac7uk00n416m5vn6lo21qupuo9il6mtk@4ax.com> 888 23 Xref: inn.example.com news.admin.hierarchies:19
-news.software.nntp:24 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Fri, 22 Feb 2002 10:24:51 -0800 <ylu1s9nzm4.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> <ylr8ne6pve.fsf@windlord.stanford.edu> <20020222021334.828$pl@newsreader.com> <ylvgcq3q5r.fsf@windlord.stanford.edu> <20020222120943.799$AG@newsreader.com> 1353 29 Xref: inn.example.com news.software.nntp:24
-news.software.nntp:23 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 23:57:04 -0800 <ylvgcq3q5r.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> <ylr8ne6pve.fsf@windlord.stanford.edu> <20020222021334.828$pl@newsreader.com> 2024 48 Xref: inn.example.com news.software.nntp:23
-news.software.nntp:22 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 21:35:01 -0800 <ylr8ne6pve.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> <yleljecpr8.fsf@windlord.stanford.edu> <20020221224023.453$bg@newsreader.com> 1560 38 Xref: inn.example.com news.software.nntp:22
-news.software.nntp:21 Re: [yEnc] Survey time! (Compression or not?) Russ Allbery <rra@stanford.edu> Thu, 21 Feb 2002 16:40:59 -0800 <yleljecpr8.fsf@windlord.stanford.edu> <a504os$736$6@pegasus.csx.cam.ac.uk> <200220022141483852%planb@newsreaders.com> <20020220230116.405$a3@newsreader.com> <1014270020.729921@ok-corral.gunslinger.net> <20020221152617.647$FV@newsreader.com> <a53ut8$7i4$4@pegasus.csx.cam.ac.uk> <20020221183904.819$lz@newsreader.com> 1560 35 Xref: inn.example.com news.software.nntp:21
-news.software.nntp:20 Re: "Recomended Format of Usenet Articles with 8-bit Attachements" (yEnc) Russ Allbery <rra@stanford.edu> Wed, 20 Feb 2002 13:49:54 -0800 <ylwux7su0t.fsf@windlord.stanford.edu> <3c7615d0.11232095@news> 1280 30 Xref: inn.example.com news.software.nntp:20
-news.software.nntp:19 Re: Usefor: Message/external-body - any experiences ? Russ Allbery <rra@stanford.edu> Tue, 19 Feb 2002 10:36:56 -0800 <yl8z9p71yv.fsf@windlord.stanford.edu> <5955a.j22200@archiver.winews.net> 921 22 Xref: inn.example.com news.software.nntp:19
-news.software.nntp:18 Re: [yEnc] some newbie questions Russ Allbery <rra@stanford.edu> Tue, 19 Feb 2002 10:34:36 -0800 <yleljh722r.fsf@windlord.stanford.edu> <3c6e6798.9093644@news> <a4kc41$ou1$2@pegasus.csx.cam.ac.uk> <3c702e8c.7007252@news> <a4pknt$4pg$2@pegasus.csx.cam.ac.uk> <53488.j22209@archiver.winews.net> 872 21 Xref: inn.example.com news.software.nntp:18
-gnu.misc.discuss:3 Re: Money matters Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 20:12:07 -0800 <ylr8nixg88.fsf@windlord.stanford.edu> <1629dcd9.0202160842.36e8bdab@posting.google.com> <C4cc8.17$X5.109616@burlma1-snr2> <87heoek2h5.fsf@toncho.dhh.gt.org> <Rvhc8.29$X5.122317@burlma1-snr2> <yl3czyyzmv.fsf@windlord.stanford.edu> <slrna73glj.9cp.jmaynard@thebrain.conmicro.cx> 1896 35 Xref: inn.example.com gnu.misc.discuss:3
-gnu.misc.discuss:2 Re: Money matters Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 18:27:36 -0800 <yl3czyyzmv.fsf@windlord.stanford.edu> <1629dcd9.0202160842.36e8bdab@posting.google.com> <C4cc8.17$X5.109616@burlma1-snr2> <87heoek2h5.fsf@toncho.dhh.gt.org> <Rvhc8.29$X5.122317@burlma1-snr2> 1014 21 Xref: inn.example.com gnu.misc.discuss:2
-news.software.nntp:17 Re: RFC 977 extensions? Russ Allbery <rra@stanford.edu> Mon, 18 Feb 2002 13:46:21 -0800 <ylvgcu31le.fsf@windlord.stanford.edu> <Xns91B9E610EE161M8@62.2.16.82> 786 21 Xref: inn.example.com news.software.nntp:17
-news.software.nntp:16 Re: [yEnc] some newbie questions Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 15:43:07 -0800 <ylpu33brp0.fsf@windlord.stanford.edu> <3c6e6798.9093644@news> <a4kc41$ou1$2@pegasus.csx.cam.ac.uk> <3c702e8c.7007252@news> 1000 24 Xref: inn.example.com news.software.nntp:16
-news.admin.net-abuse.policy:11 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 13:58:51 -0800 <yllmdrdb38.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <87pu3mj826.fsf@erlenstar.demon.co.uk> <3mqs5us2puq2ov9gpqn7cqn8hhstojsesj@4ax.com> <b2059324.0202170829.47a7abce@posting.google.com> <3C7022DC.2F2E87DF@trin.ity> 546 11 Xref: inn.example.com news.admin.net-abuse.policy:11
-news.groups:464 Re: [History] The Guidelines: a preliminary revision history Russ Allbery <rra@stanford.edu> Sun, 17 Feb 2002 00:05:02 -0800 <ylbseoh6tt.fsf@windlord.stanford.edu> <dbc8daca.0202161159.4c0a1eee@posting.google.com> <yleljlnogd.fsf@windlord.stanford.edu> <dbc8daca.0202162324.1ce3b411@posting.google.com> 845 22 Xref: inn.example.com news.groups:64
-news.groups:260 Re: [History] The Guidelines: a preliminary revision history Russ Allbery <rra@stanford.edu> Sat, 16 Feb 2002 12:47:46 -0800 <yleljlnogd.fsf@windlord.stanford.edu> <dbc8daca.0202161159.4c0a1eee@posting.google.com> 7082 173 Xref: inn.example.com news.groups:60
-news.groups:59 Re: Professional practice (was Re: RESULT: sci.military.nuclear-bio-chem fails 73:25) Russ Allbery <rra@stanford.edu> Fri, 15 Feb 2002 19:59:06 -0800 <ylofiq6prp.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yly9i1as0j.fsf@windlord.stanford.edu> <a474cg$qou$1@panix2.panix.com> <yl8za0agmq.fsf@windlord.stanford.edu> <a4jcua$nqo$1@panix2.panix.com> 500 12 Xref: inn.example.com news.groups:59
-news.groups:58 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 21:40:08 -0800 <ylvgczi9qf.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> <3c6038d6.774936@news.storm.ca> <a3pg75$3vk$1@gw.retro.com> <3c604f11.3004891@news.storm.ca> <3n516u0ahojobsdiknc99l00f0euoujb60@4ax.com> <3C60A31C.A5D832F7@elepar.com> <slrna6lpis.6k8.dbt@pianosa.catch22.org> <3C6B5EA3.4A10@mcimail.com> <slrna6p6q1.4c8.dbt@pianosa.catch22.org> 718 17 Xref: inn.example.com news.groups:58
-news.groups:57 Re: comp.distributed again? Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 13:43:52 -0800 <ylu1sjkacn.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a4co04$d94$1@slb2.atl.mindspring.net> <a4edc2$uds$5@dent.deepthot.org> <a4frn0$71f$1@slb3.atl.mindspring.net> <a4frot$inj$8@dent.deepthot.org> 360 10 Xref: inn.example.com news.groups:57
-news.software.nntp:15 Re: chan.c problem with INN 2.3.[012] on AIX 4.2 Russ Allbery <rra@stanford.edu> Thu, 14 Feb 2002 11:49:28 -0800 <yl7kpfq1x3.fsf@windlord.stanford.edu> <fa8727e8.0202141109.7875ddc@posting.google.com> 1449 42 Xref: inn.example.com news.software.nntp:15
-gnu.emacs.gnus:8 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Wed, 13 Feb 2002 13:46:55 -0800 <yl3d05awc0.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> <ylbsev7et9.fsf@windlord.stanford.edu> <ilu665235iy.fsf@extundo.com> <ylwuxia2hh.fsf@windlord.stanford.edu> <1yfpzc36.fsf@hschmi22.userfqdn.rz-online.de> 326 11 Xref: inn.example.com gnu.emacs.gnus:8
-gnu.emacs.gnus:7 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Tue, 12 Feb 2002 12:07:06 -0800 <ylwuxia2hh.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> <ylbsev7et9.fsf@windlord.stanford.edu> <ilu665235iy.fsf@extundo.com> 426 11 Xref: inn.example.com gnu.emacs.gnus:7
-news.software.nntp:14 Re: rebuilding overview with makehistory Russ Allbery <rra@stanford.edu> Tue, 12 Feb 2002 11:15:20 -0800 <yladuefr5j.fsf@windlord.stanford.edu> <slrna6gcn5.nmf.br@panix2.panix.com> <ylofiv5tv3.fsf@windlord.stanford.edu> <slrna6ig0n.qig.br@panix2.panix.com> 505 13 Xref: inn.example.com news.software.nntp:14
-news.software.nntp:13 Re: rebuilding overview with makehistory Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 18:14:40 -0800 <ylofiv5tv3.fsf@windlord.stanford.edu> <slrna6gcn5.nmf.br@panix2.panix.com> 687 20 Xref: inn.example.com news.software.nntp:13
-gnu.emacs.gnus:6 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 15:56:50 -0800 <ylbsev7et9.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <uy9hzy4yp.fsf@synopsys.com> 1021 23 Xref: inn.example.com gnu.emacs.gnus:6
-gnu.emacs.gnus:2 Re: modifying Sender: to (valid) From: of gnus-posting-styles Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 15:55:01 -0800 <ylheon7ewa.fsf@windlord.stanford.edu> <m0it93yajy.fsf@k2.onsight.com> <vxkbsevzlcc.fsf@cinnamon.vanillaknot.com> <m0it9339nj.fsf@k2.onsight.com> 175 8 Xref: inn.example.com gnu.emacs.gnus:2
-news.admin.technical:2 Re: Maximum Length of Newsgroup Description field Russ Allbery <rra@stanford.edu> Mon, 11 Feb 2002 13:05:47 -0800 <ylit9391as.fsf@windlord.stanford.edu> <Xns91B278CC1107Djaydejaydenet@157.54.3.22> 526 12 Xref: inn.example.com news.admin.technical:2
-news.groups:56 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 20:01:15 -0800 <yleljs8y5w.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> <yly9i1as0j.fsf@windlord.stanford.edu> <a47aeg01e39@enews3.newsguy.com> 1482 35 Xref: inn.example.com news.groups:56
-news.groups:53 Re: Professional practice (was Re: RESULT: sci.military.nuclear-bio-chem fails 73:25) Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 18:37:01 -0800 <yl8za0agmq.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> <yly9i1as0j.fsf@windlord.stanford.edu> <a474cg$qou$1@panix2.panix.com> 1274 30 Xref: inn.example.com news.groups:53
-gnu.emacs.gnus:1 Re: Gnus, Postings, and Anti-spam? Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 14:37:51 -0800 <ylheoparpc.fsf@windlord.stanford.edu> <ubsezbqfg.fsf@synopsys.com> <geg.y1ysn8apwb0.fsf@fly.verified.de> <eljuvgy6.fsf@ichimusai.org> <geg.y1y3d0apg8z.fsf@fly.verified.de> <vgd52d4a.fsf@ichimusai.org> 862 23 Xref: inn.example.com gnu.emacs.gnus:1
-news.groups:50 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 14:31:08 -0800 <yly9i1as0j.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> <yln0yh22y7.fsf@windlord.stanford.edu> <3c68f0c2.3904908@supernews.seanet.com> 1723 38 Xref: inn.example.com news.groups:50
-news.groups:49 Re: 2nd RFD: sci.space.moderated moderated Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 12:12:17 -0800 <ylsn89f65a.fsf@windlord.stanford.edu> <1010713186.32070@isc.org> <a440uv$r73$2@dent.deepthot.org> <u6b36tthfaecfb@corp.supernews.com> <a448lr$il$1@dent.deepthot.org> <3c65d1dc$0$67479$892e7fe2@authen.puce.readfreenews.net> 3599 70 Xref: inn.example.com news.groups:49
-news.groups:48 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 11:48:18 -0800 <yly9i1f799.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylheop22ug.fsf@windlord.stanford.edu> <a46ec6$lee$1@samba.rahul.net> <ylpu3dgoni.fsf@windlord.stanford.edu> <a46i88$m4m$1@samba.rahul.net> 1563 32 Xref: inn.example.com news.groups:48
-news.groups:47 Re: 2nd RFD: sci.space.moderated moderated Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 10:54:24 -0800 <ylk7tlgobj.fsf@windlord.stanford.edu> <1010713186.32070@isc.org> <3N898.13340$Zu6.55955@news-server.bigpond.net.au> <u6argep8r8l2c2@corp.supernews.com> <Xns91B0C720E8590grahamdrabblelineone@ID-77355.user.dfncis.de> <a440uv$r73$2@dent.deepthot.org> <u6b36tthfaecfb@corp.supernews.com> 1235 23 Xref: inn.example.com news.groups:47
-news.groups:46 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 10:47:13 -0800 <ylpu3dgoni.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <yllme3azio.fsf@windlord.stanford.edu> <a44mu80urn@enews2.newsguy.com> <ylheop22ug.fsf@windlord.stanford.edu> <a46ec6$lee$1@samba.rahul.net> 1052 28 Xref: inn.example.com news.groups:46
-news.software.nntp:12 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Sun, 10 Feb 2002 09:32:55 -0800 <yl8za1kzso.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <yl3d0a8ibo.fsf@windlord.stanford.edu> <21049.a22200@archiver.winews.net> 1915 40 Xref: inn.example.com news.software.nntp:12
-news.groups:44 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 23:49:43 -0800 <ylheop22ug.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <a44mu80urn@enews2.newsguy.com> 810 16 Xref: inn.example.com news.groups:44
-news.groups:43 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 23:47:28 -0800 <yln0yh22y7.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> <yllme3azio.fsf@windlord.stanford.edu> <GrAr0y.AsA@world.std.com> 2306 45 Xref: inn.example.com news.groups:43
-news.software.nntp:11 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 13:18:51 -0800 <yl3d0a8ibo.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <ylit9723rb.fsf@windlord.stanford.edu> <2504c.922202@archiver.winews.net> 1075 27 Xref: inn.example.com news.software.nntp:11
-comp.lang.perl.moderated:1 Re: perldoc vs man why so much slower Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:47:26 -0800 <yl8za28js1.fsf@windlord.stanford.edu> <m1d6zfnl9h.fsf@reader.newsguy.com> <20020209180911.23756.qmail@plover.com> 799 20 Xref: inn.example.com comp.lang.perl.moderated:1
-news.admin.hierarchies:18 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:25:07 -0800 <ylvgd68kt8.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> <ylu1srclla.fsf@windlord.stanford.edu> <m37kpmdayt.fsf@defun.localdomain> 580 18 Xref: inn.example.com news.admin.hierarchies:18
-news.groups:42 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:20:01 -0800 <yl1yfu9zm6.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3uq5f$n81$1@news.orst.edu> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <3c651972$0$67480$892e7fe2@authen.puce.readfreenews.net> 990 19 Xref: inn.example.com news.groups:42
-news.admin.hierarchies:13 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Sat, 09 Feb 2002 12:00:56 -0800 <yl8za2a0hz.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> 905 23 Xref: inn.example.com news.admin.hierarchies:13
-news.groups:41 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 23:24:31 -0800 <yllme3azio.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> <ylsn8b76ad.fsf@windlord.stanford.edu> <a42f8b$rfj$1@samba.rahul.net> 1282 26 Xref: inn.example.com news.groups:41
-news.admin.hierarchies:12 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 20:42:25 -0800 <ylu1srclla.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> 505 14 Xref: inn.example.com news.admin.hierarchies:12
-news.groups:40 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 18:11:54 -0800 <ylsn8b76ad.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3tb6q$i69$1@gw.retro.com> <a3uq5f$n81$1@news.orst.edu> <a3v87u$ihf$1@panix2.panix.com> <a409ek$qc8$1@gw.retro.com> 1995 40 Xref: inn.example.com news.groups:40
-news.software.nntp:10 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 12:15:43 -0800 <ylsn8bwx00.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> <ylit9723rb.fsf@windlord.stanford.edu> <C2W88.119862$i3.977629@news.easynews.com> 749 19 Xref: inn.example.com news.software.nntp:10
-news.software.nntp:9 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 11:05:28 -0800 <ylit9723rb.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> <a405vd$huq$1@newsread4.arcor-online.net> 556 16 Xref: inn.example.com news.software.nntp:9
-news.software.nntp:6 Re: innd and Microsoft Exchange Russ Allbery <rra@stanford.edu> Fri, 08 Feb 2002 11:04:25 -0800 <ylofiz23t2.fsf@windlord.stanford.edu> <623f5703.0202070541.2b943211@posting.google.com> <yleljx41dn.fsf@windlord.stanford.edu> <3C63AD90.492F3C00@eproduction.ch> 541 14 Xref: inn.example.com news.software.nntp:6
-news.software.nntp:5 Re: innd and Microsoft Exchange Russ Allbery <rra@stanford.edu> Thu, 07 Feb 2002 10:01:40 -0800 <yleljx41dn.fsf@windlord.stanford.edu> <623f5703.0202070541.2b943211@posting.google.com> 1013 21 Xref: inn.example.com news.software.nntp:5
-news.groups:39 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Thu, 07 Feb 2002 00:46:46 -0800 <yl3d0dn0g9.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> <yl8za5n769.fsf@windlord.stanford.edu> <a3tb6q$i69$1@gw.retro.com> 5108 96 Xref: inn.example.com news.groups:39
-news.groups:38 Re: RESULT: sci.military.nuclear-bio-chem fails 73:25 Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 22:21:34 -0800 <yl8za5n769.fsf@windlord.stanford.edu> <1012432821.79903@isc.org> <1j6l5u499l6ru00rn6ibje0cgsv32jkrk1@4ax.com> <a3f1oq02gd2@enews3.newsguy.com> <a3obho02a17@enews2.newsguy.com> <a3pcp9$3d8$1@gw.retro.com> 1093 26 Xref: inn.example.com news.groups:38
-news.admin.hierarchies:11 Re: control.ctl maintenance (was: [INFO] bc.* and van.*) Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 16:20:13 -0800 <yleljyp2gy.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> <yllme6s1np.fsf@windlord.stanford.edu> <EKi88.17124$gW4.11422684@news1.rdc1.mi.home.com> 688 18 Xref: inn.example.com news.admin.hierarchies:11
-news.admin.hierarchies:7 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 16:19:10 -0800 <ylk7tqp2ip.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3ptk7.3vuai51.1@mid.glglgl.de> <a3qmdq$1akiad$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> <yllme6s1np.fsf@windlord.stanford.edu> <a3sbmu$1ao4a2$1@ID-80930.news.dfncis.de> 421 11 Xref: inn.example.com news.admin.hierarchies:7
-news.admin.hierarchies:4 Re: [INFO] bc.* and van.* Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 14:09:30 -0800 <yllme6s1np.fsf@windlord.stanford.edu> <a36mup$160fpd$1@ID-80930.news.dfncis.de> <a3ptk7.3vuai51.1@mid.glglgl.de> <a3qmdq$1akiad$1@ID-80930.news.dfncis.de> <a3qseq.3vue8up.1@mid.glglgl.de> <a3qvtt$19gllq$1@ID-80930.news.dfncis.de> 972 20 Xref: inn.example.com news.admin.hierarchies:4
-news.admin.hierarchies:3 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 14:00:23 -0800 <yl8za6tgnc.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> <yl665bqhku.fsf@windlord.stanford.edu> <m3lme68jz6.fsf@defun.localdomain> 478 17 Xref: inn.example.com news.admin.hierarchies:3
-news.admin.net-abuse.policy:10 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:58:09 -0800 <yleljytgr2.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> <ylr8ny7eaf.fsf@windlord.stanford.edu> <1013015167.535798@ok-corral.gunslinger.net> 548 13 Xref: inn.example.com news.admin.net-abuse.policy:10
-news.admin.net-abuse.policy:9 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:57:38 -0800 <ylk7tqtgrx.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> <ylr8ny7eaf.fsf@windlord.stanford.edu> <878za6o8h5.fsf@erlenstar.demon.co.uk> 578 16 Xref: inn.example.com news.admin.net-abuse.policy:9
-news.software.nntp:4 Re: first > last Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 13:50:15 -0800 <yly9i6uvoo.fsf@windlord.stanford.edu> <3C61951F.8080606@gemal.dk> 850 19 Xref: inn.example.com news.software.nntp:4
-news.software.nntp:3 Re: Trailing spaces in body on INN 2.3.3 ? Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 08:45:04 -0800 <yllme67e5r.fsf@windlord.stanford.edu> <52419.622207@archiver.winews.net> 852 21 Xref: inn.example.com news.software.nntp:3
-news.admin.net-abuse.policy:8 Re: [RETROMODERATION] teenfem terrorists Russ Allbery <rra@stanford.edu> Wed, 06 Feb 2002 08:42:16 -0800 <ylr8ny7eaf.fsf@windlord.stanford.edu> <6f826u0dag3c5gosbps2elao0scnu38k0p@news-01.easynews.com> 740 18 Xref: inn.example.com news.admin.net-abuse.policy:8
-news.admin.hierarchies:2 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 21:56:17 -0800 <yl665bqhku.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> <yl7kprjrx4.fsf@windlord.stanford.edu> <m3y9i7xluu.fsf@defun.localdomain> 828 19 Xref: inn.example.com news.admin.hierarchies:2
-news.software.nntp:2 Re: INN on another user/group Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 19:14:03 -0800 <ylg04fs3no.fsf@windlord.stanford.edu> <3c609757$0$20968$afc38c87@news.optusnet.com.au> 593 15 Xref: inn.example.com news.software.nntp:2
-news.groups:37 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 18:07:55 -0800 <ylvgdbicqs.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> <3C608D3D.C87E3610@diogenes.sacramento.ca.us> 623 13 Xref: inn.example.com news.groups:37
-news.admin.hierarchies:1 Re: Are the active files at ftp.isc.org maintained? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:54:47 -0800 <yl7kprjrx4.fsf@windlord.stanford.edu> <m3lme7zhep.fsf@defun.localdomain> 877 21 Xref: inn.example.com news.admin.hierarchies:1
-news.admin.technical:1 Re: nnrpd Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:53:18 -0800 <yld6zjjrzl.fsf@windlord.stanford.edu> <a3psen$7p4$1@quasar.ctc.edu> 543 13 Xref: inn.example.com news.admin.technical:1
-news.groups:36 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:51:33 -0800 <ylit9bjs2i.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <Xns91AD188E6226grahamdrabblelineone@ID-77355.user.dfncis.de> 1067 21 Xref: inn.example.com news.groups:36
-news.groups:34 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:46:28 -0800 <ylofj3jsaz.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> <m2k7trcxes.fsf@dan.jacobson.tw> <3C6077F5.AE1C5ED8@sfo.com> 882 22 Xref: inn.example.com news.groups:34
-news.software.nntp:1 Re: peering under the storage API Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 17:04:13 -0800 <ylit9bl8tu.fsf@windlord.stanford.edu> <slrna60q6l.3fo.br@panix2.panix.com> 546 14 Xref: inn.example.com news.software.nntp:1
-news.admin.net-abuse.policy:7 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Tue, 05 Feb 2002 08:52:18 -0800 <yl4rkvx459.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> <ylr8o1xb4b.fsf@windlord.stanford.edu> <Gr1CnE.Iny@world.std.com> <ylk7tsofmi.fsf@windlord.stanford.edu> <Gr1LLx.6xF@world.std.com> 3618 69 Xref: inn.example.com news.admin.net-abuse.policy:7
-news.groups:33 Re: CFV: sci.geo.cartography Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 19:04:16 -0800 <ylheowbpe7.fsf@windlord.stanford.edu> <1010622320.26971@isc.org> <1012843693.45036@isc.org> <3c5f4805$0$36783$892e7fe2@authen.puce.readfreenews.net> 851 17 Xref: inn.example.com news.groups:33
-news.groups:32 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 19:02:56 -0800 <yln0yobpgf.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> <yl4rkwu8mx.fsf@windlord.stanford.edu> <a3n74c026se@enews4.newsguy.com> <ylofj4rcf0.fsf@windlord.stanford.edu> <a3nbva02f0r@enews4.newsguy.com> 1280 26 Xref: inn.example.com news.groups:32
-news.admin.net-abuse.policy:6 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 17:56:53 -0800 <ylk7tsofmi.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> <ylr8o1xb4b.fsf@windlord.stanford.edu> <Gr1CnE.Iny@world.std.com> 961 18 Xref: inn.example.com news.admin.net-abuse.policy:6
-news.groups:27 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 16:37:55 -0800 <ylofj4rcf0.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> <yl4rkwu8mx.fsf@windlord.stanford.edu> <a3n74c026se@enews4.newsguy.com> 899 22 Xref: inn.example.com news.groups:27
-news.groups:26 Re: [META RFD] Removal of low traffic groups. Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 15:31:18 -0800 <yl4rkwu8mx.fsf@windlord.stanford.edu> <Xns91A5EF6DA9BCEgrahamdrabblelineone@ID-77355.user.dfncis.de> <3c5f0eb7$0$36784$892e7fe2@authen.puce.readfreenews.net> <3c5u5u08g2u5tva8i6gd1087ug4uma6051@4ax.com> 578 15 Xref: inn.example.com news.groups:26
-gnu.utils.bug:1 Re: let's beef up the tsort info page Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 14:03:41 -0800 <yl4rkwx5tu.fsf@windlord.stanford.edu> <m2wuxtj3gh.fsf@dan.jacobson.tw> 2409 73 Xref: inn.example.com gnu.utils.bug:1
-csd.bboard:2 Re: comp.doc.techreports submissions from Stanford Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 12:31:16 -0800 <yl3d0hxa3v.fsf@windlord.stanford.edu> <yl4rkx3xvo.fsf@windlord.stanford.edu> 794 16 Xref: inn.example.com csd.bboard:2
-news.admin.net-abuse.policy:5 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 12:09:24 -0800 <ylr8o1xb4b.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> <ylr8o2z2c5.fsf@windlord.stanford.edu> <Gr0r5x.M8y@world.std.com> 1751 38 Xref: inn.example.com news.admin.net-abuse.policy:5
-csd.bboard:1 comp.doc.techreports submissions from Stanford Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 10:28:11 -0800 <yl4rkx3xvo.fsf@windlord.stanford.edu> 672 18 Xref: inn.example.com csd.bboard:1
-comp.lang.perl.misc:1 Re: want to learn perl from free sources Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 09:51:12 -0800 <yln0yp87an.fsf@windlord.stanford.edu> <m2r8o1iu11.fsf@dan.jacobson.tw> 641 15 Xref: inn.example.com comp.lang.perl.misc:1
-gnu.misc.discuss:1 Re: want to learn perl from free sources Russ Allbery <rra@stanford.edu> Mon, 04 Feb 2002 09:51:12 -0800 <yln0yp87an.fsf@windlord.stanford.edu> <m2r8o1iu11.fsf@dan.jacobson.tw> 641 15 Xref: inn.example.com gnu.misc.discuss:1
-news.admin.net-abuse.policy:4 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 13:23:54 -0800 <ylr8o2z2c5.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> <ylelk21l3n.fsf@windlord.stanford.edu> <Gqz2AI.JH2@world.std.com> 533 12 Xref: inn.example.com news.admin.net-abuse.policy:4
-news.groups:25 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 13:21:34 -0800 <ylwuxuz2g1.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <20020202150653$4dbb@babylon.ks.uiuc.edu> <FRRtIeAzyYX8Ewxl@merlyn.demon.co.uk> 668 15 Xref: inn.example.com news.groups:25
-news.admin.net-abuse.policy:1 Re: [ALT hierarchy] Anyone can newgroup and anyone can rmgroup ? Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 10:22:36 -0800 <ylelk21l3n.fsf@windlord.stanford.edu> <5Re78.4895$XS6.585609@news2-win.server.ntlworld.com> 1448 31 Xref: inn.example.com news.admin.net-abuse.policy:1
-news.groups:24 Re: Guidelines for Big Eight Newsgroup Creation Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 09:38:27 -0800 <ylzo2q31po.fsf@windlord.stanford.edu> <big-eight-faq-1012550404$22697@windlord.stanford.edu> <vvjq5u8l1dnrdankh4q7l2d043ud8kt11o@4ax.com> 971 22 Xref: inn.example.com news.groups:24
-news.groups:23 Re: [History] Re: A Chronology of Usenet Newsgroups: Start Post Russ Allbery <rra@stanford.edu> Sun, 03 Feb 2002 09:34:04 -0800 <yl665e4ghf.fsf@windlord.stanford.edu> <3c4a31e3$0$95685$892e7fe2@authen.puce.readfreenews.net> <a301ve02s1r@enews2.newsguy.com> <dbc8daca.0201280231.791aeb03@posting.google.com> <8I07QDHHw-B@khms.westfalen.de> <3c5d3981$0$36784$892e7fe2@authen.puce.readfreenews.net> 617 15 Xref: inn.example.com news.groups:23
-news.groups:22 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 17:42:27 -0800 <ylr8o3wdbw.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <08_68.11847$gW4.9091001@news1.rdc1.mi.home.com> 1405 29 Xref: inn.example.com news.groups:22
-news.groups:21 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 17:38:39 -0800 <ylwuxvwdi8.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <PE2$9TMo7+W8Ew43@merlyn.demon.co.uk> <20020202150653$4dbb@babylon.ks.uiuc.edu> <fo1o5uoo90uh1qreh20u6n1ci70jt28mmg@4ax.com> <1f6z4v6.1fbjkdq18w29f4N%kmorgan@aptalaska.net> <lqto5u0p5sblo0ui9hal0nil52e3nlbssm@4ax.com> 316 9 Xref: inn.example.com news.groups:21
-news.groups:19 Re: The beer truck (was Re: Pre-RFD - Exec Board Newsgroup Creation) Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 12:51:44 -0800 <yl8zab38v3.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylhep0vi11.fsf@windlord.stanford.edu> <a3h7be$dec$1@panix2.panix.com> <yladur7nfw.fsf@windlord.stanford.edu> <a3hd8t$sin$1@panix2.panix.com> 481 16 Xref: inn.example.com news.groups:19
-news.groups:18 Re: The beer truck (was Re: Pre-RFD - Exec Board Newsgroup Creation) Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 10:23:15 -0800 <yladur7nfw.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3h7be$dec$1@panix2.panix.com> 375 11 Xref: inn.example.com news.groups:18
-news.groups:17 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Sat, 02 Feb 2002 10:20:43 -0800 <ylg04j7nk4.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3g0i9$6ch$1@samba.rahul.net> 680 16 Xref: inn.example.com news.groups:17
-news.groups:16 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:35:38 -0800 <yl4rl0369h.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <Xns91A8BC08432FEpeskyirritantcom@209.155.56.83> 326 12 Xref: inn.example.com news.groups:16
-news.groups:15 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:12:32 -0800 <yladus37bz.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <i8jm5u4l8bt7lk93mramtmbouhtg58tpnb@4ax.com> 643 14 Xref: inn.example.com news.groups:15
-news.groups:14 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 19:08:02 -0800 <ylg04k37jh.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <a3fgk302sdn@enews1.newsguy.com> 808 18 Xref: inn.example.com news.groups:14
-news.groups:13 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 18:10:18 -0800 <ylu1t03a7p.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> <yl4rl0u1ae.fsf@windlord.stanford.edu> <v1hm5u4mrhllm98ng1jhp5gco7sflbm4jq@4ax.com> 902 27 Xref: inn.example.com news.groups:13
-news.groups:12 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 17:20:57 -0800 <yl4rl0u1ae.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <1hem5uc8efskp0efdahvnpphg2qtrlt9pc@4ax.com> 1651 36 Xref: inn.example.com news.groups:12
-news.groups:8 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 17:10:47 -0800 <yladusu1rc.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> <ylhep0vi11.fsf@windlord.stanford.edu> <3ndm5u8fgomord7vmh164ce7pcteh496sp@4ax.com> 2363 47 Xref: inn.example.com news.groups:8
-news.groups:7 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 16:34:02 -0800 <ylhep0vi11.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> <ylvgdgye47.fsf@windlord.stanford.edu> <tuam5ug6iomvjscick3a2fftfs7d20rrfk@4ax.com> 2834 55 Xref: inn.example.com news.groups:7
-news.groups:2 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 15:32:03 -0800 <ylofj8ye18.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3eep7$q6r$1@samba.rahul.net> <a3epeq$rt$1@gw.retro.com> <a3f201$n8$1@samba.rahul.net> <a3f7v9$3kg$1@gw.retro.com> 448 11 Xref: inn.example.com news.groups:2
-news.groups:1 Re: Pre-RFD - Exec Board Newsgroup Creation Russ Allbery <rra@stanford.edu> Fri, 01 Feb 2002 15:30:16 -0800 <ylvgdgye47.fsf@windlord.stanford.edu> <20020131191005$5818@babylon.ks.uiuc.edu> <a3cdbm$dt3$1@samba.rahul.net> <a3coga$jiv$1@news.orst.edu> <3C5AE4E5.B0A79442@elepar.com> <a3f1o2$nvo$1@news.orst.edu> <3b7m5ug5lmovmhotuegmkq13jpmcubrh0n@4ax.com> 3124 58 Xref: inn.example.com news.groups:1
+++ /dev/null
-#!/usr/bin/perl
-
-## $Id: munge-data 5144 2002-02-24 06:24:55Z rra $
-##
-## Munge .overview data into something suitable for test data.
-##
-## This script isn't used regularly and is here only for the use of INN
-## developers and other people needing to generate more overview test data.
-## It expects overview data but possibly with extra fields at the end, snips
-## off To: data (to avoid putting people's e-mail addresses into INN test
-## data), and if Newsgroups: data is present, rewrites the Xref header to use
-## it instead of keeping the Xref data (this is so that I can use .overview
-## files from Gnus as test data). It generates overview data but with the
-## newsgroup name and a colon prepended to the article number so that it can
-## be split apart into overview data for multiple groups.
-##
-## Please don't include overview information for people's articles into INN's
-## test suite without their permission.
-
-my %number;
-while (<>) {
- s/\s+$//;
- my @data = split /\t/;
- @data = grep { !/^To:/ } @data;
- my $group = pop @data;
- my $xref = pop @data;
- if ($group =~ s/^Newsgroups: //) {
- my @groups = split (/\s*,\s*/, $group);
- for (@groups) {
- $number{$_} = 1 unless $number{$_};
- $data[0] = $_ . ':' . $number{$_}++;
- $number{$_} += int (rand 5) if rand (10) > 8;
- print join ("\t", @data, "Xref: inn.example.com $data[0]"), "\n";
- }
- } else {
- $xref =~ s/Xref:\s*\S+\s+//;
- my @xref = split (' ', $xref);
- for (@xref) {
- $data[0] = $_;
- print join ("\t", @data, "Xref: inn.example.com $xref"), "\n";
- }
- }
-}
+++ /dev/null
-/* $Id: tradindexed-t.c 6388 2003-07-12 19:07:56Z rra $ */
-/* tradindexed test suite. */
-
-#include "config.h"
-#include "clibrary.h"
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "inn/innconf.h"
-#include "inn/hashtab.h"
-#include "inn/messages.h"
-#include "inn/vector.h"
-#include "libinn.h"
-#include "libtest.h"
-#include "ov.h"
-#include "storage.h"
-
-#include "../storage/tradindexed/tradindexed.h"
-
-/* Used as the artificial token for all articles inserted into overview. */
-static const TOKEN faketoken = { 1, 1, "" };
-
-struct group {
- char *group;
- unsigned long count;
- unsigned long low;
- unsigned long high;
-};
-
-static const void *
-group_key(const void *entry)
-{
- const struct group *group = (const struct group *) entry;
- return group->group;
-}
-
-static bool
-group_eq(const void *key, const void *entry)
-{
- const char *first = key;
- const char *second;
-
- second = ((const struct group *) entry)->group;
- return !strcmp(first, second);
-}
-
-static void
-group_del(void *entry)
-{
- struct group *group = (struct group *) entry;
-
- free(group->group);
- free(group);
-}
-
-/* Build a stripped-down innconf struct that contains only those settings that
- the tradindexed overview method cares about. */
-static void
-fake_innconf(void)
-{
- innconf = xmalloc(sizeof(*innconf));
- innconf->pathoverview = xstrdup("tdx-tmp");
- innconf->overcachesize = 20;
- innconf->groupbaseexpiry = true;
- innconf->tradindexedmmap = true;
-}
-
-/* Initialize the overview database. */
-static bool
-overview_init(void)
-{
- fake_innconf();
- if (access("data/basic", F_OK) < 0)
- if (access("overview/data/basic", F_OK) == 0)
- if (chdir("overview") != 0)
- sysdie("Cannot cd to overview");
- if (mkdir("tdx-tmp", 0755) != 0 && errno != EEXIST)
- sysdie("Cannot mkdir tdx-tmp");
- return tradindexed_open(OV_READ | OV_WRITE);
-}
-
-/* Check to be sure that the line wasn't too long, and then parse the
- beginning of the line from one of our data files, setting the article
- number (via the passed pointer) and returning a pointer to the beginning of
- the real overview data. This function nul-terminates the group name and
- leaves it at the beginning of the buffer. (Ugly interface, but it's just a
- test suite.) */
-static char *
-overview_data_parse(char *data, unsigned long *artnum)
-{
- char *start;
-
- if (data[strlen(data) - 1] != '\n')
- die("Line too long in input data");
-
- start = strchr(data, ':');
- if (start == NULL)
- die("No colon found in input data");
- *start = '\0';
- start++;
- *artnum = strtoul(start, NULL, 10);
- if (artnum == 0)
- die("Cannot parse article number in input data");
- return start;
-}
-
-/* Load an empty overview database from a file, in the process populating a
- hash table with each group, the high water mark, and the count of messages
- that should be in the group. Returns the hash table on success and dies on
- failure. Takes the name of the data file to load. */
-static struct hash *
-overview_load(const char *data)
-{
- struct hash *groups;
- struct group *group;
- FILE *overview;
- char buffer[4096];
- char flag[] = "y";
- char *start;
- unsigned long artnum;
-
- /* Run through the overview data. Each time we see a group, we update our
- stored information about that group, which we'll use for verification
- later. We store that in a local hash table. */
- groups = hash_create(32, hash_string, group_key, group_eq, group_del);
- if (groups == NULL)
- die("Cannot create a hash table");
- overview = fopen(data, "r");
- if (overview == NULL)
- sysdie("Cannot open %s for reading", data);
- while (fgets(buffer, sizeof(buffer), overview) != NULL) {
- start = overview_data_parse(buffer, &artnum);
-
- /* See if we've already seen this group. If not, create it in the
- overview and the hash table; otherwise, update our local hash table
- entry. */
- group = hash_lookup(groups, buffer);
- if (group == NULL) {
- group = xmalloc(sizeof(struct group));
- group->group = xstrdup(buffer);
- group->count = 1;
- group->low = artnum;
- group->high = artnum;
- if (!hash_insert(groups, group->group, group))
- die("Cannot insert %s into hash table", group->group);
- if (!tradindexed_groupadd(group->group, 0, 0, flag))
- die("Cannot insert group %s into overview", group->group);
- } else {
- group->count++;
- group->low = (artnum < group->low) ? artnum : group->low;
- group->high = (artnum > group->high) ? artnum : group->high;
- }
-
- /* Do the actual insert of the data. Note that we set the arrival
- time and expires time in a deterministic fashion so that we can
- check later if that data is being stored properly. */
- if (!tradindexed_add(group->group, artnum, faketoken, start,
- strlen(start), artnum * 10,
- (artnum % 5 == 0) ? artnum * 100 : artnum))
- die("Cannot insert %s:%lu into overview", group->group, artnum);
- }
- fclose(overview);
- return groups;
-}
-
-/* Verify that all of the group data looks correct; this is low mark, high
- mark, and article count. Returns true if all the data is right, false
- otherwise. This function is meant to be called as a hash traversal
- function, which means that it will be called for each element in our local
- hash table of groups with the group struct as the first argument and a
- pointer to a status as the second argument. */
-static void
-overview_verify_groups(void *data, void *cookie)
-{
- struct group *group = (struct group *) data;
- bool *status = (bool *) cookie;
- int low, high, count, flag;
-
- if (!tradindexed_groupstats(group->group, &low, &high, &count, &flag)) {
- warn("Unable to get data for %s", group->group);
- *status = false;
- return;
- }
- if ((unsigned long) low != group->low) {
- warn("Low article wrong for %s: %lu != %lu", group->group,
- (unsigned long) low, group->low);
- *status = false;
- }
- if ((unsigned long) high != group->high) {
- warn("High article wrong for %s: %lu != %lu", group->group,
- (unsigned long) high, group->high);
- *status = false;
- }
- if ((unsigned long) count != group->count) {
- warn("Article count wrong for %s: %lu != %lu", group->group,
- (unsigned long) count, group->count);
- *status = false;
- }
- if (flag != 'y') {
- warn("Flag wrong for %s: %c != y", group->group, (char) flag);
- *status = false;
- }
-}
-
-/* Verify the components of the overview data for a particular entry. */
-static bool
-check_data(const char *group, unsigned long artnum, const char *expected,
- const char *seen, int length, TOKEN token)
-{
- bool status = true;
-
- if (strlen(expected) != (size_t) length) {
- warn("Length wrong for %s:%lu: %d != %lu", group, artnum, length,
- (unsigned long) strlen(expected));
- status = false;
- }
- if (memcmp(&token, &faketoken, sizeof(token)) != 0) {
- warn("Token wrong for %s:%lu", group, artnum);
- status = false;
- }
- if (memcmp(expected, seen, length) != 0) {
- warn("Data mismatch for %s:%lu", group, artnum);
- warn("====\n%s\n====\n%s\n====", expected, seen);
- status = false;
- }
- return status;
-}
-
-/* Read through the data again, looking up each article as we go and verifying
- that the data stored in overview is the same as the data we put there. Do
- this two ways each time, once via getartinfo and once via opensearch.
- Return true if everything checks out, false otherwise. Takes the path to
- the data file. */
-static bool
-overview_verify_data(const char *data)
-{
- FILE *overdata;
- char buffer[4096];
- char *start;
- unsigned long artnum, overnum;
- char *overview;
- int length;
- TOKEN token;
- bool status = true;
- void *search;
- time_t arrived;
-
- overdata = fopen(data, "r");
- if (overdata == NULL)
- sysdie("Cannot open %s for reading", data);
- while (fgets(buffer, sizeof(buffer), overdata) != NULL) {
- start = overview_data_parse(buffer, &artnum);
-
- /* Now check that the overview data is correct for that group. */
- if (!tradindexed_getartinfo(buffer, artnum, &token)) {
- warn("No overview data found for %s:%lu", buffer, artnum);
- status = false;
- continue;
- }
- if (memcmp(&token, &faketoken, sizeof(token)) != 0) {
- warn("Token wrong for %s:%lu", buffer, artnum);
- status = false;
- }
-
- /* Do the same thing, except use search. */
- search = tradindexed_opensearch(buffer, artnum, artnum);
- if (search == NULL) {
- warn("Unable to open search for %s:%lu", buffer, artnum);
- status = false;
- continue;
- }
- if (!tradindexed_search(search, &overnum, &overview, &length, &token,
- &arrived)) {
- warn("No overview data found for %s:%lu", buffer, artnum);
- status = false;
- continue;
- }
- if (overnum != artnum) {
- warn("Incorrect article number in search for %s:%lu: %lu != %lu",
- buffer, artnum, overnum, artnum);
- status = false;
- }
- if (!check_data(buffer, artnum, start, overview, length, token))
- status = false;
- if ((unsigned long) arrived != artnum * 10) {
- warn("Arrival time wrong for %s:%lu: %lu != %lu", buffer, artnum,
- (unsigned long) arrived, artnum * 10);
- status = false;
- }
- if (tradindexed_search(search, &overnum, &overview, &length, &token,
- &arrived)) {
- warn("Unexpected article found for %s:%lu", buffer, artnum);
- status = false;
- }
- tradindexed_closesearch(search);
- }
- fclose(overdata);
- return status;
-}
-
-/* Try an overview search and verify that all of the data is returned in the
- right order. The first group mentioned in the provided data file will be
- the group the search is done in, and the search will cover all articles
- from the second article to the second-to-the-last article in the group.
- Returns true if everything checks out, false otherwise. */
-static bool
-overview_verify_search(const char *data)
-{
- unsigned long artnum, overnum, i;
- unsigned long start = 0;
- unsigned long end = 0;
- unsigned long last = 0;
- struct vector *expected;
- char *line, *group;
- FILE *overview;
- char buffer[4096];
- int length;
- TOKEN token;
- void *search;
- time_t arrived;
- bool status = true;
-
- overview = fopen(data, "r");
- if (overview == NULL)
- sysdie("Cannot open %s for reading", data);
- expected = vector_new();
- if (fgets(buffer, sizeof(buffer), overview) == NULL)
- die("Unexpected end of file in %s", data);
- overview_data_parse(buffer, &artnum);
- group = xstrdup(buffer);
- while (fgets(buffer, sizeof(buffer), overview) != NULL) {
- line = overview_data_parse(buffer, &artnum);
- if (strcmp(group, buffer) != 0)
- continue;
- vector_add(expected, line);
- if (start == 0)
- start = artnum;
- end = last;
- last = artnum;
- }
- search = tradindexed_opensearch(group, start, end);
- if (search == NULL) {
- warn("Unable to open search for %s:%lu", buffer, start);
- free(group);
- vector_free(expected);
- return false;
- }
- i = 0;
- while (tradindexed_search(search, &overnum, &line, &length, &token,
- &arrived)) {
- if (!check_data(group, overnum, expected->strings[i], line, length,
- token))
- status = false;
- if ((unsigned long) arrived != overnum * 10) {
- warn("Arrival time wrong for %s:%lu: %lu != %lu", group, overnum,
- (unsigned long) arrived, overnum * 10);
- status = false;
- }
- i++;
- }
- tradindexed_closesearch(search);
- if (overnum != end) {
- warn("End of search in %s wrong: %lu != %lu", group, overnum, end);
- status = false;
- }
- if (i != expected->count - 1) {
- warn("Didn't see all expected entries in %s", group);
- status = false;
- }
- free(group);
- vector_free(expected);
- return status;
-}
-
-/* Try an overview search and verify that all of the data is returned in the
- right order. The search will cover everything from article 1 to the
- highest numbered article plus one. There were some problems with a search
- low-water mark lower than the base of the group. Returns true if
- everything checks out, false otherwise. */
-static bool
-overview_verify_full_search(const char *data)
-{
- unsigned long artnum, overnum, i;
- unsigned long end = 0;
- struct vector *expected;
- char *line;
- char *group = NULL;
- FILE *overview;
- char buffer[4096];
- int length;
- TOKEN token;
- void *search;
- time_t arrived;
- bool status = true;
-
- overview = fopen(data, "r");
- if (overview == NULL)
- sysdie("Cannot open %s for reading", data);
- expected = vector_new();
- while (fgets(buffer, sizeof(buffer), overview) != NULL) {
- line = overview_data_parse(buffer, &artnum);
- if (group == NULL)
- group = xstrdup(buffer);
- vector_add(expected, line);
- end = artnum;
- }
- search = tradindexed_opensearch(group, 1, end + 1);
- if (search == NULL) {
- warn("Unable to open full search for %s", group);
- free(group);
- vector_free(expected);
- return false;
- }
- i = 0;
- while (tradindexed_search(search, &overnum, &line, &length, &token,
- &arrived)) {
- if (!check_data(group, overnum, expected->strings[i], line, length,
- token))
- status = false;
- if ((unsigned long) arrived != overnum * 10) {
- warn("Arrival time wrong for %s:%lu: %lu != %lu", group, overnum,
- (unsigned long) arrived, overnum * 10);
- status = false;
- }
- i++;
- }
- tradindexed_closesearch(search);
- if (overnum != end) {
- warn("End of search in %s wrong: %lu != %lu", group, overnum, end);
- status = false;
- }
- if (i != expected->count) {
- warn("Didn't see all expected entries in %s", group);
- status = false;
- }
- free(group);
- vector_free(expected);
- return status;
-}
-
-int
-main(void)
-{
- struct hash *groups;
- bool status;
-
- puts("21");
-
- if (!overview_init())
- die("Opening the overview database failed, cannot continue");
- ok(1, true);
-
- groups = overview_load("data/basic");
- ok(2, true);
- status = true;
- hash_traverse(groups, overview_verify_groups, &status);
- ok(3, status);
- ok(4, overview_verify_data("data/basic"));
- ok(5, overview_verify_search("data/basic"));
- hash_free(groups);
- tradindexed_close();
- system("/bin/rm -r tdx-tmp");
- ok(6, true);
-
- if (!overview_init())
- die("Opening the overview database failed, cannot continue");
- ok(7, true);
-
- groups = overview_load("data/reversed");
- ok(8, true);
- status = true;
- hash_traverse(groups, overview_verify_groups, &status);
- ok(9, status);
- ok(10, overview_verify_data("data/basic"));
- ok(11, overview_verify_search("data/basic"));
- hash_free(groups);
- tradindexed_close();
- system("/bin/rm -r tdx-tmp");
- ok(12, true);
-
- if (!overview_init())
- die("Opening the overview database failed, cannot continue");
- ok(13, true);
-
- groups = overview_load("data/high-numbered");
- ok(14, true);
- ok(15, overview_verify_data("data/high-numbered"));
- ok(16, overview_verify_full_search("data/high-numbered"));
- hash_free(groups);
- tradindexed_close();
- system("/bin/rm -r tdx-tmp");
- ok(17, true);
-
- if (!overview_init())
- die("Opening the overview database failed, cannot continue");
- ok(18, true);
-
- groups = overview_load("data/bogus");
- ok(19, true);
- ok(20, overview_verify_data("data/bogus"));
- hash_free(groups);
- tradindexed_close();
- system("/bin/rm -r tdx-tmp");
- ok(21, true);
-
- return 0;
-}
+++ /dev/null
-/* $Id: runtests.c 7578 2006-09-11 23:03:12Z eagle $
-
- Run a set of tests, reporting results.
-
- Copyright 2000, 2001 Russ Allbery <rra@stanford.edu>
-
- Please note that this file is maintained separately from INN by the above
- author (which is why the coding style is slightly different). Any fixes
- added to the INN tree should also be reported to the above author if
- necessary.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
- Usage:
-
- runtests <test-list>
-
- Expects a list of executables located in the given file, one line per
- executable. For each one, runs it as part of a test suite, reporting
- results. Test output should start with a line containing the number of
- tests (numbered from 1 to this number), and then each line should be in
- the following format:
-
- ok <number>
- not ok <number>
- ok <number> # skip
-
- where <number> is the number of the test. ok indicates success, not ok
- indicates failure, and "# skip" indicates the test was skipped for some
- reason (maybe because it doesn't apply to this platform).
-
- This file is completely stand-alone by intention. As stated more
- formally in the license above, you are welcome to include it in your
- packages as a test suite driver. It requires ANSI C (__FILE__, __LINE__,
- void, const, stdarg.h, string.h) and POSIX (fcntl.h, unistd.h, pid_t) and
- won't compile out of the box on SunOS without adjustments to include
- strings.h instead. This is intentionally not fixed using autoconf so
- that this file will not have a dependency on autoconf (although you're
- welcome to fix it for your project if you want). Since it doesn't matter
- as much that the test suite for the software package be utterly portable
- to older systems, this file should be portable enough for most purposes.
-
- Any bug reports, bug fixes, and improvements are very much welcome and
- should be sent to the e-mail address above. */
-
-#include "config.h"
-#include "clibrary.h"
-#include "portable/wait.h"
-#include "portable/time.h"
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-
-/* sys/time.h must be included before sys/resource.h on some platforms. */
-#include <sys/resource.h>
-
-/* Test status codes. */
-enum test_status {
- TEST_FAIL,
- TEST_PASS,
- TEST_SKIP,
- TEST_INVALID
-};
-
-/* Error exit statuses for test processes. */
-#define CHILDERR_DUP 100 /* Couldn't redirect stderr or stdout. */
-#define CHILDERR_EXEC 101 /* Couldn't exec child process. */
-#define CHILDERR_STDERR 102 /* Couldn't open stderr file. */
-
-/* Structure to hold data for a set of tests. */
-struct testset {
- const char *file; /* The file name of the test. */
- int count; /* Expected count of tests. */
- int current; /* The last seen test number. */
- int passed; /* Count of passing tests. */
- int failed; /* Count of failing lists. */
- int skipped; /* Count of skipped tests (passed). */
- enum test_status *results; /* Table of results by test number. */
- int aborted; /* Whether the set as aborted. */
- int reported; /* Whether the results were reported. */
- int status; /* The exit status of the test. */
-};
-
-/* Structure to hold a linked list of test sets. */
-struct testlist {
- struct testset *ts;
- struct testlist *next;
-};
-
-/* Header used for test output. %s is replaced by the file name of the list
- of tests. */
-static const char banner[] = "\n\
-Running all tests listed in %s. If any tests fail, run the failing\n\
-test program by hand to see more details. The test program will have the\n\
-same name as the test set but with \".t\" appended.\n\n";
-
-/* Header for reports of failed tests. */
-static const char header[] = "\n\
-Failed Set Fail/Total (%) Skip Stat Failing Tests\n\
--------------------------- -------------- ---- ---- ------------------------";
-
-/* Include the file name and line number in malloc failures. */
-#define xmalloc(size) x_malloc((size), __FILE__, __LINE__)
-#define xstrdup(p) x_strdup((p), __FILE__, __LINE__)
-
-/* Internal prototypes. */
-static void sysdie(const char *format, ...);
-static void *x_malloc(size_t, const char *file, int line);
-static char *x_strdup(const char *, const char *file, int line);
-static int test_analyze(struct testset *);
-static int test_batch(const char *testlist);
-static void test_checkline(const char *line, struct testset *);
-static void test_fail_summary(const struct testlist *);
-static int test_init(const char *line, struct testset *);
-static int test_print_range(int first, int last, int chars, int limit);
-static void test_summarize(struct testset *, int status);
-static pid_t test_start(const char *path, int *fd);
-static double tv_diff(const struct timeval *, const struct timeval *);
-static double tv_seconds(const struct timeval *);
-static double tv_sum(const struct timeval *, const struct timeval *);
-
-
-/* Report a fatal error, including the results of strerror, and exit. */
-static void
-sysdie(const char *format, ...)
-{
- int oerrno;
- va_list args;
-
- oerrno = errno;
- fflush(stdout);
- fprintf(stderr, "runtests: ");
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
- fprintf(stderr, ": %s\n", strerror(oerrno));
- exit(1);
-}
-
-
-/* Allocate memory, reporting a fatal error and exiting on failure. */
-static void *
-x_malloc(size_t size, const char *file, int line)
-{
- void *p;
-
- p = malloc(size);
- if (!p)
- sysdie("failed to malloc %lu bytes at %s line %d",
- (unsigned long) size, file, line);
- return p;
-}
-
-
-/* Copy a string, reporting a fatal error and exiting on failure. */
-static char *
-x_strdup(const char *s, const char *file, int line)
-{
- char *p;
- size_t len;
-
- len = strlen(s) + 1;
- p = malloc(len);
- if (!p)
- sysdie("failed to strdup %lu bytes at %s line %d",
- (unsigned long) len, file, line);
- memcpy(p, s, len);
- return p;
-}
-
-
-/* Given a struct timeval, return the number of seconds it represents as a
- double. Use difftime() to convert a time_t to a double. */
-static double
-tv_seconds(const struct timeval *tv)
-{
- return difftime(tv->tv_sec, 0) + tv->tv_usec * 1e-6;
-}
-
-/* Given two struct timevals, return the difference in seconds. */
-static double
-tv_diff(const struct timeval *tv1, const struct timeval *tv0)
-{
- return tv_seconds(tv1) - tv_seconds(tv0);
-}
-
-/* Given two struct timevals, return the sum in seconds as a double. */
-static double
-tv_sum(const struct timeval *tv1, const struct timeval *tv2)
-{
- return tv_seconds(tv1) + tv_seconds(tv2);
-}
-
-
-/* Read the first line of test output, which should contain the range of
- test numbers, and initialize the testset structure. Assume it was zeroed
- before being passed in. Return true if initialization succeeds, false
- otherwise. */
-static int
-test_init(const char *line, struct testset *ts)
-{
- int i;
-
- /* Prefer a simple number of tests, but if the count is given as a range
- such as 1..10, accept that too for compatibility with Perl's
- Test::Harness. */
- while (isspace((unsigned char)(*line))) line++;
- if (!strncmp(line, "1..", 3)) line += 3;
-
- /* Get the count, check it for validity, and initialize the struct. */
- i = atoi(line);
- if (i <= 0) {
- puts("invalid test count");
- ts->aborted = 1;
- ts->reported = 1;
- return 0;
- }
- ts->count = i;
- ts->results = xmalloc(ts->count * sizeof(enum test_status));
- for (i = 0; i < ts->count; i++) ts->results[i] = TEST_INVALID;
- return 1;
-}
-
-
-/* Start a program, connecting its stdout to a pipe on our end and its
- stderr to /dev/null, and storing the file descriptor to read from in the
- two argument. Returns the PID of the new process. Errors are fatal. */
-static pid_t
-test_start(const char *path, int *fd)
-{
- int fds[2], errfd;
- pid_t child;
-
- if (pipe(fds) == -1) sysdie("can't create pipe");
- child = fork();
- if (child == (pid_t) -1) {
- sysdie("can't fork");
- } else if (child == 0) {
- /* In child. Set up our stdout and stderr. */
- errfd = open("/dev/null", O_WRONLY);
- if (errfd < 0) _exit(CHILDERR_STDERR);
- if (dup2(errfd, 2) == -1) _exit(CHILDERR_DUP);
- close(fds[0]);
- if (dup2(fds[1], 1) == -1) _exit(CHILDERR_DUP);
-
- /* Now, exec our process. */
- if (execl(path, path, (char *) 0) == -1) _exit(CHILDERR_EXEC);
- } else {
- /* In parent. Close the extra file descriptor. */
- close(fds[1]);
- }
- *fd = fds[0];
- return child;
-}
-
-
-/* Given a single line of output from a test, parse it and return the
- success status of that test. Anything printed to stdout not matching the
- form /^(not )?ok \d+/ is ignored. Sets ts->current to the test number
- that just reported status. */
-static void
-test_checkline(const char *line, struct testset *ts)
-{
- enum test_status status = TEST_PASS;
- int current;
-
- /* If the given line isn't newline-terminated, it was too big for an
- fgets(), which means ignore it. */
- if (line[strlen(line) - 1] != '\n') return;
-
- /* Parse the line, ignoring something we can't parse. */
- if (!strncmp(line, "not ", 4)) {
- status = TEST_FAIL;
- line += 4;
- }
- if (strncmp(line, "ok ", 3)) return;
- line += 3;
- current = atoi(line);
- if (current == 0) return;
- if (current < 0 || current > ts->count) {
- printf("invalid test number %d\n", current);
- ts->aborted = 1;
- ts->reported = 1;
- return;
- }
- while (isspace((unsigned char)(*line))) line++;
- while (isdigit((unsigned char)(*line))) line++;
- while (isspace((unsigned char)(*line))) line++;
- if (*line == '#') {
- line++;
- while (isspace((unsigned char)(*line))) line++;
- if (!strncmp(line, "skip", 4)) status = TEST_SKIP;
- }
-
- /* Make sure that the test number is in range and not a duplicate. */
- if (ts->results[current - 1] != TEST_INVALID) {
- printf("duplicate test number %d\n", current);
- ts->aborted = 1;
- ts->reported = 1;
- return;
- }
-
- /* Good results. Increment our various counters. */
- switch (status) {
- case TEST_PASS: ts->passed++; break;
- case TEST_FAIL: ts->failed++; break;
- case TEST_SKIP: ts->skipped++; break;
- default: break;
- }
- ts->current = current;
- ts->results[current - 1] = status;
-}
-
-
-/* Print out a range of test numbers, returning the number of characters it
- took up. Add a comma and a space before the range if chars indicates
- that something has already been printed on the line, and print
- ... instead if chars plus the space needed would go over the limit (use a
- limit of 0 to disable this. */
-static int
-test_print_range(int first, int last, int chars, int limit)
-{
- int needed = 0;
- int out = 0;
- int n;
-
- if (chars > 0) {
- needed += 2;
- if (!limit || chars <= limit) out += printf(", ");
- }
- for (n = first; n > 0; n /= 10)
- needed++;
- if (last > first) {
- for (n = last; n > 0; n /= 10)
- needed++;
- needed++;
- }
- if (limit && chars + needed > limit) {
- if (chars <= limit) out += printf("...");
- } else {
- if (last > first) out += printf("%d-", first);
- out += printf("%d", last);
- }
- return out;
-}
-
-
-/* Summarize a single test set. The second argument is 0 if the set exited
- cleanly, a positive integer representing the exit status if it exited
- with a non-zero status, and a negative integer representing the signal
- that terminated it if it was killed by a signal. */
-static void
-test_summarize(struct testset *ts, int status)
-{
- int i;
- int missing = 0;
- int failed = 0;
- int first = 0;
- int last = 0;
-
- if (ts->aborted) {
- fputs("aborted", stdout);
- if (ts->count > 0)
- printf(", passed %d/%d", ts->passed, ts->count - ts->skipped);
- } else {
- for (i = 0; i < ts->count; i++) {
- if (ts->results[i] == TEST_INVALID) {
- if (missing == 0) fputs("MISSED ", stdout);
- if (first && i == last) {
- last = i + 1;
- } else {
- if (first) {
- test_print_range(first, last, missing - 1, 0);
- }
- missing++;
- first = i + 1;
- last = i + 1;
- }
- }
- }
- if (first) test_print_range(first, last, missing - 1, 0);
- first = 0;
- last = 0;
- for (i = 0; i < ts->count; i++) {
- if (ts->results[i] == TEST_FAIL) {
- if (missing && !failed) fputs("; ", stdout);
- if (failed == 0) fputs("FAILED ", stdout);
- if (first && i == last) {
- last = i + 1;
- } else {
- if (first) {
- test_print_range(first, last, failed - 1, 0);
- }
- failed++;
- first = i + 1;
- last = i + 1;
- }
- }
- }
- if (first) test_print_range(first, last, failed - 1, 0);
- if (!missing && !failed) {
- fputs(!status ? "ok" : "dubious", stdout);
- if (ts->skipped > 0) printf(" (skipped %d tests)", ts->skipped);
- }
- }
- if (status > 0) {
- printf(" (exit status %d)", status);
- } else if (status < 0) {
- printf(" (killed by signal %d%s)", -status,
- WCOREDUMP(ts->status) ? ", core dumped" : "");
- }
- putchar('\n');
-}
-
-
-/* Given a test set, analyze the results, classify the exit status, handle a
- few special error messages, and then pass it along to test_summarize()
- for the regular output. */
-static int
-test_analyze(struct testset *ts)
-{
- if (ts->reported) return 0;
- if (WIFEXITED(ts->status) && WEXITSTATUS(ts->status) != 0) {
- switch (WEXITSTATUS(ts->status)) {
- case CHILDERR_DUP:
- if (!ts->reported) puts("can't dup file descriptors");
- break;
- case CHILDERR_EXEC:
- if (!ts->reported) puts("execution failed (not found?)");
- break;
- case CHILDERR_STDERR:
- if (!ts->reported) puts("can't open /dev/null");
- break;
- default:
- test_summarize(ts, WEXITSTATUS(ts->status));
- break;
- }
- return 0;
- } else if (WIFSIGNALED(ts->status)) {
- test_summarize(ts, -WTERMSIG(ts->status));
- return 0;
- } else {
- test_summarize(ts, 0);
- return (ts->failed == 0);
- }
-}
-
-
-/* Runs a single test set, accumulating and then reporting the results.
- Returns true if the test set was successfully run and all tests passed,
- false otherwise. */
-static int
-test_run(struct testset *ts)
-{
- pid_t testpid, child;
- int outfd, i, status;
- FILE *output;
- char buffer[BUFSIZ];
- char *file;
-
- /* Initialize the test and our data structures, flagging this set in
- error if the initialization fails. */
- file = xmalloc(strlen(ts->file) + 3);
- strcpy(file, ts->file);
- strcat(file, ".t");
- testpid = test_start(file, &outfd);
- free(file);
- output = fdopen(outfd, "r");
- if (!output) sysdie("fdopen failed");
- if (!fgets(buffer, sizeof(buffer), output)) ts->aborted = 1;
- if (!ts->aborted && !test_init(buffer, ts)) {
- while (fgets(buffer, sizeof(buffer), output))
- ;
- ts->aborted = 1;
- }
-
- /* Pass each line of output to test_checkline(). */
- while (!ts->aborted && fgets(buffer, sizeof(buffer), output))
- test_checkline(buffer, ts);
- if (ferror(output)) ts->aborted = 1;
-
- /* Close the output descriptor, retrieve the exit status, and pass that
- information to test_analyze() for eventual output. */
- fclose(output);
- child = waitpid(testpid, &ts->status, 0);
- if (child == (pid_t) -1)
- sysdie("waitpid for %u failed", (unsigned int) testpid);
- status = test_analyze(ts);
-
- /* Convert missing tests to failed tests. */
- for (i = 0; i < ts->count; i++) {
- if (ts->results[i] == TEST_INVALID) {
- ts->failed++;
- ts->results[i] = TEST_FAIL;
- status = 0;
- }
- }
- return status;
-}
-
-
-/* Summarize a list of test failures. */
-static void
-test_fail_summary(const struct testlist *fails)
-{
- struct testset *ts;
- int i, chars, total, first, last;
-
- puts(header);
-
- /* Failed Set Fail/Total (%) Skip Stat Failing (25)
- -------------------------- -------------- ---- ---- -------------- */
- for (; fails; fails = fails->next) {
- ts = fails->ts;
- total = ts->count - ts->skipped;
- printf("%-26.26s %4d/%-4d %3.0f%% %4d ", ts->file, ts->failed,
- total, total ? (ts->failed * 100.0) / total : 0,
- ts->skipped);
- if (WIFEXITED(ts->status)) {
- printf("%4d ", WEXITSTATUS(ts->status));
- } else {
- printf(" -- ");
- }
- if (ts->aborted) {
- puts("aborted");
- continue;
- }
- chars = 0;
- first = 0;
- last = 0;
- for (i = 0; i < ts->count; i++) {
- if (ts->results[i] == TEST_FAIL) {
- if (first && i == last) {
- last = i + 1;
- } else {
- if (first)
- chars += test_print_range(first, last, chars, 20);
- first = i + 1;
- last = i + 1;
- }
- }
- }
- if (first) test_print_range(first, last, chars, 20);
- putchar('\n');
- }
-}
-
-
-/* Run a batch of tests from a given file listing each test on a line by
- itself. The file must be rewindable. Returns true iff all tests
- passed. */
-static int
-test_batch(const char *testlist)
-{
- FILE *tests;
- size_t length, i;
- size_t longest = 0;
- char buffer[BUFSIZ];
- int line;
- struct testset ts, *tmp;
- struct timeval start, end;
- struct rusage stats;
- struct testlist *failhead = 0;
- struct testlist *failtail = 0;
- int total = 0;
- int passed = 0;
- int skipped = 0;
- int failed = 0;
- int aborted = 0;
-
- /* Open our file of tests to run and scan it, checking for lines that
- are too long and searching for the longest line. */
- tests = fopen(testlist, "r");
- if (!tests) sysdie("can't open %s", testlist);
- line = 0;
- while (fgets(buffer, sizeof(buffer), tests)) {
- line++;
- length = strlen(buffer) - 1;
- if (buffer[length] != '\n') {
- fprintf(stderr, "%s:%d: line too long\n", testlist, line);
- exit(1);
- }
- if (length > longest) longest = length;
- }
- if (fseek(tests, 0, SEEK_SET) == -1)
- sysdie("can't rewind %s", testlist);
-
- /* Add two to longest and round up to the nearest tab stop. This is how
- wide the column for printing the current test name will be. */
- longest += 2;
- if (longest % 8) longest += 8 - (longest % 8);
-
- /* Start the wall clock timer. */
- gettimeofday(&start, NULL);
-
- /* Now, plow through our tests again, running each one. Check line
- length again out of paranoia. */
- line = 0;
- while (fgets(buffer, sizeof(buffer), tests)) {
- line++;
- length = strlen(buffer) - 1;
- if (buffer[length] != '\n') {
- fprintf(stderr, "%s:%d: line too long\n", testlist, line);
- exit(1);
- }
- buffer[length] = '\0';
- fputs(buffer, stdout);
- for (i = length; i < longest; i++) putchar('.');
- memset(&ts, 0, sizeof(ts));
- ts.file = xstrdup(buffer);
- if (!test_run(&ts)) {
- tmp = xmalloc(sizeof(struct testset));
- memcpy(tmp, &ts, sizeof(struct testset));
- if (!failhead) {
- failhead = xmalloc(sizeof(struct testset));
- failhead->ts = tmp;
- failhead->next = 0;
- failtail = failhead;
- } else {
- failtail->next = xmalloc(sizeof(struct testset));
- failtail = failtail->next;
- failtail->ts = tmp;
- failtail->next = 0;
- }
- }
- aborted += ts.aborted;
- total += ts.count;
- passed += ts.passed;
- skipped += ts.skipped;
- failed += ts.failed;
- }
- total -= skipped;
-
- /* Stop the timer and get our child resource statistics. */
- gettimeofday(&end, NULL);
- getrusage(RUSAGE_CHILDREN, &stats);
-
- /* Print out our final results. */
- if (failhead) test_fail_summary(failhead);
- putchar('\n');
- if (aborted) {
- printf("Aborted %d test sets, passed %d/%d tests.\n", aborted,
- passed, total);
- } else if (failed == 0) {
- fputs("All tests successful", stdout);
- if (skipped) printf(", %d tests skipped", skipped);
- puts(".");
- } else {
- printf("Failed %d/%d tests, %.2f%% okay.\n", failed, total,
- (total - failed) * 100.0 / total);
- }
- printf("Files=%d, Tests=%d", line, total);
- printf(", %.2f seconds", tv_diff(&end, &start));
- printf(" (%.2f usr + %.2f sys = %.2f CPU)\n",
- tv_seconds(&stats.ru_utime), tv_seconds(&stats.ru_stime),
- tv_sum(&stats.ru_utime, &stats.ru_stime));
- return !(failed || aborted);
-}
-
-
-/* Main routine. Given a file listing tests, run each test listed. */
-int
-main(int argc, char *argv[])
-{
- if (argc != 2) {
- fprintf(stderr, "Usage: runtests <test-list>\n");
- exit(1);
- }
- printf(banner, argv[1]);
- exit(test_batch(argv[1]) ? 0 : 1);
-}
+++ /dev/null
-#! /bin/sh
-# $Id: convdate.t 5754 2002-09-09 00:48:21Z rra $
-#
-# Test suite for convdate.
-
-# The count starts at 1 and is updated each time ok is printed. printcount
-# takes "ok" or "not ok".
-count=1
-printcount () {
- echo "$1 $count $2"
- count=`expr $count + 1`
-}
-
-# Given the output from convdate and the expected output, compare them.
-compare () {
- status=$?
- if [ $status = 0 ] && [ "$1" = "$2" ] ; then
- printcount "ok"
- else
- echo " $1"
- echo " $2"
- printcount "not ok"
- fi
-}
-
-# Find convdate.
-convdate=false
-for file in ../expire/convdate ../../expire/convdate expire/convdate ; do
- [ -x $file ] && convdate=$file
-done
-if [ $convdate = "false" ] ; then
- echo "Could not find convdate" >&2
- exit 1
-fi
-
-# Print out the count of tests.
-echo 7
-
-# Run our tests. These are all from the man page, but with time zones
-# added.
-TZ=EST5EDT; export TZ
-compare "`$convdate 'feb 10, 1991 10am EST'`" 'Sun Feb 10 10:00:00 1991'
-compare "`$convdate '12pm EST 12/13/91' '12am EDT 5/4/90'`" \
- 'Fri Dec 13 12:00:00 1991
-Fri May 4 00:00:00 1990'
-compare "`$convdate -n 'feb 10, 1991 10am-0500' '12am-0400 5/5/90'`" \
- '666198000
-641880000'
-compare "`$convdate -c 666198000`" 'Sun Feb 10 10:00:00 1991'
-compare "`$convdate -dc 666198000`" 'Sun, 10 Feb 1991 15:00:00 +0000 (UTC)'
-compare "`env TZ=PST8PDT $convdate -dlc 666198000`" \
- 'Sun, 10 Feb 1991 07:00:00 -0800 (PST)'
-compare "`env TZ=EST5EDT $convdate -dlc 666198000`" \
- 'Sun, 10 Feb 1991 10:00:00 -0500 (EST)'